mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
pgindent run. Make it all clean.
This commit is contained in:
@@ -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.181 2001/02/15 01:10:28 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.182 2001/03/22 03:59:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -228,7 +228,7 @@ transformStmt(ParseState *pstate, Node *parseTree)
|
||||
(SelectStmt *) parseTree);
|
||||
else
|
||||
result = transformSetOperationStmt(pstate,
|
||||
(SelectStmt *) parseTree);
|
||||
(SelectStmt *) parseTree);
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -302,11 +302,11 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
/*
|
||||
* If a non-nil rangetable/namespace was passed in, and we are doing
|
||||
* INSERT/SELECT, arrange to pass the rangetable/namespace down to the
|
||||
* SELECT. This can only happen if we are inside a CREATE RULE,
|
||||
* and in that case we want the rule's OLD and NEW rtable entries to
|
||||
* SELECT. This can only happen if we are inside a CREATE RULE, and
|
||||
* in that case we want the rule's OLD and NEW rtable entries to
|
||||
* appear as part of the SELECT's rtable, not as outer references for
|
||||
* it. (Kluge!) The SELECT's joinlist is not affected however.
|
||||
* We must do this before adding the target table to the INSERT's rtable.
|
||||
* it. (Kluge!) The SELECT's joinlist is not affected however. We
|
||||
* must do this before adding the target table to the INSERT's rtable.
|
||||
*/
|
||||
if (stmt->selectStmt)
|
||||
{
|
||||
@@ -324,7 +324,7 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
/*
|
||||
* Must get write lock on INSERT target table before scanning SELECT,
|
||||
* else we will grab the wrong kind of initial lock if the target
|
||||
* table is also mentioned in the SELECT part. Note that the target
|
||||
* 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,
|
||||
@@ -336,17 +336,17 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
if (stmt->selectStmt)
|
||||
{
|
||||
ParseState *sub_pstate = make_parsestate(pstate->parentParseState);
|
||||
Query *selectQuery;
|
||||
Query *selectQuery;
|
||||
RangeTblEntry *rte;
|
||||
RangeTblRef *rtr;
|
||||
|
||||
/*
|
||||
* Process the source SELECT.
|
||||
*
|
||||
* It is important that this be handled just like a standalone SELECT;
|
||||
* otherwise the behavior of SELECT within INSERT might be different
|
||||
* from a stand-alone SELECT. (Indeed, Postgres up through 6.5 had
|
||||
* bugs of just that nature...)
|
||||
* It is important that this be handled just like a standalone
|
||||
* SELECT; otherwise the behavior of SELECT within INSERT might be
|
||||
* different from a stand-alone SELECT. (Indeed, Postgres up
|
||||
* through 6.5 had bugs of just that nature...)
|
||||
*/
|
||||
sub_pstate->p_rtable = sub_rtable;
|
||||
sub_pstate->p_namespace = sub_namespace;
|
||||
@@ -360,9 +360,10 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
Assert(selectQuery->commandType == CMD_SELECT);
|
||||
if (selectQuery->into || selectQuery->isPortal)
|
||||
elog(ERROR, "INSERT ... SELECT may not specify INTO");
|
||||
|
||||
/*
|
||||
* Make the source be a subquery in the INSERT's rangetable,
|
||||
* and add it to the INSERT's joinlist.
|
||||
* Make the source be a subquery in the INSERT's rangetable, and
|
||||
* add it to the INSERT's joinlist.
|
||||
*/
|
||||
rte = addRangeTableEntryForSubquery(pstate,
|
||||
selectQuery,
|
||||
@@ -373,18 +374,19 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
rtr->rtindex = length(pstate->p_rtable);
|
||||
Assert(rte == rt_fetch(rtr->rtindex, pstate->p_rtable));
|
||||
pstate->p_joinlist = lappend(pstate->p_joinlist, rtr);
|
||||
|
||||
/*
|
||||
* Generate a targetlist for the INSERT that selects all
|
||||
* the non-resjunk columns from the subquery. (We need this to
|
||||
* be separate from the subquery's tlist because we may add
|
||||
* columns, insert datatype coercions, etc.)
|
||||
* Generate a targetlist for the INSERT that selects all the
|
||||
* non-resjunk columns from the subquery. (We need this to be
|
||||
* separate from the subquery's tlist because we may add columns,
|
||||
* insert datatype coercions, etc.)
|
||||
*
|
||||
* HACK: constants in the INSERT's targetlist are copied up as-is
|
||||
* rather than being referenced as subquery outputs. This is mainly
|
||||
* to ensure that when we try to coerce them to the target column's
|
||||
* datatype, the right things happen for UNKNOWN constants.
|
||||
* Otherwise this fails:
|
||||
* INSERT INTO foo SELECT 'bar', ... FROM baz
|
||||
* rather than being referenced as subquery outputs. This is
|
||||
* mainly to ensure that when we try to coerce them to the target
|
||||
* column's datatype, the right things happen for UNKNOWN
|
||||
* constants. Otherwise this fails: INSERT INTO foo SELECT 'bar',
|
||||
* ... FROM baz
|
||||
*/
|
||||
qry->targetList = NIL;
|
||||
foreach(tl, selectQuery->targetList)
|
||||
@@ -411,9 +413,10 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* For INSERT ... VALUES, transform the given list of values
|
||||
* to form a targetlist for the INSERT.
|
||||
* For INSERT ... VALUES, transform the given list of values to
|
||||
* form a targetlist for the INSERT.
|
||||
*/
|
||||
qry->targetList = transformTargetList(pstate, stmt->targetList);
|
||||
}
|
||||
@@ -466,8 +469,8 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
|
||||
* have defaults and were not assigned to by the user.
|
||||
*
|
||||
* XXX wouldn't it make more sense to do this further downstream, after
|
||||
* the rule rewriter? As is, altering a column default will not change
|
||||
* the behavior of INSERTs in already-defined rules.
|
||||
* the rule rewriter? As is, altering a column default will not
|
||||
* change the behavior of INSERTs in already-defined rules.
|
||||
*/
|
||||
rd_att = pstate->p_target_relation->rd_att;
|
||||
if (rd_att->constr && rd_att->constr->num_defval > 0)
|
||||
@@ -618,8 +621,8 @@ CreateIndexName(char *table_name, char *column_name,
|
||||
* The type name for makeObjectName is label, or labelN if that's
|
||||
* necessary to prevent collisions among multiple indexes for the same
|
||||
* table. Note there is no check for collisions with already-existing
|
||||
* indexes, only among the indexes we're about to create now; this ought
|
||||
* to be improved someday.
|
||||
* indexes, only among the indexes we're about to create now; this
|
||||
* ought to be improved someday.
|
||||
*/
|
||||
strcpy(typename, label);
|
||||
|
||||
@@ -748,7 +751,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
|
||||
constraint = makeNode(Constraint);
|
||||
constraint->contype = CONSTR_UNIQUE;
|
||||
constraint->name = NULL; /* assign later */
|
||||
constraint->name = NULL; /* assign later */
|
||||
column->constraints = lappend(column->constraints,
|
||||
constraint);
|
||||
|
||||
@@ -948,7 +951,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
else if (constraint->contype == CONSTR_PRIMARY)
|
||||
index->idxname = makeObjectName(stmt->relname, NULL, "pkey");
|
||||
else
|
||||
index->idxname = NULL; /* will set it later */
|
||||
index->idxname = NULL; /* will set it later */
|
||||
|
||||
index->relname = stmt->relname;
|
||||
index->accessMethod = "btree";
|
||||
@@ -956,9 +959,9 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
index->withClause = NIL;
|
||||
index->whereClause = NULL;
|
||||
|
||||
foreach (keys, constraint->keys)
|
||||
foreach(keys, constraint->keys)
|
||||
{
|
||||
bool found = false;
|
||||
bool found = false;
|
||||
|
||||
key = (Ident *) lfirst(keys);
|
||||
Assert(IsA(key, Ident));
|
||||
@@ -982,14 +985,14 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
else
|
||||
{
|
||||
/* try inherited tables */
|
||||
List *inhRelnames = stmt->inhRelnames;
|
||||
List *inher;
|
||||
List *inhRelnames = stmt->inhRelnames;
|
||||
List *inher;
|
||||
|
||||
foreach (inher, inhRelnames)
|
||||
foreach(inher, inhRelnames)
|
||||
{
|
||||
Value *inh = lfirst(inher);
|
||||
Relation rel;
|
||||
int count;
|
||||
Value *inh = lfirst(inher);
|
||||
Relation rel;
|
||||
int count;
|
||||
|
||||
Assert(IsA(inh, String));
|
||||
rel = heap_openr(strVal(inh), AccessShareLock);
|
||||
@@ -999,26 +1002,28 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
for (count = 0; count < rel->rd_att->natts; count++)
|
||||
{
|
||||
Form_pg_attribute inhattr = rel->rd_att->attrs[count];
|
||||
char *inhname = NameStr(inhattr->attname);
|
||||
char *inhname = NameStr(inhattr->attname);
|
||||
|
||||
if (strcmp(key->name, inhname) == 0)
|
||||
{
|
||||
found = true;
|
||||
|
||||
/*
|
||||
* If the column is inherited, we currently have
|
||||
* no easy way to force it to be NOT NULL.
|
||||
* Only way I can see to fix this would be to
|
||||
* convert the inherited-column info to ColumnDef
|
||||
* nodes before we reach this point, and then
|
||||
* create the table from those nodes rather than
|
||||
* referencing the parent tables later. That
|
||||
* would likely be cleaner, but too much work
|
||||
* to contemplate right now. Instead, raise an
|
||||
* error if the inherited column won't be NOT NULL.
|
||||
* (Would a NOTICE be more reasonable?)
|
||||
* If the column is inherited, we currently
|
||||
* have no easy way to force it to be NOT
|
||||
* NULL. Only way I can see to fix this would
|
||||
* be to convert the inherited-column info to
|
||||
* ColumnDef nodes before we reach this point,
|
||||
* and then create the table from those nodes
|
||||
* rather than referencing the parent tables
|
||||
* later. That would likely be cleaner, but
|
||||
* too much work to contemplate right now.
|
||||
* Instead, raise an error if the inherited
|
||||
* column won't be NOT NULL. (Would a NOTICE
|
||||
* be more reasonable?)
|
||||
*/
|
||||
if (constraint->contype == CONSTR_PRIMARY &&
|
||||
! inhattr->attnotnull)
|
||||
!inhattr->attnotnull)
|
||||
elog(ERROR, "inherited attribute \"%s\" cannot be a PRIMARY KEY because it is not marked NOT NULL",
|
||||
inhname);
|
||||
break;
|
||||
@@ -1047,10 +1052,10 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
|
||||
/*
|
||||
* Scan the index list and remove any redundant index specifications.
|
||||
* This can happen if, for instance, the user writes SERIAL PRIMARY KEY
|
||||
* or SERIAL UNIQUE. A strict reading of SQL92 would suggest raising
|
||||
* an error instead, but that strikes me as too anal-retentive.
|
||||
* - tgl 2001-02-14
|
||||
* This can happen if, for instance, the user writes SERIAL PRIMARY
|
||||
* KEY or SERIAL UNIQUE. A strict reading of SQL92 would suggest
|
||||
* raising an error instead, but that strikes me as too
|
||||
* anal-retentive. - tgl 2001-02-14
|
||||
*/
|
||||
dlist = ilist;
|
||||
ilist = NIL;
|
||||
@@ -1075,12 +1080,13 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
|
||||
if (equal(index->indexParams, priorindex->indexParams))
|
||||
{
|
||||
|
||||
/*
|
||||
* If the prior index is as yet unnamed, and this one
|
||||
* is named, then transfer the name to the prior index.
|
||||
* This ensures that if we have named and unnamed
|
||||
* constraints, we'll use (at least one of) the names
|
||||
* for the index.
|
||||
* is named, then transfer the name to the prior
|
||||
* index. This ensures that if we have named and
|
||||
* unnamed constraints, we'll use (at least one of)
|
||||
* the names for the index.
|
||||
*/
|
||||
if (priorindex->idxname == NULL)
|
||||
priorindex->idxname = index->idxname;
|
||||
@@ -1149,46 +1155,57 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
if (fkconstraint->constr_name == NULL)
|
||||
fkconstraint->constr_name = "<unnamed>";
|
||||
|
||||
/*
|
||||
/*
|
||||
* Check to see if the attributes mentioned by the constraint
|
||||
* actually exist on this table.
|
||||
*/
|
||||
if (fkconstraint->fk_attrs!=NIL) {
|
||||
int found=0;
|
||||
List *cols;
|
||||
List *fkattrs;
|
||||
Ident *fkattr = NULL;
|
||||
ColumnDef *col;
|
||||
foreach(fkattrs, fkconstraint->fk_attrs) {
|
||||
found=0;
|
||||
fkattr=lfirst(fkattrs);
|
||||
foreach(cols, stmt->tableElts) {
|
||||
col=lfirst(cols);
|
||||
if (strcmp(col->colname, fkattr->name)==0) {
|
||||
found=1;
|
||||
if (fkconstraint->fk_attrs != NIL)
|
||||
{
|
||||
int found = 0;
|
||||
List *cols;
|
||||
List *fkattrs;
|
||||
Ident *fkattr = NULL;
|
||||
ColumnDef *col;
|
||||
|
||||
foreach(fkattrs, fkconstraint->fk_attrs)
|
||||
{
|
||||
found = 0;
|
||||
fkattr = lfirst(fkattrs);
|
||||
foreach(cols, stmt->tableElts)
|
||||
{
|
||||
col = lfirst(cols);
|
||||
if (strcmp(col->colname, fkattr->name) == 0)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found)
|
||||
break;
|
||||
}
|
||||
if (!found) { /* try inherited tables */
|
||||
List *inher;
|
||||
List *inhRelnames=stmt->inhRelnames;
|
||||
Relation rel;
|
||||
foreach (inher, inhRelnames) {
|
||||
Value *inh=lfirst(inher);
|
||||
int count;
|
||||
if (!found)
|
||||
{ /* try inherited tables */
|
||||
List *inher;
|
||||
List *inhRelnames = stmt->inhRelnames;
|
||||
Relation rel;
|
||||
|
||||
foreach(inher, inhRelnames)
|
||||
{
|
||||
Value *inh = lfirst(inher);
|
||||
int count;
|
||||
|
||||
Assert(IsA(inh, String));
|
||||
rel=heap_openr(strVal(inh), AccessShareLock);
|
||||
rel = heap_openr(strVal(inh), AccessShareLock);
|
||||
if (rel->rd_rel->relkind != RELKIND_RELATION)
|
||||
elog(ERROR, "inherited table \"%s\" is not a relation",
|
||||
strVal(inh));
|
||||
for (count = 0; count < rel->rd_att->natts; count++) {
|
||||
char *name=NameStr(rel->rd_att->attrs[count]->attname);
|
||||
if (strcmp(fkattr->name, name) == 0) {
|
||||
found=1;
|
||||
strVal(inh));
|
||||
for (count = 0; count < rel->rd_att->natts; count++)
|
||||
{
|
||||
char *name = NameStr(rel->rd_att->attrs[count]->attname);
|
||||
|
||||
if (strcmp(fkattr->name, name) == 0)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1197,9 +1214,8 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
found=1;
|
||||
}
|
||||
else
|
||||
found = 1;
|
||||
if (!found)
|
||||
elog(ERROR, "columns referenced in foreign key constraint not found.");
|
||||
}
|
||||
@@ -1238,35 +1254,44 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
fkconstraint->pktable_name);
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (strcmp(fkconstraint->pktable_name, stmt->relname)!=0)
|
||||
else
|
||||
{
|
||||
if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0)
|
||||
transformFkeyCheckAttrs(fkconstraint);
|
||||
else {
|
||||
else
|
||||
{
|
||||
/* Get a unique/pk constraint from above */
|
||||
List *index;
|
||||
int found=0;
|
||||
List *index;
|
||||
int found = 0;
|
||||
|
||||
foreach(index, ilist)
|
||||
{
|
||||
IndexStmt *ind=lfirst(index);
|
||||
IndexElem *indparm;
|
||||
List *indparms;
|
||||
List *pkattrs;
|
||||
Ident *pkattr;
|
||||
if (ind->unique) {
|
||||
int count=0;
|
||||
foreach(indparms, ind->indexParams) {
|
||||
IndexStmt *ind = lfirst(index);
|
||||
IndexElem *indparm;
|
||||
List *indparms;
|
||||
List *pkattrs;
|
||||
Ident *pkattr;
|
||||
|
||||
if (ind->unique)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
foreach(indparms, ind->indexParams)
|
||||
count++;
|
||||
}
|
||||
if (count!=length(fkconstraint->pk_attrs))
|
||||
found=0;
|
||||
else {
|
||||
foreach(pkattrs, fkconstraint->pk_attrs) {
|
||||
found=0;
|
||||
pkattr=lfirst(pkattrs);
|
||||
foreach(indparms, ind->indexParams) {
|
||||
indparm=lfirst(indparms);
|
||||
if (strcmp(indparm->name, pkattr->name)==0) {
|
||||
found=1;
|
||||
if (count != length(fkconstraint->pk_attrs))
|
||||
found = 0;
|
||||
else
|
||||
{
|
||||
foreach(pkattrs, fkconstraint->pk_attrs)
|
||||
{
|
||||
found = 0;
|
||||
pkattr = lfirst(pkattrs);
|
||||
foreach(indparms, ind->indexParams)
|
||||
{
|
||||
indparm = lfirst(indparms);
|
||||
if (strcmp(indparm->name, pkattr->name) == 0)
|
||||
{
|
||||
found = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -1283,6 +1308,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
fkconstraint->pktable_name);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
|
||||
* action.
|
||||
@@ -1309,13 +1335,13 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
|
||||
fk_trigger->args = NIL;
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->constr_name));
|
||||
makeString(fkconstraint->constr_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(stmt->relname));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->pktable_name));
|
||||
makeString(fkconstraint->pktable_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->match_type));
|
||||
makeString(fkconstraint->match_type));
|
||||
fk_attr = fkconstraint->fk_attrs;
|
||||
pk_attr = fkconstraint->pk_attrs;
|
||||
if (length(fk_attr) != length(pk_attr))
|
||||
@@ -1388,13 +1414,13 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
|
||||
fk_trigger->args = NIL;
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->constr_name));
|
||||
makeString(fkconstraint->constr_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(stmt->relname));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->pktable_name));
|
||||
makeString(fkconstraint->pktable_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->match_type));
|
||||
makeString(fkconstraint->match_type));
|
||||
fk_attr = fkconstraint->fk_attrs;
|
||||
pk_attr = fkconstraint->pk_attrs;
|
||||
while (fk_attr != NIL)
|
||||
@@ -1461,13 +1487,13 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
|
||||
|
||||
fk_trigger->args = NIL;
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->constr_name));
|
||||
makeString(fkconstraint->constr_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(stmt->relname));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->pktable_name));
|
||||
makeString(fkconstraint->pktable_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->match_type));
|
||||
makeString(fkconstraint->match_type));
|
||||
fk_attr = fkconstraint->fk_attrs;
|
||||
pk_attr = fkconstraint->pk_attrs;
|
||||
while (fk_attr != NIL)
|
||||
@@ -1558,18 +1584,18 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
|
||||
/*
|
||||
* To avoid deadlock, make sure the first thing we do is grab
|
||||
* AccessExclusiveLock on the target relation. This will be
|
||||
* needed by DefineQueryRewrite(), and we don't want to grab a lesser
|
||||
* lock beforehand. We don't need to hold a refcount on the relcache
|
||||
* AccessExclusiveLock on the target relation. This will be needed by
|
||||
* DefineQueryRewrite(), and we don't want to grab a lesser lock
|
||||
* beforehand. We don't need to hold a refcount on the relcache
|
||||
* entry, however.
|
||||
*/
|
||||
heap_close(heap_openr(stmt->object->relname, AccessExclusiveLock),
|
||||
NoLock);
|
||||
|
||||
/*
|
||||
* NOTE: 'OLD' must always have a varno equal to 1 and 'NEW'
|
||||
* equal to 2. Set up their RTEs in the main pstate for use
|
||||
* in parsing the rule qualification.
|
||||
* NOTE: 'OLD' must always have a varno equal to 1 and 'NEW' equal to
|
||||
* 2. Set up their RTEs in the main pstate for use in parsing the
|
||||
* rule qualification.
|
||||
*/
|
||||
Assert(pstate->p_rtable == NIL);
|
||||
oldrte = addRangeTableEntry(pstate, stmt->object->relname,
|
||||
@@ -1581,13 +1607,15 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
/* Must override addRangeTableEntry's default access-check flags */
|
||||
oldrte->checkForRead = false;
|
||||
newrte->checkForRead = false;
|
||||
|
||||
/*
|
||||
* They must be in the namespace too for lookup purposes, but only add
|
||||
* the one(s) that are relevant for the current kind of rule. In an
|
||||
* UPDATE rule, quals must refer to OLD.field or NEW.field to be
|
||||
* unambiguous, but there's no need to be so picky for INSERT & DELETE.
|
||||
* (Note we marked the RTEs "inFromCl = true" above to allow unqualified
|
||||
* references to their fields.) We do not add them to the joinlist.
|
||||
* unambiguous, but there's no need to be so picky for INSERT &
|
||||
* DELETE. (Note we marked the RTEs "inFromCl = true" above to allow
|
||||
* unqualified references to their fields.) We do not add them to the
|
||||
* joinlist.
|
||||
*/
|
||||
switch (stmt->event)
|
||||
{
|
||||
@@ -1613,7 +1641,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
/* take care of the where clause */
|
||||
stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
|
||||
|
||||
if (length(pstate->p_rtable) != 2) /* naughty, naughty... */
|
||||
if (length(pstate->p_rtable) != 2) /* naughty, naughty... */
|
||||
elog(ERROR, "Rule WHERE condition may not contain references to other relations");
|
||||
|
||||
/* save info about sublinks in where clause */
|
||||
@@ -1632,7 +1660,7 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
|
||||
nothing_qry->commandType = CMD_NOTHING;
|
||||
nothing_qry->rtable = pstate->p_rtable;
|
||||
nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
|
||||
nothing_qry->jointree = makeFromExpr(NIL, NULL); /* no join wanted */
|
||||
|
||||
stmt->actions = makeList1(nothing_qry);
|
||||
}
|
||||
@@ -1652,12 +1680,12 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
has_new;
|
||||
|
||||
/*
|
||||
* Set up OLD/NEW in the rtable for this statement. The entries
|
||||
* are marked not inFromCl because we don't want them to be
|
||||
* referred to by unqualified field names nor "*" in the rule
|
||||
* actions. We must add them to the namespace, however, or they
|
||||
* won't be accessible at all. We decide later whether to put
|
||||
* them in the joinlist.
|
||||
* Set up OLD/NEW in the rtable for this statement. The
|
||||
* entries are marked not inFromCl because we don't want them
|
||||
* to be referred to by unqualified field names nor "*" in the
|
||||
* rule actions. We must add them to the namespace, however,
|
||||
* 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),
|
||||
@@ -1676,7 +1704,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
/*
|
||||
* If the action is INSERT...SELECT, OLD/NEW have been pushed
|
||||
* down into the SELECT, and that's what we need to look at.
|
||||
* (Ugly kluge ... try to fix this when we redesign querytrees.)
|
||||
* (Ugly kluge ... try to fix this when we redesign
|
||||
* querytrees.)
|
||||
*/
|
||||
sub_qry = getInsertSelectQuery(top_subqry, NULL);
|
||||
|
||||
@@ -1716,19 +1745,21 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* For efficiency's sake, add OLD to the rule action's jointree
|
||||
* only if it was actually referenced in the statement or qual.
|
||||
* For efficiency's sake, add OLD to the rule action's
|
||||
* jointree only if it was actually referenced in the
|
||||
* statement or qual.
|
||||
*
|
||||
* For INSERT, NEW is not really a relation (only a reference to
|
||||
* the to-be-inserted tuple) and should never be added to the
|
||||
* jointree.
|
||||
*
|
||||
* For UPDATE, we treat NEW as being another kind of reference to
|
||||
* OLD, because it represents references to *transformed* tuples
|
||||
* of the existing relation. It would be wrong to enter NEW
|
||||
* separately in the jointree, since that would cause a double
|
||||
* join of the updated relation. It's also wrong to fail to make
|
||||
* a jointree entry if only NEW and not OLD is mentioned.
|
||||
* OLD, because it represents references to *transformed*
|
||||
* tuples of the existing relation. It would be wrong to
|
||||
* enter NEW separately in the jointree, since that would
|
||||
* cause a double join of the updated relation. It's also
|
||||
* wrong to fail to make a jointree entry if only NEW and not
|
||||
* OLD is mentioned.
|
||||
*/
|
||||
if (has_old || (has_new && stmt->event == CMD_UPDATE))
|
||||
{
|
||||
@@ -1772,12 +1803,12 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
if (stmt->forUpdate)
|
||||
elog(ERROR, "DECLARE/UPDATE is not supported"
|
||||
"\n\tCursors must be READ ONLY");
|
||||
|
||||
/*
|
||||
* 15 august 1991 -- since 3.0 postgres does locking
|
||||
* right, we discovered that portals were violating
|
||||
* locking protocol. portal locks cannot span xacts.
|
||||
* as a short-term fix, we installed the check here.
|
||||
* -- mao
|
||||
* 15 august 1991 -- since 3.0 postgres does locking right, we
|
||||
* discovered that portals were violating locking protocol.
|
||||
* portal locks cannot span xacts. as a short-term fix, we
|
||||
* installed the check here. -- mao
|
||||
*/
|
||||
if (!IsTransactionBlock())
|
||||
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
|
||||
@@ -1785,7 +1816,7 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
qry->into = stmt->portalname;
|
||||
qry->isTemp = stmt->istemp;
|
||||
qry->isPortal = TRUE;
|
||||
qry->isBinary = stmt->binary; /* internal portal */
|
||||
qry->isBinary = stmt->binary; /* internal portal */
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -1881,8 +1912,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
qry->commandType = CMD_SELECT;
|
||||
|
||||
/*
|
||||
* Find leftmost leaf SelectStmt; extract the one-time-only items
|
||||
* from it and from the top-level node.
|
||||
* Find leftmost leaf SelectStmt; extract the one-time-only items from
|
||||
* it and from the top-level node.
|
||||
*/
|
||||
leftmostSelect = stmt->larg;
|
||||
while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
|
||||
@@ -1902,8 +1933,8 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
|
||||
/*
|
||||
* These are not one-time, exactly, but we want to process them here
|
||||
* and not let transformSetOperationTree() see them --- else it'll just
|
||||
* recurse right back here!
|
||||
* and not let transformSetOperationTree() see them --- else it'll
|
||||
* just recurse right back here!
|
||||
*/
|
||||
sortClause = stmt->sortClause;
|
||||
limitOffset = stmt->limitOffset;
|
||||
@@ -1936,11 +1967,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
leftmostRTI = ((RangeTblRef *) node)->rtindex;
|
||||
leftmostQuery = rt_fetch(leftmostRTI, pstate->p_rtable)->subquery;
|
||||
Assert(leftmostQuery != NULL);
|
||||
|
||||
/*
|
||||
* Generate dummy targetlist for outer query using column names of
|
||||
* leftmost select and common datatypes of topmost set operation.
|
||||
* Also make lists of the dummy vars and their names for use in
|
||||
* parsing ORDER BY.
|
||||
* leftmost select and common datatypes of topmost set operation. Also
|
||||
* make lists of the dummy vars and their names for use in parsing
|
||||
* ORDER BY.
|
||||
*/
|
||||
qry->targetList = NIL;
|
||||
targetvars = NIL;
|
||||
@@ -1948,11 +1980,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
lefttl = leftmostQuery->targetList;
|
||||
foreach(dtlist, sostmt->colTypes)
|
||||
{
|
||||
Oid colType = (Oid) lfirsti(dtlist);
|
||||
Resdom *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
|
||||
char *colName = pstrdup(leftResdom->resname);
|
||||
Resdom *resdom;
|
||||
Node *expr;
|
||||
Oid colType = (Oid) lfirsti(dtlist);
|
||||
Resdom *leftResdom = ((TargetEntry *) lfirst(lefttl))->resdom;
|
||||
char *colName = pstrdup(leftResdom->resname);
|
||||
Resdom *resdom;
|
||||
Node *expr;
|
||||
|
||||
resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
|
||||
colType,
|
||||
@@ -1970,6 +2002,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
targetnames = lappend(targetnames, makeString(colName));
|
||||
lefttl = lnext(lefttl);
|
||||
}
|
||||
|
||||
/*
|
||||
* Insert one-time items into top-level query
|
||||
*
|
||||
@@ -1983,12 +2016,12 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
if (forUpdate)
|
||||
elog(ERROR, "DECLARE/UPDATE is not supported"
|
||||
"\n\tCursors must be READ ONLY");
|
||||
|
||||
/*
|
||||
* 15 august 1991 -- since 3.0 postgres does locking
|
||||
* right, we discovered that portals were violating
|
||||
* locking protocol. portal locks cannot span xacts.
|
||||
* as a short-term fix, we installed the check here.
|
||||
* -- mao
|
||||
* 15 august 1991 -- since 3.0 postgres does locking right, we
|
||||
* discovered that portals were violating locking protocol.
|
||||
* portal locks cannot span xacts. as a short-term fix, we
|
||||
* installed the check here. -- mao
|
||||
*/
|
||||
if (!IsTransactionBlock())
|
||||
elog(ERROR, "DECLARE CURSOR may only be used in begin/end transaction blocks");
|
||||
@@ -2008,10 +2041,11 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
}
|
||||
|
||||
/*
|
||||
* As a first step towards supporting sort clauses that are expressions
|
||||
* using the output columns, generate a namespace entry that makes the
|
||||
* output columns visible. A JoinExpr node is handy for this, since
|
||||
* we can easily control the Vars generated upon matches.
|
||||
* As a first step towards supporting sort clauses that are
|
||||
* expressions using the output columns, generate a namespace entry
|
||||
* that makes the output columns visible. A JoinExpr node is handy
|
||||
* for this, since we can easily control the Vars generated upon
|
||||
* matches.
|
||||
*
|
||||
* Note: we don't yet do anything useful with such cases, but at least
|
||||
* "ORDER BY upper(foo)" will draw the right error message rather than
|
||||
@@ -2065,7 +2099,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
|
||||
static Node *
|
||||
transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
{
|
||||
bool isLeaf;
|
||||
bool isLeaf;
|
||||
|
||||
Assert(stmt && IsA(stmt, SelectStmt));
|
||||
|
||||
@@ -2104,9 +2138,9 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
if (isLeaf)
|
||||
{
|
||||
/* Process leaf SELECT */
|
||||
List *selectList;
|
||||
Query *selectQuery;
|
||||
char selectName[32];
|
||||
List *selectList;
|
||||
Query *selectQuery;
|
||||
char selectName[32];
|
||||
RangeTblEntry *rte;
|
||||
RangeTblRef *rtr;
|
||||
|
||||
@@ -2114,13 +2148,14 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
* Transform SelectStmt into a Query.
|
||||
*
|
||||
* Note: previously transformed sub-queries don't affect the parsing
|
||||
* of this sub-query, because they are not in the toplevel pstate's
|
||||
* namespace list.
|
||||
* of this sub-query, because they are not in the toplevel
|
||||
* pstate's namespace list.
|
||||
*/
|
||||
selectList = parse_analyze((Node *) stmt, pstate);
|
||||
|
||||
Assert(length(selectList) == 1);
|
||||
selectQuery = (Query *) lfirst(selectList);
|
||||
|
||||
/*
|
||||
* Make the leaf query be a subquery in the top-level rangetable.
|
||||
*/
|
||||
@@ -2130,8 +2165,10 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
makeAttr(pstrdup(selectName),
|
||||
NULL),
|
||||
false);
|
||||
|
||||
/*
|
||||
* Return a RangeTblRef to replace the SelectStmt in the set-op tree.
|
||||
* Return a RangeTblRef to replace the SelectStmt in the set-op
|
||||
* tree.
|
||||
*/
|
||||
rtr = makeNode(RangeTblRef);
|
||||
/* assume new rte is at end */
|
||||
@@ -2143,8 +2180,8 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
{
|
||||
/* Process an internal node (set operation node) */
|
||||
SetOperationStmt *op = makeNode(SetOperationStmt);
|
||||
List *lcoltypes;
|
||||
List *rcoltypes;
|
||||
List *lcoltypes;
|
||||
List *rcoltypes;
|
||||
const char *context;
|
||||
|
||||
context = (stmt->op == SETOP_UNION ? "UNION" :
|
||||
@@ -2159,6 +2196,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
*/
|
||||
op->larg = transformSetOperationTree(pstate, stmt->larg);
|
||||
op->rarg = transformSetOperationTree(pstate, stmt->rarg);
|
||||
|
||||
/*
|
||||
* Verify that the two children have the same number of non-junk
|
||||
* columns, and determine the types of the merged output columns.
|
||||
@@ -2171,9 +2209,9 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt)
|
||||
op->colTypes = NIL;
|
||||
while (lcoltypes != NIL)
|
||||
{
|
||||
Oid lcoltype = (Oid) lfirsti(lcoltypes);
|
||||
Oid rcoltype = (Oid) lfirsti(rcoltypes);
|
||||
Oid rescoltype;
|
||||
Oid lcoltype = (Oid) lfirsti(lcoltypes);
|
||||
Oid rcoltype = (Oid) lfirsti(rcoltypes);
|
||||
Oid rescoltype;
|
||||
|
||||
rescoltype = select_common_type(makeListi2(lcoltype, rcoltype),
|
||||
context);
|
||||
@@ -2197,9 +2235,9 @@ getSetColTypes(ParseState *pstate, Node *node)
|
||||
{
|
||||
RangeTblRef *rtr = (RangeTblRef *) node;
|
||||
RangeTblEntry *rte = rt_fetch(rtr->rtindex, pstate->p_rtable);
|
||||
Query *selectQuery = rte->subquery;
|
||||
List *result = NIL;
|
||||
List *tl;
|
||||
Query *selectQuery = rte->subquery;
|
||||
List *result = NIL;
|
||||
List *tl;
|
||||
|
||||
Assert(selectQuery != NULL);
|
||||
/* Get types of non-junk columns */
|
||||
@@ -2392,13 +2430,13 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
|
||||
|
||||
fk_trigger->args = NIL;
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->constr_name));
|
||||
makeString(fkconstraint->constr_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(stmt->relname));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->pktable_name));
|
||||
makeString(fkconstraint->pktable_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->match_type));
|
||||
makeString(fkconstraint->match_type));
|
||||
fk_attr = fkconstraint->fk_attrs;
|
||||
pk_attr = fkconstraint->pk_attrs;
|
||||
if (length(fk_attr) != length(pk_attr))
|
||||
@@ -2469,13 +2507,13 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
|
||||
|
||||
fk_trigger->args = NIL;
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->constr_name));
|
||||
makeString(fkconstraint->constr_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(stmt->relname));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->pktable_name));
|
||||
makeString(fkconstraint->pktable_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->match_type));
|
||||
makeString(fkconstraint->match_type));
|
||||
fk_attr = fkconstraint->fk_attrs;
|
||||
pk_attr = fkconstraint->pk_attrs;
|
||||
while (fk_attr != NIL)
|
||||
@@ -2540,13 +2578,13 @@ transformAlterTableStmt(ParseState *pstate, AlterTableStmt *stmt)
|
||||
|
||||
fk_trigger->args = NIL;
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->constr_name));
|
||||
makeString(fkconstraint->constr_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(stmt->relname));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->pktable_name));
|
||||
makeString(fkconstraint->pktable_name));
|
||||
fk_trigger->args = lappend(fk_trigger->args,
|
||||
makeString(fkconstraint->match_type));
|
||||
makeString(fkconstraint->match_type));
|
||||
fk_attr = fkconstraint->fk_attrs;
|
||||
pk_attr = fkconstraint->pk_attrs;
|
||||
while (fk_attr != NIL)
|
||||
@@ -2613,7 +2651,7 @@ transformForUpdate(Query *qry, List *forUpdate)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!intMember(i, rowMarks)) /* avoid duplicates */
|
||||
if (!intMember(i, rowMarks)) /* avoid duplicates */
|
||||
rowMarks = lappendi(rowMarks, i);
|
||||
rte->checkForWrite = true;
|
||||
}
|
||||
@@ -2641,7 +2679,7 @@ transformForUpdate(Query *qry, List *forUpdate)
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!intMember(i, rowMarks)) /* avoid duplicates */
|
||||
if (!intMember(i, rowMarks)) /* avoid duplicates */
|
||||
rowMarks = lappendi(rowMarks, i);
|
||||
rte->checkForWrite = true;
|
||||
}
|
||||
@@ -2662,10 +2700,10 @@ transformForUpdate(Query *qry, List *forUpdate)
|
||||
* transformFkeyCheckAttrs -
|
||||
*
|
||||
* Try to make sure that the attributes of a referenced table
|
||||
* belong to a unique (or primary key) constraint.
|
||||
* belong to a unique (or primary key) constraint.
|
||||
*
|
||||
*/
|
||||
static void
|
||||
static void
|
||||
transformFkeyCheckAttrs(FkConstraint *fkconstraint)
|
||||
{
|
||||
Relation pkrel;
|
||||
@@ -2696,7 +2734,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
|
||||
|
||||
foreach(indexoidscan, indexoidlist)
|
||||
{
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
HeapTuple indexTuple;
|
||||
Form_pg_index indexStruct;
|
||||
|
||||
@@ -2710,24 +2748,28 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
|
||||
|
||||
if (indexStruct->indisunique)
|
||||
{
|
||||
List *attrl;
|
||||
List *attrl;
|
||||
|
||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++);
|
||||
if (i!=length(fkconstraint->pk_attrs))
|
||||
found=false;
|
||||
else {
|
||||
if (i != length(fkconstraint->pk_attrs))
|
||||
found = false;
|
||||
else
|
||||
{
|
||||
/* go through the fkconstraint->pk_attrs list */
|
||||
foreach(attrl, fkconstraint->pk_attrs)
|
||||
{
|
||||
Ident *attr=lfirst(attrl);
|
||||
Ident *attr = lfirst(attrl);
|
||||
|
||||
found = false;
|
||||
for (i = 0; i < INDEX_MAX_KEYS && indexStruct->indkey[i] != 0; i++)
|
||||
{
|
||||
int pkattno = indexStruct->indkey[i];
|
||||
if (pkattno>0)
|
||||
int pkattno = indexStruct->indkey[i];
|
||||
|
||||
if (pkattno > 0)
|
||||
{
|
||||
char *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
|
||||
if (strcmp(name, attr->name)==0)
|
||||
char *name = NameStr(pkrel_attrs[pkattno - 1]->attname);
|
||||
|
||||
if (strcmp(name, attr->name) == 0)
|
||||
{
|
||||
found = true;
|
||||
break;
|
||||
@@ -2741,7 +2783,7 @@ transformFkeyCheckAttrs(FkConstraint *fkconstraint)
|
||||
}
|
||||
ReleaseSysCache(indexTuple);
|
||||
if (found)
|
||||
break;
|
||||
break;
|
||||
}
|
||||
if (!found)
|
||||
elog(ERROR, "UNIQUE constraint matching given keys for referenced table \"%s\" not found",
|
||||
@@ -2790,7 +2832,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
|
||||
|
||||
foreach(indexoidscan, indexoidlist)
|
||||
{
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
Oid indexoid = lfirsti(indexoidscan);
|
||||
|
||||
indexTuple = SearchSysCache(INDEXRELID,
|
||||
ObjectIdGetDatum(indexoid),
|
||||
@@ -2826,7 +2868,7 @@ transformFkeyGetPrimaryKey(FkConstraint *fkconstraint)
|
||||
Ident *pkattr = makeNode(Ident);
|
||||
|
||||
pkattr->name = DatumGetCString(DirectFunctionCall1(nameout,
|
||||
NameGetDatum(&(pkrel_attrs[pkattno - 1]->attname))));
|
||||
NameGetDatum(&(pkrel_attrs[pkattno - 1]->attname))));
|
||||
pkattr->indirection = NIL;
|
||||
pkattr->isRel = false;
|
||||
|
||||
@@ -2935,7 +2977,7 @@ transformConstraintAttrs(List *constraintList)
|
||||
static FromExpr *
|
||||
makeFromExpr(List *fromlist, Node *quals)
|
||||
{
|
||||
FromExpr *f = makeNode(FromExpr);
|
||||
FromExpr *f = makeNode(FromExpr);
|
||||
|
||||
f->fromlist = fromlist;
|
||||
f->quals = quals;
|
||||
@@ -2978,19 +3020,20 @@ transformColumnType(ParseState *pstate, ColumnDef *column)
|
||||
}
|
||||
|
||||
/*
|
||||
* Is this the name of a complex type? If so, implement
|
||||
* it as a set.
|
||||
* Is this the name of a complex type? If so, implement it as a set.
|
||||
*
|
||||
* XXX this is a hangover from ancient Berkeley code that probably
|
||||
* doesn't work anymore anyway.
|
||||
*/
|
||||
if (typeTypeRelid(ctype) != InvalidOid)
|
||||
{
|
||||
/* (Eventually add in here that the set can only
|
||||
* contain one element.)
|
||||
*/
|
||||
typename->setof = true;
|
||||
}
|
||||
if (typeTypeRelid(ctype) != InvalidOid)
|
||||
{
|
||||
|
||||
ReleaseSysCache(ctype);
|
||||
/*
|
||||
* (Eventually add in here that the set can only contain one
|
||||
* element.)
|
||||
*/
|
||||
typename->setof = true;
|
||||
}
|
||||
|
||||
ReleaseSysCache(ctype);
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.89 2001/02/21 18:53:46 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.90 2001/03/22 03:59:40 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -37,7 +37,7 @@ static ScanKeyword ScanKeywords[] = {
|
||||
{"aggregate", AGGREGATE},
|
||||
{"all", ALL},
|
||||
{"alter", ALTER},
|
||||
{"analyse", ANALYSE}, /* British spelling */
|
||||
{"analyse", ANALYSE}, /* British spelling */
|
||||
{"analyze", ANALYZE},
|
||||
{"and", AND},
|
||||
{"any", ANY},
|
||||
@@ -312,16 +312,16 @@ ScanKeywordLookup(char *text)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Apply an ASCII-only downcasing. We must not use tolower() since
|
||||
* it may produce the wrong translation in some locales (eg, Turkish),
|
||||
* Apply an ASCII-only downcasing. We must not use tolower() since it
|
||||
* may produce the wrong translation in some locales (eg, Turkish),
|
||||
* and we don't trust isupper() very much either. In an ASCII-based
|
||||
* encoding the tests against A and Z are sufficient, but we also check
|
||||
* isupper() so that we will work correctly under EBCDIC. The actual
|
||||
* case conversion step should work for either ASCII or EBCDIC.
|
||||
* encoding the tests against A and Z are sufficient, but we also
|
||||
* check isupper() so that we will work correctly under EBCDIC. The
|
||||
* actual case conversion step should work for either ASCII or EBCDIC.
|
||||
*/
|
||||
for (i = 0; i < len; i++)
|
||||
{
|
||||
char ch = text[i];
|
||||
char ch = text[i];
|
||||
|
||||
if (ch >= 'A' && ch <= 'Z' && isupper((unsigned char) ch))
|
||||
ch += 'a' - 'A';
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.77 2001/02/16 03:16:57 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.78 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -39,17 +39,17 @@
|
||||
static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};
|
||||
|
||||
static void extractUniqueColumns(List *common_colnames,
|
||||
List *src_colnames, List *src_colvars,
|
||||
List **res_colnames, List **res_colvars);
|
||||
List *src_colnames, List *src_colvars,
|
||||
List **res_colnames, List **res_colvars);
|
||||
static Node *transformJoinUsingClause(ParseState *pstate,
|
||||
List *leftVars, List *rightVars);
|
||||
List *leftVars, List *rightVars);
|
||||
static Node *transformJoinOnClause(ParseState *pstate, JoinExpr *j,
|
||||
List *containedRels);
|
||||
List *containedRels);
|
||||
static RangeTblRef *transformTableEntry(ParseState *pstate, RangeVar *r);
|
||||
static RangeTblRef *transformRangeSubselect(ParseState *pstate,
|
||||
RangeSubselect *r);
|
||||
RangeSubselect *r);
|
||||
static Node *transformFromClauseItem(ParseState *pstate, Node *n,
|
||||
List **containedRels);
|
||||
List **containedRels);
|
||||
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
|
||||
List *tlist, int clause);
|
||||
static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
|
||||
@@ -78,10 +78,10 @@ transformFromClause(ParseState *pstate, List *frmList)
|
||||
List *fl;
|
||||
|
||||
/*
|
||||
* The grammar will have produced a list of RangeVars, RangeSubselects,
|
||||
* and/or JoinExprs. Transform each one (possibly adding entries to the
|
||||
* rtable), check for duplicate refnames, and then add it to the joinlist
|
||||
* and namespace.
|
||||
* The grammar will have produced a list of RangeVars,
|
||||
* RangeSubselects, and/or JoinExprs. Transform each one (possibly
|
||||
* adding entries to the rtable), check for duplicate refnames, and
|
||||
* then add it to the joinlist and namespace.
|
||||
*/
|
||||
foreach(fl, frmList)
|
||||
{
|
||||
@@ -126,11 +126,11 @@ setTargetTable(ParseState *pstate, char *relname,
|
||||
heap_close(pstate->p_target_relation, NoLock);
|
||||
|
||||
/*
|
||||
* Open target rel and grab suitable lock (which we will hold till
|
||||
* end of transaction).
|
||||
* Open target rel and grab suitable lock (which we will hold till end
|
||||
* of transaction).
|
||||
*
|
||||
* analyze.c will eventually do the corresponding heap_close(),
|
||||
* but *not* release the lock.
|
||||
* analyze.c will eventually do the corresponding heap_close(), but *not*
|
||||
* release the lock.
|
||||
*/
|
||||
pstate->p_target_relation = heap_openr(relname, RowExclusiveLock);
|
||||
|
||||
@@ -148,10 +148,10 @@ setTargetTable(ParseState *pstate, char *relname,
|
||||
* Override addRangeTableEntry's default checkForRead, and instead
|
||||
* mark target table as requiring write access.
|
||||
*
|
||||
* If we find an explicit reference to the rel later during
|
||||
* parse analysis, scanRTEForColumn will change checkForRead
|
||||
* to 'true' again. That can't happen for INSERT but it is
|
||||
* possible for UPDATE and DELETE.
|
||||
* If we find an explicit reference to the rel later during parse
|
||||
* analysis, scanRTEForColumn will change checkForRead to 'true'
|
||||
* again. That can't happen for INSERT but it is possible for UPDATE
|
||||
* and DELETE.
|
||||
*/
|
||||
rte->checkForRead = false;
|
||||
rte->checkForWrite = true;
|
||||
@@ -169,7 +169,7 @@ setTargetTable(ParseState *pstate, char *relname,
|
||||
* Simplify InhOption (yes/no/default) into boolean yes/no.
|
||||
*
|
||||
* The reason we do things this way is that we don't want to examine the
|
||||
* SQL_inheritance option flag until parse_analyze is run. Otherwise,
|
||||
* SQL_inheritance option flag until parse_analyze is run. Otherwise,
|
||||
* we'd do the wrong thing with query strings that intermix SET commands
|
||||
* with queries.
|
||||
*/
|
||||
@@ -178,7 +178,7 @@ interpretInhOption(InhOption inhOpt)
|
||||
{
|
||||
switch (inhOpt)
|
||||
{
|
||||
case INH_NO:
|
||||
case INH_NO:
|
||||
return false;
|
||||
case INH_YES:
|
||||
return true;
|
||||
@@ -246,7 +246,7 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
|
||||
|
||||
/*
|
||||
* We cheat a little bit here by building an untransformed operator
|
||||
* tree whose leaves are the already-transformed Vars. This is OK
|
||||
* tree whose leaves are the already-transformed Vars. This is OK
|
||||
* because transformExpr() won't complain about already-transformed
|
||||
* subnodes.
|
||||
*/
|
||||
@@ -288,7 +288,11 @@ transformJoinUsingClause(ParseState *pstate, List *leftVars, List *rightVars)
|
||||
|
||||
if (exprType(result) != BOOLOID)
|
||||
{
|
||||
/* This could only happen if someone defines a funny version of '=' */
|
||||
|
||||
/*
|
||||
* This could only happen if someone defines a funny version of
|
||||
* '='
|
||||
*/
|
||||
elog(ERROR, "JOIN/USING clause must return type bool, not type %s",
|
||||
typeidTypeName(exprType(result)));
|
||||
}
|
||||
@@ -312,11 +316,12 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
|
||||
/*
|
||||
* This is a tad tricky, for two reasons. First, the namespace that
|
||||
* the join expression should see is just the two subtrees of the JOIN
|
||||
* plus any outer references from upper pstate levels. So, temporarily
|
||||
* set this pstate's namespace accordingly. (We need not check for
|
||||
* refname conflicts, because transformFromClauseItem() already did.)
|
||||
* NOTE: this code is OK only because the ON clause can't legally alter
|
||||
* the namespace by causing implicit relation refs to be added.
|
||||
* plus any outer references from upper pstate levels. So,
|
||||
* temporarily set this pstate's namespace accordingly. (We need not
|
||||
* check for refname conflicts, because transformFromClauseItem()
|
||||
* already did.) NOTE: this code is OK only because the ON clause
|
||||
* can't legally alter the namespace by causing implicit relation refs
|
||||
* to be added.
|
||||
*/
|
||||
save_namespace = pstate->p_namespace;
|
||||
pstate->p_namespace = makeList2(j->larg, j->rarg);
|
||||
@@ -333,17 +338,18 @@ transformJoinOnClause(ParseState *pstate, JoinExpr *j,
|
||||
|
||||
/*
|
||||
* Second, we need to check that the ON condition doesn't refer to any
|
||||
* rels outside the input subtrees of the JOIN. It could do that despite
|
||||
* our hack on the namespace if it uses fully-qualified names. So, grovel
|
||||
* through the transformed clause and make sure there are no bogus
|
||||
* references. (Outer references are OK, and are ignored here.)
|
||||
* rels outside the input subtrees of the JOIN. It could do that
|
||||
* despite our hack on the namespace if it uses fully-qualified names.
|
||||
* So, grovel through the transformed clause and make sure there are
|
||||
* no bogus references. (Outer references are OK, and are ignored
|
||||
* here.)
|
||||
*/
|
||||
clause_varnos = pull_varnos(result);
|
||||
foreach(l, clause_varnos)
|
||||
{
|
||||
int varno = lfirsti(l);
|
||||
int varno = lfirsti(l);
|
||||
|
||||
if (! intMember(varno, containedRels))
|
||||
if (!intMember(varno, containedRels))
|
||||
{
|
||||
elog(ERROR, "JOIN/ON clause refers to \"%s\", which is not part of JOIN",
|
||||
rt_fetch(varno, pstate->p_rtable)->eref->relname);
|
||||
@@ -400,21 +406,21 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
|
||||
RangeTblRef *rtr;
|
||||
|
||||
/*
|
||||
* We require user to supply an alias for a subselect, per SQL92.
|
||||
* To relax this, we'd have to be prepared to gin up a unique alias
|
||||
* for an unlabeled subselect.
|
||||
* We require user to supply an alias for a subselect, per SQL92. To
|
||||
* relax this, we'd have to be prepared to gin up a unique alias for
|
||||
* an unlabeled subselect.
|
||||
*/
|
||||
if (r->name == NULL)
|
||||
elog(ERROR, "sub-select in FROM must have an alias");
|
||||
|
||||
/*
|
||||
* Analyze and transform the subquery. This is a bit tricky because
|
||||
* Analyze and transform the subquery. This is a bit tricky because
|
||||
* we don't want the subquery to be able to see any FROM items already
|
||||
* created in the current query (per SQL92, the scope of a FROM item
|
||||
* does not include other FROM items). But it does need to be able to
|
||||
* see any further-up parent states, so we can't just pass a null parent
|
||||
* pstate link. So, temporarily make the current query level have an
|
||||
* empty namespace.
|
||||
* does not include other FROM items). But it does need to be able to
|
||||
* see any further-up parent states, so we can't just pass a null
|
||||
* parent pstate link. So, temporarily make the current query level
|
||||
* have an empty namespace.
|
||||
*/
|
||||
save_namespace = pstate->p_namespace;
|
||||
pstate->p_namespace = NIL;
|
||||
@@ -422,7 +428,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
|
||||
pstate->p_namespace = save_namespace;
|
||||
|
||||
/*
|
||||
* Check that we got something reasonable. Some of these conditions
|
||||
* Check that we got something reasonable. Some of these conditions
|
||||
* are probably impossible given restrictions of the grammar, but
|
||||
* check 'em anyway.
|
||||
*/
|
||||
@@ -513,9 +519,9 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
*containedRels = nconc(l_containedRels, r_containedRels);
|
||||
|
||||
/*
|
||||
* Check for conflicting refnames in left and right subtrees. Must
|
||||
* do this because higher levels will assume I hand back a self-
|
||||
* consistent namespace subtree.
|
||||
* Check for conflicting refnames in left and right subtrees.
|
||||
* Must do this because higher levels will assume I hand back a
|
||||
* self- consistent namespace subtree.
|
||||
*/
|
||||
checkNameSpaceConflicts(pstate, j->larg, j->rarg);
|
||||
|
||||
@@ -556,12 +562,11 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
}
|
||||
|
||||
/*
|
||||
* Natural join does not explicitly specify columns; must
|
||||
* generate columns to join. Need to run through the list of
|
||||
* columns from each table or join result and match up the
|
||||
* column names. Use the first table, and check every column
|
||||
* in the second table for a match. (We'll check that the
|
||||
* matches were unique later on.)
|
||||
* Natural join does not explicitly specify columns; must generate
|
||||
* columns to join. Need to run through the list of columns from
|
||||
* each table or join result and match up the column names. Use
|
||||
* the first table, and check every column in the second table for
|
||||
* a match. (We'll check that the matches were unique later on.)
|
||||
* The result of this step is a list of column names just like an
|
||||
* explicitly-written USING list.
|
||||
*/
|
||||
@@ -571,7 +576,7 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
List *lx,
|
||||
*rx;
|
||||
|
||||
Assert(j->using == NIL); /* shouldn't have USING() too */
|
||||
Assert(j->using == NIL); /* shouldn't have USING() too */
|
||||
|
||||
foreach(lx, l_colnames)
|
||||
{
|
||||
@@ -605,17 +610,18 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
|
||||
if (j->using)
|
||||
{
|
||||
|
||||
/*
|
||||
* JOIN/USING (or NATURAL JOIN, as transformed above).
|
||||
* Transform the list into an explicit ON-condition,
|
||||
* and generate a list of result columns.
|
||||
* Transform the list into an explicit ON-condition, and
|
||||
* generate a list of result columns.
|
||||
*/
|
||||
List *ucols = j->using;
|
||||
List *l_usingvars = NIL;
|
||||
List *r_usingvars = NIL;
|
||||
List *ucol;
|
||||
|
||||
Assert(j->quals == NULL); /* shouldn't have ON() too */
|
||||
Assert(j->quals == NULL); /* shouldn't have ON() too */
|
||||
|
||||
foreach(ucol, ucols)
|
||||
{
|
||||
@@ -679,22 +685,22 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
colvar = r_colvar;
|
||||
break;
|
||||
default:
|
||||
{
|
||||
/* Need COALESCE(l_colvar, r_colvar) */
|
||||
CaseExpr *c = makeNode(CaseExpr);
|
||||
CaseWhen *w = makeNode(CaseWhen);
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
{
|
||||
/* Need COALESCE(l_colvar, r_colvar) */
|
||||
CaseExpr *c = makeNode(CaseExpr);
|
||||
CaseWhen *w = makeNode(CaseWhen);
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
|
||||
a->oper = NOTNULL;
|
||||
a->lexpr = l_colvar;
|
||||
w->expr = (Node *) a;
|
||||
w->result = l_colvar;
|
||||
c->args = makeList1(w);
|
||||
c->defresult = r_colvar;
|
||||
colvar = transformExpr(pstate, (Node *) c,
|
||||
EXPR_COLUMN_FIRST);
|
||||
break;
|
||||
}
|
||||
a->oper = NOTNULL;
|
||||
a->lexpr = l_colvar;
|
||||
w->expr = (Node *) a;
|
||||
w->result = l_colvar;
|
||||
c->args = makeList1(w);
|
||||
c->defresult = r_colvar;
|
||||
colvar = transformExpr(pstate, (Node *) c,
|
||||
EXPR_COLUMN_FIRST);
|
||||
break;
|
||||
}
|
||||
}
|
||||
res_colvars = lappend(res_colvars, colvar);
|
||||
}
|
||||
@@ -730,6 +736,7 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
*/
|
||||
if (j->alias)
|
||||
{
|
||||
|
||||
/*
|
||||
* If a column alias list is specified, substitute the alias
|
||||
* names into my output-column list
|
||||
@@ -751,7 +758,8 @@ transformFromClauseItem(ParseState *pstate, Node *n, List **containedRels)
|
||||
else
|
||||
elog(ERROR, "transformFromClauseItem: unexpected node (internal error)"
|
||||
"\n\t%s", nodeToString(n));
|
||||
return NULL; /* can't get here, just keep compiler quiet */
|
||||
return NULL; /* can't get here, just keep compiler
|
||||
* quiet */
|
||||
}
|
||||
|
||||
|
||||
@@ -848,8 +856,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
* is a matching column. If so, fall through to let
|
||||
* transformExpr() do the rest. NOTE: if name could refer
|
||||
* ambiguously to more than one column name exposed by FROM,
|
||||
* colnameToVar will elog(ERROR). That's just what
|
||||
* we want here.
|
||||
* colnameToVar will elog(ERROR). That's just what we want
|
||||
* here.
|
||||
*/
|
||||
if (colnameToVar(pstate, name) != NULL)
|
||||
name = NULL;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.55 2001/02/27 07:07:00 ishii Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.56 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -78,7 +78,7 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
{
|
||||
/* We know the source constant is really of type 'text' */
|
||||
char *val = DatumGetCString(DirectFunctionCall1(textout,
|
||||
con->constvalue));
|
||||
con->constvalue));
|
||||
|
||||
newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
|
||||
pfree(val);
|
||||
@@ -227,9 +227,9 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
||||
|
||||
/* don't choke on references to no-longer-existing types */
|
||||
if (!typeidIsValid(inputTypeId))
|
||||
return false;
|
||||
if (!typeidIsValid(targetTypeId))
|
||||
return false;
|
||||
return false;
|
||||
if (!typeidIsValid(targetTypeId))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Else, try for explicit conversion using functions: look for a
|
||||
@@ -240,7 +240,7 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
||||
oid_array[0] = inputTypeId;
|
||||
|
||||
ftup = SearchSysCache(PROCNAME,
|
||||
PointerGetDatum(typeidTypeName(targetTypeId)),
|
||||
PointerGetDatum(typeidTypeName(targetTypeId)),
|
||||
Int32GetDatum(1),
|
||||
PointerGetDatum(oid_array),
|
||||
0);
|
||||
@@ -333,7 +333,7 @@ coerce_type_typmod(ParseState *pstate, Node *node,
|
||||
*
|
||||
* XXX this code is WRONG, since (for example) given the input (int4,int8)
|
||||
* it will select int4, whereas according to SQL92 clause 9.3 the correct
|
||||
* answer is clearly int8. To fix this we need a notion of a promotion
|
||||
* answer is clearly int8. To fix this we need a notion of a promotion
|
||||
* hierarchy within type categories --- something more complete than
|
||||
* just a single preferred type.
|
||||
*/
|
||||
@@ -349,7 +349,7 @@ select_common_type(List *typeids, const char *context)
|
||||
pcategory = TypeCategory(ptype);
|
||||
foreach(l, lnext(typeids))
|
||||
{
|
||||
Oid ntype = (Oid) lfirsti(l);
|
||||
Oid ntype = (Oid) lfirsti(l);
|
||||
|
||||
/* move on to next one if no new information... */
|
||||
if (ntype && (ntype != UNKNOWNOID) && (ntype != ptype))
|
||||
@@ -362,20 +362,21 @@ select_common_type(List *typeids, const char *context)
|
||||
}
|
||||
else if (TypeCategory(ntype) != pcategory)
|
||||
{
|
||||
|
||||
/*
|
||||
* both types in different categories? then
|
||||
* not much hope...
|
||||
* both types in different categories? then not much
|
||||
* hope...
|
||||
*/
|
||||
elog(ERROR, "%s types \"%s\" and \"%s\" not matched",
|
||||
context, typeidTypeName(ptype), typeidTypeName(ntype));
|
||||
context, typeidTypeName(ptype), typeidTypeName(ntype));
|
||||
}
|
||||
else if (IsPreferredType(pcategory, ntype)
|
||||
&& !IsPreferredType(pcategory, ptype)
|
||||
&& can_coerce_type(1, &ptype, &ntype))
|
||||
{
|
||||
|
||||
/*
|
||||
* new one is preferred and can convert? then
|
||||
* take it...
|
||||
* new one is preferred and can convert? then take it...
|
||||
*/
|
||||
ptype = ntype;
|
||||
pcategory = TypeCategory(ptype);
|
||||
@@ -384,16 +385,15 @@ select_common_type(List *typeids, const char *context)
|
||||
}
|
||||
|
||||
/*
|
||||
* If all the inputs were UNKNOWN type --- ie, unknown-type literals ---
|
||||
* then resolve as type TEXT. This situation comes up with constructs
|
||||
* like
|
||||
* SELECT (CASE WHEN foo THEN 'bar' ELSE 'baz' END);
|
||||
* SELECT 'foo' UNION SELECT 'bar';
|
||||
* It might seem desirable to leave the construct's output type as
|
||||
* UNKNOWN, but that really doesn't work, because we'd probably end up
|
||||
* needing a runtime coercion from UNKNOWN to something else, and we
|
||||
* usually won't have it. We need to coerce the unknown literals while
|
||||
* they are still literals, so a decision has to be made now.
|
||||
* If all the inputs were UNKNOWN type --- ie, unknown-type literals
|
||||
* --- then resolve as type TEXT. This situation comes up with
|
||||
* constructs like SELECT (CASE WHEN foo THEN 'bar' ELSE 'baz' END);
|
||||
* SELECT 'foo' UNION SELECT 'bar'; It might seem desirable to leave
|
||||
* the construct's output type as UNKNOWN, but that really doesn't
|
||||
* work, because we'd probably end up needing a runtime coercion from
|
||||
* UNKNOWN to something else, and we usually won't have it. We need
|
||||
* to coerce the unknown literals while they are still literals, so a
|
||||
* decision has to be made now.
|
||||
*/
|
||||
if (ptype == UNKNOWNOID)
|
||||
ptype = TEXTOID;
|
||||
@@ -420,9 +420,7 @@ coerce_to_common_type(ParseState *pstate, Node *node,
|
||||
if (inputTypeId == targetTypeId)
|
||||
return node; /* no work */
|
||||
if (can_coerce_type(1, &inputTypeId, &targetTypeId))
|
||||
{
|
||||
node = coerce_type(pstate, node, inputTypeId, targetTypeId, -1);
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "%s unable to convert to type \"%s\"",
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.91 2001/02/16 03:16:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.92 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -384,9 +384,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
left_list = lnext(left_list);
|
||||
|
||||
/*
|
||||
* It's OK to use oper() not compatible_oper() here,
|
||||
* because make_subplan() will insert type coercion
|
||||
* calls if needed.
|
||||
* It's OK to use oper() not compatible_oper()
|
||||
* here, because make_subplan() will insert type
|
||||
* coercion calls if needed.
|
||||
*/
|
||||
optup = oper(op,
|
||||
exprType(lexpr),
|
||||
@@ -458,10 +458,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
c->defresult = (Node *) n;
|
||||
}
|
||||
c->defresult = transformExpr(pstate, c->defresult, precedence);
|
||||
|
||||
/*
|
||||
* Note: default result is considered the most significant
|
||||
* type in determining preferred type. This is how the code
|
||||
* worked before, but it seems a little bogus to me --- tgl
|
||||
* type in determining preferred type. This is how the
|
||||
* code worked before, but it seems a little bogus to me
|
||||
* --- tgl
|
||||
*/
|
||||
typeids = lconsi(exprType(c->defresult), typeids);
|
||||
|
||||
@@ -571,7 +573,7 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
|
||||
* appear
|
||||
*/
|
||||
if (ident->indirection == NIL &&
|
||||
refnameRangeOrJoinEntry(pstate, ident->name, &sublevels_up) != NULL)
|
||||
refnameRangeOrJoinEntry(pstate, ident->name, &sublevels_up) != NULL)
|
||||
{
|
||||
ident->isRel = TRUE;
|
||||
result = (Node *) ident;
|
||||
@@ -580,7 +582,7 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
|
||||
if (result == NULL || precedence == EXPR_COLUMN_FIRST)
|
||||
{
|
||||
/* try to find the ident as a column */
|
||||
Node *var = colnameToVar(pstate, ident->name);
|
||||
Node *var = colnameToVar(pstate, ident->name);
|
||||
|
||||
if (var != NULL)
|
||||
result = transformIndirection(pstate, var, ident->indirection);
|
||||
@@ -852,7 +854,7 @@ parser_typecast_constant(Value *expr, TypeName *typename)
|
||||
{
|
||||
case T_Integer:
|
||||
const_string = DatumGetCString(DirectFunctionCall1(int4out,
|
||||
Int32GetDatum(expr->val.ival)));
|
||||
Int32GetDatum(expr->val.ival)));
|
||||
string_palloced = true;
|
||||
break;
|
||||
case T_Float:
|
||||
@@ -931,7 +933,7 @@ parser_typecast_expression(ParseState *pstate,
|
||||
|
||||
/*
|
||||
* Given a TypeName node as returned by the grammar, generate the internal
|
||||
* name of the corresponding type. Note this does NOT check if the type
|
||||
* name of the corresponding type. Note this does NOT check if the type
|
||||
* exists or not.
|
||||
*/
|
||||
char *
|
||||
@@ -939,11 +941,12 @@ TypeNameToInternalName(TypeName *typename)
|
||||
{
|
||||
if (typename->arrayBounds != NIL)
|
||||
{
|
||||
|
||||
/*
|
||||
* By convention, the name of an array type is the name of its
|
||||
* element type with "_" prepended.
|
||||
*/
|
||||
char *arrayname = palloc(strlen(typename->name) + 2);
|
||||
char *arrayname = palloc(strlen(typename->name) + 2);
|
||||
|
||||
sprintf(arrayname, "_%s", typename->name);
|
||||
return arrayname;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.100 2001/03/14 23:55:33 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.101 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -72,7 +72,7 @@ ParseNestedFuncOrColumn(ParseState *pstate, Attr *attr, int precedence)
|
||||
if (attr->paramNo != NULL)
|
||||
{
|
||||
Param *param = (Param *) transformExpr(pstate,
|
||||
(Node *) attr->paramNo,
|
||||
(Node *) attr->paramNo,
|
||||
EXPR_RELATION_FIRST);
|
||||
|
||||
retval = ParseFuncOrColumn(pstate, strVal(lfirst(attr->attrs)),
|
||||
@@ -277,7 +277,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
if (nargs == 1 && !must_be_agg)
|
||||
{
|
||||
/* Is it a plain Relation name from the parser? */
|
||||
if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
|
||||
if (IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel)
|
||||
{
|
||||
Ident *ident = (Ident *) first_arg;
|
||||
|
||||
@@ -337,7 +337,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
if (nargs != 1)
|
||||
elog(ERROR, "Aggregate functions may only have one parameter");
|
||||
/* Agg's argument can't be a relation name, either */
|
||||
if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
|
||||
if (IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel)
|
||||
elog(ERROR, "Aggregate functions cannot be applied to relation names");
|
||||
could_be_agg = true;
|
||||
}
|
||||
@@ -345,7 +345,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
{
|
||||
/* Try to parse as an aggregate if above-mentioned checks are OK */
|
||||
could_be_agg = (nargs == 1) &&
|
||||
!(IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel);
|
||||
!(IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel);
|
||||
}
|
||||
|
||||
if (could_be_agg)
|
||||
@@ -424,7 +424,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
{
|
||||
Node *arg = lfirst(i);
|
||||
|
||||
if (IsA(arg, Ident) && ((Ident *) arg)->isRel)
|
||||
if (IsA(arg, Ident) &&((Ident *) arg)->isRel)
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
int vnum;
|
||||
@@ -440,21 +440,18 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
&sublevels_up);
|
||||
|
||||
if (rteorjoin == NULL)
|
||||
{
|
||||
rte = addImplicitRTE(pstate, refname);
|
||||
}
|
||||
else if (IsA(rteorjoin, RangeTblEntry))
|
||||
{
|
||||
rte = (RangeTblEntry *) rteorjoin;
|
||||
}
|
||||
else if (IsA(rteorjoin, JoinExpr))
|
||||
{
|
||||
|
||||
/*
|
||||
* We have f(x) or more likely x.f where x is a join and f
|
||||
* is not one of the attribute names of the join (else we'd
|
||||
* have recognized it above). We don't support functions on
|
||||
* join tuples (since we don't have a named type for the join
|
||||
* tuples), so error out.
|
||||
* is not one of the attribute names of the join (else
|
||||
* we'd have recognized it above). We don't support
|
||||
* functions on join tuples (since we don't have a named
|
||||
* type for the join tuples), so error out.
|
||||
*/
|
||||
elog(ERROR, "No such attribute or function %s.%s",
|
||||
refname, funcname);
|
||||
@@ -525,14 +522,14 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
{ /* we know all of these fields already */
|
||||
|
||||
/*
|
||||
* We create a funcnode with a placeholder function seteval().
|
||||
* At runtime, seteval() will execute the function identified
|
||||
* by the funcid it receives as parameter.
|
||||
* We create a funcnode with a placeholder function seteval(). At
|
||||
* runtime, seteval() will execute the function identified by the
|
||||
* funcid it receives as parameter.
|
||||
*
|
||||
* Example: retrieve (emp.mgr.name). The plan for this will scan the
|
||||
* emp relation, projecting out the mgr attribute, which is a funcid.
|
||||
* This function is then called (via seteval()) and "name" is
|
||||
* projected from its result.
|
||||
* emp relation, projecting out the mgr attribute, which is a
|
||||
* funcid. This function is then called (via seteval()) and "name"
|
||||
* is projected from its result.
|
||||
*/
|
||||
funcid = F_SETEVAL;
|
||||
rettype = toid;
|
||||
@@ -639,11 +636,12 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
retval = (Node *) expr;
|
||||
|
||||
/*
|
||||
* For sets, we want to project out the desired attribute of the tuples.
|
||||
* For sets, we want to project out the desired attribute of the
|
||||
* tuples.
|
||||
*/
|
||||
if (attisset)
|
||||
{
|
||||
FieldSelect *fselect;
|
||||
FieldSelect *fselect;
|
||||
|
||||
fselect = setup_field_select(retval, funcname, argrelid);
|
||||
rettype = fselect->resulttype;
|
||||
@@ -952,31 +950,31 @@ func_select_candidate(int nargs,
|
||||
* columns.
|
||||
*
|
||||
* We do this by examining each unknown argument position to see if we
|
||||
* can determine a "type category" for it. If any candidate has an
|
||||
* can determine a "type category" for it. If any candidate has an
|
||||
* input datatype of STRING category, use STRING category (this bias
|
||||
* towards STRING is appropriate since unknown-type literals look like
|
||||
* strings). Otherwise, if all the candidates agree on the type
|
||||
* category of this argument position, use that category. Otherwise,
|
||||
* fail because we cannot determine a category.
|
||||
*
|
||||
* If we are able to determine a type category, also notice whether
|
||||
* any of the candidates takes a preferred datatype within the category.
|
||||
* If we are able to determine a type category, also notice whether any
|
||||
* of the candidates takes a preferred datatype within the category.
|
||||
*
|
||||
* Having completed this examination, remove candidates that accept
|
||||
* the wrong category at any unknown position. Also, if at least one
|
||||
* candidate accepted a preferred type at a position, remove candidates
|
||||
* that accept non-preferred types.
|
||||
* Having completed this examination, remove candidates that accept the
|
||||
* wrong category at any unknown position. Also, if at least one
|
||||
* candidate accepted a preferred type at a position, remove
|
||||
* candidates that accept non-preferred types.
|
||||
*
|
||||
* If we are down to one candidate at the end, we win.
|
||||
*/
|
||||
resolved_unknowns = false;
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
bool have_conflict;
|
||||
bool have_conflict;
|
||||
|
||||
if (input_typeids[i] != UNKNOWNOID)
|
||||
continue;
|
||||
resolved_unknowns = true; /* assume we can do it */
|
||||
resolved_unknowns = true; /* assume we can do it */
|
||||
slot_category[i] = INVALID_TYPE;
|
||||
slot_has_preferred_type[i] = false;
|
||||
have_conflict = false;
|
||||
@@ -1012,7 +1010,11 @@ func_select_candidate(int nargs,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remember conflict, but keep going (might find STRING) */
|
||||
|
||||
/*
|
||||
* Remember conflict, but keep going (might find
|
||||
* STRING)
|
||||
*/
|
||||
have_conflict = true;
|
||||
}
|
||||
}
|
||||
@@ -1034,7 +1036,7 @@ func_select_candidate(int nargs,
|
||||
current_candidate != NULL;
|
||||
current_candidate = current_candidate->next)
|
||||
{
|
||||
bool keepit = true;
|
||||
bool keepit = true;
|
||||
|
||||
current_typeids = current_candidate->args;
|
||||
for (i = 0; i < nargs; i++)
|
||||
@@ -1185,7 +1187,7 @@ func_get_detail(char *funcname,
|
||||
ftup = SearchSysCache(PROCNAME,
|
||||
PointerGetDatum(funcname),
|
||||
Int32GetDatum(nargs),
|
||||
PointerGetDatum(*true_typeids),
|
||||
PointerGetDatum(*true_typeids),
|
||||
0);
|
||||
Assert(HeapTupleIsValid(ftup));
|
||||
break;
|
||||
@@ -1542,12 +1544,12 @@ ParseComplexProjection(ParseState *pstate,
|
||||
Iter *iter = (Iter *) first_arg;
|
||||
|
||||
/*
|
||||
* If the argument of the Iter returns a tuple,
|
||||
* funcname may be a projection. If so, we stick
|
||||
* the FieldSelect *inside* the Iter --- this is
|
||||
* klugy, but necessary because ExecTargetList()
|
||||
* currently does the right thing only when the
|
||||
* Iter node is at the top level of a targetlist item.
|
||||
* If the argument of the Iter returns a tuple, funcname
|
||||
* may be a projection. If so, we stick the FieldSelect
|
||||
* *inside* the Iter --- this is klugy, but necessary
|
||||
* because ExecTargetList() currently does the right thing
|
||||
* only when the Iter node is at the top level of a
|
||||
* targetlist item.
|
||||
*/
|
||||
argtype = iter->itertype;
|
||||
argrelid = typeidTypeRelid(argtype);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.52 2001/02/14 21:35:04 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.53 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -136,7 +136,7 @@ make_op(char *opname, Node *ltree, Node *rtree)
|
||||
|
||||
newop = makeOper(oprid(tup),/* opno */
|
||||
InvalidOid,/* opid */
|
||||
opform->oprresult); /* operator result type */
|
||||
opform->oprresult); /* operator result type */
|
||||
|
||||
result = makeNode(Expr);
|
||||
result->typeOid = opform->oprresult;
|
||||
@@ -235,7 +235,7 @@ make_var(ParseState *pstate, RangeTblEntry *rte, int attrno)
|
||||
* forceSlice If true, treat subscript as array slice in all cases
|
||||
* assignFrom NULL for array fetch, else transformed expression for source.
|
||||
*/
|
||||
ArrayRef *
|
||||
ArrayRef *
|
||||
transformArraySubscripts(ParseState *pstate,
|
||||
Node *arrayBase,
|
||||
Oid arrayType,
|
||||
@@ -449,7 +449,7 @@ make_const(Value *value)
|
||||
|
||||
typeid = FLOAT8OID;
|
||||
typelen = sizeof(float8);
|
||||
typebyval = false; /* XXX might change someday */
|
||||
typebyval = false; /* XXX might change someday */
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.47 2001/02/16 03:16:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.48 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -63,7 +63,7 @@ oprid(Operator op)
|
||||
Oid
|
||||
oprfuncid(Operator op)
|
||||
{
|
||||
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);
|
||||
Form_pg_operator pgopform = (Form_pg_operator) GETSTRUCT(op);
|
||||
|
||||
return pgopform->oprcode;
|
||||
}
|
||||
@@ -416,34 +416,35 @@ oper_select_candidate(int nargs,
|
||||
}
|
||||
|
||||
/*
|
||||
* Second try: same algorithm as for unknown resolution in parse_func.c.
|
||||
* Second try: same algorithm as for unknown resolution in
|
||||
* parse_func.c.
|
||||
*
|
||||
* We do this by examining each unknown argument position to see if we
|
||||
* can determine a "type category" for it. If any candidate has an
|
||||
* can determine a "type category" for it. If any candidate has an
|
||||
* input datatype of STRING category, use STRING category (this bias
|
||||
* towards STRING is appropriate since unknown-type literals look like
|
||||
* strings). Otherwise, if all the candidates agree on the type
|
||||
* category of this argument position, use that category. Otherwise,
|
||||
* fail because we cannot determine a category.
|
||||
*
|
||||
* If we are able to determine a type category, also notice whether
|
||||
* any of the candidates takes a preferred datatype within the category.
|
||||
* If we are able to determine a type category, also notice whether any
|
||||
* of the candidates takes a preferred datatype within the category.
|
||||
*
|
||||
* Having completed this examination, remove candidates that accept
|
||||
* the wrong category at any unknown position. Also, if at least one
|
||||
* candidate accepted a preferred type at a position, remove candidates
|
||||
* that accept non-preferred types.
|
||||
* Having completed this examination, remove candidates that accept the
|
||||
* wrong category at any unknown position. Also, if at least one
|
||||
* candidate accepted a preferred type at a position, remove
|
||||
* candidates that accept non-preferred types.
|
||||
*
|
||||
* If we are down to one candidate at the end, we win.
|
||||
*/
|
||||
resolved_unknowns = false;
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
bool have_conflict;
|
||||
bool have_conflict;
|
||||
|
||||
if (input_typeids[i] != UNKNOWNOID)
|
||||
continue;
|
||||
resolved_unknowns = true; /* assume we can do it */
|
||||
resolved_unknowns = true; /* assume we can do it */
|
||||
slot_category[i] = INVALID_TYPE;
|
||||
slot_has_preferred_type[i] = false;
|
||||
have_conflict = false;
|
||||
@@ -479,7 +480,11 @@ oper_select_candidate(int nargs,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Remember conflict, but keep going (might find STRING) */
|
||||
|
||||
/*
|
||||
* Remember conflict, but keep going (might find
|
||||
* STRING)
|
||||
*/
|
||||
have_conflict = true;
|
||||
}
|
||||
}
|
||||
@@ -501,7 +506,7 @@ oper_select_candidate(int nargs,
|
||||
current_candidate != NULL;
|
||||
current_candidate = current_candidate->next)
|
||||
{
|
||||
bool keepit = true;
|
||||
bool keepit = true;
|
||||
|
||||
current_typeids = current_candidate->args;
|
||||
for (i = 0; i < nargs; i++)
|
||||
@@ -602,7 +607,8 @@ oper_inexact(char *op, Oid arg1, Oid arg2)
|
||||
if (ncandidates == 0)
|
||||
return NULL;
|
||||
|
||||
/* Otherwise, check for compatible datatypes, and then try to resolve
|
||||
/*
|
||||
* Otherwise, check for compatible datatypes, and then try to resolve
|
||||
* the conflict if more than one candidate remains.
|
||||
*/
|
||||
inputOids[0] = arg1;
|
||||
@@ -659,18 +665,18 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noError)
|
||||
*
|
||||
* This is tighter than oper() because it will not return an operator that
|
||||
* requires coercion of the input datatypes (but binary-compatible operators
|
||||
* are accepted). Otherwise, the semantics are the same.
|
||||
* are accepted). Otherwise, the semantics are the same.
|
||||
*/
|
||||
Operator
|
||||
compatible_oper(char *op, Oid arg1, Oid arg2, bool noError)
|
||||
{
|
||||
Operator optup;
|
||||
Form_pg_operator opform;
|
||||
Form_pg_operator opform;
|
||||
|
||||
/* oper() will find the best available match */
|
||||
optup = oper(op, arg1, arg2, noError);
|
||||
if (optup == (Operator) NULL)
|
||||
return (Operator) NULL; /* must be noError case */
|
||||
return (Operator) NULL; /* must be noError case */
|
||||
|
||||
/* but is it good enough? */
|
||||
opform = (Form_pg_operator) GETSTRUCT(optup);
|
||||
@@ -825,8 +831,11 @@ right_oper(char *op, Oid arg)
|
||||
unary_op_error(op, arg, FALSE);
|
||||
else
|
||||
{
|
||||
/* We must run oper_select_candidate even if only one candidate,
|
||||
* otherwise we may falsely return a non-type-compatible operator.
|
||||
|
||||
/*
|
||||
* We must run oper_select_candidate even if only one
|
||||
* candidate, otherwise we may falsely return a
|
||||
* non-type-compatible operator.
|
||||
*/
|
||||
targetOid = oper_select_candidate(1, &arg, candidates);
|
||||
if (targetOid != NULL)
|
||||
@@ -879,8 +888,11 @@ left_oper(char *op, Oid arg)
|
||||
unary_op_error(op, arg, TRUE);
|
||||
else
|
||||
{
|
||||
/* We must run oper_select_candidate even if only one candidate,
|
||||
* otherwise we may falsely return a non-type-compatible operator.
|
||||
|
||||
/*
|
||||
* We must run oper_select_candidate even if only one
|
||||
* candidate, otherwise we may falsely return a
|
||||
* non-type-compatible operator.
|
||||
*/
|
||||
targetOid = oper_select_candidate(1, &arg, candidates);
|
||||
if (targetOid != NULL)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.52 2001/02/14 21:35:04 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.53 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -31,11 +31,11 @@
|
||||
|
||||
|
||||
static Node *scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
|
||||
char *refname);
|
||||
char *refname);
|
||||
static Node *scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte,
|
||||
char *colname);
|
||||
char *colname);
|
||||
static Node *scanJoinForColumn(JoinExpr *join, char *colname,
|
||||
int sublevels_up);
|
||||
int sublevels_up);
|
||||
static bool isForUpdate(ParseState *pstate, char *relname);
|
||||
static List *expandNamesVars(ParseState *pstate, List *names, List *vars);
|
||||
static void warnAutoRange(ParseState *pstate, char *refname);
|
||||
@@ -145,7 +145,8 @@ scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
|
||||
if (j->alias)
|
||||
{
|
||||
if (strcmp(j->alias->relname, refname) == 0)
|
||||
return (Node *) j; /* matched a join alias */
|
||||
return (Node *) j; /* matched a join alias */
|
||||
|
||||
/*
|
||||
* Tables within an aliased join are invisible from outside
|
||||
* the join, according to the scope rules of SQL92 (the join
|
||||
@@ -154,7 +155,7 @@ scanNameSpaceForRefname(ParseState *pstate, Node *nsnode,
|
||||
return NULL;
|
||||
}
|
||||
result = scanNameSpaceForRefname(pstate, j->larg, refname);
|
||||
if (! result)
|
||||
if (!result)
|
||||
result = scanNameSpaceForRefname(pstate, j->rarg, refname);
|
||||
}
|
||||
else if (IsA(nsnode, List))
|
||||
@@ -185,7 +186,7 @@ scanNameSpaceForConflict(ParseState *pstate, Node *nsnode,
|
||||
|
||||
/*
|
||||
* Recursively check for refname conflicts between two namespaces or
|
||||
* namespace subtrees. Raise an error if any is found.
|
||||
* namespace subtrees. Raise an error if any is found.
|
||||
*
|
||||
* Works by recursively scanning namespace1 in the same way that
|
||||
* scanNameSpaceForRefname does, and then looking in namespace2 for
|
||||
@@ -214,6 +215,7 @@ checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
|
||||
if (j->alias)
|
||||
{
|
||||
scanNameSpaceForConflict(pstate, namespace2, j->alias->relname);
|
||||
|
||||
/*
|
||||
* Tables within an aliased join are invisible from outside
|
||||
* the join, according to the scope rules of SQL92 (the join
|
||||
@@ -229,9 +231,7 @@ checkNameSpaceConflicts(ParseState *pstate, Node *namespace1,
|
||||
List *l;
|
||||
|
||||
foreach(l, (List *) namespace1)
|
||||
{
|
||||
checkNameSpaceConflicts(pstate, lfirst(l), namespace2);
|
||||
}
|
||||
}
|
||||
else
|
||||
elog(ERROR, "checkNameSpaceConflicts: unexpected node type %d",
|
||||
@@ -290,8 +290,8 @@ scanRTEForColumn(ParseState *pstate, RangeTblEntry *rte, char *colname)
|
||||
List *c;
|
||||
|
||||
/*
|
||||
* Scan the user column names (or aliases) for a match.
|
||||
* Complain if multiple matches.
|
||||
* Scan the user column names (or aliases) for a match. Complain if
|
||||
* multiple matches.
|
||||
*/
|
||||
foreach(c, rte->eref->attrs)
|
||||
{
|
||||
@@ -354,7 +354,8 @@ scanJoinForColumn(JoinExpr *join, char *colname, int sublevels_up)
|
||||
{
|
||||
if (result)
|
||||
elog(ERROR, "Column reference \"%s\" is ambiguous", colname);
|
||||
result = copyObject(nth(attnum-1, join->colvars));
|
||||
result = copyObject(nth(attnum - 1, join->colvars));
|
||||
|
||||
/*
|
||||
* If referencing an uplevel join item, we must adjust
|
||||
* sublevels settings in the copied expression.
|
||||
@@ -385,20 +386,20 @@ colnameToVar(ParseState *pstate, char *colname)
|
||||
|
||||
/*
|
||||
* We need to look only at top-level namespace items, and even for
|
||||
* those, ignore RTEs that are marked as not inFromCl and not
|
||||
* the query's target relation.
|
||||
* those, ignore RTEs that are marked as not inFromCl and not the
|
||||
* query's target relation.
|
||||
*/
|
||||
foreach(ns, pstate->p_namespace)
|
||||
{
|
||||
Node *nsnode = (Node *) lfirst(ns);
|
||||
Node *newresult = NULL;
|
||||
Node *nsnode = (Node *) lfirst(ns);
|
||||
Node *newresult = NULL;
|
||||
|
||||
if (IsA(nsnode, RangeTblRef))
|
||||
{
|
||||
int varno = ((RangeTblRef *) nsnode)->rtindex;
|
||||
RangeTblEntry *rte = rt_fetch(varno, pstate->p_rtable);
|
||||
|
||||
if (! rte->inFromCl &&
|
||||
if (!rte->inFromCl &&
|
||||
rte != pstate->p_target_rangetblentry)
|
||||
continue;
|
||||
|
||||
@@ -452,7 +453,7 @@ qualifiedNameToVar(ParseState *pstate, char *refname, char *colname,
|
||||
|
||||
if (rteorjoin == NULL)
|
||||
{
|
||||
if (! implicitRTEOK)
|
||||
if (!implicitRTEOK)
|
||||
return NULL;
|
||||
rteorjoin = (Node *) addImplicitRTE(pstate, refname);
|
||||
sublevels_up = 0;
|
||||
@@ -505,9 +506,9 @@ addRangeTableEntry(ParseState *pstate,
|
||||
|
||||
/*
|
||||
* Get the rel's OID. This access also ensures that we have an
|
||||
* up-to-date relcache entry for the rel. Since this is typically
|
||||
* the first access to a rel in a statement, be careful to get the
|
||||
* right access level depending on whether we're doing SELECT FOR UPDATE.
|
||||
* up-to-date relcache entry for the rel. Since this is typically the
|
||||
* first access to a rel in a statement, be careful to get the right
|
||||
* access level depending on whether we're doing SELECT FOR UPDATE.
|
||||
*/
|
||||
lockmode = isForUpdate(pstate, relname) ? RowShareLock : AccessShareLock;
|
||||
rel = heap_openr(relname, lockmode);
|
||||
@@ -517,8 +518,8 @@ addRangeTableEntry(ParseState *pstate,
|
||||
numaliases = length(eref->attrs);
|
||||
|
||||
/*
|
||||
* Since the rel is open anyway, let's check that the
|
||||
* number of column aliases is reasonable. - Thomas 2000-02-04
|
||||
* Since the rel is open anyway, let's check that the number of column
|
||||
* aliases is reasonable. - Thomas 2000-02-04
|
||||
*/
|
||||
maxattrs = RelationGetNumberOfAttributes(rel);
|
||||
if (maxattrs < numaliases)
|
||||
@@ -536,9 +537,9 @@ addRangeTableEntry(ParseState *pstate,
|
||||
rte->eref = eref;
|
||||
|
||||
/*
|
||||
* Drop the rel refcount, but keep the access lock till end of transaction
|
||||
* so that the table can't be deleted or have its schema modified
|
||||
* underneath us.
|
||||
* Drop the rel refcount, but keep the access lock till end of
|
||||
* transaction so that the table can't be deleted or have its schema
|
||||
* modified underneath us.
|
||||
*/
|
||||
heap_close(rel, NoLock);
|
||||
|
||||
@@ -557,11 +558,11 @@ addRangeTableEntry(ParseState *pstate,
|
||||
rte->checkForRead = true;
|
||||
rte->checkForWrite = false;
|
||||
|
||||
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
|
||||
rte->checkAsUser = InvalidOid; /* not set-uid by default, either */
|
||||
|
||||
/*
|
||||
* Add completed RTE to pstate's range table list, but not to join list
|
||||
* nor namespace --- caller must do that if appropriate.
|
||||
* Add completed RTE to pstate's range table list, but not to join
|
||||
* list nor namespace --- caller must do that if appropriate.
|
||||
*/
|
||||
if (pstate != NULL)
|
||||
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
||||
@@ -637,8 +638,8 @@ addRangeTableEntryForSubquery(ParseState *pstate,
|
||||
rte->checkAsUser = InvalidOid;
|
||||
|
||||
/*
|
||||
* Add completed RTE to pstate's range table list, but not to join list
|
||||
* nor namespace --- caller must do that if appropriate.
|
||||
* Add completed RTE to pstate's range table list, but not to join
|
||||
* list nor namespace --- caller must do that if appropriate.
|
||||
*/
|
||||
if (pstate != NULL)
|
||||
pstate->p_rtable = lappend(pstate->p_rtable, rte);
|
||||
@@ -665,7 +666,7 @@ isForUpdate(ParseState *pstate, char *relname)
|
||||
else
|
||||
{
|
||||
/* just the named tables */
|
||||
List *l;
|
||||
List *l;
|
||||
|
||||
foreach(l, pstate->p_forUpdate)
|
||||
{
|
||||
@@ -683,7 +684,7 @@ isForUpdate(ParseState *pstate, char *relname)
|
||||
|
||||
/*
|
||||
* Add the given RTE as a top-level entry in the pstate's join list
|
||||
* and/or name space list. (We assume caller has checked for any
|
||||
* and/or name space list. (We assume caller has checked for any
|
||||
* namespace conflict.)
|
||||
*/
|
||||
void
|
||||
@@ -854,9 +855,10 @@ expandJoinAttrs(ParseState *pstate, JoinExpr *join, int sublevels_up)
|
||||
List *vars;
|
||||
|
||||
vars = copyObject(join->colvars);
|
||||
|
||||
/*
|
||||
* If referencing an uplevel join item, we must adjust
|
||||
* sublevels settings in the copied expression.
|
||||
* If referencing an uplevel join item, we must adjust sublevels
|
||||
* settings in the copied expression.
|
||||
*/
|
||||
if (sublevels_up > 0)
|
||||
IncrementVarSublevelsUp((Node *) vars, sublevels_up, 0);
|
||||
@@ -922,15 +924,17 @@ get_rte_attribute_name(RangeTblEntry *rte, AttrNumber attnum)
|
||||
* If there is an alias, use it
|
||||
*/
|
||||
if (attnum > 0 && attnum <= length(rte->eref->attrs))
|
||||
return strVal(nth(attnum-1, rte->eref->attrs));
|
||||
return strVal(nth(attnum - 1, rte->eref->attrs));
|
||||
|
||||
/*
|
||||
* Can get here for a system attribute (which never has an alias),
|
||||
* or if alias name list is too short (which probably can't happen
|
||||
* Can get here for a system attribute (which never has an alias), or
|
||||
* if alias name list is too short (which probably can't happen
|
||||
* anymore). Neither of these cases is valid for a subselect RTE.
|
||||
*/
|
||||
if (rte->relid == InvalidOid)
|
||||
elog(ERROR, "Invalid attnum %d for rangetable entry %s",
|
||||
attnum, rte->eref->relname);
|
||||
|
||||
/*
|
||||
* Use the real name of the table's column
|
||||
*/
|
||||
@@ -1007,6 +1011,7 @@ attnameIsSet(Relation rd, char *name)
|
||||
}
|
||||
return get_attisset(RelationGetRelid(rd), name);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -1020,6 +1025,7 @@ attnumAttNelems(Relation rd, int attid)
|
||||
{
|
||||
return rd->rd_att->attrs[attid - 1]->attnelems;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* given attribute id, return type of that attribute */
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.65 2001/02/14 21:35:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.66 2001/03/22 03:59:41 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -131,11 +131,11 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
if (IsA(rteorjoin, RangeTblEntry))
|
||||
p_target = nconc(p_target,
|
||||
expandRelAttrs(pstate,
|
||||
(RangeTblEntry *) rteorjoin));
|
||||
(RangeTblEntry *) rteorjoin));
|
||||
else if (IsA(rteorjoin, JoinExpr))
|
||||
p_target = nconc(p_target,
|
||||
expandJoinAttrs(pstate,
|
||||
(JoinExpr *) rteorjoin,
|
||||
(JoinExpr *) rteorjoin,
|
||||
sublevels_up));
|
||||
else
|
||||
elog(ERROR, "transformTargetList: unexpected node type %d",
|
||||
@@ -217,6 +217,7 @@ updateTargetListEntry(ParseState *pstate,
|
||||
|
||||
if (pstate->p_is_insert)
|
||||
{
|
||||
|
||||
/*
|
||||
* The command is INSERT INTO table (arraycol[subscripts]) ...
|
||||
* so there is not really a source array value to work with.
|
||||
@@ -229,6 +230,7 @@ updateTargetListEntry(ParseState *pstate,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Build a Var for the array to be updated.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.34 2001/01/24 19:43:03 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_type.c,v 1.35 2001/03/22 03:59:42 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -136,6 +136,7 @@ typeTypElem(Type typ)
|
||||
|
||||
return typtup->typelem;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -149,6 +150,7 @@ typeInfunc(Type typ)
|
||||
|
||||
return typtup->typinput;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef NOT_USED
|
||||
@@ -162,6 +164,7 @@ typeOutfunc(Type typ)
|
||||
|
||||
return typtup->typoutput;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/* Given a type structure and a string, returns the internal form of
|
||||
@@ -218,10 +221,11 @@ typeidTypeName(Oid id)
|
||||
if (!HeapTupleIsValid(tup))
|
||||
elog(ERROR, "Unable to locate type oid %u in catalog", id);
|
||||
typetuple = (Form_pg_type) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* pstrdup here because result may need to outlive the syscache entry
|
||||
* (eg, it might end up as part of a parse tree that will outlive
|
||||
* the current transaction...)
|
||||
* (eg, it might end up as part of a parse tree that will outlive the
|
||||
* current transaction...)
|
||||
*/
|
||||
result = pstrdup(NameStr(typetuple->typname));
|
||||
ReleaseSysCache(tup);
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
* Portions Copyright (c) 1994, Regents of the University of California
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.48 2001/01/24 19:43:03 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.49 2001/03/22 03:59:42 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -30,6 +30,7 @@
|
||||
|
||||
#if defined(FLEX_SCANNER)
|
||||
extern void DeleteBuffer(void);
|
||||
|
||||
#endif /* FLEX_SCANNER */
|
||||
|
||||
char *parseString; /* the char* which holds the string to be
|
||||
@@ -82,7 +83,7 @@ parser(char *str, Oid *typev, int nargs)
|
||||
* token lookahead. We reduce these cases to one-token lookahead by combining
|
||||
* tokens here, in order to keep the grammar LR(1).
|
||||
*
|
||||
* Using a filter is simpler than trying to recognize multiword tokens
|
||||
* Using a filter is simpler than trying to recognize multiword tokens
|
||||
* directly in scan.l, because we'd have to allow for comments between the
|
||||
* words ...
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user