@@ -807,17 +807,16 @@ RelationBuildRuleLock(Relation relation)
807807 * RelationBuildPartitionKey
808808 * Build and attach to relcache partition key data of relation
809809 *
810- * Partitioning key data is stored in CacheMemoryContext to ensure it survives
811- * as long as the relcache. To avoid leaking memory in that context in case
812- * of an error partway through this function, we build the structure in the
813- * working context (which must be short-lived) and copy the completed
814- * structure into the cache memory.
815- *
816- * Also, since the structure being created here is sufficiently complex, we
817- * make a private child context of CacheMemoryContext for each relation that
818- * has associated partition key information. That means no complicated logic
819- * to free individual elements whenever the relcache entry is flushed - just
820- * delete the context.
810+ * Partitioning key data is a complex structure; to avoid complicated logic to
811+ * free individual elements whenever the relcache entry is flushed, we give it
812+ * its own memory context, child of CacheMemoryContext, which can easily be
813+ * deleted on its own. To avoid leaking memory in that context in case of an
814+ * error partway through this function, the context is initially created as a
815+ * child of CurTransactionContext and only re-parented to CacheMemoryContext
816+ * at the end, when no further errors are possible. Also, we don't make this
817+ * context the current context except in very brief code sections, out of fear
818+ * that some of our callees allocate memory on their own which would be leaked
819+ * permanently.
821820 */
822821static void
823822RelationBuildPartitionKey (Relation relation )
@@ -850,9 +849,9 @@ RelationBuildPartitionKey(Relation relation)
850849 RelationGetRelationName (relation ),
851850 MEMCONTEXT_COPY_NAME ,
852851 ALLOCSET_SMALL_SIZES );
853- oldcxt = MemoryContextSwitchTo (partkeycxt );
854852
855- key = (PartitionKey ) palloc0 (sizeof (PartitionKeyData ));
853+ key = (PartitionKey ) MemoryContextAllocZero (partkeycxt ,
854+ sizeof (PartitionKeyData ));
856855
857856 /* Fixed-length attributes */
858857 form = (Form_pg_partitioned_table ) GETSTRUCT (tuple );
@@ -894,17 +893,20 @@ RelationBuildPartitionKey(Relation relation)
894893 /*
895894 * Run the expressions through const-simplification since the planner
896895 * will be comparing them to similarly-processed qual clause operands,
897- * and may fail to detect valid matches without this step. We don't
898- * need to bother with canonicalize_qual() though, because partition
899- * expressions are not full-fledged qualification clauses.
896+ * and may fail to detect valid matches without this step; fix
897+ * opfuncids while at it. We don't need to bother with
898+ * canonicalize_qual() though, because partition expressions are not
899+ * full-fledged qualification clauses.
900900 */
901- expr = eval_const_expressions (NULL , (Node * ) expr );
901+ expr = eval_const_expressions (NULL , expr );
902+ fix_opfuncids (expr );
902903
903- /* May as well fix opfuncids too */
904- fix_opfuncids (( Node * ) expr );
905- key -> partexprs = ( List * ) expr ;
904+ oldcxt = MemoryContextSwitchTo ( partkeycxt );
905+ key -> partexprs = ( List * ) copyObject ( expr );
906+ MemoryContextSwitchTo ( oldcxt ) ;
906907 }
907908
909+ oldcxt = MemoryContextSwitchTo (partkeycxt );
908910 key -> partattrs = (AttrNumber * ) palloc0 (key -> partnatts * sizeof (AttrNumber ));
909911 key -> partopfamily = (Oid * ) palloc0 (key -> partnatts * sizeof (Oid ));
910912 key -> partopcintype = (Oid * ) palloc0 (key -> partnatts * sizeof (Oid ));
@@ -919,8 +921,9 @@ RelationBuildPartitionKey(Relation relation)
919921 key -> parttypbyval = (bool * ) palloc0 (key -> partnatts * sizeof (bool ));
920922 key -> parttypalign = (char * ) palloc0 (key -> partnatts * sizeof (char ));
921923 key -> parttypcoll = (Oid * ) palloc0 (key -> partnatts * sizeof (Oid ));
924+ MemoryContextSwitchTo (oldcxt );
922925
923- /* For the hash partitioning, an extended hash function will be used. */
926+ /* determine support function number to search for */
924927 procnum = (key -> strategy == PARTITION_STRATEGY_HASH ) ?
925928 HASHEXTENDED_PROC : BTORDER_PROC ;
926929
@@ -952,7 +955,7 @@ RelationBuildPartitionKey(Relation relation)
952955 if (!OidIsValid (funcid ))
953956 ereport (ERROR ,
954957 (errcode (ERRCODE_INVALID_OBJECT_DEFINITION ),
955- errmsg ("operator class \"%s\" of access method %s is missing support function %d for data type \"%s\" " ,
958+ errmsg ("operator class \"%s\" of access method %s is missing support function %d for type %s " ,
956959 NameStr (opclassform -> opcname ),
957960 (key -> strategy == PARTITION_STRATEGY_HASH ) ?
958961 "hash" : "btree" ,
@@ -989,11 +992,13 @@ RelationBuildPartitionKey(Relation relation)
989992
990993 ReleaseSysCache (tuple );
991994
992- /* Success --- make the relcache point to the newly constructed key */
995+ /*
996+ * Success --- reparent our context and make the relcache point to the
997+ * newly constructed key
998+ */
993999 MemoryContextSetParent (partkeycxt , CacheMemoryContext );
9941000 relation -> rd_partkeycxt = partkeycxt ;
9951001 relation -> rd_partkey = key ;
996- MemoryContextSwitchTo (oldcxt );
9971002}
9981003
9991004/*
0 commit comments