Compare commits
3 Commits
c5e4ec293e
...
441ee1677e
Author | SHA1 | Date |
---|---|---|
Tom Lane | 441ee1677e | |
Tom Lane | fce3b26e97 | |
Peter Eisentraut | 5a8366ad75 |
|
@ -330,21 +330,21 @@ F843 POSITION_REGEX function NO consider regexp_instr()
|
|||
F844 SUBSTRING_REGEX function NO consider regexp_substr()
|
||||
F845 TRANSLATE_REGEX function NO consider regexp_replace()
|
||||
F846 Octet support in regular expression operators NO
|
||||
F847 Nonconstant regular expressions NO
|
||||
F850 Top-level <order by clause> in <query expression> YES
|
||||
F851 <order by clause> in subqueries YES
|
||||
F852 Top-level <order by clause> in views YES
|
||||
F855 Nested <order by clause> in <query expression> YES
|
||||
F856 Nested <fetch first clause> in <query expression> YES
|
||||
F857 Top-level <fetch first clause> in <query expression> YES
|
||||
F858 <fetch first clause> in subqueries YES
|
||||
F859 Top-level <fetch first clause> in views YES
|
||||
F847 Non-constant regular expressions NO
|
||||
F850 Top-level ORDER BY in query expression YES
|
||||
F851 ORDER BY in subqueries YES
|
||||
F852 Top-level ORDER BY in views YES
|
||||
F855 Nested ORDER BY in query expression YES
|
||||
F856 Nested FETCH FIRST in query expression YES
|
||||
F857 Top-level FETCH FIRST in query expression YES
|
||||
F858 FETCH FIRST in subqueries YES
|
||||
F859 Top-level FETCH FIRST in views YES
|
||||
F860 Dynamic FETCH FIRST row count YES
|
||||
F861 Top-level <result offset clause> in <query expression> YES
|
||||
F862 <result offset clause> in subqueries YES
|
||||
F863 Nested <result offset clause> in <query expression> YES
|
||||
F864 Top-level <result offset clause> in views YES
|
||||
F865 <offset row count> in <result offset clause> YES
|
||||
F861 Top-level OFFSET in query expression YES
|
||||
F862 OFFSET in subqueries YES
|
||||
F863 Nested OFFSET in query expression YES
|
||||
F864 Top-level OFFSET in views YES
|
||||
F865 Dynamic offset row count in OFFSET YES
|
||||
F866 FETCH FIRST clause: PERCENT option NO
|
||||
F867 FETCH FIRST clause: WITH TIES option YES
|
||||
F868 ORDER BY in grouped table YES
|
||||
|
@ -419,7 +419,7 @@ T046 CLOB data type NO
|
|||
T047 POSITION, OCTET_LENGTH, TRIM, and SUBSTRING for BLOBs NO
|
||||
T048 Concatenation of BLOBs NO
|
||||
T049 BLOB locator: non-holdable NO
|
||||
T050 POSITION, CHAR_LENGTH, OCTET_LENGTH, LOWER, TRIM, UPPER, and SUBSTRING CLOBs NO
|
||||
T050 POSITION, CHAR_LENGTH, OCTET_LENGTH, LOWER, TRIM, UPPER, and SUBSTRING for CLOBs NO
|
||||
T051 Row types NO
|
||||
T053 Explicit aliases for all-fields reference NO
|
||||
T054 GREATEST and LEAST YES different null handling
|
||||
|
@ -487,11 +487,11 @@ T325 Qualified SQL parameter references YES
|
|||
T326 Table functions NO
|
||||
T331 Basic roles YES
|
||||
T332 Extended roles YES
|
||||
T341 Overloading of SQL-invoked functions and procedures YES
|
||||
T351 Bracketed SQL comments (/*...*/ comments) YES
|
||||
T341 Overloading of SQL-invoked functions and SQL-invoked procedures YES
|
||||
T351 Bracketed comments YES
|
||||
T431 Extended grouping capabilities YES
|
||||
T432 Nested and concatenated GROUPING SETS YES
|
||||
T433 Multiargument GROUPING function YES
|
||||
T433 Multi-argument GROUPING function YES
|
||||
T434 GROUP BY DISTINCT YES
|
||||
T441 ABS and MOD functions YES
|
||||
T461 Symmetric BETWEEN predicate YES
|
||||
|
@ -703,8 +703,8 @@ X152 IS VALID predicate: with CONTENT option NO
|
|||
X153 IS VALID predicate: with SEQUENCE option NO
|
||||
X155 IS VALID predicate: NAMESPACE without ELEMENT clause NO
|
||||
X157 IS VALID predicate: NO NAMESPACE with ELEMENT clause NO
|
||||
X160 Basic Information Schema for registered XML Schemas NO
|
||||
X161 Advanced Information Schema for registered XML Schemas NO
|
||||
X160 Basic Information Schema for registered XML schemas NO
|
||||
X161 Advanced Information Schema for registered XML schemas NO
|
||||
X170 XML null handling options NO
|
||||
X171 NIL ON NO CONTENT option NO
|
||||
X181 XML(DOCUMENT(UNTYPED)) type NO
|
||||
|
|
|
@ -4341,15 +4341,40 @@ ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup
|
|||
}
|
||||
|
||||
/*
|
||||
* Ensure that the current transition value is a child of the aggcontext,
|
||||
* rather than the per-tuple context.
|
||||
* Ensure that the new transition value is stored in the aggcontext,
|
||||
* rather than the per-tuple context. This should be invoked only when
|
||||
* we know (a) the transition data type is pass-by-reference, and (b)
|
||||
* the newValue is distinct from the oldValue.
|
||||
*
|
||||
* NB: This can change the current memory context.
|
||||
*
|
||||
* We copy the presented newValue into the aggcontext, except when the datum
|
||||
* points to a R/W expanded object that is already a child of the aggcontext,
|
||||
* in which case we need not copy. We then delete the oldValue, if not null.
|
||||
*
|
||||
* If the presented datum points to a R/W expanded object that is a child of
|
||||
* some other context, ideally we would just reparent it under the aggcontext.
|
||||
* Unfortunately, that doesn't work easily, and it wouldn't help anyway for
|
||||
* aggregate-aware transfns. We expect that a transfn that deals in expanded
|
||||
* objects and is aware of the memory management conventions for aggregate
|
||||
* transition values will (1) on first call, return a R/W expanded object that
|
||||
* is already in the right context, allowing us to do nothing here, and (2) on
|
||||
* subsequent calls, modify and return that same object, so that control
|
||||
* doesn't even reach here. However, if we have a generic transfn that
|
||||
* returns a new R/W expanded object (probably in the per-tuple context),
|
||||
* reparenting that result would cause problems. We'd pass that R/W object to
|
||||
* the next invocation of the transfn, and then it would be at liberty to
|
||||
* change or delete that object, and if it deletes it then our own attempt to
|
||||
* delete the now-old transvalue afterwards would be a double free. We avoid
|
||||
* this problem by forcing the stored transvalue to always be a flat
|
||||
* non-expanded object unless the transfn is visibly doing aggregate-aware
|
||||
* memory management. This is somewhat inefficient, but the best answer to
|
||||
* that is to write a smarter transfn.
|
||||
*/
|
||||
Datum
|
||||
ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans,
|
||||
Datum newValue, bool newValueIsNull,
|
||||
Datum oldValue, bool oldValueIsNull)
|
||||
ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
|
||||
Datum newValue, bool newValueIsNull,
|
||||
Datum oldValue, bool oldValueIsNull)
|
||||
{
|
||||
Assert(newValue != oldValue);
|
||||
|
||||
|
@ -4559,12 +4584,10 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
|
|||
/*
|
||||
* For pass-by-ref datatype, must copy the new value into aggcontext and
|
||||
* free the prior transValue. But if transfn returned a pointer to its
|
||||
* first input, we don't need to do anything. Also, if transfn returned a
|
||||
* pointer to a R/W expanded object that is already a child of the
|
||||
* aggcontext, assume we can adopt that value without copying it.
|
||||
* first input, we don't need to do anything.
|
||||
*
|
||||
* It's safe to compare newVal with pergroup->transValue without regard
|
||||
* for either being NULL, because ExecAggTransReparent() takes care to set
|
||||
* for either being NULL, because ExecAggCopyTransValue takes care to set
|
||||
* transValue to 0 when NULL. Otherwise we could end up accidentally not
|
||||
* reparenting, when the transValue has the same numerical value as
|
||||
* newValue, despite being NULL. This is a somewhat hot path, making it
|
||||
|
@ -4573,10 +4596,10 @@ ExecAggPlainTransByRef(AggState *aggstate, AggStatePerTrans pertrans,
|
|||
* argument.
|
||||
*/
|
||||
if (DatumGetPointer(newVal) != DatumGetPointer(pergroup->transValue))
|
||||
newVal = ExecAggTransReparent(aggstate, pertrans,
|
||||
newVal, fcinfo->isnull,
|
||||
pergroup->transValue,
|
||||
pergroup->transValueIsNull);
|
||||
newVal = ExecAggCopyTransValue(aggstate, pertrans,
|
||||
newVal, fcinfo->isnull,
|
||||
pergroup->transValue,
|
||||
pergroup->transValueIsNull);
|
||||
|
||||
pergroup->transValue = newVal;
|
||||
pergroup->transValueIsNull = fcinfo->isnull;
|
||||
|
|
|
@ -778,12 +778,10 @@ advance_transition_function(AggState *aggstate,
|
|||
/*
|
||||
* If pass-by-ref datatype, must copy the new value into aggcontext and
|
||||
* free the prior transValue. But if transfn returned a pointer to its
|
||||
* first input, we don't need to do anything. Also, if transfn returned a
|
||||
* pointer to a R/W expanded object that is already a child of the
|
||||
* aggcontext, assume we can adopt that value without copying it.
|
||||
* first input, we don't need to do anything.
|
||||
*
|
||||
* It's safe to compare newVal with pergroup->transValue without regard
|
||||
* for either being NULL, because ExecAggTransReparent() takes care to set
|
||||
* for either being NULL, because ExecAggCopyTransValue takes care to set
|
||||
* transValue to 0 when NULL. Otherwise we could end up accidentally not
|
||||
* reparenting, when the transValue has the same numerical value as
|
||||
* newValue, despite being NULL. This is a somewhat hot path, making it
|
||||
|
@ -793,10 +791,10 @@ advance_transition_function(AggState *aggstate,
|
|||
*/
|
||||
if (!pertrans->transtypeByVal &&
|
||||
DatumGetPointer(newVal) != DatumGetPointer(pergroupstate->transValue))
|
||||
newVal = ExecAggTransReparent(aggstate, pertrans,
|
||||
newVal, fcinfo->isnull,
|
||||
pergroupstate->transValue,
|
||||
pergroupstate->transValueIsNull);
|
||||
newVal = ExecAggCopyTransValue(aggstate, pertrans,
|
||||
newVal, fcinfo->isnull,
|
||||
pergroupstate->transValue,
|
||||
pergroupstate->transValueIsNull);
|
||||
|
||||
pergroupstate->transValue = newVal;
|
||||
pergroupstate->transValueIsNull = fcinfo->isnull;
|
||||
|
|
|
@ -368,7 +368,8 @@ advance_windowaggregate(WindowAggState *winstate,
|
|||
* free the prior transValue. But if transfn returned a pointer to its
|
||||
* first input, we don't need to do anything. Also, if transfn returned a
|
||||
* pointer to a R/W expanded object that is already a child of the
|
||||
* aggcontext, assume we can adopt that value without copying it.
|
||||
* aggcontext, assume we can adopt that value without copying it. (See
|
||||
* comments for ExecAggCopyTransValue, which this code duplicates.)
|
||||
*/
|
||||
if (!peraggstate->transtypeByVal &&
|
||||
DatumGetPointer(newVal) != DatumGetPointer(peraggstate->transValue))
|
||||
|
@ -533,7 +534,8 @@ advance_windowaggregate_base(WindowAggState *winstate,
|
|||
* free the prior transValue. But if invtransfn returned a pointer to its
|
||||
* first input, we don't need to do anything. Also, if invtransfn
|
||||
* returned a pointer to a R/W expanded object that is already a child of
|
||||
* the aggcontext, assume we can adopt that value without copying it.
|
||||
* the aggcontext, assume we can adopt that value without copying it. (See
|
||||
* comments for ExecAggCopyTransValue, which this code duplicates.)
|
||||
*
|
||||
* Note: the checks for null values here will never fire, but it seems
|
||||
* best to have this stanza look just like advance_windowaggregate.
|
||||
|
|
|
@ -2314,7 +2314,7 @@ llvm_compile_expr(ExprState *state)
|
|||
params[5] = LLVMBuildTrunc(b, v_transnull,
|
||||
TypeParamBool, "");
|
||||
|
||||
v_fn = llvm_pg_func(mod, "ExecAggTransReparent");
|
||||
v_fn = llvm_pg_func(mod, "ExecAggCopyTransValue");
|
||||
v_newval =
|
||||
LLVMBuildCall(b, v_fn,
|
||||
params, lengthof(params),
|
||||
|
|
|
@ -102,7 +102,7 @@ FunctionReturningBool(void)
|
|||
void *referenced_functions[] =
|
||||
{
|
||||
ExecAggInitGroup,
|
||||
ExecAggTransReparent,
|
||||
ExecAggCopyTransValue,
|
||||
ExecEvalPreOrderedDistinctSingle,
|
||||
ExecEvalPreOrderedDistinctMulti,
|
||||
ExecEvalAggOrderedTransDatum,
|
||||
|
|
|
@ -807,9 +807,9 @@ extern void ExecEvalSysVar(ExprState *state, ExprEvalStep *op,
|
|||
|
||||
extern void ExecAggInitGroup(AggState *aggstate, AggStatePerTrans pertrans, AggStatePerGroup pergroup,
|
||||
ExprContext *aggcontext);
|
||||
extern Datum ExecAggTransReparent(AggState *aggstate, AggStatePerTrans pertrans,
|
||||
Datum newValue, bool newValueIsNull,
|
||||
Datum oldValue, bool oldValueIsNull);
|
||||
extern Datum ExecAggCopyTransValue(AggState *aggstate, AggStatePerTrans pertrans,
|
||||
Datum newValue, bool newValueIsNull,
|
||||
Datum oldValue, bool oldValueIsNull);
|
||||
extern bool ExecEvalPreOrderedDistinctSingle(AggState *aggstate,
|
||||
AggStatePerTrans pertrans);
|
||||
extern bool ExecEvalPreOrderedDistinctMulti(AggState *aggstate,
|
||||
|
|
|
@ -136,18 +136,22 @@ static ResourceOwner shared_simple_eval_resowner = NULL;
|
|||
MemoryContextAllocZero(get_eval_mcontext(estate), sz)
|
||||
|
||||
/*
|
||||
* We use a session-wide hash table for caching cast information.
|
||||
* We use two session-wide hash tables for caching cast information.
|
||||
*
|
||||
* Once built, the compiled expression trees (cast_expr fields) survive for
|
||||
* the life of the session. At some point it might be worth invalidating
|
||||
* those after pg_cast changes, but for the moment we don't bother.
|
||||
* cast_expr_hash entries (of type plpgsql_CastExprHashEntry) hold compiled
|
||||
* expression trees for casts. These survive for the life of the session and
|
||||
* are shared across all PL/pgSQL functions and DO blocks. At some point it
|
||||
* might be worth invalidating them after pg_cast changes, but for the moment
|
||||
* we don't bother.
|
||||
*
|
||||
* The evaluation state trees (cast_exprstate) are managed in the same way as
|
||||
* simple expressions (i.e., we assume cast expressions are always simple).
|
||||
* There is a separate hash table shared_cast_hash (with entries of type
|
||||
* plpgsql_CastHashEntry) containing evaluation state trees for these
|
||||
* expressions, which are managed in the same way as simple expressions
|
||||
* (i.e., we assume cast expressions are always simple).
|
||||
*
|
||||
* As with simple expressions, DO blocks don't use the shared hash table but
|
||||
* must have their own. This isn't ideal, but we don't want to deal with
|
||||
* multiple simple_eval_estates within a DO block.
|
||||
* As with simple expressions, DO blocks don't use the shared_cast_hash table
|
||||
* but must have their own evaluation state trees. This isn't ideal, but we
|
||||
* don't want to deal with multiple simple_eval_estates within a DO block.
|
||||
*/
|
||||
typedef struct /* lookup key for cast info */
|
||||
{
|
||||
|
@ -158,18 +162,24 @@ typedef struct /* lookup key for cast info */
|
|||
int32 dsttypmod; /* destination typmod for cast */
|
||||
} plpgsql_CastHashKey;
|
||||
|
||||
typedef struct /* cast_hash table entry */
|
||||
typedef struct /* cast_expr_hash table entry */
|
||||
{
|
||||
plpgsql_CastHashKey key; /* hash key --- MUST BE FIRST */
|
||||
Expr *cast_expr; /* cast expression, or NULL if no-op cast */
|
||||
CachedExpression *cast_cexpr; /* cached expression backing the above */
|
||||
} plpgsql_CastExprHashEntry;
|
||||
|
||||
typedef struct /* cast_hash table entry */
|
||||
{
|
||||
plpgsql_CastHashKey key; /* hash key --- MUST BE FIRST */
|
||||
plpgsql_CastExprHashEntry *cast_centry; /* link to matching expr entry */
|
||||
/* ExprState is valid only when cast_lxid matches current LXID */
|
||||
ExprState *cast_exprstate; /* expression's eval tree */
|
||||
bool cast_in_use; /* true while we're executing eval tree */
|
||||
LocalTransactionId cast_lxid;
|
||||
} plpgsql_CastHashEntry;
|
||||
|
||||
static MemoryContext shared_cast_context = NULL;
|
||||
static HTAB *cast_expr_hash = NULL;
|
||||
static HTAB *shared_cast_hash = NULL;
|
||||
|
||||
/*
|
||||
|
@ -4025,6 +4035,17 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
|
|||
estate->paramLI->parserSetupArg = NULL; /* filled during use */
|
||||
estate->paramLI->numParams = estate->ndatums;
|
||||
|
||||
/* Create the session-wide cast-expression hash if we didn't already */
|
||||
if (cast_expr_hash == NULL)
|
||||
{
|
||||
ctl.keysize = sizeof(plpgsql_CastHashKey);
|
||||
ctl.entrysize = sizeof(plpgsql_CastExprHashEntry);
|
||||
cast_expr_hash = hash_create("PLpgSQL cast expressions",
|
||||
16, /* start small and extend */
|
||||
&ctl,
|
||||
HASH_ELEM | HASH_BLOBS);
|
||||
}
|
||||
|
||||
/* set up for use of appropriate simple-expression EState and cast hash */
|
||||
if (simple_eval_estate)
|
||||
{
|
||||
|
@ -4037,7 +4058,6 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
|
|||
16, /* start small and extend */
|
||||
&ctl,
|
||||
HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
|
||||
estate->cast_hash_context = CurrentMemoryContext;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -4045,19 +4065,14 @@ plpgsql_estate_setup(PLpgSQL_execstate *estate,
|
|||
/* Create the session-wide cast-info hash table if we didn't already */
|
||||
if (shared_cast_hash == NULL)
|
||||
{
|
||||
shared_cast_context = AllocSetContextCreate(TopMemoryContext,
|
||||
"PLpgSQL cast info",
|
||||
ALLOCSET_DEFAULT_SIZES);
|
||||
ctl.keysize = sizeof(plpgsql_CastHashKey);
|
||||
ctl.entrysize = sizeof(plpgsql_CastHashEntry);
|
||||
ctl.hcxt = shared_cast_context;
|
||||
shared_cast_hash = hash_create("PLpgSQL cast cache",
|
||||
16, /* start small and extend */
|
||||
&ctl,
|
||||
HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);
|
||||
HASH_ELEM | HASH_BLOBS);
|
||||
}
|
||||
estate->cast_hash = shared_cast_hash;
|
||||
estate->cast_hash_context = shared_cast_context;
|
||||
}
|
||||
/* likewise for the simple-expression resource owner */
|
||||
if (simple_eval_resowner)
|
||||
|
@ -7768,6 +7783,7 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
|
|||
{
|
||||
plpgsql_CastHashKey cast_key;
|
||||
plpgsql_CastHashEntry *cast_entry;
|
||||
plpgsql_CastExprHashEntry *expr_entry;
|
||||
bool found;
|
||||
LocalTransactionId curlxid;
|
||||
MemoryContext oldcontext;
|
||||
|
@ -7781,10 +7797,28 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
|
|||
&cast_key,
|
||||
HASH_ENTER, &found);
|
||||
if (!found) /* initialize if new entry */
|
||||
cast_entry->cast_cexpr = NULL;
|
||||
{
|
||||
/* We need a second lookup to see if a cast_expr_hash entry exists */
|
||||
expr_entry = (plpgsql_CastExprHashEntry *) hash_search(cast_expr_hash,
|
||||
&cast_key,
|
||||
HASH_ENTER,
|
||||
&found);
|
||||
if (!found) /* initialize if new expr entry */
|
||||
expr_entry->cast_cexpr = NULL;
|
||||
|
||||
if (cast_entry->cast_cexpr == NULL ||
|
||||
!cast_entry->cast_cexpr->is_valid)
|
||||
cast_entry->cast_centry = expr_entry;
|
||||
cast_entry->cast_exprstate = NULL;
|
||||
cast_entry->cast_in_use = false;
|
||||
cast_entry->cast_lxid = InvalidLocalTransactionId;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Use always-valid link to avoid a second hash lookup */
|
||||
expr_entry = cast_entry->cast_centry;
|
||||
}
|
||||
|
||||
if (expr_entry->cast_cexpr == NULL ||
|
||||
!expr_entry->cast_cexpr->is_valid)
|
||||
{
|
||||
/*
|
||||
* We've not looked up this coercion before, or we have but the cached
|
||||
|
@ -7797,10 +7831,10 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
|
|||
/*
|
||||
* Drop old cached expression if there is one.
|
||||
*/
|
||||
if (cast_entry->cast_cexpr)
|
||||
if (expr_entry->cast_cexpr)
|
||||
{
|
||||
FreeCachedExpression(cast_entry->cast_cexpr);
|
||||
cast_entry->cast_cexpr = NULL;
|
||||
FreeCachedExpression(expr_entry->cast_cexpr);
|
||||
expr_entry->cast_cexpr = NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -7881,9 +7915,11 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
|
|||
((RelabelType *) cast_expr)->arg == (Expr *) placeholder)
|
||||
cast_expr = NULL;
|
||||
|
||||
/* Now we can fill in the hashtable entry. */
|
||||
cast_entry->cast_cexpr = cast_cexpr;
|
||||
cast_entry->cast_expr = (Expr *) cast_expr;
|
||||
/* Now we can fill in the expression hashtable entry. */
|
||||
expr_entry->cast_cexpr = cast_cexpr;
|
||||
expr_entry->cast_expr = (Expr *) cast_expr;
|
||||
|
||||
/* Be sure to reset the exprstate hashtable entry, too. */
|
||||
cast_entry->cast_exprstate = NULL;
|
||||
cast_entry->cast_in_use = false;
|
||||
cast_entry->cast_lxid = InvalidLocalTransactionId;
|
||||
|
@ -7892,7 +7928,7 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
|
|||
}
|
||||
|
||||
/* Done if we have determined that this is a no-op cast. */
|
||||
if (cast_entry->cast_expr == NULL)
|
||||
if (expr_entry->cast_expr == NULL)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
|
@ -7911,7 +7947,7 @@ get_cast_hashentry(PLpgSQL_execstate *estate,
|
|||
if (cast_entry->cast_lxid != curlxid || cast_entry->cast_in_use)
|
||||
{
|
||||
oldcontext = MemoryContextSwitchTo(estate->simple_eval_estate->es_query_cxt);
|
||||
cast_entry->cast_exprstate = ExecInitExpr(cast_entry->cast_expr, NULL);
|
||||
cast_entry->cast_exprstate = ExecInitExpr(expr_entry->cast_expr, NULL);
|
||||
cast_entry->cast_in_use = false;
|
||||
cast_entry->cast_lxid = curlxid;
|
||||
MemoryContextSwitchTo(oldcontext);
|
||||
|
|
|
@ -1076,7 +1076,6 @@ typedef struct PLpgSQL_execstate
|
|||
|
||||
/* lookup table to use for executing type casts */
|
||||
HTAB *cast_hash;
|
||||
MemoryContext cast_hash_context;
|
||||
|
||||
/* memory context for statement-lifespan temporary values */
|
||||
MemoryContext stmt_mcontext; /* current stmt context, or NULL if none */
|
||||
|
|
Loading…
Reference in New Issue