aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/backend/utils/cache/relcache.c109
-rw-r--r--src/include/access/hash.h2
-rw-r--r--src/test/regress/expected/create_table.out14
-rw-r--r--src/test/regress/sql/create_table.sql15
4 files changed, 60 insertions, 80 deletions
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index a69b078f91a..c48ec20eee3 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -266,7 +266,6 @@ static Relation AllocateRelationDesc(Form_pg_class relp);
static void RelationParseRelOptions(Relation relation, HeapTuple tuple);
static void RelationBuildTupleDesc(Relation relation);
static void RelationBuildPartitionKey(Relation relation);
-static PartitionKey copy_partition_key(PartitionKey fromkey);
static Relation RelationBuildDesc(Oid targetRelId, bool insertIt);
static void RelationInitPhysicalAddr(Relation relation);
static void load_critical_index(Oid indexoid, Oid heapoid);
@@ -811,17 +810,16 @@ RelationBuildRuleLock(Relation relation)
* 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)
@@ -849,7 +847,12 @@ RelationBuildPartitionKey(Relation relation)
if (!HeapTupleIsValid(tuple))
return;
- key = (PartitionKey) palloc0(sizeof(PartitionKeyData));
+ partkeycxt = AllocSetContextCreate(CurTransactionContext,
+ RelationGetRelationName(relation),
+ ALLOCSET_SMALL_SIZES);
+
+ key = (PartitionKey) MemoryContextAllocZero(partkeycxt,
+ sizeof(PartitionKeyData));
/* Fixed-length attributes */
form = (Form_pg_partitioned_table) GETSTRUCT(tuple);
@@ -896,13 +899,15 @@ RelationBuildPartitionKey(Relation relation)
* expressions should be in canonical form already (ie, no need for
* OR-merging or constant elimination).
*/
- 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));
@@ -917,6 +922,7 @@ RelationBuildPartitionKey(Relation relation)
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);
/* Copy partattrs and fill other per-attribute info */
memcpy(key->partattrs, attrs, key->partnatts * sizeof(int16));
@@ -951,7 +957,7 @@ RelationBuildPartitionKey(Relation relation)
BTORDER_PROC, opclassform->opcintype, opclassform->opcintype,
opclassform->opcfamily);
- fmgr_info(funcid, &key->partsupfunc[i]);
+ fmgr_info_cxt(funcid, &key->partsupfunc[i], partkeycxt);
/* Collation */
key->partcollation[i] = collation->values[i];
@@ -984,68 +990,13 @@ RelationBuildPartitionKey(Relation relation)
ReleaseSysCache(tuple);
- /* Success --- now copy to the cache memory */
- partkeycxt = AllocSetContextCreate(CacheMemoryContext,
- RelationGetRelationName(relation),
- ALLOCSET_SMALL_SIZES);
+ /*
+ * Success --- reparent our context and make the relcache point to the
+ * newly constructed key
+ */
+ MemoryContextSetParent(partkeycxt, CacheMemoryContext);
relation->rd_partkeycxt = partkeycxt;
- oldcxt = MemoryContextSwitchTo(relation->rd_partkeycxt);
- relation->rd_partkey = copy_partition_key(key);
- MemoryContextSwitchTo(oldcxt);
-}
-
-/*
- * copy_partition_key
- *
- * The copy is allocated in the current memory context.
- */
-static PartitionKey
-copy_partition_key(PartitionKey fromkey)
-{
- PartitionKey newkey;
- int n;
-
- newkey = (PartitionKey) palloc(sizeof(PartitionKeyData));
-
- newkey->strategy = fromkey->strategy;
- newkey->partnatts = n = fromkey->partnatts;
-
- newkey->partattrs = (AttrNumber *) palloc(n * sizeof(AttrNumber));
- memcpy(newkey->partattrs, fromkey->partattrs, n * sizeof(AttrNumber));
-
- newkey->partexprs = copyObject(fromkey->partexprs);
-
- newkey->partopfamily = (Oid *) palloc(n * sizeof(Oid));
- memcpy(newkey->partopfamily, fromkey->partopfamily, n * sizeof(Oid));
-
- newkey->partopcintype = (Oid *) palloc(n * sizeof(Oid));
- memcpy(newkey->partopcintype, fromkey->partopcintype, n * sizeof(Oid));
-
- newkey->partsupfunc = (FmgrInfo *) palloc(n * sizeof(FmgrInfo));
- memcpy(newkey->partsupfunc, fromkey->partsupfunc, n * sizeof(FmgrInfo));
-
- newkey->partcollation = (Oid *) palloc(n * sizeof(Oid));
- memcpy(newkey->partcollation, fromkey->partcollation, n * sizeof(Oid));
-
- newkey->parttypid = (Oid *) palloc(n * sizeof(Oid));
- memcpy(newkey->parttypid, fromkey->parttypid, n * sizeof(Oid));
-
- newkey->parttypmod = (int32 *) palloc(n * sizeof(int32));
- memcpy(newkey->parttypmod, fromkey->parttypmod, n * sizeof(int32));
-
- newkey->parttyplen = (int16 *) palloc(n * sizeof(int16));
- memcpy(newkey->parttyplen, fromkey->parttyplen, n * sizeof(int16));
-
- newkey->parttypbyval = (bool *) palloc(n * sizeof(bool));
- memcpy(newkey->parttypbyval, fromkey->parttypbyval, n * sizeof(bool));
-
- newkey->parttypalign = (char *) palloc(n * sizeof(bool));
- memcpy(newkey->parttypalign, fromkey->parttypalign, n * sizeof(char));
-
- newkey->parttypcoll = (Oid *) palloc(n * sizeof(Oid));
- memcpy(newkey->parttypcoll, fromkey->parttypcoll, n * sizeof(Oid));
-
- return newkey;
+ relation->rd_partkey = key;
}
/*
diff --git a/src/include/access/hash.h b/src/include/access/hash.h
index 72fce3038c0..7d44714718e 100644
--- a/src/include/access/hash.h
+++ b/src/include/access/hash.h
@@ -290,7 +290,7 @@ typedef HashMetaPageData *HashMetaPage;
/*
* When a new operator class is declared, we require that the user supply
- * us with an amproc procudure for hashing a key of the new type.
+ * us with an amproc procedure for hashing a key of the new type.
* Since we only have one such proc in amproc, it's number 1.
*/
#define HASHPROC 1
diff --git a/src/test/regress/expected/create_table.out b/src/test/regress/expected/create_table.out
index f887781c6df..1e99c96703b 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -764,8 +764,22 @@ Partition of: range_parted4 FOR VALUES FROM (6, 8, MINVALUE) TO (9, MAXVALUE, MA
Partition constraint: ((abs(a) IS NOT NULL) AND (abs(b) IS NOT NULL) AND (c IS NOT NULL) AND ((abs(a) > 6) OR ((abs(a) = 6) AND (abs(b) >= 8))) AND (abs(a) <= 9))
DROP TABLE range_parted4;
+-- user-defined operator class in partition key
+CREATE FUNCTION my_int4_sort(int4,int4) RETURNS int LANGUAGE sql
+ AS $$ SELECT case WHEN $1 = $2 THEN 0 WHEN $1 > $2 THEN 1 ELSE -1 END; $$;
+CREATE OPERATOR CLASS test_int4_ops FOR TYPE int4 USING btree AS
+ OPERATOR 1 < (int4,int4), OPERATOR 2 <= (int4,int4),
+ OPERATOR 3 = (int4,int4), OPERATOR 4 >= (int4,int4),
+ OPERATOR 5 > (int4,int4), FUNCTION 1 my_int4_sort(int4,int4);
+CREATE TABLE partkey_t (a int4) PARTITION BY RANGE (a test_int4_ops);
+CREATE TABLE partkey_t_1 PARTITION OF partkey_t FOR VALUES FROM (0) TO (1000);
+INSERT INTO partkey_t VALUES (100);
+INSERT INTO partkey_t VALUES (200);
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+DROP TABLE partkey_t;
+DROP OPERATOR CLASS test_int4_ops USING btree;
+DROP FUNCTION my_int4_sort(int4,int4);
-- comments on partitioned tables columns
CREATE TABLE parted_col_comment (a int, b text) PARTITION BY LIST (a);
COMMENT ON TABLE parted_col_comment IS 'Am partitioned table';
diff --git a/src/test/regress/sql/create_table.sql b/src/test/regress/sql/create_table.sql
index 9e8fc2f11f2..754184756c3 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -637,8 +637,23 @@ CREATE TABLE range_parted4_3 PARTITION OF range_parted4 FOR VALUES FROM (6, 8, M
\d+ range_parted4_3
DROP TABLE range_parted4;
+-- user-defined operator class in partition key
+CREATE FUNCTION my_int4_sort(int4,int4) RETURNS int LANGUAGE sql
+ AS $$ SELECT case WHEN $1 = $2 THEN 0 WHEN $1 > $2 THEN 1 ELSE -1 END; $$;
+CREATE OPERATOR CLASS test_int4_ops FOR TYPE int4 USING btree AS
+ OPERATOR 1 < (int4,int4), OPERATOR 2 <= (int4,int4),
+ OPERATOR 3 = (int4,int4), OPERATOR 4 >= (int4,int4),
+ OPERATOR 5 > (int4,int4), FUNCTION 1 my_int4_sort(int4,int4);
+CREATE TABLE partkey_t (a int4) PARTITION BY RANGE (a test_int4_ops);
+CREATE TABLE partkey_t_1 PARTITION OF partkey_t FOR VALUES FROM (0) TO (1000);
+INSERT INTO partkey_t VALUES (100);
+INSERT INTO partkey_t VALUES (200);
+
-- cleanup
DROP TABLE parted, list_parted, range_parted, list_parted2, range_parted2, range_parted3;
+DROP TABLE partkey_t;
+DROP OPERATOR CLASS test_int4_ops USING btree;
+DROP FUNCTION my_int4_sort(int4,int4);
-- comments on partitioned tables columns
CREATE TABLE parted_col_comment (a int, b text) PARTITION BY LIST (a);