@@ -712,11 +712,6 @@ DefineIndex(Oid relationId,
712
712
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
713
713
errmsg ("cannot create index on partitioned table \"%s\" concurrently" ,
714
714
RelationGetRelationName (rel ))));
715
- if (stmt -> excludeOpNames )
716
- ereport (ERROR ,
717
- (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
718
- errmsg ("cannot create exclusion constraints on partitioned table \"%s\"" ,
719
- RelationGetRelationName (rel ))));
720
715
}
721
716
722
717
/*
@@ -923,15 +918,16 @@ DefineIndex(Oid relationId,
923
918
index_check_primary_key (rel , indexInfo , is_alter_table , stmt );
924
919
925
920
/*
926
- * If this table is partitioned and we're creating a unique index or a
927
- * primary key, make sure that the partition key is a subset of the
928
- * index's columns. Otherwise it would be possible to violate uniqueness
929
- * by putting values that ought to be unique in different partitions.
921
+ * If this table is partitioned and we're creating a unique index, primary
922
+ * key, or exclusion constraint, make sure that the partition key is a
923
+ * subset of the index's columns. Otherwise it would be possible to
924
+ * violate uniqueness by putting values that ought to be unique in
925
+ * different partitions.
930
926
*
931
927
* We could lift this limitation if we had global indexes, but those have
932
928
* their own problems, so this is a useful feature combination.
933
929
*/
934
- if (partitioned && (stmt -> unique || stmt -> primary ))
930
+ if (partitioned && (stmt -> unique || stmt -> excludeOpNames ))
935
931
{
936
932
PartitionKey key = RelationGetPartitionKey (rel );
937
933
const char * constraint_type ;
@@ -941,7 +937,7 @@ DefineIndex(Oid relationId,
941
937
constraint_type = "PRIMARY KEY" ;
942
938
else if (stmt -> unique )
943
939
constraint_type = "UNIQUE" ;
944
- else if (stmt -> excludeOpNames != NIL )
940
+ else if (stmt -> excludeOpNames )
945
941
constraint_type = "EXCLUDE" ;
946
942
else
947
943
{
@@ -984,11 +980,11 @@ DefineIndex(Oid relationId,
984
980
* We'll need to be able to identify the equality operators
985
981
* associated with index columns, too. We know what to do with
986
982
* btree opclasses; if there are ever any other index types that
987
- * support unique indexes, this logic will need extension.
983
+ * support unique indexes, this logic will need extension. But if
984
+ * we have an exclusion constraint, it already knows the
985
+ * operators, so we don't have to infer them.
988
986
*/
989
- if (accessMethodId == BTREE_AM_OID )
990
- eq_strategy = BTEqualStrategyNumber ;
991
- else
987
+ if (stmt -> unique && accessMethodId != BTREE_AM_OID )
992
988
ereport (ERROR ,
993
989
(errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
994
990
errmsg ("cannot match partition key to an index using access method \"%s\"" ,
@@ -1019,17 +1015,38 @@ DefineIndex(Oid relationId,
1019
1015
& idx_opfamily ,
1020
1016
& idx_opcintype ))
1021
1017
{
1022
- Oid idx_eqop ;
1018
+ Oid idx_eqop = InvalidOid ;
1019
+
1020
+ if (stmt -> unique )
1021
+ idx_eqop = get_opfamily_member (idx_opfamily ,
1022
+ idx_opcintype ,
1023
+ idx_opcintype ,
1024
+ BTEqualStrategyNumber );
1025
+ else if (stmt -> excludeOpNames )
1026
+ idx_eqop = indexInfo -> ii_ExclusionOps [j ];
1027
+ Assert (idx_eqop );
1023
1028
1024
- idx_eqop = get_opfamily_member (idx_opfamily ,
1025
- idx_opcintype ,
1026
- idx_opcintype ,
1027
- eq_strategy );
1028
1029
if (ptkey_eqop == idx_eqop )
1029
1030
{
1030
1031
found = true;
1031
1032
break ;
1032
1033
}
1034
+ else if (stmt -> excludeOpNames )
1035
+ {
1036
+ /*
1037
+ * We found a match, but it's not an equality
1038
+ * operator. Instead of failing below with an
1039
+ * error message about a missing column, fail now
1040
+ * and explain that the operator is wrong.
1041
+ */
1042
+ Form_pg_attribute att = TupleDescAttr (RelationGetDescr (rel ), key -> partattrs [i ] - 1 );
1043
+
1044
+ ereport (ERROR ,
1045
+ (errcode (ERRCODE_FEATURE_NOT_SUPPORTED ),
1046
+ errmsg ("cannot match partition key to index on column \"%s\" using non-equal operator \"%s\"" ,
1047
+ NameStr (att -> attname ),
1048
+ get_opname (indexInfo -> ii_ExclusionOps [j ]))));
1049
+ }
1033
1050
}
1034
1051
}
1035
1052
}
@@ -1101,7 +1118,7 @@ DefineIndex(Oid relationId,
1101
1118
constraint_type = "PRIMARY KEY" ;
1102
1119
else if (stmt -> unique )
1103
1120
constraint_type = "UNIQUE" ;
1104
- else if (stmt -> excludeOpNames != NIL )
1121
+ else if (stmt -> excludeOpNames )
1105
1122
constraint_type = "EXCLUDE" ;
1106
1123
else
1107
1124
{
0 commit comments