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

Commit76ea606

Browse files
committed
Check equality semantics for unique indexes on partitioned tables.
We require the partition key to be a subset of the set of columnsbeing made unique, so that physically-separate indexes on the differentpartitions are sufficient to enforce the uniqueness constraint.The existing code checked that the listed columns appear, but did notinquire into the index semantics, which is a serious oversight giventhat different index opclasses might enforce completely differentnotions of uniqueness.Ideally, perhaps, we'd just match the partition key opfamily to theindex opfamily. But hash partitioning uses hash opfamilies which wecan't directly match to btree opfamilies. Hence, look up the equalityoperator in each family, and accept if it's the same operator. Thisshould be okay in a fairly general sense, since the equality operatorought to precisely represent the opfamily's notion of uniqueness.A remaining weak spot is that we don't have a cross-index-AM notion ofwhich opfamily member is "equality". But we know which one to use forhash and btree AMs, and those are the only two that are relevant hereat present. (Any non-core AMs that know how to enforce equality areout of luck, for now.)Back-patch to v11 where this feature was introduced.Guancheng Luo, revised a bit by meDiscussion:https://postgr.es/m/D9C3CEF7-04E8-47A1-8300-CA1DCD5ED40D@gmail.com
1 parentf79bea4 commit76ea606

File tree

1 file changed

+78
-26
lines changed

1 file changed

+78
-26
lines changed

‎src/backend/commands/indexcmds.c

Lines changed: 78 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -822,44 +822,75 @@ DefineIndex(Oid relationId,
822822

823823
/*
824824
* If this table is partitioned and we're creating a unique index or a
825-
* primary key, make sure that theindexed columns are part of the
826-
*partition key. Otherwise it would be possible to violate uniqueness by
827-
* putting values that ought to be unique in different partitions.
825+
* primary key, make sure that thepartition key is a subset of the
826+
*index's columns. Otherwise it would be possible to violate uniqueness
827+
*byputting values that ought to be unique in different partitions.
828828
*
829829
* We could lift this limitation if we had global indexes, but those have
830830
* their own problems, so this is a useful feature combination.
831831
*/
832832
if (partitioned&& (stmt->unique||stmt->primary))
833833
{
834-
PartitionKeykey=rel->rd_partkey;
834+
PartitionKeykey=RelationGetPartitionKey(rel);
835+
constchar*constraint_type;
835836
inti;
836837

838+
if (stmt->primary)
839+
constraint_type="PRIMARY KEY";
840+
elseif (stmt->unique)
841+
constraint_type="UNIQUE";
842+
elseif (stmt->excludeOpNames!=NIL)
843+
constraint_type="EXCLUDE";
844+
else
845+
{
846+
elog(ERROR,"unknown constraint type");
847+
constraint_type=NULL;/* keep compiler quiet */
848+
}
849+
837850
/*
838-
* A partitioned table can have unique indexes, as long as all the
839-
* columns in the partition key appear in the unique key. A
840-
* partition-local index can enforce global uniqueness iff the PK
841-
* value completely determines the partition that a row is in.
842-
*
843-
* Thus, verify that all the columns in the partition key appear in
844-
* the unique key definition.
851+
* Verify that all the columns in the partition key appear in the
852+
* unique key definition, with the same notion of equality.
845853
*/
846854
for (i=0;i<key->partnatts;i++)
847855
{
848856
boolfound= false;
857+
inteq_strategy;
858+
Oidptkey_eqop;
849859
intj;
850-
constchar*constraint_type;
851-
852-
if (stmt->primary)
853-
constraint_type="PRIMARY KEY";
854-
elseif (stmt->unique)
855-
constraint_type="UNIQUE";
856-
elseif (stmt->excludeOpNames!=NIL)
857-
constraint_type="EXCLUDE";
860+
861+
/*
862+
* Identify the equality operator associated with this partkey
863+
* column. For list and range partitioning, partkeys use btree
864+
* operator classes; hash partitioning uses hash operator classes.
865+
* (Keep this in sync with ComputePartitionAttrs!)
866+
*/
867+
if (key->strategy==PARTITION_STRATEGY_HASH)
868+
eq_strategy=HTEqualStrategyNumber;
858869
else
859-
{
860-
elog(ERROR,"unknown constraint type");
861-
constraint_type=NULL;/* keep compiler quiet */
862-
}
870+
eq_strategy=BTEqualStrategyNumber;
871+
872+
ptkey_eqop=get_opfamily_member(key->partopfamily[i],
873+
key->partopcintype[i],
874+
key->partopcintype[i],
875+
eq_strategy);
876+
if (!OidIsValid(ptkey_eqop))
877+
elog(ERROR,"missing operator %d(%u,%u) in partition opfamily %u",
878+
eq_strategy,key->partopcintype[i],key->partopcintype[i],
879+
key->partopfamily[i]);
880+
881+
/*
882+
* We'll need to be able to identify the equality operators
883+
* associated with index columns, too. We know what to do with
884+
* btree opclasses; if there are ever any other index types that
885+
* support unique indexes, this logic will need extension.
886+
*/
887+
if (accessMethodId==BTREE_AM_OID)
888+
eq_strategy=BTEqualStrategyNumber;
889+
else
890+
ereport(ERROR,
891+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
892+
errmsg("cannot match partition key to an index using access method \"%s\"",
893+
accessMethodName)));
863894

864895
/*
865896
* It may be possible to support UNIQUE constraints when partition
@@ -873,19 +904,40 @@ DefineIndex(Oid relationId,
873904
errdetail("%s constraints cannot be used when partition keys include expressions.",
874905
constraint_type)));
875906

907+
/* Search the index column(s) for a match */
876908
for (j=0;j<indexInfo->ii_NumIndexKeyAttrs;j++)
877909
{
878910
if (key->partattrs[i]==indexInfo->ii_IndexAttrNumbers[j])
879911
{
880-
found= true;
881-
break;
912+
/* Matched the column, now what about the equality op? */
913+
Oididx_opfamily;
914+
Oididx_opcintype;
915+
916+
if (get_opclass_opfamily_and_input_type(classObjectId[j],
917+
&idx_opfamily,
918+
&idx_opcintype))
919+
{
920+
Oididx_eqop;
921+
922+
idx_eqop=get_opfamily_member(idx_opfamily,
923+
idx_opcintype,
924+
idx_opcintype,
925+
eq_strategy);
926+
if (ptkey_eqop==idx_eqop)
927+
{
928+
found= true;
929+
break;
930+
}
931+
}
882932
}
883933
}
934+
884935
if (!found)
885936
{
886937
Form_pg_attributeatt;
887938

888-
att=TupleDescAttr(RelationGetDescr(rel),key->partattrs[i]-1);
939+
att=TupleDescAttr(RelationGetDescr(rel),
940+
key->partattrs[i]-1);
889941
ereport(ERROR,
890942
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
891943
errmsg("insufficient columns in %s constraint definition",

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp