Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitecfe59e

Browse files
committed
Refactor validation of new partitions a little bit.
Move some logic that is currently in ATExecAttachPartition toseparate functions to facilitate future code reuse.Ashutosh Bapat and Jeevan LadheDiscussion:http://postgr.es/m/CA+Tgmobbnamyvii0pRdg9pp_jLHSUvq7u5SiRrVV0tEFFU58Tg@mail.gmail.com
1 parent1e56883 commitecfe59e

File tree

1 file changed

+172
-146
lines changed

1 file changed

+172
-146
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 172 additions & 146 deletions
Original file line numberDiff line numberDiff line change
@@ -473,6 +473,11 @@ static void CreateInheritance(Relation child_rel, Relation parent_rel);
473473
staticvoidRemoveInheritance(Relationchild_rel,Relationparent_rel);
474474
staticObjectAddressATExecAttachPartition(List**wqueue,Relationrel,
475475
PartitionCmd*cmd);
476+
staticboolPartConstraintImpliedByRelConstraint(Relationscanrel,
477+
List*partConstraint);
478+
staticvoidValidatePartitionConstraints(List**wqueue,Relationscanrel,
479+
List*scanrel_children,
480+
List*partConstraint);
476481
staticObjectAddressATExecDetachPartition(Relationrel,RangeVar*name);
477482

478483

@@ -13424,6 +13429,169 @@ ComputePartitionAttrs(Relation rel, List *partParams, AttrNumber *partattrs,
1342413429
}
1342513430
}
1342613431

