1
0
mirror of https://github.com/postgres/postgres.git synced 2025-07-28 23:42:10 +03:00

First phase of SCHEMA changes, concentrating on fixing the grammar and

the parsetree representation.  As yet we don't *do* anything with schema
names, just drop 'em on the floor; but you can enter schema-compatible
command syntax, and there's even a primitive CREATE SCHEMA command.
No doc updates yet, except to note that you can now extract a field
from a function-returning-row's result with (foo(...)).fieldname.
This commit is contained in:
Tom Lane
2002-03-21 16:02:16 +00:00
parent 8c9c8ca2b5
commit 95ef6a3448
52 changed files with 2039 additions and 1535 deletions

View File

@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.220 2002/03/12 00:51:52 tgl Exp $
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.221 2002/03/21 16:00:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -43,13 +43,30 @@
#endif
/* State shared by transformCreateSchemaStmt and its subroutines */
typedef struct
{
const char *stmtType; /* "CREATE TABLE" or "ALTER TABLE" */
char *schemaname; /* name of schema */
char *authid; /* owner of schema */
List *tables; /* CREATE TABLE items */
List *views; /* CREATE VIEW items */
List *grants; /* GRANT items */
List *fwconstraints; /* Forward referencing FOREIGN KEY constraints */
List *alters; /* Generated ALTER items (from the above) */
List *ixconstraints; /* index-creating constraints */
List *blist; /* "before list" of things to do before
* creating the schema */
List *alist; /* "after list" of things to do after
* creating the schema */
} CreateSchemaStmtContext;
/* State shared by transformCreateStmt and its subroutines */
typedef struct
{
const char *stmtType; /* "CREATE TABLE" or "ALTER TABLE" */
char *relname; /* name of relation */
List *inhRelnames; /* names of relations to inherit from */
bool istemp; /* is it to be a temp relation? */
RangeVar *relation; /* relation to create */
List *inhRelations; /* relations to inherit from */
bool hasoids; /* does relation have an OID column? */
Oid relOid; /* OID of table, if ALTER TABLE case */
List *columns; /* ColumnDef items */
@ -330,8 +347,8 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
qry->commandType = CMD_DELETE;
/* set up range table with just the result rel */
qry->resultRelation = setTargetTable(pstate, stmt->relname,
interpretInhOption(stmt->inhOpt),
qry->resultRelation = setTargetTable(pstate, stmt->relation->relname,
interpretInhOption(stmt->relation->inhOpt),
true);
qry->distinctClause = NIL;
@ -398,7 +415,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
* table is also mentioned in the SELECT part. Note that the target
* table is not added to the joinlist or namespace.
*/
qry->resultRelation = setTargetTable(pstate, stmt->relname,
qry->resultRelation = setTargetTable(pstate, stmt->relation->relname,
false, false);
/*
@ -443,7 +460,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
*/
rte = addRangeTableEntryForSubquery(pstate,
selectQuery,
makeAttr("*SELECT*", NULL),
makeAlias("*SELECT*", NIL),
true);
rtr = makeNode(RangeTblRef);
/* assume new rte is at end */
@ -515,14 +532,15 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt,
foreach(tl, qry->targetList)
{
TargetEntry *tle = (TargetEntry *) lfirst(tl);
Ident *id;
ResTarget *col;
Assert(!tle->resdom->resjunk);
if (icolumns == NIL || attnos == NIL)
elog(ERROR, "INSERT has more expressions than target columns");
id = (Ident *) lfirst(icolumns);
updateTargetListEntry(pstate, tle, id->name, lfirsti(attnos),
id->indirection);
col = (ResTarget *) lfirst(icolumns);
Assert(IsA(col, ResTarget));
updateTargetListEntry(pstate, tle, col->name, lfirsti(attnos),
col->indirection);
icolumns = lnext(icolumns);
attnos = lnext(attnos);
}
@ -691,9 +709,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt,
List *elements;
cxt.stmtType = "CREATE TABLE";
cxt.relname = stmt->relname;
cxt.inhRelnames = stmt->inhRelnames;
cxt.istemp = stmt->istemp;
cxt.relation = stmt->relation;
cxt.inhRelations = stmt->inhRelations;
cxt.hasoids = stmt->hasoids;
cxt.relOid = InvalidOid;
cxt.columns = NIL;
@ -805,7 +822,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
* conflicting constraints the user wrote (like a different
* DEFAULT).
*/
sname = makeObjectName(cxt->relname, column->colname, "seq");
sname = makeObjectName((cxt->relation)->relname, column->colname, "seq");
/*
* Create an expression tree representing the function call
@ -845,12 +862,12 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
* CREATE/ALTER TABLE.
*/
sequence = makeNode(CreateSeqStmt);
sequence->seqname = pstrdup(sname);
sequence->istemp = cxt->istemp;
sequence->sequence = copyObject(cxt->relation);
sequence->sequence->relname = pstrdup(sname);
sequence->options = NIL;
elog(NOTICE, "%s will create implicit sequence '%s' for SERIAL column '%s.%s'",
cxt->stmtType, sequence->seqname, cxt->relname, column->colname);
cxt->stmtType, sequence->sequence->relname, (cxt->relation)->relname, column->colname);
cxt->blist = lappend(cxt->blist, sequence);
}
@ -875,9 +892,6 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
Ident *id = makeNode(Ident);
id->name = column->colname;
id->indirection = NIL;
id->isRel = false;
fkconstraint->fk_attrs = makeList1(id);
cxt->fkconstraints = lappend(cxt->fkconstraints, fkconstraint);
@ -891,7 +905,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
case CONSTR_NULL:
if (saw_nullable && column->is_not_null)
elog(ERROR, "%s/(NOT) NULL conflicting declaration for '%s.%s'",
cxt->stmtType, cxt->relname, column->colname);
cxt->stmtType, (cxt->relation)->relname, column->colname);
column->is_not_null = FALSE;
saw_nullable = true;
break;
@ -899,7 +913,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
case CONSTR_NOTNULL:
if (saw_nullable && !column->is_not_null)
elog(ERROR, "%s/(NOT) NULL conflicting declaration for '%s.%s'",
cxt->stmtType, cxt->relname, column->colname);
cxt->stmtType, (cxt->relation)->relname, column->colname);
column->is_not_null = TRUE;
saw_nullable = true;
break;
@ -907,14 +921,14 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
case CONSTR_DEFAULT:
if (column->raw_default != NULL)
elog(ERROR, "%s/DEFAULT multiple values specified for '%s.%s'",
cxt->stmtType, cxt->relname, column->colname);
cxt->stmtType, (cxt->relation)->relname, column->colname);
column->raw_default = constraint->raw_expr;
Assert(constraint->cooked_expr == NULL);
break;
case CONSTR_PRIMARY:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relname,
constraint->name = makeObjectName((cxt->relation)->relname,
NULL,
"pkey");
if (constraint->keys == NIL)
@ -928,7 +942,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
case CONSTR_UNIQUE:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relname,
constraint->name = makeObjectName((cxt->relation)->relname,
column->colname,
"key");
if (constraint->keys == NIL)
@ -942,7 +956,7 @@ transformColumnDefinition(ParseState *pstate, CreateStmtContext *cxt,
case CONSTR_CHECK:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relname,
constraint->name = makeObjectName((cxt->relation)->relname,
column->colname,
NULL);
cxt->ckconstraints = lappend(cxt->ckconstraints, constraint);
@ -970,7 +984,7 @@ transformTableConstraint(ParseState *pstate, CreateStmtContext *cxt,
{
case CONSTR_PRIMARY:
if (constraint->name == NULL)
constraint->name = makeObjectName(cxt->relname,
constraint->name = makeObjectName((cxt->relation)->relname,
NULL,
"pkey");
cxt->ixconstraints = lappend(cxt->ixconstraints, constraint);
@ -1034,21 +1048,21 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
/* In ALTER TABLE case, a primary index might already exist */
if (cxt->pkey != NULL ||
(OidIsValid(cxt->relOid) &&
relationHasPrimaryKey(cxt->relname)))
relationHasPrimaryKey((cxt->relation)->relname)))
elog(ERROR, "%s / PRIMARY KEY multiple primary keys"
" for table '%s' are not allowed",
cxt->stmtType, cxt->relname);
cxt->stmtType, (cxt->relation)->relname);
cxt->pkey = index;
}
if (constraint->name != NULL)
index->idxname = pstrdup(constraint->name);
else if (constraint->contype == CONSTR_PRIMARY)
index->idxname = makeObjectName(cxt->relname, NULL, "pkey");
index->idxname = makeObjectName((cxt->relation)->relname, NULL, "pkey");
else
index->idxname = NULL; /* will set it later */
index->relname = cxt->relname;
index->relation = cxt->relation;
index->accessMethod = DEFAULT_INDEX_TYPE;
index->indexParams = NIL;
index->whereClause = NULL;
@ -1089,19 +1103,19 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
*/
found = true;
}
else if (cxt->inhRelnames)
else if (cxt->inhRelations)
{
/* try inherited tables */
List *inher;
foreach(inher, cxt->inhRelnames)
foreach(inher, cxt->inhRelations)
{
Value *inh = lfirst(inher);
RangeVar *inh = lfirst(inher);
Relation rel;
int count;
Assert(IsA(inh, String));
rel = heap_openr(strVal(inh), AccessShareLock);
Assert(IsA(inh, RangeVar));
rel = heap_openr(inh->relname, AccessShareLock);
if (rel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "inherited table \"%s\" is not a relation",
strVal(inh));
@ -1257,7 +1271,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
if (index->idxname == NULL && index->indexParams != NIL)
{
iparam = lfirst(index->indexParams);
index->idxname = CreateIndexName(cxt->relname, iparam->name,
index->idxname = CreateIndexName((cxt->relation)->relname, iparam->name,
"key", cxt->alist);
}
if (index->idxname == NULL) /* should not happen */
@ -1268,7 +1282,7 @@ transformIndexConstraints(ParseState *pstate, CreateStmtContext *cxt)
cxt->stmtType,
(strcmp(cxt->stmtType, "ALTER TABLE") == 0) ? "ADD " : "",
(index->primary ? "PRIMARY KEY" : "UNIQUE"),
index->idxname, cxt->relname);
index->idxname, (cxt->relation)->relname);
}
}
@ -1328,7 +1342,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
*/
if (fkconstraint->pk_attrs == NIL)
{
if (strcmp(fkconstraint->pktable_name, cxt->relname) != 0)
if (strcmp(fkconstraint->pktable->relname, (cxt->relation)->relname) != 0)
transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
else if (cxt->pkey != NULL)
{
@ -1342,8 +1356,6 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
Ident *pkattr = (Ident *) makeNode(Ident);
pkattr->name = pstrdup(ielem->name);
pkattr->indirection = NIL;
pkattr->isRel = false;
fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs,
pkattr);
if (attnum >= INDEX_MAX_KEYS)
@ -1360,13 +1372,13 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
transformFkeyGetPrimaryKey(fkconstraint, pktypoid);
else
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
}
}
else
{
/* Validate the specified referenced key list */
if (strcmp(fkconstraint->pktable_name, cxt->relname) != 0)
if (strcmp(fkconstraint->pktable->relname, (cxt->relation)->relname) != 0)
transformFkeyCheckAttrs(fkconstraint, pktypoid);
else
{
@ -1422,7 +1434,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
transformFkeyCheckAttrs(fkconstraint, pktypoid);
else
elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
}
}
}
@ -1447,7 +1459,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
*/
fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
fk_trigger->relname = cxt->relname;
fk_trigger->relation = cxt->relation;
fk_trigger->funcname = "RI_FKey_check_ins";
fk_trigger->before = false;
fk_trigger->row = true;
@ -1462,15 +1474,15 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
fk_trigger->isconstraint = true;
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrelname = fkconstraint->pktable_name;
fk_trigger->constrrel = fkconstraint->pktable;
fk_trigger->args = NIL;
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->constr_name));
fk_trigger->args = lappend(fk_trigger->args,
makeString(cxt->relname));
makeString((cxt->relation)->relname));
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->pktable_name));
makeString(fkconstraint->pktable->relname));
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->match_type));
fk_attr = fkconstraint->fk_attrs;
@ -1478,7 +1490,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
if (length(fk_attr) != length(pk_attr))
elog(ERROR, "number of key attributes in referenced table must be equal to foreign key"
"\n\tIllegal FOREIGN KEY definition references \"%s\"",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
while (fk_attr != NIL)
{
@ -1502,7 +1514,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
*/
fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
fk_trigger->relname = fkconstraint->pktable_name;
fk_trigger->relation = fkconstraint->pktable;
fk_trigger->before = false;
fk_trigger->row = true;
fk_trigger->actions[0] = 'd';
@ -1515,7 +1527,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
fk_trigger->isconstraint = true;
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrelname = cxt->relname;
fk_trigger->constrrel = cxt->relation;
switch ((fkconstraint->actions & FKCONSTR_ON_DELETE_MASK)
>> FKCONSTR_ON_DELETE_SHIFT)
{
@ -1545,9 +1557,9 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->constr_name));
fk_trigger->args = lappend(fk_trigger->args,
makeString(cxt->relname));
makeString((cxt->relation)->relname));
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->pktable_name));
makeString(fkconstraint->pktable->relname));
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->match_type));
fk_attr = fkconstraint->fk_attrs;
@ -1574,7 +1586,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
*/
fk_trigger = (CreateTrigStmt *) makeNode(CreateTrigStmt);
fk_trigger->trigname = fkconstraint->constr_name;
fk_trigger->relname = fkconstraint->pktable_name;
fk_trigger->relation = fkconstraint->pktable;
fk_trigger->before = false;
fk_trigger->row = true;
fk_trigger->actions[0] = 'u';
@ -1587,7 +1599,7 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
fk_trigger->isconstraint = true;
fk_trigger->deferrable = fkconstraint->deferrable;
fk_trigger->initdeferred = fkconstraint->initdeferred;
fk_trigger->constrrelname = cxt->relname;
fk_trigger->constrrel = cxt->relation;
switch ((fkconstraint->actions & FKCONSTR_ON_UPDATE_MASK)
>> FKCONSTR_ON_UPDATE_SHIFT)
{
@ -1617,9 +1629,9 @@ transformFKConstraints(ParseState *pstate, CreateStmtContext *cxt)
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->constr_name));
fk_trigger->args = lappend(fk_trigger->args,
makeString(cxt->relname));
makeString((cxt->relation)->relname));
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->pktable_name));
makeString(fkconstraint->pktable->relname));
fk_trigger->args = lappend(fk_trigger->args,
makeString(fkconstraint->match_type));
fk_attr = fkconstraint->fk_attrs;
@ -1672,7 +1684,7 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
* easily support predicates on indexes created implicitly by
* CREATE TABLE. Fortunately, that's not necessary.
*/
rte = addRangeTableEntry(pstate, stmt->relname, NULL, false, true);
rte = addRangeTableEntry(pstate, stmt->relation->relname, NULL, false, true);
/* no to join list, yes to namespace */
addRTEtoQuery(pstate, rte, false, true);
@ -1712,7 +1724,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
* beforehand. We don't need to hold a refcount on the relcache
* entry, however.
*/
heap_close(heap_openr(stmt->object->relname, AccessExclusiveLock),
heap_close(heap_openr(stmt->relation->relname, AccessExclusiveLock),
NoLock);
/*
@ -1721,11 +1733,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
* rule qualification.
*/
Assert(pstate->p_rtable == NIL);
oldrte = addRangeTableEntry(pstate, stmt->object->relname,
makeAttr("*OLD*", NULL),
oldrte = addRangeTableEntry(pstate, stmt->relation->relname,
makeAlias("*OLD*", NIL),
false, true);
newrte = addRangeTableEntry(pstate, stmt->object->relname,
makeAttr("*NEW*", NULL),
newrte = addRangeTableEntry(pstate, stmt->relation->relname,
makeAlias("*NEW*", NIL),
false, true);
/* Must override addRangeTableEntry's default access-check flags */
oldrte->checkForRead = false;
@ -1812,11 +1824,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt,
* or they won't be accessible at all. We decide later
* whether to put them in the joinlist.
*/
oldrte = addRangeTableEntry(sub_pstate, stmt->object->relname,
makeAttr("*OLD*", NULL),
oldrte = addRangeTableEntry(sub_pstate, stmt->relation->relname,
makeAlias("*OLD*", NIL),
false, false);
newrte = addRangeTableEntry(sub_pstate, stmt->object->relname,
makeAttr("*NEW*", NULL),
newrte = addRangeTableEntry(sub_pstate, stmt->relation->relname,
makeAlias("*NEW*", NIL),
false, false);
oldrte->checkForRead = false;
newrte->checkForRead = false;
@ -1950,8 +1962,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
if (!IsTransactionBlock())
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
qry->into = stmt->portalname;
qry->isTemp = stmt->istemp;
qry->into = makeNode(RangeVar);
qry->into->relname = stmt->portalname;
qry->isPortal = TRUE;
qry->isBinary = stmt->binary; /* internal portal */
}
@ -1959,7 +1971,6 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
{
/* SELECT */
qry->into = stmt->into;
qry->isTemp = stmt->istemp;
qry->isPortal = FALSE;
qry->isBinary = FALSE;
}
@ -2033,8 +2044,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
int leftmostRTI;
Query *leftmostQuery;
SetOperationStmt *sostmt;
char *into;
bool istemp;
RangeVar *into;
List *intoColNames;
char *portalname;
bool binary;
@ -2065,14 +2075,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
Assert(leftmostSelect && IsA(leftmostSelect, SelectStmt) &&
leftmostSelect->larg == NULL);
into = leftmostSelect->into;
istemp = leftmostSelect->istemp;
intoColNames = leftmostSelect->intoColNames;
portalname = stmt->portalname;
binary = stmt->binary;
/* clear them to prevent complaints in transformSetOperationTree() */
leftmostSelect->into = NULL;
leftmostSelect->istemp = false;
leftmostSelect->intoColNames = NIL;
stmt->portalname = NULL;
stmt->binary = false;
@ -2174,8 +2182,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
if (!IsTransactionBlock())
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
qry->into = portalname;
qry->isTemp = istemp;
qry->into = makeNode(RangeVar);
qry->into->relname = portalname;
qry->isPortal = TRUE;
qry->isBinary = binary; /* internal portal */
}
@ -2183,7 +2191,6 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
{
/* SELECT */
qry->into = into;
qry->isTemp = istemp;
qry->isPortal = FALSE;
qry->isBinary = FALSE;
}
@ -2325,8 +2332,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
sprintf(selectName, "*SELECT* %d", length(pstate->p_rtable) + 1);
rte = addRangeTableEntryForSubquery(pstate,
selectQuery,
makeAttr(pstrdup(selectName),
NULL),
makeAlias(selectName, NIL),
false);
/*
@ -2468,8 +2474,8 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
qry->commandType = CMD_UPDATE;
pstate->p_is_update = true;
qry->resultRelation = setTargetTable(pstate, stmt->relname,
interpretInhOption(stmt->inhOpt),
qry->resultRelation = setTargetTable(pstate, stmt->relation->relname,
interpretInhOption(stmt->relation->inhOpt),
true);
/*
@ -2553,11 +2559,11 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
{
case 'A':
cxt.stmtType = "ALTER TABLE";
cxt.relname = stmt->relname;
cxt.inhRelnames = NIL;
cxt.istemp = is_temp_rel_name(stmt->relname);
cxt.relation = stmt->relation;
cxt.inhRelations = NIL;
cxt.relation->istemp = is_temp_rel_name(stmt->relation->relname);
cxt.relOid = GetSysCacheOid(RELNAME,
PointerGetDatum(stmt->relname),
PointerGetDatum((stmt->relation)->relname),
0, 0, 0);
cxt.hasoids = SearchSysCacheExists(ATTNUM,
ObjectIdGetDatum(cxt.relOid),
@ -2585,11 +2591,11 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt,
case 'C':
cxt.stmtType = "ALTER TABLE";
cxt.relname = stmt->relname;
cxt.inhRelnames = NIL;
cxt.istemp = is_temp_rel_name(stmt->relname);
cxt.relation = stmt->relation;
cxt.inhRelations = NIL;
cxt.relation->istemp = is_temp_rel_name(stmt->relation->relname);
cxt.relOid = GetSysCacheOid(RELNAME,
PointerGetDatum(stmt->relname),
PointerGetDatum((stmt->relation)->relname),
0, 0, 0);
cxt.hasoids = SearchSysCacheExists(ATTNUM,
ObjectIdGetDatum(cxt.relOid),
@ -2713,15 +2719,18 @@ transformTypeRefsList(ParseState *pstate, List *l)
static void
transformTypeRef(ParseState *pstate, TypeName *tn)
{
Attr *att;
ColumnRef *cref;
Node *n;
Var *v;
char *tyn;
if (tn->attrname == NULL)
return;
att = makeAttr(tn->name, tn->attrname);
n = transformExpr(pstate, (Node *) att, EXPR_COLUMN_FIRST);
/* XXX this needs work; can't type name be qualified? */
cref = makeNode(ColumnRef);
cref->fields = makeList2(makeString(tn->name), makeString(tn->attrname));
cref->indirection = NIL;
n = transformExpr(pstate, (Node *) cref);
if (!IsA(n, Var))
elog(ERROR, "unsupported expression in %%TYPE");
v = (Var *) n;
@ -2791,7 +2800,7 @@ transformForUpdate(Query *qry, List *forUpdate)
RangeTblEntry *rte = (RangeTblEntry *) lfirst(rt);
++i;
if (strcmp(rte->eref->relname, relname) == 0)
if (strcmp(rte->eref->aliasname, relname) == 0)
{
if (rte->subquery)
{
@ -2835,11 +2844,11 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
/*
* Open the referenced table
*/
pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
pkrel = heap_openr(fkconstraint->pktable->relname, AccessShareLock);
if (pkrel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "Referenced relation \"%s\" is not a table",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
/*
* Get the list of index OIDs for the table from the relcache, and
@ -2901,7 +2910,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint, Oid *pktypoid)
}
if (!found)
elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
freeList(indexoidlist);
heap_close(pkrel, AccessShareLock);
@ -2928,11 +2937,11 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
/*
* Open the referenced table
*/
pkrel = heap_openr(fkconstraint->pktable_name, AccessShareLock);
pkrel = heap_openr(fkconstraint->pktable->relname, AccessShareLock);
if (pkrel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "Referenced relation \"%s\" is not a table",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
/*
* Get the list of index OIDs for the table from the relcache, and
@ -2965,7 +2974,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
*/
if (indexStruct == NULL)
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
fkconstraint->pktable_name);
fkconstraint->pktable->relname);
/*
* Now build the list of PK attributes from the indkey definition
@ -2977,8 +2986,6 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint, Oid *pktypoid)
Ident *pkattr = makeNode(Ident);
pkattr->name = pstrdup(NameStr(*attnumAttName(pkrel, pkattno)));
pkattr->indirection = NIL;
pkattr->isRel = false;
pktypoid[attnum++] = attnumTypeId(pkrel, pkattno);
fkconstraint->pk_attrs = lappend(fkconstraint->pk_attrs, pkattr);
@ -3070,14 +3077,14 @@ transformFkeyGetColType(CreateStmtContext *cxt, char *colname)
if (sysatt)
return sysatt->atttypid;
/* Look for column among inherited columns (if CREATE TABLE case) */
foreach(inher, cxt->inhRelnames)
foreach(inher, cxt->inhRelations)
{
Value *inh = lfirst(inher);
RangeVar *inh = lfirst(inher);
Relation rel;
int count;
Assert(IsA(inh, String));
rel = heap_openr(strVal(inh), AccessShareLock);
Assert(IsA(inh, RangeVar));
rel = heap_openr(inh->relname, AccessShareLock);
if (rel->rd_rel->relkind != RELKIND_RELATION)
elog(ERROR, "inherited table \"%s\" is not a relation",
strVal(inh));
@ -3248,3 +3255,104 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
ReleaseSysCache(ctype);
}
/*
* analyzeCreateSchemaStmt -
* analyzes the "create schema" statement
*
* Split the schema element list into individual commands and place
* them in the result list in an order such that there are no
* forward references (e.g. GRANT to a table created later in the list).
*
* SQL92 also allows constraints to make forward references, so thumb through
* the table columns and move forward references to a posterior alter-table
* command.
*
* The result is a list of parse nodes that still need to be analyzed ---
* but we can't analyze the later commands until we've executed the earlier
* ones, because of possible inter-object references.
*
* Note: Called from commands/command.c
*/
List *
analyzeCreateSchemaStmt(CreateSchemaStmt *stmt)
{
CreateSchemaStmtContext cxt;
List *result;
List *elements;
cxt.stmtType = "CREATE SCHEMA";
cxt.schemaname = stmt->schemaname;
cxt.authid = stmt->authid;
cxt.tables = NIL;
cxt.views = NIL;
cxt.grants = NIL;
cxt.fwconstraints = NIL;
cxt.alters = NIL;
cxt.blist = NIL;
cxt.alist = NIL;
/*
* Run through each schema element in the schema element list.
* Separate statements by type, and do preliminary analysis.
*/
foreach(elements, stmt->schemaElts)
{
Node *element = lfirst(elements);
switch (nodeTag(element))
{
case T_CreateStmt:
{
CreateStmt *elp = (CreateStmt *) element;
if (elp->relation->schemaname == NULL)
elp->relation->schemaname = cxt.schemaname;
else if (strcmp(cxt.schemaname, elp->relation->schemaname))
elog(ERROR, "New table refers to a schema (%s)"
" different from the one being created (%s)",
elp->relation->schemaname, cxt.schemaname);
/*
* XXX todo: deal with constraints
*/
cxt.tables = lappend(cxt.tables, element);
}
break;
case T_ViewStmt:
{
ViewStmt *elp = (ViewStmt *) element;
if (elp->view->schemaname == NULL)
elp->view->schemaname = cxt.schemaname;
else if (strcmp(cxt.schemaname, elp->view->schemaname))
elog(ERROR, "New view refers to a schema (%s)"
" different from the one being created (%s)",
elp->view->schemaname, cxt.schemaname);
/*
* XXX todo: deal with references between views
*/
cxt.views = lappend(cxt.views, element);
}
break;
case T_GrantStmt:
cxt.grants = lappend(cxt.grants, element);
break;
default:
elog(ERROR, "parser: unsupported schema node (internal error)");
}
}
result = NIL;
result = nconc(result, cxt.tables);
result = nconc(result, cxt.views);
result = nconc(result, cxt.grants);
return result;
}