mirror of
https://github.com/postgres/postgres.git
synced 2025-04-21 12:05:57 +03:00
Transform ALTER TABLE/SET TYPE/USING expr during parse analysis
This lets later stages have access to the transformed expression; in particular it allows DDL-deparsing code during event triggers to pass the transformed expression to ruleutils.c, so that the complete command can be deparsed. This shuffles the timing of the transform calls a bit: previously, nothing was transformed during parse analysis, and only the RELKIND_RELATION case was being handled during execution. After this patch, all expressions are transformed during parse analysis (including those for relkinds other than RELATION), and the error for other relation kinds is thrown only during execution. So we do more work than before to reject some bogus cases. That seems acceptable.
This commit is contained in:
parent
4ff695b17d
commit
9550e8348b
@ -7776,7 +7776,7 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
char *colName = cmd->name;
|
char *colName = cmd->name;
|
||||||
ColumnDef *def = (ColumnDef *) cmd->def;
|
ColumnDef *def = (ColumnDef *) cmd->def;
|
||||||
TypeName *typeName = def->typeName;
|
TypeName *typeName = def->typeName;
|
||||||
Node *transform = def->raw_default;
|
Node *transform = def->cooked_default;
|
||||||
HeapTuple tuple;
|
HeapTuple tuple;
|
||||||
Form_pg_attribute attTup;
|
Form_pg_attribute attTup;
|
||||||
AttrNumber attnum;
|
AttrNumber attnum;
|
||||||
@ -7835,34 +7835,13 @@ ATPrepAlterColumnType(List **wqueue,
|
|||||||
{
|
{
|
||||||
/*
|
/*
|
||||||
* Set up an expression to transform the old data value to the new
|
* Set up an expression to transform the old data value to the new
|
||||||
* type. If a USING option was given, transform and use that
|
* type. If a USING option was given, use the expression as transformed
|
||||||
* expression, else just take the old value and try to coerce it. We
|
* by transformAlterTableStmt, else just take the old value and try to
|
||||||
* do this first so that type incompatibility can be detected before
|
* coerce it. We do this first so that type incompatibility can be
|
||||||
* we waste effort, and because we need the expression to be parsed
|
* detected before we waste effort, and because we need the expression
|
||||||
* against the original table row type.
|
* to be parsed against the original table row type.
|
||||||
*/
|
*/
|
||||||
if (transform)
|
if (!transform)
|
||||||
{
|
|
||||||
RangeTblEntry *rte;
|
|
||||||
|
|
||||||
/* Expression must be able to access vars of old table */
|
|
||||||
rte = addRangeTableEntryForRelation(pstate,
|
|
||||||
rel,
|
|
||||||
NULL,
|
|
||||||
false,
|
|
||||||
true);
|
|
||||||
addRTEtoQuery(pstate, rte, false, true, true);
|
|
||||||
|
|
||||||
transform = transformExpr(pstate, transform,
|
|
||||||
EXPR_KIND_ALTER_COL_TRANSFORM);
|
|
||||||
|
|
||||||
/* It can't return a set */
|
|
||||||
if (expression_returns_set(transform))
|
|
||||||
ereport(ERROR,
|
|
||||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
|
||||||
errmsg("transform expression must not return a set")));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
{
|
||||||
transform = (Node *) makeVar(1, attnum,
|
transform = (Node *) makeVar(1, attnum,
|
||||||
attTup->atttypid, attTup->atttypmod,
|
attTup->atttypid, attTup->atttypmod,
|
||||||
|
@ -2372,6 +2372,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
|
|||||||
List *newcmds = NIL;
|
List *newcmds = NIL;
|
||||||
bool skipValidation = true;
|
bool skipValidation = true;
|
||||||
AlterTableCmd *newcmd;
|
AlterTableCmd *newcmd;
|
||||||
|
RangeTblEntry *rte;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We must not scribble on the passed-in AlterTableStmt, so copy it. (This
|
* We must not scribble on the passed-in AlterTableStmt, so copy it. (This
|
||||||
@ -2382,10 +2383,17 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
|
|||||||
/* Caller is responsible for locking the relation */
|
/* Caller is responsible for locking the relation */
|
||||||
rel = relation_open(relid, NoLock);
|
rel = relation_open(relid, NoLock);
|
||||||
|
|
||||||
/* Set up pstate and CreateStmtContext */
|
/* Set up pstate */
|
||||||
pstate = make_parsestate(NULL);
|
pstate = make_parsestate(NULL);
|
||||||
pstate->p_sourcetext = queryString;
|
pstate->p_sourcetext = queryString;
|
||||||
|
rte = addRangeTableEntryForRelation(pstate,
|
||||||
|
rel,
|
||||||
|
NULL,
|
||||||
|
false,
|
||||||
|
true);
|
||||||
|
addRTEtoQuery(pstate, rte, false, true, true);
|
||||||
|
|
||||||
|
/* Set up CreateStmtContext */
|
||||||
cxt.pstate = pstate;
|
cxt.pstate = pstate;
|
||||||
if (stmt->relkind == OBJECT_FOREIGN_TABLE)
|
if (stmt->relkind == OBJECT_FOREIGN_TABLE)
|
||||||
{
|
{
|
||||||
@ -2413,8 +2421,8 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
|
|||||||
|
|
||||||
/*
|
/*
|
||||||
* The only subtypes that currently require parse transformation handling
|
* The only subtypes that currently require parse transformation handling
|
||||||
* are ADD COLUMN and ADD CONSTRAINT. These largely re-use code from
|
* are ADD COLUMN, ADD CONSTRAINT and SET DATA TYPE. These largely re-use
|
||||||
* CREATE TABLE.
|
* code from CREATE TABLE.
|
||||||
*/
|
*/
|
||||||
foreach(lcmd, stmt->cmds)
|
foreach(lcmd, stmt->cmds)
|
||||||
{
|
{
|
||||||
@ -2446,6 +2454,7 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
|
|||||||
newcmds = lappend(newcmds, cmd);
|
newcmds = lappend(newcmds, cmd);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case AT_AddConstraint:
|
case AT_AddConstraint:
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -2472,6 +2481,31 @@ transformAlterTableStmt(Oid relid, AlterTableStmt *stmt,
|
|||||||
newcmds = lappend(newcmds, cmd);
|
newcmds = lappend(newcmds, cmd);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case AT_AlterColumnType:
|
||||||
|
{
|
||||||
|
ColumnDef *def = (ColumnDef *) cmd->def;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* For ALTER COLUMN TYPE, transform the USING clause if
|
||||||
|
* one was specified.
|
||||||
|
*/
|
||||||
|
if (def->raw_default)
|
||||||
|
{
|
||||||
|
def->cooked_default =
|
||||||
|
transformExpr(pstate, def->raw_default,
|
||||||
|
EXPR_KIND_ALTER_COL_TRANSFORM);
|
||||||
|
|
||||||
|
/* it can't return a set */
|
||||||
|
if (expression_returns_set(def->cooked_default))
|
||||||
|
ereport(ERROR,
|
||||||
|
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||||
|
errmsg("transform expression must not return a set")));
|
||||||
|
}
|
||||||
|
|
||||||
|
newcmds = lappend(newcmds, cmd);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
newcmds = lappend(newcmds, cmd);
|
newcmds = lappend(newcmds, cmd);
|
||||||
break;
|
break;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user