summaryrefslogtreecommitdiff
path: root/src/backend/parser/parse_utilcmd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/parse_utilcmd.c')
-rw-r--r--src/backend/parser/parse_utilcmd.c27
1 files changed, 22 insertions, 5 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index a1c73fdc78..57ea3fa116 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -81,6 +81,7 @@ typedef struct
List *ckconstraints; /* CHECK constraints */
List *fkconstraints; /* FOREIGN KEY constraints */
List *ixconstraints; /* index-creating constraints */
+ List *likeclauses; /* LIKE clauses that need post-processing */
List *blist; /* "before list" of things to do before
* creating the table */
List *alist; /* "after list" of things to do after creating
@@ -228,6 +229,7 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
cxt.ckconstraints = NIL;
cxt.fkconstraints = NIL;
cxt.ixconstraints = NIL;
+ cxt.likeclauses = NIL;
cxt.blist = NIL;
cxt.alist = NIL;
cxt.pkey = NULL;
@@ -308,6 +310,20 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
transformIndexConstraints(&cxt);
/*
+ * Re-consideration of LIKE clauses should happen after creation of
+ * indexes, but before creation of foreign keys. This order is critical
+ * because a LIKE clause may attempt to create a primary key. If there's
+ * also a pkey in the main CREATE TABLE list, creation of that will not
+ * check for a duplicate at runtime (since index_check_primary_key()
+ * expects that we rejected dups here). Creation of the LIKE-generated
+ * pkey behaves like ALTER TABLE ADD, so it will check, but obviously that
+ * only works if it happens second. On the other hand, we want to make
+ * pkeys before foreign key constraints, in case the user tries to make a
+ * self-referential FK.
+ */
+ cxt.alist = list_concat(cxt.alist, cxt.likeclauses);
+
+ /*
* Postprocess foreign-key constraints.
*/
transformFKConstraints(&cxt, true, false);
@@ -722,7 +738,7 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint)
* Change the LIKE <srctable> portion of a CREATE TABLE statement into
* column definitions that recreate the user defined column portions of
* <srctable>. Also, if there are any LIKE options that we can't fully
- * process at this point, add the TableLikeClause to cxt->alist, which
+ * process at this point, add the TableLikeClause to cxt->likeclauses, which
* will cause utility.c to call expandTableLikeClause() after the new
* table has been created.
*/
@@ -892,13 +908,13 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
* We cannot yet deal with CHECK constraints or indexes, since we don't
* yet know what column numbers the copied columns will have in the
* finished table. If any of those options are specified, add the LIKE
- * clause to cxt->alist so that expandTableLikeClause will be called after
- * we do know that.
+ * clause to cxt->likeclauses so that expandTableLikeClause will be called
+ * after we do know that.
*/
if (table_like_clause->options &
(CREATE_TABLE_LIKE_CONSTRAINTS |
CREATE_TABLE_LIKE_INDEXES))
- cxt->alist = lappend(cxt->alist, table_like_clause);
+ cxt->likeclauses = lappend(cxt->likeclauses, table_like_clause);
/*
* Close the parent rel, but keep our AccessShareLock on it until xact
@@ -2065,7 +2081,7 @@ transformFKConstraints(CreateStmtContext *cxt,
* Note: the ADD CONSTRAINT command must also execute after any index
* creation commands. Thus, this should run after
* transformIndexConstraints, so that the CREATE INDEX commands are
- * already in cxt->alist.
+ * already in cxt->alist. See also the handling of cxt->likeclauses.
*/
if (!isAddConstraint)
{
@@ -2574,6 +2590,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
cxt.ckconstraints = NIL;
cxt.fkconstraints = NIL;
cxt.ixconstraints = NIL;
+ cxt.likeclauses = NIL;
cxt.blist = NIL;
cxt.alist = NIL;
cxt.pkey = NULL;