git.postgresql.org Git - postgresql.git/commitdiff (original) (raw)

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 */

{

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;

/*

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)

+ {

+ memset(&ctl, 0, sizeof(ctl));

+ 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)

{

16, /* start small and extend */

&ctl,

HASH_ELEM | HASH_BLOBS | HASH_CONTEXT);

- estate->cast_hash_context = CurrentMemoryContext;

}

else

{

/* 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);

memset(&ctl, 0, sizeof(ctl));

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)

{

plpgsql_CastHashKey cast_key;

plpgsql_CastHashEntry *cast_entry;

+ plpgsql_CastExprHashEntry *expr_entry;

bool found;

LocalTransactionId curlxid;

MemoryContext oldcontext;

(void *) &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;

+ 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 (cast_entry->cast_cexpr == NULL ||

- !cast_entry->cast_cexpr->is_valid)

+ 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

/*

* 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;

}

/*

((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;

}

/* 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;

/*

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);

/* lookup table to use for executing type casts */

HTAB *cast_hash;

- MemoryContext cast_hash_context;

+ MemoryContext cast_hash_context; /* not used; now always NULL */

/* memory context for statement-lifespan temporary values */

MemoryContext stmt_mcontext; /* current stmt context, or NULL if none */