Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit bb4114a

Browse files
committed
Allow whole-row Vars to be used in partitioning expressions.
In the wake of commit 5b93123, there's no particular reason for this restriction (previously, it was problematic because of the implied rowtype reference). A simple constraint on a whole-row Var probably isn't that useful, but conceivably somebody would want to pass one to a function that extracts a partitioning key. Besides which, we're expending much more code to enforce the restriction than we save by having it, since the latter quantity is now zero. So drop the restriction. Amit Langote Discussion: https://postgr.es/m/CA+HiwqFUzjfj9HEsJtYWcr1SgQ_=iCAvQ=O2Sx6aQxoDu4OiHw@mail.gmail.com
1 parent 42f74f4 commit bb4114a

File tree

8 files changed

+64
-77
lines changed

8 files changed

+64
-77
lines changed

src/backend/catalog/partition.c

+11-18
Original file line numberDiff line numberDiff line change
@@ -181,45 +181,38 @@ index_get_partition(Relation partition, Oid indexId)
181181
}
182182

183183
/*
184-
* map_partition_varattnos - maps varattno of any Vars in expr from the
185-
* attno's of 'from_rel' to the attno's of 'to_rel' partition, each of which
186-
* may be either a leaf partition or a partitioned table, but both of which
187-
* must be from the same partitioning hierarchy.
184+
* map_partition_varattnos - maps varattnos of all Vars in 'expr' (that have
185+
* varno 'fromrel_varno') from the attnums of 'from_rel' to the attnums of
186+
* 'to_rel', each of which may be either a leaf partition or a partitioned
187+
* table, but both of which must be from the same partitioning hierarchy.
188188
*
189-
* Even though all of the same column names must be present in all relations
190-
* in the hierarchy, and they must also have the same types, the attnos may
191-
* be different.
192-
*
193-
* If found_whole_row is not NULL, *found_whole_row returns whether a
194-
* whole-row variable was found in the input expression.
189+
* We need this because even though all of the same column names must be
190+
* present in all relations in the hierarchy, and they must also have the
191+
* same types, the attnums may be different.
195192
*
196193
* Note: this will work on any node tree, so really the argument and result
197194
* should be declared "Node *". But a substantial majority of the callers
198195
* are working on Lists, so it's less messy to do the casts internally.
199196
*/
200197
List *
201198
map_partition_varattnos(List *expr, int fromrel_varno,
202-
Relation to_rel, Relation from_rel,
203-
bool *found_whole_row)
199+
Relation to_rel, Relation from_rel)
204200
{
205-
bool my_found_whole_row = false;
206-
207201
if (expr != NIL)
208202
{
209203
AttrMap *part_attmap;
204+
bool found_whole_row;
210205

211206
part_attmap = build_attrmap_by_name(RelationGetDescr(to_rel),
212207
RelationGetDescr(from_rel));
213208
expr = (List *) map_variable_attnos((Node *) expr,
214209
fromrel_varno, 0,
215210
part_attmap,
216211
RelationGetForm(to_rel)->reltype,
217-
&my_found_whole_row);
212+
&found_whole_row);
213+
/* Since we provided a to_rowtype, we may ignore found_whole_row. */
218214
}
219215

220-
if (found_whole_row)
221-
*found_whole_row = my_found_whole_row;
222-
223216
return expr;
224217
}
225218

src/backend/commands/tablecmds.c

+10-30
Original file line numberDiff line numberDiff line change
@@ -15168,15 +15168,11 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNu
1516815168
*/
1516915169

