diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c index 27b596cb59..cb56f9f246 100644 --- a/src/backend/commands/tablecmds.c +++ b/src/backend/commands/tablecmds.c @@ -831,6 +831,19 @@ DefineRelation(CreateStmt *stmt, char relkind, Oid ownerId, { CookedConstraint *cooked; + /* + * If column has identity sequence but is not marked as identity column, + * then it means that this sequence was created by CREATE TABLE LIKE (see comment in + * transformTableLikeClause). We have to patch default expression, storing new sequence OID. + */ + if (!colDef->identity && colDef->identitySequence) + { + FuncExpr* nextval = ((FuncExpr*)colDef->cooked_default)->funcid == F_NEXTVAL_OID + ? (FuncExpr*)colDef->cooked_default + : (FuncExpr*)linitial(((FuncExpr*)colDef->cooked_default)->args); + ((Const*)linitial(nextval->args))->constvalue = RangeVarGetRelid(colDef->identitySequence, NoLock, false); + colDef->identitySequence = NULL; + } cooked = (CookedConstraint *) palloc(sizeof(CookedConstraint)); cooked->contype = CONSTR_DEFAULT; cooked->conoid = InvalidOid; /* until created */ diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c index 25abc544fc..70296d02a2 100644 --- a/src/backend/parser/parse_utilcmd.c +++ b/src/backend/parser/parse_utilcmd.c @@ -64,6 +64,7 @@ #include "rewrite/rewriteManip.h" #include "utils/acl.h" #include "utils/builtins.h" +#include "utils/fmgroids.h" #include "utils/lsyscache.h" #include "utils/partcache.h" #include "utils/rel.h" @@ -913,6 +914,19 @@ transformTableConstraint(CreateStmtContext *cxt, Constraint *constraint) } } +/* + * Check if sequence was implicitly created by Postgres for SERIAL column + */ +static bool +is_autogenerated_sequence(Relation rel, char* colname, Oid seqid) +{ + char* seqname = makeObjectName(RelationGetRelationName(rel), + colname, + "seq"); + return strcmp(get_rel_name(seqid), seqname) == 0; +} + + /* * transformTableLikeClause * @@ -1072,7 +1086,32 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla { if (attrdef[i].adnum == parent_attno) { + FuncExpr* nextval; this_default = stringToNode(attrdef[i].adbin); + /* + * If sequence is implicitly generated for SERIAL or BIGSERIAL field, + * then default expression has for nextval('REL_COL_seq') or nextval('REL_COL_seq')::int + * Let's create new sequence for the target relation in this case. + * Since default expression is referencing sequence OID and we do not have it + * at this moment, then let DefineRelation do the work of patching default expression. + */ + if (def->identitySequence == NULL + && IsA(this_default, FuncExpr) + && ((nextval = (FuncExpr*)this_default)->funcid == F_NEXTVAL_OID + || (((FuncExpr*)this_default)->funcid == F_INT84 + && IsA(linitial(((FuncExpr*)this_default)->args), FuncExpr) + && (nextval = (FuncExpr*)linitial(((FuncExpr*)this_default)->args))->funcid == F_NEXTVAL_OID))) + { + Oid seq_relid = ((Const*)linitial(nextval->args))->constvalue; + List *seq_options = sequence_options(seq_relid); + if (is_autogenerated_sequence(relation, def->colname, seq_relid)) + { + generateSerialExtraStmts(cxt, def, + InvalidOid, seq_options, + false, false, + NULL, NULL); + } + } break; } }