Hi,

It seems to me that we currently allow expressions that are anonymous
and self-referencing composite type records as partition key, but
shouldn't.  Allowing them leads to this:

create table foo (a int) partition by list ((row(a, b)));
create table foo1 partition of foo for values in ('(1)'::foo);
create table foo2 partition of foo for values in ('(2)'::foo);
explain select * from foo where row(a) = '(1)'::foo;
ERROR:  stack depth limit exceeded

Stack trace is this:

#0  errfinish (dummy=0) at elog.c:442
#1  0x0000000000911a51 in check_stack_depth () at postgres.c:3288
#2  0x00000000007970e6 in expression_tree_mutator (node=0x31890a0,
mutator=0x82095f <eval_const_expressions_mutator>,
context=0x7fff0578ef60) at nodeFuncs.c:2526
#3  0x000000000082340b in eval_const_expressions_mutator
(node=0x31890a0, context=0x7fff0578ef60) at clauses.c:3605
#4  0x000000000079875c in expression_tree_mutator (node=0x31890f8,
mutator=0x82095f <eval_const_expressions_mutator>,
context=0x7fff0578ef60) at nodeFuncs.c:2996
#5  0x000000000082340b in eval_const_expressions_mutator
(node=0x31890f8, context=0x7fff0578ef60) at clauses.c:3605
#6  0x000000000079810c in expression_tree_mutator (node=0x3188cc8,
mutator=0x82095f <eval_const_expressions_mutator>,
context=0x7fff0578ef60) at nodeFuncs.c:2863
#7  0x000000000082225d in eval_const_expressions_mutator
(node=0x3188cc8, context=0x7fff0578ef60) at clauses.c:3154
#8  0x000000000079875c in expression_tree_mutator (node=0x3189240,
mutator=0x82095f <eval_const_expressions_mutator>,
context=0x7fff0578ef60) at nodeFuncs.c:2996
#9  0x000000000082340b in eval_const_expressions_mutator
(node=0x3189240, context=0x7fff0578ef60) at clauses.c:3605
#10 0x000000000082090c in eval_const_expressions (root=0x0,
node=0x3189240) at clauses.c:2265
#11 0x0000000000a75169 in RelationBuildPartitionKey
(relation=0x7f5ca3e479a8) at partcache.c:139
#12 0x0000000000a7aa5e in RelationBuildDesc (targetRelId=17178,
insertIt=true) at relcache.c:1171
#13 0x0000000000a7c975 in RelationIdGetRelation (relationId=17178) at
relcache.c:2035
#14 0x000000000048e0c0 in relation_open (relationId=17178, lockmode=1)
at relation.c:59
#15 0x0000000000a8a4f7 in load_typcache_tupdesc (typentry=0x1c16bc0)
at typcache.c:793
#16 0x0000000000a8a3bb in lookup_type_cache (type_id=17180, flags=256)
at typcache.c:748
#17 0x0000000000a8bba4 in lookup_rowtype_tupdesc_internal
(type_id=17180, typmod=-1, noError=false) at typcache.c:1570
#18 0x0000000000a8be43 in lookup_rowtype_tupdesc (type_id=17180,
typmod=-1) at typcache.c:1656
#19 0x0000000000a0713f in record_cmp (fcinfo=0x7fff0578f4d0) at rowtypes.c:815
#20 0x0000000000a083e2 in btrecordcmp (fcinfo=0x7fff0578f4d0) at rowtypes.c:1276
#21 0x0000000000a97bd9 in FunctionCall2Coll (flinfo=0x2bb4a98,
collation=0, arg1=51939144, arg2=51940000) at fmgr.c:1162
#22 0x00000000008443f6 in qsort_partition_list_value_cmp (a=0x3188c50,
b=0x3188c58, arg=0x2bb46c0) at partbounds.c:1769
#23 0x0000000000af9dc6 in qsort_arg (a=0x3188c50, n=2, es=8,
cmp=0x84439a <qsort_partition_list_value_cmp>, arg=0x2bb46c0) at
qsort_arg.c:132
#24 0x000000000084186a in create_list_bounds (boundspecs=0x3188650,
nparts=2, key=0x2bb46c0, mapping=0x7fff0578f7d8) at partbounds.c:396
#25 0x00000000008410ec in partition_bounds_create
(boundspecs=0x3188650, nparts=2, key=0x2bb46c0,
mapping=0x7fff0578f7d8) at partbounds.c:206
#26 0x0000000000847622 in RelationBuildPartitionDesc
(rel=0x7f5ca3e47560) at partdesc.c:205
#27 0x0000000000a7aa6a in RelationBuildDesc (targetRelId=17178,
insertIt=true) at relcache.c:1172

Also:

create table foo (a int) partition by list ((row(a)));
create table foo1 partition of foo for values in (row(1));
create table foo2 partition of foo for values in (row(2));