1517015170
/*
15171-
* Cannot have expressions containing whole-row references or
15172-
* system column references.
15171+
* Cannot allow system column references, since that would
15172+
* make partition routing impossible: their values won't be
15173+
* known yet when we need to do that.
1517315174
*/
1517415175
pull_varattnos(expr, 1, &expr_attrs);
15175-
if (bms_is_member(0 - FirstLowInvalidHeapAttributeNumber,
15176-
expr_attrs))
15177-
ereport(ERROR,
15178-
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
15179-
errmsg("partition key expressions cannot contain whole-row references")));
1518015176
for (i = FirstLowInvalidHeapAttributeNumber; i < 0; i++)
1518115177
{
1518215178
if (bms_is_member(i - FirstLowInvalidHeapAttributeNumber,
@@ -15196,7 +15192,8 @@ ComputePartitionAttrs(ParseState *pstate, Relation rel, List *partParams, AttrNu
1519615192
{
1519715193
AttrNumber attno = i + FirstLowInvalidHeapAttributeNumber;
1519815194

15199-
if (TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
15195+
if (attno > 0 &&
15196+
TupleDescAttr(RelationGetDescr(rel), attno - 1)->attgenerated)
1520015197
ereport(ERROR,
1520115198
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
1520215199
errmsg("cannot use generated column in partition key"),
@@ -15451,7 +15448,6 @@ QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
1545115448
for (i = 0; i < partdesc->nparts; i++)
1545215449
{
1545315450
Relation part_rel;
15454-
bool found_whole_row;
1545515451
List *thisPartConstraint;
1545615452

1545715453
/*
@@ -15465,10 +15461,7 @@ QueuePartitionConstraintValidation(List **wqueue, Relation scanrel,
1546515461
*/
1546615462
thisPartConstraint =
1546715463
map_partition_varattnos(partConstraint, 1,
15468-
part_rel, scanrel, &found_whole_row);
15469-
/* There can never be a whole-row reference here */
15470-
if (found_whole_row)
15471-
elog(ERROR, "unexpected whole-row reference found in partition constraint");
15464+
part_rel, scanrel);
1547215465

1547315466
QueuePartitionConstraintValidation(wqueue, part_rel,
1547415467
thisPartConstraint,
@@ -15497,7 +15490,6 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1549715490
TupleDesc tupleDesc;
1549815491
ObjectAddress address;
1549915492
const char *trigger_name;
15500-
bool found_whole_row;
1550115493
Oid defaultPartOid;
1550215494
List *partBoundConstraint;
1550315495

@@ -15714,11 +15706,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1571415706
* numbers.
1571515707
*/
1571615708
partConstraint = map_partition_varattnos(partConstraint, 1, attachrel,
15717-
rel, &found_whole_row);
15718-
/* There can never be a whole-row reference here */
15719-
if (found_whole_row)
15720-
elog(ERROR,
15721-
"unexpected whole-row reference found in partition key");
15709+
rel);
1572215710

1572315711
/* Validate partition constraints against the table being attached. */
1572415712
QueuePartitionConstraintValidation(wqueue, attachrel, partConstraint,
@@ -15750,7 +15738,7 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1575015738
*/
1575115739
defPartConstraint =
1575215740
map_partition_varattnos(defPartConstraint,
15753-
1, defaultrel, rel, NULL);
15741+
1, defaultrel, rel);
1575415742
QueuePartitionConstraintValidation(wqueue, defaultrel,
1575515743
defPartConstraint, true);
1575615744

@@ -16004,19 +15992,11 @@ CloneRowTriggersToPartition(Relation parent, Relation partition)
1600415992
RelationGetDescr(pg_trigger), &isnull);
1600515993
if (!isnull)
1600615994
{
16007-
bool found_whole_row;
16008-
1600915995
qual = stringToNode(TextDatumGetCString(value));
1601015996
qual = (Node *) map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
16011-
partition, parent,
16012-
&found_whole_row);
16013-
if (found_whole_row)
16014-
elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
15997+
partition, parent);
1601515998
qual = (Node *) map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
16016-
partition, parent,
16017-
&found_whole_row);
16018-
if (found_whole_row)
16019-
elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
15999+
partition, parent);
1602016000
}
1602116001

1602216002
/*

src/backend/commands/trigger.c

+2-9
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,6 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
11441144
CreateTrigStmt *childStmt;
11451145
Relation childTbl;
11461146
Node *qual;
1147-
bool found_whole_row;
11481147

11491148
childTbl = table_open(partdesc->oids[i], ShareRowExclusiveLock);
11501149

@@ -1177,16 +1176,10 @@ CreateTrigger(CreateTrigStmt *stmt, const char *queryString,
11771176
qual = copyObject(whenClause);
11781177
qual = (Node *)
11791178
map_partition_varattnos((List *) qual, PRS2_OLD_VARNO,
1180-
childTbl, rel,
1181-
&found_whole_row);
1182-
if (found_whole_row)
1183-
elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
1179+
childTbl, rel);
11841180
qual = (Node *)
11851181
map_partition_varattnos((List *) qual, PRS2_NEW_VARNO,
1186-
childTbl, rel,
1187-
&found_whole_row);
1188-
if (found_whole_row)
1189-
elog(ERROR, "unexpected whole-row reference found in trigger WHEN clause");
1182+
childTbl, rel);
11901183

11911184
CreateTrigger(childStmt, queryString,
11921185
partdesc->oids[i], refRelOid,

src/backend/partitioning/partbounds.c

+2-2
Original file line numberDiff line numberDiff line change
@@ -1247,7 +1247,7 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12471247
*/
12481248
def_part_constraints =
12491249
map_partition_varattnos(def_part_constraints, 1, default_rel,
1250-
parent, NULL);
1250+
parent);
12511251

12521252
/*
12531253
* If the existing constraints on the default partition imply that it will
@@ -1297,7 +1297,7 @@ check_default_partition_contents(Relation parent, Relation default_rel,
12971297
partition_constraint = make_ands_explicit(def_part_constraints);
12981298
partition_constraint = (Expr *)
12991299
map_partition_varattnos((List *) partition_constraint, 1,
1300-
part_rel, default_rel, NULL);
1300+
part_rel, default_rel);
13011301

13021302
/*
13031303
* If the partition constraints on default partition child imply

src/backend/utils/cache/partcache.c

+1-6
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ generate_partition_qual(Relation rel)
342342
List *my_qual = NIL,
343343
*result = NIL;
344344
Relation parent;
345-
bool found_whole_row;
346345

347346
/* Guard against stack overflow due to overly deep partition tree */
348347
check_stack_depth();
@@ -388,11 +387,7 @@ generate_partition_qual(Relation rel)
388387
* in it to bear this relation's attnos. It's safe to assume varno = 1
389388
* here.
390389
*/
391-
result = map_partition_varattnos(result, 1, rel, parent,
392-
&found_whole_row);
393-
/* There can never be a whole-row reference here */
394-
if (found_whole_row)
395-
elog(ERROR, "unexpected whole-row reference found in partition key");
390+
result = map_partition_varattnos(result, 1, rel, parent);
396391

397392
/* Assert that we're not leaking any old data during assignments below */
398393
Assert(rel->rd_partcheckcxt == NULL);

src/include/catalog/partition.h

+1-2
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ extern Oid get_partition_parent(Oid relid);
2323
extern List *get_partition_ancestors(Oid relid);
2424
extern Oid index_get_partition(Relation partition, Oid indexId);
2525
extern List *map_partition_varattnos(List *expr, int fromrel_varno,
26-
Relation to_rel, Relation from_rel,
27-
bool *found_whole_row);
26+
Relation to_rel, Relation from_rel);
2827
extern bool has_partition_attrs(Relation rel, Bitmapset *attnums,
2928
bool *used_in_expr);
3029

