* RelationBuildPartitionKey
* Build and attach to relcache partition key data of relation
*
- * Partitioning key data is stored in CacheMemoryContext to ensure it survives
- * as long as the relcache. To avoid leaking memory in that context in case
- * of an error partway through this function, we build the structure in the
- * working context (which must be short-lived) and copy the completed
- * structure into the cache memory.
- *
- * Also, since the structure being created here is sufficiently complex, we
- * make a private child context of CacheMemoryContext for each relation that
- * has associated partition key information. That means no complicated logic
- * to free individual elements whenever the relcache entry is flushed - just
- * delete the context.
+ * Partitioning key data is a complex structure; to avoid complicated logic to
+ * free individual elements whenever the relcache entry is flushed, we give it
+ * its own memory context, child of CacheMemoryContext, which can easily be
+ * deleted on its own. To avoid leaking memory in that context in case of an
+ * error partway through this function, the context is initially created as a
+ * child of CurTransactionContext and only re-parented to CacheMemoryContext
+ * at the end, when no further errors are possible. Also, we don't make this
+ * context the current context except in very brief code sections, out of fear
+ * that some of our callees allocate memory on their own which would be leaked
+ * permanently.
*/
static void
RelationBuildPartitionKey(Relation relation)
RelationGetRelationName(relation),
MEMCONTEXT_COPY_NAME,
ALLOCSET_SMALL_SIZES);
- oldcxt = MemoryContextSwitchTo(partkeycxt);
- key = (PartitionKey) palloc0(sizeof(PartitionKeyData));
+ key = (PartitionKey) MemoryContextAllocZero(partkeycxt,
+ sizeof(PartitionKeyData));
/* Fixed-length attributes */
form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
/*
* Run the expressions through const-simplification since the planner
* will be comparing them to similarly-processed qual clause operands,
- * and may fail to detect valid matches without this step. We don't
- * need to bother with canonicalize_qual() though, because partition
- * expressions are not full-fledged qualification clauses.
+ * and may fail to detect valid matches without this step; fix
+ * opfuncids while at it. We don't need to bother with
+ * canonicalize_qual() though, because partition expressions are not
+ * full-fledged qualification clauses.
*/
- expr = eval_const_expressions(NULL, (Node *) expr);
+ expr = eval_const_expressions(NULL, expr);
+ fix_opfuncids(expr);
- /* May as well fix opfuncids too */
- fix_opfuncids((Node *) expr);
- key->partexprs = (List *) expr;
+ oldcxt = MemoryContextSwitchTo(partkeycxt);
+ key->partexprs = (List *) copyObject(expr);
+ MemoryContextSwitchTo(oldcxt);
}
+ oldcxt = MemoryContextSwitchTo(partkeycxt);
key->partattrs = (AttrNumber *) palloc0(key->partnatts * sizeof(AttrNumber));
key->partopfamily = (Oid *) palloc0(key->partnatts * sizeof(Oid));
key->partopcintype = (Oid *) palloc0(key->partnatts * sizeof(Oid));
key->parttypbyval = (bool *) palloc0(key->partnatts * sizeof(bool));
key->parttypalign = (char *) palloc0(key->partnatts * sizeof(char));
key->parttypcoll = (Oid *) palloc0(key->partnatts * sizeof(Oid));
+ MemoryContextSwitchTo(oldcxt);
- /* For the hash partitioning, an extended hash function will be used. */
+ /* determine support function number to search for */
procnum = (key->strategy == PARTITION_STRATEGY_HASH) ?
HASHEXTENDED_PROC : BTORDER_PROC;
if (!OidIsValid(funcid))
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("operator class \"%s\" of access method %s is missing support function %d for data type \"%s\"",
+ errmsg("operator class \"%s\" of access method %s is missing support function %d for type %s",
NameStr(opclassform->opcname),
(key->strategy == PARTITION_STRATEGY_HASH) ?
"hash" : "btree",
ReleaseSysCache(tuple);
- /* Success --- make the relcache point to the newly constructed key */
+ /*
+ * Success --- reparent our context and make the relcache point to the
+ * newly constructed key
+ */
MemoryContextSetParent(partkeycxt, CacheMemoryContext);
relation->rd_partkeycxt = partkeycxt;
relation->rd_partkey = key;
- MemoryContextSwitchTo(oldcxt);
}
/*