13432+
/*
13433+
* PartConstraintImpliedByRelConstraint
13434+
*Does scanrel's existing constraints imply the partition constraint?
13435+
*
13436+
* Existing constraints includes its check constraints and column-level
13437+
* NOT NULL constraints and partConstraint describes the partition constraint.
13438+
*/
13439+
staticbool
13440+
PartConstraintImpliedByRelConstraint(Relationscanrel,
13441+
List*partConstraint)
13442+
{
13443+
List*existConstraint=NIL;
13444+
TupleConstr*constr=RelationGetDescr(scanrel)->constr;
13445+
intnum_check,
13446+
i;
13447+
13448+
if (constr&&constr->has_not_null)
13449+
{
13450+
intnatts=scanrel->rd_att->natts;
13451+
13452+
for (i=1;i <=natts;i++)
13453+
{
13454+
Form_pg_attributeatt=scanrel->rd_att->attrs[i-1];
13455+
13456+
if (att->attnotnull&& !att->attisdropped)
13457+
{
13458+
NullTest*ntest=makeNode(NullTest);
13459+
13460+
ntest->arg= (Expr*)makeVar(1,
13461+
i,
13462+
att->atttypid,
13463+
att->atttypmod,
13464+
att->attcollation,
13465+
0);
13466+
ntest->nulltesttype=IS_NOT_NULL;
13467+
13468+
/*
13469+
* argisrow=false is correct even for a composite column,
13470+
* because attnotnull does not represent a SQL-spec IS NOT
13471+
* NULL test in such a case, just IS DISTINCT FROM NULL.
13472+
*/
13473+
ntest->argisrow= false;
13474+
ntest->location=-1;
13475+
existConstraint=lappend(existConstraint,ntest);
13476+
}
13477+
}
13478+
}
13479+
13480+
num_check= (constr!=NULL) ?constr->num_check :0;
13481+
for (i=0;i<num_check;i++)
13482+
{
13483+
Node*cexpr;
13484+
13485+
/*
13486+
* If this constraint hasn't been fully validated yet, we must ignore
13487+
* it here.
13488+
*/
13489+
if (!constr->check[i].ccvalid)
13490+
continue;
13491+
13492+
cexpr=stringToNode(constr->check[i].ccbin);
13493+
13494+
/*
13495+
* Run each expression through const-simplification and
13496+
* canonicalization. It is necessary, because we will be comparing it
13497+
* to similarly-processed partition constraint expressions, and may
13498+
* fail to detect valid matches without this.
13499+
*/
13500+
cexpr=eval_const_expressions(NULL,cexpr);
13501+
cexpr= (Node*)canonicalize_qual((Expr*)cexpr);
13502+
13503+
existConstraint=list_concat(existConstraint,
13504+
make_ands_implicit((Expr*)cexpr));
13505+
}
13506+
13507+
if (existConstraint!=NIL)
13508+
existConstraint=list_make1(make_ands_explicit(existConstraint));
13509+
13510+
/* And away we go ... */
13511+
returnpredicate_implied_by(partConstraint,existConstraint, true);
13512+
}
13513+
13514+
/*
13515+
* ValidatePartitionConstraints
13516+
*
13517+
* Check whether all rows in the given table obey the given partition
13518+
* constraint; if so, it can be attached as a partition.  We do this by
13519+
* scanning the table (or all of its leaf partitions) row by row, except when
13520+
* the existing constraints are sufficient to prove that the new partitioning
13521+
* constraint must already hold.
13522+
*/
13523+
staticvoid
13524+
ValidatePartitionConstraints(List**wqueue,Relationscanrel,
13525+
List*scanrel_children,
13526+
List*partConstraint)
13527+
{
13528+
boolfound_whole_row;
13529+
ListCell*lc;
13530+
13531+
if (partConstraint==NIL)
13532+
return;
13533+
13534+
/*
13535+
* Based on the table's existing constraints, determine if we can skip
13536+
* scanning the table to validate the partition constraint.
13537+
*/
13538+
if (PartConstraintImpliedByRelConstraint(scanrel,partConstraint))
13539+
{
13540+
ereport(INFO,
13541+
(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
13542+
RelationGetRelationName(scanrel))));
13543+
return;
13544+
}
13545+
13546+
/* Constraints proved insufficient, so we need to scan the table. */
13547+
foreach(lc,scanrel_children)
13548+
{
13549+
AlteredTableInfo*tab;
13550+
Oidpart_relid=lfirst_oid(lc);
13551+
Relationpart_rel;
13552+
List*my_partconstr=partConstraint;
13553+
13554+
/* Lock already taken */
13555+
if (part_relid!=RelationGetRelid(scanrel))
13556+
part_rel=heap_open(part_relid,NoLock);
13557+
else
13558+
part_rel=scanrel;
13559+
13560+
/*
13561+
* Skip if the partition is itself a partitioned table. We can only
13562+
* ever scan RELKIND_RELATION relations.
13563+
*/
13564+
if (part_rel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE)
13565+
{
13566+
if (part_rel!=scanrel)
13567+
heap_close(part_rel,NoLock);
13568+
continue;
13569+
}
13570+
13571+
if (part_rel!=scanrel)
13572+
{
13573+
/*
13574+
* Adjust the constraint for scanrel so that it matches this
13575+
* partition's attribute numbers.
13576+
*/
13577+
my_partconstr=map_partition_varattnos(my_partconstr,1,
13578+
part_rel,scanrel,
13579+
&found_whole_row);
13580+
/* There can never be a whole-row reference here */
13581+
if (found_whole_row)
13582+
elog(ERROR,"unexpected whole-row reference found in partition key");
13583+
}
13584+
13585+
/* Grab a work queue entry. */
13586+
tab=ATGetQueueEntry(wqueue,part_rel);
13587+
tab->partition_constraint= (Expr*)linitial(my_partconstr);
13588+
13589+
/* keep our lock until commit */
13590+
if (part_rel!=scanrel)
13591+
heap_close(part_rel,NoLock);
13592+
}
13593+
}
13594+
1342713595
/*
1342813596
* ALTER TABLE <name> ATTACH PARTITION <partition-name> FOR VALUES
1342913597
*
@@ -13435,15 +13603,12 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1343513603
Relationattachrel,
1343613604
catalog;
1343713605
List*attachrel_children;
13438-
TupleConstr*attachrel_constr;
13439-
List*partConstraint,
13440-
*existConstraint;
13606+
List*partConstraint;
1344113607
SysScanDescscan;
1344213608
ScanKeyDataskey;
1344313609
AttrNumberattno;
1344413610
intnatts;
1344513611
TupleDesctupleDesc;
13446-
boolskip_validate= false;
1344713612
ObjectAddressaddress;
1344813613
constchar*trigger_name;
1344913614
boolfound_whole_row;
@@ -13637,148 +13802,9 @@ ATExecAttachPartition(List **wqueue, Relation rel, PartitionCmd *cmd)
1363713802
if (found_whole_row)
1363813803
elog(ERROR,"unexpected whole-row reference found in partition key");
1363913804

13640-
/*
13641-
* Check if we can do away with having to scan the table being attached to
13642-
* validate the partition constraint, by *proving* that the existing
13643-
* constraints of the table *imply* the partition predicate. We include
13644-
* the table's check constraints and NOT NULL constraints in the list of
13645-
* clauses passed to predicate_implied_by().
13646-
*
13647-
* There is a case in which we cannot rely on just the result of the
13648-
* proof.
13649-
*/
13650-
attachrel_constr=tupleDesc->constr;
13651-
existConstraint=NIL;
13652-
if (attachrel_constr!=NULL)
13653-
{
13654-
intnum_check=attachrel_constr->num_check;
13655-
inti;
13656-
13657-
if (attachrel_constr->has_not_null)
13658-
{
13659-
intnatts=attachrel->rd_att->natts;
13660-
13661-
for (i=1;i <=natts;i++)
13662-
{
13663-
Form_pg_attributeatt=attachrel->rd_att->attrs[i-1];
13664-
13665-
if (att->attnotnull&& !att->attisdropped)
13666-
{
13667-
NullTest*ntest=makeNode(NullTest);
13668-
13669-
ntest->arg= (Expr*)makeVar(1,
13670-
i,
13671-
att->atttypid,
13672-
att->atttypmod,
13673-
att->attcollation,
13674-
0);
13675-
ntest->nulltesttype=IS_NOT_NULL;
13676-
13677-
/*
13678-
* argisrow=false is correct even for a composite column,
13679-
* because attnotnull does not represent a SQL-spec IS NOT
13680-
* NULL test in such a case, just IS DISTINCT FROM NULL.
13681-
*/
13682-
ntest->argisrow= false;
13683-
ntest->location=-1;
13684-
existConstraint=lappend(existConstraint,ntest);
13685-
}
13686-
}
13687-
}
13688-
13689-
for (i=0;i<num_check;i++)
13690-
{
13691-
Node*cexpr;
13692-
13693-
/*
13694-
* If this constraint hasn't been fully validated yet, we must
13695-
* ignore it here.
13696-
*/
13697-
if (!attachrel_constr->check[i].ccvalid)
13698-
continue;
13699-
13700-
cexpr=stringToNode(attachrel_constr->check[i].ccbin);
13701-
13702-
/*
13703-
* Run each expression through const-simplification and
13704-
* canonicalization. It is necessary, because we will be
13705-
* comparing it to similarly-processed qual clauses, and may fail
13706-
* to detect valid matches without this.
13707-
*/
13708-
cexpr=eval_const_expressions(NULL,cexpr);
13709-
cexpr= (Node*)canonicalize_qual((Expr*)cexpr);
13710-
13711-
existConstraint=list_concat(existConstraint,
13712-
make_ands_implicit((Expr*)cexpr));
13713-
}
13714-
13715-
existConstraint=list_make1(make_ands_explicit(existConstraint));
13716-
13717-
/* And away we go ... */
13718-
if (predicate_implied_by(partConstraint,existConstraint, true))
13719-
skip_validate= true;
13720-
}
13721-
13722-
if (skip_validate)
13723-
{
13724-
/* No need to scan the table after all. */
13725-
ereport(INFO,
13726-
(errmsg("partition constraint for table \"%s\" is implied by existing constraints",
13727-
RelationGetRelationName(attachrel))));
13728-
}
13729-
else
13730-
{
13731-
/* Constraints proved insufficient, so we need to scan the table. */
13732-
ListCell*lc;
13733-
13734-
foreach(lc,attachrel_children)
13735-
{
13736-
AlteredTableInfo*tab;
13737-
Oidpart_relid=lfirst_oid(lc);
13738-
Relationpart_rel;
13739-
List*my_partconstr=partConstraint;
13740-
13741-
/* Lock already taken */
13742-
if (part_relid!=RelationGetRelid(attachrel))
13743-
part_rel=heap_open(part_relid,NoLock);
13744-
else
13745-
part_rel=attachrel;
13746-
13747-
/*
13748-
* Skip if the partition is itself a partitioned table. We can
13749-
* only ever scan RELKIND_RELATION relations.
13750-
*/
13751-
if (part_rel->rd_rel->relkind==RELKIND_PARTITIONED_TABLE)
13752-
{
13753-
if (part_rel!=attachrel)
13754-
heap_close(part_rel,NoLock);
13755-
continue;
13756-
}
13757-
13758-
if (part_rel!=attachrel)
13759-
{
13760-
/*
13761-
* Adjust the constraint that we constructed above for
13762-
* attachRel so that it matches this partition's attribute
13763-
* numbers.
13764-
*/
13765-
my_partconstr=map_partition_varattnos(my_partconstr,1,
13766-
part_rel,attachrel,
13767-
&found_whole_row);
13768-
/* There can never be a whole-row reference here */
13769-
if (found_whole_row)
13770-
elog(ERROR,"unexpected whole-row reference found in partition key");
13771-
}
13772-
13773-
/* Grab a work queue entry. */
13774-
tab=ATGetQueueEntry(wqueue,part_rel);
13775-
tab->partition_constraint= (Expr*)linitial(my_partconstr);
13776-
13777-
/* keep our lock until commit */
13778-
if (part_rel!=attachrel)
13779-
heap_close(part_rel,NoLock);
13780-
}
13781-
}
13805+
/* Validate partition constraints against the table being attached. */
13806+
ValidatePartitionConstraints(wqueue,attachrel,attachrel_children,
13807+
partConstraint);
1378213808

1378313809
ObjectAddressSet(address,RelationRelationId,RelationGetRelid(attachrel));
1378413810

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp