aboutsummaryrefslogtreecommitdiff
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.c142
1 files changed, 77 insertions, 65 deletions
diff --git a/src/backend/parser/parse_utilcmd.c b/src/backend/parser/parse_utilcmd.c
index 42095ab8306..ee2d2b54a1d 100644
--- a/src/backend/parser/parse_utilcmd.c
+++ b/src/backend/parser/parse_utilcmd.c
@@ -347,7 +347,8 @@ transformCreateStmt(CreateStmt *stmt, const char *queryString)
*/
static void
generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
- Oid seqtypid, List *seqoptions, bool for_identity,
+ Oid seqtypid, List *seqoptions,
+ bool for_identity, bool col_exists,
char **snamespace_p, char **sname_p)
{
ListCell *option;
@@ -472,8 +473,12 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
/*
* Build an ALTER SEQUENCE ... OWNED BY command to mark the sequence as
- * owned by this column, and add it to the list of things to be done after
- * this CREATE/ALTER TABLE.
+ * owned by this column, and add it to the appropriate list of things to
+ * be done along with this CREATE/ALTER TABLE. In a CREATE or ALTER ADD
+ * COLUMN, it must be done after the statement because we don't know the
+ * column's attnum yet. But if we do have the attnum (in AT_AddIdentity),
+ * we can do the marking immediately, which improves some ALTER TABLE
+ * behaviors.
*/
altseqstmt = makeNode(AlterSeqStmt);
altseqstmt->sequence = makeRangeVar(snamespace, sname, -1);
@@ -484,7 +489,10 @@ generateSerialExtraStmts(CreateStmtContext *cxt, ColumnDef *column,
(Node *) attnamelist, -1));
altseqstmt->for_identity = for_identity;
- cxt->alist = lappend(cxt->alist, altseqstmt);
+ if (col_exists)
+ cxt->blist = lappend(cxt->blist, altseqstmt);
+ else
+ cxt->alist = lappend(cxt->alist, altseqstmt);
if (snamespace_p)
*snamespace_p = snamespace;
@@ -568,7 +576,8 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
Constraint *constraint;
generateSerialExtraStmts(cxt, column,
- column->typeName->typeOid, NIL, false,
+ column->typeName->typeOid, NIL,
+ false, false,
&snamespace, &sname);
/*
@@ -684,7 +693,8 @@ transformColumnDefinition(CreateStmtContext *cxt, ColumnDef *column)
constraint->location)));
generateSerialExtraStmts(cxt, column,
- typeOid, constraint->options, true,
+ typeOid, constraint->options,
+ true, false,
NULL, NULL);
column->identity = constraint->generated_when;
@@ -1086,7 +1096,8 @@ transformTableLikeClause(CreateStmtContext *cxt, TableLikeClause *table_like_cla
seq_relid = getIdentitySequence(RelationGetRelid(relation), attribute->attnum, false);
seq_options = sequence_options(seq_relid);
generateSerialExtraStmts(cxt, def,
- InvalidOid, seq_options, true,
+ InvalidOid, seq_options,
+ true, false,
NULL, NULL);
def->identity = attribute->attidentity;
}
@@ -2572,7 +2583,7 @@ transformFKConstraints(CreateStmtContext *cxt,
Constraint *constraint = (Constraint *) lfirst(fkclist);
AlterTableCmd *altercmd = makeNode(AlterTableCmd);
- altercmd->subtype = AT_ProcessedConstraint;
+ altercmd->subtype = AT_AddConstraint;
altercmd->name = NULL;
altercmd->def = (Node *) constraint;
alterstmt->cmds = lappend(alterstmt->cmds, altercmd);
@@ -3004,23 +3015,23 @@ transformRuleStmt(RuleStmt *stmt, const char *queryString,
* transformAlterTableStmt -
* parse analysis for ALTER TABLE
*
- * Returns a List of utility commands to be done in sequence. One of these
- * will be the transformed AlterTableStmt, but there may be additional actions
- * to be done before and after the actual AlterTable() call.
+ * Returns the transformed AlterTableStmt. There may be additional actions
+ * to be done before and after the transformed statement, which are returned
+ * in *beforeStmts and *afterStmts as lists of utility command parsetrees.
*
* To avoid race conditions, it's important that this function rely only on
* the passed-in relid (and not on stmt->relation) to determine the target
* relation.
*/
-List *
+AlterTableStmt *
transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
- const char *queryString)
+ const char *queryString,
+ List **beforeStmts, List **afterStmts)
{
Relation rel;
TupleDesc tupdesc;
ParseState *pstate;
CreateStmtContext cxt;
- List *result;
List *save_alist;
ListCell *lcmd,
*l;
@@ -3052,7 +3063,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
/* Set up CreateStmtContext */
cxt.pstate = pstate;
- if (stmt->relkind == OBJECT_FOREIGN_TABLE)
+ if (rel->rd_rel->relkind == RELKIND_FOREIGN_TABLE)
{
cxt.stmtType = "ALTER FOREIGN TABLE";
cxt.isforeign = true;
@@ -3080,9 +3091,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
cxt.ofType = false;
/*
- * The only subtypes that currently require parse transformation handling
- * are ADD COLUMN, ADD CONSTRAINT and SET DATA TYPE. These largely re-use
- * code from CREATE TABLE.
+ * Transform ALTER subcommands that need it (most don't). These largely
+ * re-use code from CREATE TABLE.
*/
foreach(lcmd, stmt->cmds)
{
@@ -3091,7 +3101,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
switch (cmd->subtype)
{
case AT_AddColumn:
- case AT_AddColumnToView:
+ case AT_AddColumnRecurse:
{
ColumnDef *def = castNode(ColumnDef, cmd->def);
@@ -3115,6 +3125,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
}
case AT_AddConstraint:
+ case AT_AddConstraintRecurse:
/*
* The original AddConstraint cmd node doesn't go to newcmds
@@ -3130,19 +3141,9 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
(int) nodeTag(cmd->def));
break;
- case AT_ProcessedConstraint:
-
- /*
- * Already-transformed ADD CONSTRAINT, so just make it look
- * like the standard case.
- */
- cmd->subtype = AT_AddConstraint;
- newcmds = lappend(newcmds, cmd);
- break;
-
case AT_AlterColumnType:
{
- ColumnDef *def = (ColumnDef *) cmd->def;
+ ColumnDef *def = castNode(ColumnDef, cmd->def);
AttrNumber attnum;
/*
@@ -3161,13 +3162,13 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
* change the data type of the sequence.
*/
attnum = get_attnum(relid, cmd->name);
+ if (attnum == InvalidAttrNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ cmd->name, RelationGetRelationName(rel))));
- /*
- * if attribute not found, something will error about it
- * later
- */
- if (attnum != InvalidAttrNumber &&
- TupleDescAttr(tupdesc, attnum - 1)->attidentity)
+ if (TupleDescAttr(tupdesc, attnum - 1)->attidentity)
{
Oid seq_relid = getIdentitySequence(relid, attnum, false);
Oid typeOid = typenameTypeId(pstate, def->typeName);
@@ -3196,16 +3197,16 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
cmd->def = (Node *) newdef;
attnum = get_attnum(relid, cmd->name);
+ if (attnum == InvalidAttrNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ cmd->name, RelationGetRelationName(rel))));
- /*
- * if attribute not found, something will error about it
- * later
- */
- if (attnum != InvalidAttrNumber)
- generateSerialExtraStmts(&cxt, newdef,
- get_atttype(relid, attnum),
- def->options, true,
- NULL, NULL);
+ generateSerialExtraStmts(&cxt, newdef,
+ get_atttype(relid, attnum),
+ def->options, true, true,
+ NULL, NULL);
newcmds = lappend(newcmds, cmd);
break;
@@ -3221,6 +3222,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
List *newseqopts = NIL;
List *newdef = NIL;
AttrNumber attnum;
+ Oid seq_relid;
/*
* Split options into those handled by ALTER SEQUENCE and
@@ -3237,29 +3239,34 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
}
attnum = get_attnum(relid, cmd->name);
+ if (attnum == InvalidAttrNumber)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_COLUMN),
+ errmsg("column \"%s\" of relation \"%s\" does not exist",
+ cmd->name, RelationGetRelationName(rel))));
- if (attnum)
- {
- Oid seq_relid = getIdentitySequence(relid, attnum, true);
+ seq_relid = getIdentitySequence(relid, attnum, true);
- if (seq_relid)
- {
- AlterSeqStmt *seqstmt;
+ if (seq_relid)
+ {
+ AlterSeqStmt *seqstmt;
- seqstmt = makeNode(AlterSeqStmt);
- seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
- get_rel_name(seq_relid), -1);
- seqstmt->options = newseqopts;
- seqstmt->for_identity = true;
- seqstmt->missing_ok = false;
+ seqstmt = makeNode(AlterSeqStmt);
+ seqstmt->sequence = makeRangeVar(get_namespace_name(get_rel_namespace(seq_relid)),
+ get_rel_name(seq_relid), -1);
+ seqstmt->options = newseqopts;
+ seqstmt->for_identity = true;
+ seqstmt->missing_ok = false;
- cxt.alist = lappend(cxt.alist, seqstmt);
- }
+ cxt.blist = lappend(cxt.blist, seqstmt);
}
/*
- * If column was not found or was not an identity column,
- * we just let the ALTER TABLE command error out later.
+ * If column was not an identity column, we just let the
+ * ALTER TABLE command error out later. (There are cases
+ * this fails to cover, but we'll need to restructure
+ * where creation of the sequence dependency linkage
+ * happens before we can fix it.)
*/
cmd->def = (Node *) newdef;
@@ -3281,6 +3288,12 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
break;
default:
+
+ /*
+ * Currently, we shouldn't actually get here for subcommand
+ * types that don't require transformation; but if we do, just
+ * emit them unchanged.
+ */
newcmds = lappend(newcmds, cmd);
break;
}
@@ -3361,11 +3374,10 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
*/
stmt->cmds = newcmds;
- result = lappend(cxt.blist, stmt);
- result = list_concat(result, cxt.alist);
- result = list_concat(result, save_alist);
+ *beforeStmts = cxt.blist;
+ *afterStmts = list_concat(cxt.alist, save_alist);
- return result;
+ return stmt;
}