explain select * from foo where row(a) = '(1)'::foo;
                        QUERY PLAN
----------------------------------------------------------
 Seq Scan on foo1 foo  (cost=0.00..41.88 rows=13 width=4)
   Filter: (ROW(a) = '(1)'::foo)
(2 rows)

explain select * from foo where row(a) = '(2)'::foo;
                        QUERY PLAN
----------------------------------------------------------
 Seq Scan on foo2 foo  (cost=0.00..41.88 rows=13 width=4)
   Filter: (ROW(a) = '(2)'::foo)
(2 rows)

-- another session
explain select * from foo where row(a) = '(1)'::foo;
ERROR:  record type has not been registered
LINE 1: explain select * from foo where row(a) = '(1)'::foo;

Attached a patch to fix that.

Thanks,
Amit
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index daa80ec4aa..8e5e3296df 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -15157,8 +15157,9 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, 
List *partParams, AttrNu
                                 */
 
                                /*
-                                * Cannot have expressions containing whole-row 
references or
-                                * system column references.
+                                * Cannot have expressions containing whole-row 
references,
+                                * system column references, or anonymous and 
self-referencing
+                                * records.
                                 */
                                pull_varattnos(expr, 1, &expr_attrs);
                                if (bms_is_member(0 - 
FirstLowInvalidHeapAttributeNumber,
@@ -15175,6 +15176,13 @@ ComputePartitionAttrs(ParseState *pstate, Relation 
rel, List *partParams, AttrNu
                                                                 
errmsg("partition key expressions cannot contain system column references")));
                                }
 
+                               if (atttype == RECORDOID ||
+                                       (type_is_rowtype(atttype) && atttype == 
rel->rd_rel->reltype))
+                                       ereport(ERROR,
+                                               
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
+                                                errmsg("partition key cannot 
be of anonymous or self-referencing composite type"),
+                                                parser_errposition(pstate, 
pelem->location)));
+
                                /*
                                 * Generated columns cannot work: They are 
computed after
                                 * BEFORE triggers, but partition routing is 
done before all
diff --git a/src/test/regress/expected/create_table.out 
b/src/test/regress/expected/create_table.out
index f63016871c..9fd772d4f8 100644
--- a/src/test/regress/expected/create_table.out
+++ b/src/test/regress/expected/create_table.out
@@ -402,6 +402,28 @@ CREATE TABLE partitioned (
 ERROR:  cannot use system column "xmin" in partition key
 LINE 3: ) PARTITION BY RANGE (xmin);
                               ^
+-- cannot use anonymous or self-referencing records
+CREATE TABLE partitioned (
+       a int,
+       b int
+) PARTITION BY RANGE (((a, b)));
+ERROR:  partition key cannot be of anonymous or self-referencing composite type
+LINE 4: ) PARTITION BY RANGE (((a, b)));
+                              ^
+CREATE TABLE partitioned (
+       a int,
+       b int
+) PARTITION BY RANGE ((row(a, b)));
+ERROR:  partition key cannot be of anonymous or self-referencing composite type
+LINE 4: ) PARTITION BY RANGE ((row(a, b)));
+                              ^
+CREATE TABLE partitioned (
+       a int,
+       b int
+) PARTITION BY RANGE ((row(a, b)::partitioned));
+ERROR:  partition key cannot be of anonymous or self-referencing composite type
+LINE 4: ) PARTITION BY RANGE ((row(a, b)::partitioned));
+                              ^
 -- functions in key must be immutable
 CREATE FUNCTION immut_func (a int) RETURNS int AS $$ SELECT a + random()::int; 
$$ LANGUAGE SQL;
 CREATE TABLE partitioned (
diff --git a/src/test/regress/sql/create_table.sql 
b/src/test/regress/sql/create_table.sql
index e835b65ac4..abf4d6e093 100644
--- a/src/test/regress/sql/create_table.sql
+++ b/src/test/regress/sql/create_table.sql
@@ -384,6 +384,20 @@ CREATE TABLE partitioned (
        a int
 ) PARTITION BY RANGE (xmin);
 
+-- cannot use anonymous or self-referencing records
+CREATE TABLE partitioned (
+       a int,
+       b int
+) PARTITION BY RANGE (((a, b)));
+CREATE TABLE partitioned (
+       a int,
+       b int
+) PARTITION BY RANGE ((row(a, b)));
+CREATE TABLE partitioned (
+       a int,
+       b int
+) PARTITION BY RANGE ((row(a, b)::partitioned));
+
 -- functions in key must be immutable
 CREATE FUNCTION immut_func (a int) RETURNS int AS $$ SELECT a + random()::int; 
$$ LANGUAGE SQL;
 CREATE TABLE partitioned (

Reply via email to