diff options
author | Peter Eisentraut <peter@eisentraut.org> | 2024-09-17 10:36:09 +0200 |
---|---|---|
committer | Peter Eisentraut <peter@eisentraut.org> | 2024-09-17 11:29:30 +0200 |
commit | fc0438b4e80535419a4e54dba87642cdf84defda (patch) | |
tree | b63dcc505ae98c2ef3b8143f6f38d2c0ca9b892b /src/include | |
parent | 7406ab623fee1addcb21c881afecbe638a0d56e9 (diff) | |
download | postgresql-fc0438b4e80535419a4e54dba87642cdf84defda.tar.gz postgresql-fc0438b4e80535419a4e54dba87642cdf84defda.zip |
Add temporal PRIMARY KEY and UNIQUE constraints
Add WITHOUT OVERLAPS clause to PRIMARY KEY and UNIQUE constraints.
These are backed by GiST indexes instead of B-tree indexes, since they
are essentially exclusion constraints with = for the scalar parts of
the key and && for the temporal part.
(previously committed as 46a0cd4cefb, reverted by 46a0cd4cefb; the new
part is this:)
Because 'empty' && 'empty' is false, the temporal PK/UQ constraint
allowed duplicates, which is confusing to users and breaks internal
expectations. For instance, when GROUP BY checks functional
dependencies on the PK, it allows selecting other columns from the
table, but in the presence of duplicate keys you could get the value
from any of their rows. So we need to forbid empties.
This all means that at the moment we can only support ranges and
multiranges for temporal PK/UQs, unlike the original patch (above).
Documentation and tests for this are added. But this could
conceivably be extended by introducing some more general support for
the notion of "empty" for other types.
Author: Paul A. Jungwirth <pj@illuminatedcomputing.com>
Reviewed-by: Peter Eisentraut <peter@eisentraut.org>
Reviewed-by: jian he <jian.universality@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/CA+renyUApHgSZF9-nd-a0+OPGharLQLO=mDHcY4_qQ0+noCUVg@mail.gmail.com
Diffstat (limited to 'src/include')
-rw-r--r-- | src/include/access/gist.h | 3 | ||||
-rw-r--r-- | src/include/catalog/catversion.h | 2 | ||||
-rw-r--r-- | src/include/catalog/index.h | 1 | ||||
-rw-r--r-- | src/include/catalog/pg_constraint.h | 10 | ||||
-rw-r--r-- | src/include/commands/defrem.h | 6 | ||||
-rw-r--r-- | src/include/nodes/execnodes.h | 1 | ||||
-rw-r--r-- | src/include/nodes/makefuncs.h | 2 | ||||
-rw-r--r-- | src/include/nodes/parsenodes.h | 2 |
8 files changed, 23 insertions, 4 deletions
diff --git a/src/include/access/gist.h b/src/include/access/gist.h index e7ced18a5ba..22dd04c1418 100644 --- a/src/include/access/gist.h +++ b/src/include/access/gist.h @@ -17,6 +17,7 @@ #define GIST_H #include "access/itup.h" +#include "access/stratnum.h" #include "access/transam.h" #include "access/xlog.h" #include "access/xlogdefs.h" @@ -246,4 +247,6 @@ typedef struct do { (e).key = (k); (e).rel = (r); (e).page = (pg); \ (e).offset = (o); (e).leafkey = (l); } while (0) +extern StrategyNumber GistTranslateStratnum(Oid opclass, StrategyNumber strat); + #endif /* GIST_H */ diff --git a/src/include/catalog/catversion.h b/src/include/catalog/catversion.h index d46a9efe908..fe92cdd632f 100644 --- a/src/include/catalog/catversion.h +++ b/src/include/catalog/catversion.h @@ -57,6 +57,6 @@ */ /* yyyymmddN */ -#define CATALOG_VERSION_NO 202409171 +#define CATALOG_VERSION_NO 202409172 #endif diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h index 7d434f8e653..2dea96f47c3 100644 --- a/src/include/catalog/index.h +++ b/src/include/catalog/index.h @@ -93,6 +93,7 @@ extern Oid index_create(Relation heapRelation, #define INDEX_CONSTR_CREATE_INIT_DEFERRED (1 << 2) #define INDEX_CONSTR_CREATE_UPDATE_INDEX (1 << 3) #define INDEX_CONSTR_CREATE_REMOVE_OLD_DEPS (1 << 4) +#define INDEX_CONSTR_CREATE_WITHOUT_OVERLAPS (1 << 5) extern Oid index_concurrently_create_copy(Relation heapRelation, Oid oldIndexId, diff --git a/src/include/catalog/pg_constraint.h b/src/include/catalog/pg_constraint.h index 7a8017f15b5..96c00624b15 100644 --- a/src/include/catalog/pg_constraint.h +++ b/src/include/catalog/pg_constraint.h @@ -107,6 +107,12 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) /* Has a local definition and cannot be inherited */ bool connoinherit; + /* + * For primary keys and unique constraints, signifies the last column uses + * overlaps instead of equals. + */ + bool conperiod; + #ifdef CATALOG_VARLEN /* variable-length fields start here */ /* @@ -146,7 +152,8 @@ CATALOG(pg_constraint,2606,ConstraintRelationId) /* * If an exclusion constraint, the OIDs of the exclusion operators for - * each column of the constraint + * each column of the constraint. Also set for unique constraints/primary + * keys using WITHOUT OVERLAPS. */ Oid conexclop[1] BKI_LOOKUP(pg_operator); @@ -238,6 +245,7 @@ extern Oid CreateConstraintEntry(const char *constraintName, bool conIsLocal, int conInhCount, bool conNoInherit, + bool conPeriod, bool is_internal); extern bool ConstraintNameIsUsed(ConstraintCategory conCat, Oid objId, diff --git a/src/include/commands/defrem.h b/src/include/commands/defrem.h index 29c511e3196..0c53d67d3ee 100644 --- a/src/include/commands/defrem.h +++ b/src/include/commands/defrem.h @@ -14,6 +14,7 @@ #ifndef DEFREM_H #define DEFREM_H +#include "access/stratnum.h" #include "catalog/objectaddress.h" #include "nodes/params.h" #include "parser/parse_node.h" @@ -44,10 +45,13 @@ extern char *ChooseRelationName(const char *name1, const char *name2, extern bool CheckIndexCompatible(Oid oldId, const char *accessMethodName, const List *attributeList, - const List *exclusionOpNames); + const List *exclusionOpNames, + bool isWithoutOverlaps); extern Oid GetDefaultOpClass(Oid type_id, Oid am_id); extern Oid ResolveOpClass(const List *opclass, Oid attrType, const char *accessMethodName, Oid accessMethodId); +extern void GetOperatorFromWellKnownStrategy(Oid opclass, Oid atttype, + Oid *opid, StrategyNumber *strat); /* commands/functioncmds.c */ extern ObjectAddress CreateFunction(ParseState *pstate, CreateFunctionStmt *stmt); diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h index 516b9487435..88467977f89 100644 --- a/src/include/nodes/execnodes.h +++ b/src/include/nodes/execnodes.h @@ -204,6 +204,7 @@ typedef struct IndexInfo bool ii_Concurrent; bool ii_BrokenHotChain; bool ii_Summarizing; + bool ii_WithoutOverlaps; int ii_ParallelWorkers; Oid ii_Am; void *ii_AmCache; diff --git a/src/include/nodes/makefuncs.h b/src/include/nodes/makefuncs.h index 5209d3de89c..0765e5c57b4 100644 --- a/src/include/nodes/makefuncs.h +++ b/src/include/nodes/makefuncs.h @@ -98,7 +98,7 @@ extern IndexInfo *makeIndexInfo(int numattrs, int numkeyattrs, Oid amoid, List *expressions, List *predicates, bool unique, bool nulls_not_distinct, bool isready, bool concurrent, - bool summarizing); + bool summarizing, bool withoutoverlaps); extern Node *makeStringConst(char *str, int location); extern DefElem *makeDefElem(char *name, Node *arg, int location); diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index d6f7e795fe1..7e58db25268 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -2744,6 +2744,7 @@ typedef struct Constraint bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ List *keys; /* String nodes naming referenced key * column(s); for UNIQUE/PK/NOT NULL */ + bool without_overlaps; /* WITHOUT OVERLAPS specified */ List *including; /* String nodes naming referenced nonkey * column(s); for UNIQUE/PK */ List *exclusions; /* list of (IndexElem, operator name) pairs; @@ -3367,6 +3368,7 @@ typedef struct IndexStmt bool nulls_not_distinct; /* null treatment for UNIQUE constraints */ bool primary; /* is index a primary key? */ bool isconstraint; /* is it for a pkey/unique constraint? */ + bool iswithoutoverlaps; /* is the constraint WITHOUT OVERLAPS? */ bool deferrable; /* is the constraint DEFERRABLE? */ bool initdeferred; /* is the constraint INITIALLY DEFERRED? */ bool transformed; /* true when transformIndexStmt is finished */ |