src/test/regress/expected/create_table.out

+25-5
Original file line numberDiff line numberDiff line change
@@ -420,11 +420,6 @@ CREATE TABLE partitioned (
420420
) PARTITION BY RANGE (immut_func(a));
421421
ERROR: functions in partition key expression must be marked IMMUTABLE
422422
DROP FUNCTION immut_func(int);
423-
-- cannot contain whole-row references
424-
CREATE TABLE partitioned (
425-
a int
426-
) PARTITION BY RANGE ((partitioned));
427-
ERROR: partition key expressions cannot contain whole-row references
428423
-- prevent using columns of unsupported types in key (type must have a btree operator class)
429424
CREATE TABLE partitioned (
430425
a point
@@ -527,6 +522,31 @@ select * from partitioned where row(a,b)::partitioned = '(1,2)'::partitioned;
527522
Filter: (ROW(a, b)::partitioned = '(1,2)'::partitioned)
528523
(2 rows)
529524

525+
drop table partitioned;
526+
-- whole-row Var in partition key works too
527+
create table partitioned (a int, b int)
528+
partition by list ((partitioned));
529+
create table partitioned1
530+
partition of partitioned for values in ('(1,2)');
531+
create table partitioned2
532+
partition of partitioned for values in ('(2,4)');
533+
explain (costs off)
534+
select * from partitioned where partitioned = '(1,2)'::partitioned;
535+
QUERY PLAN
536+
-----------------------------------------------------------------
537+
Seq Scan on partitioned1 partitioned
538+
Filter: ((partitioned.*)::partitioned = '(1,2)'::partitioned)
539+
(2 rows)
540+
541+
\d+ partitioned1
542+
Table "public.partitioned1"
543+
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
544+
--------+---------+-----------+----------+---------+---------+--------------+-------------
545+
a | integer | | | | plain | |
546+
b | integer | | | | plain | |
547+
Partition of: partitioned FOR VALUES IN ('(1,2)')
548+
Partition constraint: (((partitioned1.*)::partitioned IS DISTINCT FROM NULL) AND ((partitioned1.*)::partitioned = '(1,2)'::partitioned))
549+
530550
drop table partitioned;
531551
-- check that dependencies of partition columns are handled correctly
532552
create domain intdom1 as int;

src/test/regress/sql/create_table.sql

+12-5
Original file line numberDiff line numberDiff line change
@@ -401,11 +401,6 @@ CREATE TABLE partitioned (
401401
) PARTITION BY RANGE (immut_func(a));
402402
DROP FUNCTION immut_func(int);
403403

404-
-- cannot contain whole-row references
405-
CREATE TABLE partitioned (
406-
a int
407-
) PARTITION BY RANGE ((partitioned));
408-
409404
-- prevent using columns of unsupported types in key (type must have a btree operator class)
410405
CREATE TABLE partitioned (
411406
a point
@@ -470,6 +465,18 @@ explain (costs off)
470465
select * from partitioned where row(a,b)::partitioned = '(1,2)'::partitioned;
471466
drop table partitioned;
472467

468+
-- whole-row Var in partition key works too
469+
create table partitioned (a int, b int)
470+
partition by list ((partitioned));
471+
create table partitioned1
472+
partition of partitioned for values in ('(1,2)');
473+
create table partitioned2
474+
partition of partitioned for values in ('(2,4)');
475+
explain (costs off)
476+
select * from partitioned where partitioned = '(1,2)'::partitioned;
477+
\d+ partitioned1
478+
drop table partitioned;
479+
473480
-- check that dependencies of partition columns are handled correctly
474481
create domain intdom1 as int;
475482

0 commit comments

Comments
 (0)