*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.120 2000/01/31 04:35:48 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/catalog/heap.c,v 1.121 2000/02/15 03:36:34 thomas Exp $
*
*
* INTERFACE ROUTINES
#include "optimizer/planmain.h"
#include "optimizer/tlist.h"
#include "optimizer/var.h"
+#include "nodes/makefuncs.h"
#include "parser/parse_clause.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
*/
rte = makeNode(RangeTblEntry);
rte->relname = RelationGetRelationName(rel);
- rte->refname = RelationGetRelationName(rel);
+ rte->ref = makeNode(Attr);
+ rte->ref->relname = RelationGetRelationName(rel);
rte->relid = RelationGetRelid(rel);
rte->inh = false;
rte->inFromCl = true;
*/
rte = makeNode(RangeTblEntry);
rte->relname = RelationGetRelationName(rel);
- rte->refname = RelationGetRelationName(rel);
+ rte->ref = makeNode(Attr);
+ rte->ref->relname = RelationGetRelationName(rel);
rte->relid = RelationGetRelid(rel);
rte->inh = false;
rte->inFromCl = true;
* its sole rangetable entry. We need a ParseState for transformExpr.
*/
pstate = make_parsestate(NULL);
- makeRangeTable(pstate, NULL, NULL);
- addRangeTableEntry(pstate, relname, relname, false, true, true);
+ makeRangeTable(pstate, NULL);
+ addRangeTableEntry(pstate, relname, makeAttr(relname, NULL), false, true, true);
/*
* Process column default expressions.
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994-5, Regents of the University of California
*
- * $Id: explain.c,v 1.52 2000/01/26 05:56:13 momjian Exp $
+ * $Id: explain.c,v 1.53 2000/02/15 03:36:39 thomas Exp $
*
*/
RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
appendStringInfo(str, " on ");
- if (strcmp(rte->refname, rte->relname) != 0)
+ if (strcmp(rte->ref->relname, rte->relname) != 0)
{
appendStringInfo(str, "%s ",
stringStringInfo(rte->relname));
}
- appendStringInfo(str, stringStringInfo(rte->refname));
+ appendStringInfo(str, stringStringInfo(rte->ref->relname));
}
break;
case T_TidScan:
RangeTblEntry *rte = nth(((TidScan *) plan)->scan.scanrelid - 1, es->rtable);
appendStringInfo(str, " on ");
- if (strcmp(rte->refname, rte->relname) != 0)
+ if (strcmp(rte->ref->relname, rte->relname) != 0)
{
appendStringInfo(str, "%s ",
stringStringInfo(rte->relname));
}
- appendStringInfo(str, stringStringInfo(rte->refname));
+ appendStringInfo(str, stringStringInfo(rte->ref->relname));
}
break;
default:
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: view.c,v 1.41 2000/01/26 05:56:14 momjian Exp $
+ * $Id: view.c,v 1.42 2000/02/15 03:36:39 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "catalog/heap.h"
#include "commands/creatinh.h"
#include "commands/view.h"
+#include "nodes/makefuncs.h"
#include "parser/parse_relation.h"
#include "parser/parse_type.h"
#include "rewrite/rewriteDefine.h"
* create the 2 new range table entries and form the new range
* table... CURRENT first, then NEW....
*/
- rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
+ rt_entry1 = addRangeTableEntry(NULL, (char *) viewName,
+ makeAttr("*CURRENT*", NULL),
FALSE, FALSE, FALSE);
- rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
+ rt_entry2 = addRangeTableEntry(NULL, (char *) viewName,
+ makeAttr("*NEW*", NULL),
FALSE, FALSE, FALSE);
new_rt = lcons(rt_entry2, old_rt);
new_rt = lcons(rt_entry1, new_rt);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.108 2000/02/03 00:02:58 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/executor/execMain.c,v 1.109 2000/02/15 03:36:49 thomas Exp $
*
*-------------------------------------------------------------------------
*/
slot->ttc_buffer = InvalidBuffer;
slot->ttc_whichplan = -1;
rte->relname = RelationGetRelationName(rel);
- rte->refname = rte->relname;
+ rte->ref = makeNode(Attr);
+ rte->ref->relname = rte->relname;
rte->relid = RelationGetRelid(rel);
/* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
rtlist = lcons(rte, NIL);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.104 2000/02/07 04:40:56 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/copyfuncs.c,v 1.105 2000/02/15 03:37:08 thomas Exp $
*
*-------------------------------------------------------------------------
*/
return newnode;
}
+static Attr *
+_copyAttr(Attr *from)
+{
+ Attr *newnode = makeNode(Attr);
+
+ if (from->relname)
+ newnode->relname = pstrdup(from->relname);
+ Node_Copy(from, newnode, attrs);
+
+ return newnode;
+}
+
/* ----------------
* _copyOper
* ----------------
if (from->relname)
newnode->relname = pstrdup(from->relname);
- if (from->refname)
- newnode->refname = pstrdup(from->refname);
+ if (from->ref)
+ Node_Copy(from, newnode, ref);
newnode->relid = from->relid;
newnode->inh = from->inh;
newnode->inFromCl = from->inFromCl;
case T_Var:
retval = _copyVar(from);
break;
+ case T_Attr:
+ retval = _copyAttr(from);
+ break;
case T_Oper:
retval = _copyOper(from);
break;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.59 2000/02/07 04:40:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/equalfuncs.c,v 1.60 2000/02/15 03:37:08 thomas Exp $
*
*-------------------------------------------------------------------------
*/
return true;
}
+static bool
+_equalAttr(Attr *a, Attr *b)
+{
+ if (!strcmp(a->relname, b->relname))
+ return false;
+ if (length(a->attrs) != length(b->attrs))
+ return false;
+
+ return equal(a->attrs, b->attrs);
+}
+
static bool
_equalVar(Var *a, Var *b)
{
if (a->relname != b->relname)
return false;
}
- if (a->refname && b->refname)
+ if (a->ref && b->ref)
{
- if (strcmp(a->refname, b->refname) != 0)
+ if (! equal(a->ref, b->ref))
return false;
}
else
{
- if (a->refname != b->refname)
+ if (a->ref != b->ref)
return false;
}
if (a->relid != b->relid)
case T_EState:
retval = _equalEState(a, b);
break;
+ case T_Attr:
+ retval = _equalAttr(a, b);
+ break;
case T_Integer:
case T_String:
case T_Float:
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.34 2000/02/07 04:40:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/Attic/freefuncs.c,v 1.35 2000/02/15 03:37:08 thomas Exp $
*
*-------------------------------------------------------------------------
*/
{
if (node->relname)
pfree(node->relname);
- if (node->refname)
- pfree(node->refname);
+ if (node->ref)
+ freeObject(node->ref);
+
+ pfree(node);
+}
+
+static void
+_freeAttr(Attr *node)
+{
+ if (node->relname)
+ pfree(node->relname);
+ if (node->attrs)
+ freeObject(node->attrs);
pfree(node);
}
case T_TypeCast:
_freeTypeCast(node);
break;
+ case T_Attr:
+ _freeAttr(node);
+ break;
/*
* VALUE NODES
break;
}
}
+
+
+
+
+
+
+
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.19 2000/01/26 05:56:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.20 2000/02/15 03:37:09 thomas Exp $
*
* NOTES
* Creator functions in POSTGRES 4.2 are generated automatically. Most of
cnst->constiscast = constiscast;
return cnst;
}
+
+/*
+ * makeAttr -
+ * creates an Attr node
+ */
+Attr *
+makeAttr(char *relname, char *attname)
+{
+ Attr *a = makeNode(Attr);
+
+ a->relname = pstrdup(relname);
+ a->paramNo = NULL;
+ if (attname != NULL)
+ a->attrs = lcons(makeString(pstrdup(attname)), NIL);
+ a->indirection = NULL;
+
+ return a;
+}
+
+
+
+
+
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.106 2000/02/07 04:40:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.107 2000/02/15 03:37:09 thomas Exp $
*
* NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which
{
appendStringInfo(str, " RTE :relname ");
_outToken(str, node->relname);
- appendStringInfo(str, " :refname ");
- _outToken(str, node->refname);
+ appendStringInfo(str, " :ref ");
+ _outNode(str, node->ref);
appendStringInfo(str,
" :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
node->relid,
static void
_outAttr(StringInfo str, Attr *node)
{
- List *l;
-
- appendStringInfo(str, " ATTR ");
+ appendStringInfo(str, " ATTR :relname ");
_outToken(str, node->relname);
- appendStringInfo(str, " (");
- foreach(l, node->attrs)
- {
- _outNode(str, lfirst(l));
- if (lnext(l))
- appendStringInfo(str, " ");
- }
- appendStringInfo(str, ")");
+ appendStringInfo(str, " :attrs ");
+ _outNode(str, node->attrs);
}
static void
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.35 2000/01/26 05:56:32 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.36 2000/02/15 03:37:09 thomas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
RangeTblEntry *rte = lfirst(l);
printf("%d\t%s(%s)\t%u\t%d\t%s\n",
- i, rte->relname, rte->refname, rte->relid,
+ i, rte->relname, rte->ref->relname, rte->relid,
rte->inFromCl,
(rte->inh ? "inh" : ""));
i++;
{
rt = rt_fetch(var->varno, rtable);
relname = rt->relname;
- if (rt->refname)
- relname = rt->refname; /* table renamed */
+ if (rt->ref)
+ if (rt->ref->relname)
+ relname = rt->relname; /* table renamed */
attname = get_attname(rt->relid, var->varattno);
}
break;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.82 2000/02/07 04:40:57 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.83 2000/02/15 03:37:09 thomas Exp $
*
* NOTES
* Most of the read functions for plan nodes are tested. (In fact, they
return local_node;
}
+static List *
+_readList()
+{
+ List *local_node = NULL;
+ char *token;
+ int length;
+
+ token = lsptok(NULL, &length); /* eat "(" */
+ token = lsptok(NULL, &length); /* get "{" */
+ while (strncmp(token, "{", length) == 0)
+ {
+ nconc(local_node, nodeRead(true));
+
+ token = lsptok(NULL, &length); /* eat ")" */
+ if (strncmp(token, "}", length) != 0)
+ elog(ERROR, "badly formatted attribute list"
+ " in planstring \"%.10s\"...\n", token);
+ token = lsptok(NULL, &length); /* "{" or ")" */
+ }
+
+ return local_node;
+}
+
+static Attr *
+_readAttr()
+{
+ Attr *local_node;
+ char *token;
+ int length;
+
+ local_node = makeNode(Attr);
+
+ token = lsptok(NULL, &length); /* eat :relname */
+ token = lsptok(NULL, &length); /* get relname */
+ if (length == 0)
+ local_node->relname = pstrdup("");
+ else
+ local_node->relname = debackslash(token, length);
+
+ token = lsptok(NULL, &length); /* eat :attrs */
+ local_node->attrs = _readList();
+
+ return local_node;
+}
+
/* ----------------
* _readRangeTblEntry
* ----------------
else
local_node->relname = debackslash(token, length);
- token = lsptok(NULL, &length); /* eat :refname */
- token = lsptok(NULL, &length); /* get :refname */
- if (length == 0)
- local_node->refname = NULL;
- else
- local_node->refname = debackslash(token, length);
+ token = lsptok(NULL, &length); /* eat :ref */
+ local_node->ref = nodeRead(true);
token = lsptok(NULL, &length); /* eat :relid */
token = lsptok(NULL, &length); /* get :relid */
return_value = _readArray();
else if (length == 3 && strncmp(token, "VAR", length) == 0)
return_value = _readVar();
+ else if (length == 4 && strncmp(token, "ATTR", length) == 0)
+ return_value = _readAttr();
else if (length == 5 && strncmp(token, "CONST", length) == 0)
return_value = _readConst();
else if (length == 4 && strncmp(token, "FUNC", length) == 0)
return_value = _readCaseWhen();
else if (length == 7 && strncmp(token, "ROWMARK", length) == 0)
return_value = _readRowMark();
+#if 0
+ else if (length == 1 && strncmp(token, "{", length) == 0)
+ {
+ /* raw list (of strings?) found in Attr structure - thomas 2000-02-09 */
+ return_value = nodeRead(true);
+ token = lsptok(NULL, &length); /* eat trailing brace */
+ }
+#endif
else
elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.43 2000/02/03 06:12:19 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/prep/prepunion.c,v 1.44 2000/02/15 03:37:26 thomas Exp $
*
*-------------------------------------------------------------------------
*/
RangeTblEntry *new_entry = copyObject(old_entry);
/* ??? someone tell me what the following is doing! - ay 11/94 */
- if (!strcmp(new_entry->refname, "*CURRENT*") ||
- !strcmp(new_entry->refname, "*NEW*"))
- new_entry->refname = get_rel_name(new_relid);
+ if (!strcmp(new_entry->ref->relname, "*CURRENT*") ||
+ !strcmp(new_entry->ref->relname, "*NEW*"))
+ new_entry->ref->relname = get_rel_name(new_relid);
else
new_entry->relname = get_rel_name(new_relid);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.58 2000/01/26 05:56:40 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.59 2000/02/15 03:37:36 thomas Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
var->varattno, rte->relid);
elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
- rte->refname, attname);
+ rte->ref->relname, attname);
}
}
}
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: analyze.c,v 1.136 2000/02/05 00:20:38 wieck Exp $
+ * $Id: analyze.c,v 1.137 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
qry->commandType = CMD_DELETE;
/* set up a range table */
- makeRangeTable(pstate, NULL, NULL);
+ makeRangeTable(pstate, NULL);
setTargetTable(pstate, stmt->relname);
qry->distinctClause = NIL;
/* fix where clause */
- qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
qry->rtable = pstate->p_rtable;
qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
{
Query *qry = makeNode(Query);
- Node *fromQual;
List *icolumns;
List *attrnos;
List *attnos;
*/
/* set up a range table --- note INSERT target is not in it yet */
- makeRangeTable(pstate, stmt->fromClause, &fromQual);
+ makeRangeTable(pstate, stmt->fromClause);
qry->targetList = transformTargetList(pstate, stmt->targetList);
- qry->qual = transformWhereClause(pstate, stmt->whereClause, fromQual);
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
/* Initial processing of HAVING clause is just like WHERE clause.
* Additional work will be done in optimizer/plan/planner.c.
*/
- qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);
+ qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
qry->groupClause = transformGroupClause(pstate,
stmt->groupClause,
*
*/
if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
+ {
if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0)
transformFkeyGetPrimaryKey(fkconstraint);
else if (pkey != NULL)
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
fkconstraint->pktable_name);
}
+ }
/*
* Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
qry->commandType = CMD_UTILITY;
/* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+
qry->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable;
qry->commandType = CMD_UTILITY;
/* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+
qry->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable;
nothing_qry->commandType = CMD_NOTHING;
- addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+ addRangeTableEntry(pstate, stmt->object->relname,
+ makeAttr("*CURRENT*", NULL),
FALSE, FALSE, FALSE);
- addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+ addRangeTableEntry(pstate, stmt->object->relname,
+ makeAttr("*NEW*", NULL),
FALSE, FALSE, FALSE);
nothing_qry->rtable = pstate->p_rtable;
* NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
* equal to 2.
*/
- addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+ addRangeTableEntry(pstate, stmt->object->relname,
+ makeAttr("*CURRENT*", NULL),
FALSE, FALSE, FALSE);
- addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+ addRangeTableEntry(pstate, stmt->object->relname,
+ makeAttr("*NEW*", NULL),
FALSE, FALSE, FALSE);
pstate->p_last_resno = 1;
}
/* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+
qry->hasSubLinks = pstate->p_hasSubLinks;
qry->utilityStmt = (Node *) stmt;
transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
{
Query *qry = makeNode(Query);
- Node *fromQual;
qry->commandType = CMD_SELECT;
/* set up a range table */
- makeRangeTable(pstate, stmt->fromClause, &fromQual);
+ makeRangeTable(pstate, stmt->fromClause);
qry->into = stmt->into;
qry->isTemp = stmt->istemp;
qry->targetList = transformTargetList(pstate, stmt->targetList);
- qry->qual = transformWhereClause(pstate, stmt->whereClause, fromQual);
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
/* Initial processing of HAVING clause is just like WHERE clause.
* Additional work will be done in optimizer/plan/planner.c.
*/
- qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);
+ qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
qry->groupClause = transformGroupClause(pstate,
stmt->groupClause,
* the FROM clause is non-standard SQL syntax. We used to be able to
* do this with REPLACE in POSTQUEL so we keep the feature.
*/
- makeRangeTable(pstate, stmt->fromClause, NULL);
+ makeRangeTable(pstate, stmt->fromClause);
setTargetTable(pstate, stmt->relname);
qry->targetList = transformTargetList(pstate, stmt->targetList);
- qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
qry->hasSubLinks = pstate->p_hasSubLinks;
i = 1;
foreach(l2, qry->rtable)
{
- if (strcmp(((RangeTblEntry *) lfirst(l2))->refname, relname) == 0)
+ if (strcmp(((RangeTblEntry *) lfirst(l2))->ref->relname, relname) == 0)
{
List *l3;
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.33 2000/01/26 05:56:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.34 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
var->varattno, rte->relid);
elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
- rte->refname, attname);
+ rte->ref->relname, attname);
}
/* Otherwise, recurse. */
return expression_tree_walker(node, check_ungrouped_columns_walker,
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.51 2000/01/27 18:11:35 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.52 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
-
#include "access/heapam.h"
+#include "miscadmin.h"
#include "optimizer/tlist.h"
#include "parse.h"
+#include "nodes/makefuncs.h"
#include "parser/parse_clause.h"
#include "parser/parse_coerce.h"
#include "parser/parse_expr.h"
#include "parser/parse_relation.h"
#include "parser/parse_target.h"
-
#define ORDER_CLAUSE 0
#define GROUP_CLAUSE 1
#define DISTINCT_ON_CLAUSE 2
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause);
-static void parseFromClause(ParseState *pstate, List *frmList, Node **qual);
-static char *transformTableEntry(ParseState *pstate, RangeVar *r);
+static void parseFromClause(ParseState *pstate, List *frmList);
+RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
List *targetlist, char *opname);
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
-#ifdef ENABLE_OUTER_JOINS
-static Node *transformUsingClause(ParseState *pstate, List *onList,
- char *lname, char *rname);
+#ifndef DISABLE_OUTER_JOINS
+static Node *transformUsingClause(ParseState *pstate, List *using, List *left, List *right);
#endif
-
/*
* makeRangeTable -
* Build the initial range table from the FROM clause.
*/
void
-makeRangeTable(ParseState *pstate, List *frmList, Node **qual)
+makeRangeTable(ParseState *pstate, List *frmList)
{
/* Currently, nothing to do except this: */
- parseFromClause(pstate, frmList, qual);
+ parseFromClause(pstate, frmList);
}
/*
if ((refnameRangeTablePosn(pstate, relname, &sublevels_up) == 0)
|| (sublevels_up != 0))
- rte = addRangeTableEntry(pstate, relname, relname,
+ rte = addRangeTableEntry(pstate, relname,
+ makeAttr(relname, NULL),
FALSE, FALSE, FALSE);
else
rte = refnameRangeTableEntry(pstate, relname);
/* will close relation later, see analyze.c */
}
-/*
- * transformWhereClause -
- * transforms the qualification and make sure it is of type Boolean
- *
- * Now accept an additional argument, which is a qualification derived
- * from the JOIN/ON or JOIN/USING syntax.
- * - thomas 1998-12-16
- */
+
Node *
-transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr)
+mergeInnerJoinQuals(ParseState *pstate, Node *clause);
+
+Node *
+mergeInnerJoinQuals(ParseState *pstate, Node *clause)
{
- A_Expr *expr;
- Node *qual;
+ A_Expr *expr = (A_Expr *) pstate->p_join_quals;
- if ((a_expr == NULL) && (o_expr == NULL))
- return NULL; /* no qualifiers */
+ if (expr == NULL)
+ return clause;
- if ((a_expr != NULL) && (o_expr != NULL))
+ if (clause != NULL)
{
A_Expr *a = makeNode(A_Expr);
a->oper = AND;
a->opname = NULL;
- a->lexpr = o_expr;
- a->rexpr = a_expr;
+ a->lexpr = (Node *) expr;
+ a->rexpr = clause;
expr = a;
}
- else if (o_expr != NULL)
- expr = (A_Expr *) o_expr;
- else
- expr = (A_Expr *) a_expr;
+
+ /* Make sure that we don't do this twice... */
+ pstate->p_join_quals = NULL;
+
+ return (Node *) expr;
+} /* mergeInnerJoinQuals() */
+
+/*
+ * transformWhereClause -
+ * transforms the qualification and make sure it is of type Boolean
+ */
+Node *
+transformWhereClause(ParseState *pstate, Node *clause)
+{
+ Node *qual;
+
+ if (pstate->p_join_quals != NULL)
+ clause = mergeInnerJoinQuals(pstate, clause);
+
+ if (clause == NULL)
+ return NULL;
pstate->p_in_where_clause = true;
- qual = transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST);
+ qual = transformExpr(pstate, clause, EXPR_COLUMN_FIRST);
pstate->p_in_where_clause = false;
if (exprType(qual) != BOOLOID)
return qual;
}
-#ifdef ENABLE_OUTER_JOINS
-static Attr *
-makeAttr(char *relname, char *attname)
+#ifndef DISABLE_JOIN_SYNTAX
+char *
+AttrString(Attr *attr);
+
+char *
+AttrString(Attr *attr)
{
- Attr *a = makeNode(Attr);
+ Value *val;
+
+ Assert(length(attr->attrs) == 1);
+
+ val = lfirst(attr->attrs);
- a->relname = relname;
- a->paramNo = NULL;
- a->attrs = lcons(makeString(attname), NIL);
- a->indirection = NULL;
+ Assert(IsA(val, String));
- return a;
+ return strVal(val);
+}
+
+List *
+ListTableAsAttrs(ParseState *pstate, char *table);
+List *
+ListTableAsAttrs(ParseState *pstate, char *table)
+{
+ List *rlist = NULL;
+ List *col;
+
+ Attr *attr = expandTable(pstate, table, TRUE);
+ foreach(col, attr->attrs)
+ {
+ Attr *a;
+ a = makeAttr(table, strVal((Value *) col));
+ rlist = lappend(rlist, a);
+ }
+
+ return rlist;
+}
+
+List *
+makeUniqueAttrList(List *candidates, List *idents);
+List *
+makeUniqueAttrList(List *attrs, List *filter)
+{
+ List *result = NULL;
+ List *candidate;
+
+ foreach(candidate, attrs)
+ {
+ List *fmember;
+ bool match = FALSE;
+// char *field;
+ Attr *cattr = lfirst(candidate);
+
+ Assert(IsA(cattr, Attr));
+ Assert(length(cattr->attrs) == 1);
+
+// field = strVal(lfirst(ccol));
+// bool match = FALSE;
+
+ foreach(fmember, filter)
+ {
+ Attr *fattr = lfirst(fmember);
+ Assert(IsA(fattr, Attr));
+ Assert(length(fattr->attrs) == 1);
+
+ if (strcmp(strVal(lfirst(cattr->attrs)), strVal(lfirst(fattr->attrs))) == 0)
+ {
+ match = TRUE;
+ break;
+ }
+ }
+
+ if (!match)
+ result = lappend(result, cattr);
+ }
+
+ return result;
+}
+
+List *
+makeAttrList(Attr *attr);
+
+List *
+makeAttrList(Attr *attr)
+{
+ List *result = NULL;
+
+ char *name = attr->relname;
+ List *col;
+
+ foreach (col, attr->attrs)
+ {
+ Attr *newattr = makeAttr(name, strVal((Value *) lfirst(col)));
+
+ result = lappend(result, newattr);
+ }
+
+ return result;
+}
+
+/* ExpandAttrs()
+ * Take an existing attribute node and return a list of attribute nodes
+ * with one attribute name per node.
+ */
+List *
+ExpandAttrs(Attr *attr);
+List *
+ExpandAttrs(Attr *attr)
+{
+ List *col;
+ char *relname = attr->relname;
+ List *rlist = NULL;
+
+ Assert(attr != NULL);
+
+ if ((attr->attrs == NULL) || (length(attr->attrs) <= 1))
+ return lcons(attr, NIL);
+
+ foreach(col, attr->attrs)
+ {
+ Attr *attr = lfirst(col);
+
+ rlist = lappend(rlist, makeAttr(relname, AttrString(attr)));
+ }
+
+ return rlist;
}
-#endif
-#ifdef ENABLE_OUTER_JOINS
/* transformUsingClause()
* Take an ON or USING clause from a join expression and expand if necessary.
*/
static Node *
-transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname)
+transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *rightList)
{
A_Expr *expr = NULL;
- List *on;
- Node *qual;
+ List *using;
- foreach(on, onList)
+ foreach(using, usingList)
{
- qual = lfirst(on);
+ List *col;
+ A_Expr *e;
- /*
- * Ident node means it is just a column name from a real USING
- * clause...
+ Attr *uattr = lfirst(using);
+ Attr *lattr = NULL, *rattr = NULL;
+
+ /* find the first instances of this column in the shape list
+ * and the last table in the shape list...
*/
- if (IsA(qual, Ident))
+ foreach (col, leftList)
{
- Ident *i = (Ident *) qual;
- Attr *lattr = makeAttr(lname, i->name);
- Attr *rattr = makeAttr(rname, i->name);
- A_Expr *e = makeNode(A_Expr);
-
- e->oper = OP;
- e->opname = "=";
- e->lexpr = (Node *) lattr;
- e->rexpr = (Node *) rattr;
+ Attr *attr = lfirst(col);
- if (expr != NULL)
+ if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
{
- A_Expr *a = makeNode(A_Expr);
+ lattr = attr;
+ break;
+ }
+ }
+ foreach (col, rightList)
+ {
+ Attr *attr = lfirst(col);
- a->oper = AND;
- a->opname = NULL;
- a->lexpr = (Node *) expr;
- a->rexpr = (Node *) e;
- expr = a;
+ if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
+ {
+ rattr = attr;
+ break;
}
- else
- expr = e;
}
- /* otherwise, we have an expression from an ON clause... */
- else
+ Assert((lattr != NULL) && (rattr != NULL));
+
+ e = makeNode(A_Expr);
+ e->oper = OP;
+ e->opname = "=";
+ e->lexpr = (Node *) lattr;
+ e->rexpr = (Node *) rattr;
+
+ if (expr != NULL)
{
- if (expr != NULL)
- {
- A_Expr *a = makeNode(A_Expr);
+ A_Expr *a = makeNode(A_Expr);
- a->oper = AND;
- a->opname = NULL;
- a->lexpr = (Node *) expr;
- a->rexpr = (Node *) qual;
- expr = a;
- }
- else
- expr = (A_Expr *) qual;
+ a->oper = AND;
+ a->opname = NULL;
+ a->lexpr = (Node *) expr;
+ a->rexpr = (Node *) e;
+ expr = a;
}
+ else
+ expr = e;
}
- return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
-}
+ return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
+} /* transformUsiongClause() */
#endif
-static char *
+
+RangeTblEntry *
transformTableEntry(ParseState *pstate, RangeVar *r)
{
RelExpr *baserel = r->relExpr;
char *relname = baserel->relname;
- char *refname = r->name;
+#if 0
+ char *refname;
+ List *columns;
+#endif
RangeTblEntry *rte;
- if (refname == NULL)
+#if 0
+ if (r->name != NULL)
+ refname = r->name->relname;
+ else
+ refname = NULL;
+
+ columns = ListTableAsAttrs(pstate, relname);
+
+ /* alias might be specified... */
+ if (r->name != NULL)
+ {
+#ifndef DISABLE_JOIN_SYNTAX
+ if (length(columns) > 0)
+ {
+ if (length(r->name->attrs) > 0)
+ {
+ if (length(columns) != length(r->name->attrs))
+ elog(ERROR, "'%s' has %d columns but %d %s specified",
+ relname, length(columns), length(r->name->attrs),
+ ((length(r->name->attrs) != 1)? "aliases": "alias"));
+
+ aliasList = nconc(aliasList, r->name->attrs);
+ }
+ else
+ {
+ r->name->attrs = columns;
+
+ aliasList = nconc(aliasList, r->name->attrs);
+ }
+ }
+ else
+ {
+ elog(NOTICE, "transformTableEntry: column aliases not handled (internal error)");
+ }
+#else
+ elog(ERROR, "Column aliases not yet supported");
+#endif
+ }
+ else
+ {
refname = relname;
+ aliasList = nconc(aliasList, columns);
+ }
+#endif
+
+ if (r->name == NULL)
+ r->name = makeAttr(relname, NULL);
/*
* marks this entry to indicate it comes from the FROM clause. In SQL,
* we expand * to foo.x.
*/
- rte = addRangeTableEntry(pstate, relname, refname,
+ rte = addRangeTableEntry(pstate, relname, r->name,
baserel->inh, TRUE, TRUE);
- return refname;
-}
+ return rte;
+} /* transformTableEntry() */
+
/*
* parseFromClause -
* - thomas 1998-12-16
*/
static void
-parseFromClause(ParseState *pstate, List *frmList, Node **qual)
+parseFromClause(ParseState *pstate, List *frmList)
{
- List *fl;
+// List *shape, *alias;
+// Node **qual;
+// char *lname, *rname;
- if (qual != NULL)
- *qual = NULL;
+ List *fl;
foreach(fl, frmList)
{
* eg. select * from foo f where f.x = 1; will generate wrong answer
* if we expand * to foo.x.
*/
+
+ /* Plain vanilla inner join, just like we've always had? */
if (IsA(n, RangeVar))
+ {
transformTableEntry(pstate, (RangeVar *) n);
+ }
+
+ /* A newfangled join expression? */
else if (IsA(n, JoinExpr))
{
- JoinExpr *j = (JoinExpr *) n;
+#ifndef DISABLE_JOIN_SYNTAX
+// char *lname, *rname;
+ RangeTblEntry *l_rte, *r_rte;
+ Attr *l_name, *r_name;
+ JoinExpr *j = (JoinExpr *) n;
-#ifdef ENABLE_OUTER_JOINS
- char *lname = transformTableEntry(pstate, (RangeVar *) j->larg);
+ if (j->alias != NULL)
+ elog(ERROR, "JOIN table aliases are not supported");
-#endif
- char *rname;
+ /* nested join? then handle the left one first... */
+ if (IsA(j->larg, JoinExpr))
+ {
+ parseFromClause(pstate, lcons(j->larg, NIL));
+ l_name = ((JoinExpr *)j->larg)->alias;
+ }
+ else
+ {
+ Assert(IsA(j->larg, RangeVar));
+ l_rte = transformTableEntry(pstate, (RangeVar *) j->larg);
+ l_name = expandTable(pstate, l_rte->ref->relname, TRUE);
+ }
- if (IsA((Node *) j->rarg, RangeVar))
- rname = transformTableEntry(pstate, (RangeVar *) j->rarg);
+ if (IsA(j->rarg, JoinExpr))
+ {
+// elog(ERROR, "Nested JOINs are not yet supported");
+ parseFromClause(pstate, lcons(j->rarg, NIL));
+ l_name = ((JoinExpr *)j->larg)->alias;
+ }
else
- elog(ERROR, "Nested JOINs are not yet supported");
+ {
+ Assert(IsA(j->rarg, RangeVar));
+ r_rte = transformTableEntry(pstate, (RangeVar *) j->rarg);
+ r_name = expandTable(pstate, r_rte->ref->relname, TRUE);
+ }
+
+ /* 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.
+ */
+ if (j->isNatural)
+ {
+ List *lx, *rx;
+ List *rlist = NULL;
+
+ foreach(lx, l_name->attrs)
+ {
+ Ident *id = NULL;
+ Value *l_col = lfirst(lx);
+ Assert(IsA(l_col, String));
+
+ foreach(rx, r_name->attrs)
+ {
+ Value *r_col = lfirst(rx);
+ Assert(IsA(r_col, String));
+
+// if (equal(l_col, r_col))
+ if (strcmp(strVal(l_col), strVal(r_col)) == 0)
+ {
+ id = (Ident *) makeNode(Ident);
+ id->name = strVal(l_col);
+ break;
+ }
+ }
+
+ /* right column matched? then keep as join column... */
+ if (id != NULL)
+ rlist = lappend(rlist, id);
+ }
+ j->quals = rlist;
+
+ printf("NATURAL JOIN columns are %s\n", nodeToString(rlist));
+ }
-#ifdef ENABLE_OUTER_JOINS
if (j->jointype == INNER_P)
{
+ /* CROSS JOIN */
+ if (j->quals == NULL)
+ {
+ printf("CROSS JOIN...\n");
+ }
- /*
+ /* JOIN/USING
* This is an inner join, so rip apart the join node and
* transform into a traditional FROM list. NATURAL JOIN
- * and USING clauses both change the shape of the result.
+ * and JOIN USING both change the shape of the result.
* Need to generate a list of result columns to use for
- * target list expansion and validation. Not doing this
- * yet though!
+ * target list expansion and validation.
*/
- if (IsA(j->quals, List))
- j->quals = lcons(transformUsingClause(pstate, (List *) j->quals, lname, rname), NIL);
+ else if (IsA(j->quals, List))
+ {
+ /*
+ * List of Ident nodes means column names from a real USING
+ * clause. Determine the shape of the joined table.
+ */
+// List *ltable, *rtable;
+ List *ucols, *ucol;
+ List *shape = NULL;
+ List *alias = NULL;
+ List *l_shape, *r_shape;
+
+ List *l_cols = makeAttrList(l_name);
+ List *r_cols = makeAttrList(r_name);
+
+ printf("USING input tables are:\n %s\n %s\n",
+ nodeToString(l_name), nodeToString(r_name));
+
+ printf("USING expanded tables are:\n %s\n %s\n",
+ nodeToString(l_cols), nodeToString(r_cols));
+
+ /* Columns from the USING clause... */
+ ucols = (List *)j->quals;
+ foreach(ucol, ucols)
+ {
+ List *col;
+ Attr *l_attr = NULL, *r_attr = NULL;
+ Ident *id = lfirst(ucol);
+
+ Attr *attr = makeAttr("", id->name);
+
+ foreach(col, l_cols)
+ {
+ attr = lfirst(col);
+ if (strcmp(AttrString(attr), id->name) == 0)
+ {
+ l_attr = attr;
+ break;
+ }
+ }
+
+ foreach(col, r_cols)
+ {
+ attr = lfirst(col);
+ if (strcmp(AttrString(attr), id->name) == 0)
+ {
+ r_attr = attr;
+ break;
+ }
+ }
+
+ if (l_attr == NULL)
+ elog(ERROR, "USING column '%s' not found in table '%s'",
+ id->name, l_name->relname);
+ if (r_attr == NULL)
+ elog(ERROR, "USING column '%s' not found in table '%s'",
+ id->name, r_name->relname);
+
+ shape = lappend(shape, l_attr);
+ alias = lappend(alias, makeAttr("", AttrString(l_attr)));
+ }
+ printf("JOIN/USING join columns are %s\n", nodeToString(shape));
+
+ /* Remaining columns from the left side... */
+ l_shape = makeUniqueAttrList(makeAttrList(l_name), shape);
+ printf("JOIN/USING left columns are %s\n", nodeToString(l_shape));
+
+ r_shape = makeUniqueAttrList(makeAttrList(r_name), shape);
+
+ printf("JOIN/USING right columns are %s\n", nodeToString(r_shape));
+
+ printf("JOIN/USING input quals are %s\n", nodeToString(j->quals));
+
+ j->quals = (List *) transformUsingClause(pstate, shape, l_cols, r_cols);
+
+ printf("JOIN/USING transformed quals are %s\n", nodeToString(j->quals));
+
+ alias = nconc(nconc(alias, listCopy(l_shape)), listCopy(r_shape));
+ shape = nconc(nconc(shape, l_shape), r_shape);
+
+ printf("JOIN/USING shaped table is %s\n", nodeToString(shape));
+ printf("JOIN/USING alias list is %s\n", nodeToString(alias));
+
+ pstate->p_shape = shape;
+ pstate->p_alias = alias;
+ }
+
+ /* otherwise, must be an expression from an ON clause... */
+ else
+ {
+ j->quals = (List *) lcons(j->quals, NIL);
+ }
+
+ pstate->p_join_quals = (Node *) j->quals;
+
+#if 0
if (qual == NULL)
elog(ERROR, "JOIN/ON not supported in this context");
+ printf("Table aliases are %s\n", nodeToString(*aliasList));
+#endif
+
+#if 0
if (*qual == NULL)
- *qual = lfirst(j->quals);
+ {
+#endif
+
+#if 0
+ /* merge qualified join clauses... */
+ if (j->quals != NULL)
+ {
+ if (*qual != NULL)
+ {
+ A_Expr *a = makeNode(A_Expr);
+
+ a->oper = AND;
+ a->opname = NULL;
+ a->lexpr = (Node *) *qual;
+ a->rexpr = (Node *) j->quals;
+
+ *qual = (Node *)a;
+ }
+ else
+ {
+ *qual = (Node *)j->quals;
+ }
+ }
+#endif
+
+#if 0
+ }
else
+ {
elog(ERROR, "Multiple JOIN/ON clauses not handled (internal error)");
+ *qual = lappend(*qual, j->quals);
+ }
+#endif
/*
* if we are transforming this node back into a FROM list,
* then we will need to replace the node with two nodes.
* Will need access to the previous list item to change
* the link pointer to reference these new nodes. Try
- * accumulating and returning a new list. - thomas
- * 1999-01-08 Not doing this yet though!
+ * accumulating and returning a new list.
+ * - thomas 1999-01-08 Not doing this yet though!
*/
}
else if ((j->jointype == LEFT)
|| (j->jointype == RIGHT)
|| (j->jointype == FULL))
- elog(ERROR, "OUTER JOIN is not implemented");
+ elog(ERROR, "OUTER JOIN is not yet supported");
else
elog(ERROR, "Unrecognized JOIN clause; tag is %d (internal error)",
j->jointype);
elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)"
"\n\t%s", nodeToString(n));
}
-}
+} /* parseFromClause() */
/*
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.67 2000/01/26 05:56:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.68 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
if (exprType(lexpr) != BOOLOID)
- elog(ERROR, "left-hand side of AND is type '%s', not bool",
- typeidTypeName(exprType(lexpr)));
+ elog(ERROR, "left-hand side of AND is type '%s', not '%s'",
+ typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID));
if (exprType(rexpr) != BOOLOID)
- elog(ERROR, "right-hand side of AND is type '%s', not bool",
- typeidTypeName(exprType(rexpr)));
+ elog(ERROR, "right-hand side of AND is type '%s', not '%s'",
+ typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
expr->typeOid = BOOLOID;
expr->opType = AND_EXPR;
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
if (exprType(lexpr) != BOOLOID)
- elog(ERROR, "left-hand side of OR is type '%s', not bool",
- typeidTypeName(exprType(lexpr)));
+ elog(ERROR, "left-hand side of OR is type '%s', not '%s'",
+ typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID));
if (exprType(rexpr) != BOOLOID)
- elog(ERROR, "right-hand side of OR is type '%s', not bool",
- typeidTypeName(exprType(rexpr)));
+ elog(ERROR, "right-hand side of OR is type '%s', not '%s'",
+ typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
expr->typeOid = BOOLOID;
expr->opType = OR_EXPR;
expr->args = makeList(lexpr, rexpr, -1);
Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
if (exprType(rexpr) != BOOLOID)
- elog(ERROR, "argument to NOT is type '%s', not bool",
- typeidTypeName(exprType(rexpr)));
+ elog(ERROR, "argument to NOT is type '%s', not '%s'",
+ typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
expr->typeOid = BOOLOID;
expr->opType = NOT_EXPR;
expr->args = makeList(rexpr, -1);
pstate->p_hasSubLinks = true;
qtrees = parse_analyze(lcons(sublink->subselect, NIL), pstate);
if (length(qtrees) != 1)
- elog(ERROR, "parser: bad query in subselect");
+ elog(ERROR, "Bad query in subselect");
qtree = (Query *) lfirst(qtrees);
if (qtree->commandType != CMD_SELECT ||
qtree->resultRelation != 0)
- elog(ERROR, "parser: bad query in subselect");
+ elog(ERROR, "Bad query in subselect");
sublink->subselect = (Node *) qtree;
if (sublink->subLinkType == EXISTS_SUBLINK)
*/
if (tlist == NIL ||
((TargetEntry *) lfirst(tlist))->resdom->resjunk)
- elog(ERROR, "parser: subselect must have a field");
+ elog(ERROR, "Subselect must have a field");
while ((tlist = lnext(tlist)) != NIL)
{
if (! ((TargetEntry *) lfirst(tlist))->resdom->resjunk)
- elog(ERROR, "parser: subselect must have only one field");
+ elog(ERROR, "Subselect must have only one field");
}
/* EXPR needs no lefthand or combining operator.
* These fields should be NIL already, but make sure.
/* Combining operators other than =/<> is dubious... */
if (length(left_list) != 1 &&
strcmp(op, "=") != 0 && strcmp(op, "<>") != 0)
- elog(ERROR, "parser: '%s' is not usable for row comparison",
+ elog(ERROR, "Row comparison cannot use '%s'",
op);
sublink->oper = NIL;
continue;
if (left_list == NIL)
- elog(ERROR, "parser: Subselect has too many fields.");
+ elog(ERROR, "Subselect has too many fields");
lexpr = lfirst(left_list);
left_list = lnext(left_list);
opform = (Form_pg_operator) GETSTRUCT(optup);
if (opform->oprresult != BOOLOID)
- elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
+ elog(ERROR, "'%s' result type of '%s' must return '%s'"
+ " to be used with quantified predicate subquery",
+ op, typeidTypeName(opform->oprresult),
+ typeidTypeName(BOOLOID));
newop = makeOper(oprid(optup),/* opno */
InvalidOid, /* opid */
sublink->oper = lappend(sublink->oper, newop);
}
if (left_list != NIL)
- elog(ERROR, "parser: Subselect has too few fields.");
+ elog(ERROR, "Subselect has too few fields");
}
result = (Node *) expr;
break;
}
else
{
- elog(ERROR, "CASE/ELSE unable to convert to type %s",
+ elog(ERROR, "CASE/ELSE unable to convert to type '%s'",
typeidTypeName(ptype));
}
}
}
else
{
- elog(ERROR, "CASE/WHEN unable to convert to type %s",
+ elog(ERROR, "CASE/WHEN unable to convert to type '%s'",
typeidTypeName(ptype));
}
}
}
default:
/* should not reach here */
- elog(ERROR, "transformExpr: does not know how to transform node %d",
- nodeTag(expr));
+ elog(ERROR, "transformExpr: does not know how to transform node %d"
+ " (internal error)", nodeTag(expr));
break;
}
if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
{
/* Convert it to a fully qualified Attr, and transform that */
+#ifndef DISABLE_JOIN_SYNTAX
+ Attr *att = makeAttr(rte->ref->relname, ident->name);
+#else
Attr *att = makeNode(Attr);
att->relname = rte->refname;
att->paramNo = NULL;
att->attrs = lcons(makeString(ident->name), NIL);
+#endif
att->indirection = ident->indirection;
return transformAttr(pstate, att, precedence);
}
}
if (result == NULL)
- elog(ERROR, "attribute '%s' not found", ident->name);
+ elog(ERROR, "Attribute '%s' not found", ident->name);
return result;
}
TargetEntry *tent;
if (! qtree || ! IsA(qtree, Query))
- elog(ERROR, "exprType: can't get type for untransformed sublink");
+ elog(ERROR, "Cannot get type for untransformed sublink");
tent = (TargetEntry *) lfirst(qtree->targetList);
type = tent->resdom->restype;
}
type = UNKNOWNOID;
break;
default:
- elog(ERROR, "exprType: don't know how to get type for %d node",
+ elog(ERROR, "Do not know how to get type for %d node",
nodeTag(expr));
break;
}
break;
default:
elog(ERROR,
- "parser_typecast_constant: cannot cast this expression to type '%s'",
+ "Cannot cast this expression to type '%s'",
typename->name);
}
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.68 2000/01/26 05:56:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.69 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
{
RangeTblEntry *rte;
+ AttrNumber attnum;
Ident *ident = (Ident *) first_arg;
/*
rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL)
{
- rte = addRangeTableEntry(pstate, refname, refname,
+ rte = addRangeTableEntry(pstate, refname,
+ makeAttr(refname, NULL),
FALSE, FALSE, TRUE);
#ifdef WARN_FROM
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
relname = rte->relname;
relid = rte->relid;
+ attnum = InvalidAttrNumber;
/*
* If the attr isn't a set, just make a var for it. If it is
* a set, treat it like a function and drop through.
+ * Look through the explicit column list first, since we
+ * now allow column aliases.
+ * - thomas 2000-02-07
*/
- if (get_attnum(relid, funcname) != InvalidAttrNumber)
+ if (rte->ref->attrs != NULL)
+ {
+ List *c;
+ /* start counting attributes/columns from one.
+ * zero is reserved for InvalidAttrNumber.
+ * - thomas 2000-01-27
+ */
+ int i = 1;
+ foreach (c, rte->ref->attrs)
+ {
+ char *colname = strVal(lfirst(c));
+ /* found a match? */
+ if (strcmp(colname, funcname) == 0)
+ {
+ char *basename = get_attname(relid, i);
+
+ if (basename != NULL)
+ {
+ funcname = basename;
+ attnum = i;
+ }
+ /* attnum was initialized to InvalidAttrNumber
+ * earlier, so no need to reset it if the
+ * above test fails. - thomas 2000-02-07
+ */
+ break;
+ }
+ i++;
+ }
+ if (attnum == InvalidAttrNumber)
+ attnum = specialAttNum(funcname);
+ }
+ else
+ {
+ attnum = get_attnum(relid, funcname);
+ }
+
+ if (attnum != InvalidAttrNumber)
{
return (Node *) make_var(pstate,
relid,
rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL)
{
- rte = addRangeTableEntry(pstate, refname, refname,
+ rte = addRangeTableEntry(pstate, refname,
+ makeAttr(refname, NULL),
FALSE, FALSE, TRUE);
#ifdef WARN_FROM
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
relname = rte->relname;
- vnum = refnameRangeTablePosn(pstate, rte->refname, NULL);
+ vnum = refnameRangeTablePosn(pstate, rte->ref->relname, NULL);
/*
* for func(relname), the param to the function is the tuple
if (attisset)
{
if (!strcmp(funcname, "*"))
- funcnode->func_tlist = expandAll(pstate, relname, refname, curr_resno);
+ funcnode->func_tlist = expandAll(pstate, relname,
+ makeAttr(refname, NULL),
+ curr_resno);
else
{
funcnode->func_tlist = setup_tlist(funcname, argrelid);
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.34 2000/01/26 05:56:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.35 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
"cid",
};
+/* refnameRangeTableEntries()
+ * Given refname, return a list of range table entries
+ * This is possible with JOIN syntax, where tables in a join
+ * acquire the same reference name
+ * - thomas 2000-01-20
+ */
+List *
+refnameRangeTableEntries(ParseState *pstate, char *refname);
+
+List *
+refnameRangeTableEntries(ParseState *pstate, char *refname)
+{
+ List *rteList = NULL;
+ List *temp;
+
+ while (pstate != NULL)
+ {
+ foreach(temp, pstate->p_rtable)
+ {
+ RangeTblEntry *rte = lfirst(temp);
+
+ if (strcmp(rte->ref->relname, refname) == 0)
+ rteList = lappend(rteList, rte);
+ }
+ /* only allow correlated columns in WHERE clause */
+ if (pstate->p_in_where_clause)
+ pstate = pstate->parentParseState;
+ else
+ break;
+ }
+ return rteList;
+}
+
/* given refname, return a pointer to the range table entry */
RangeTblEntry *
refnameRangeTableEntry(ParseState *pstate, char *refname)
{
RangeTblEntry *rte = lfirst(temp);
+#ifndef DISABLE_JOIN_SYNTAX
+ if (strcmp(rte->ref->relname, refname) == 0)
+#else
if (!strcmp(rte->refname, refname))
+#endif
return rte;
}
/* only allow correlated columns in WHERE clause */
{
RangeTblEntry *rte = lfirst(temp);
+#ifndef DISABLE_JOIN_SYNTAX
+ if (strcmp(rte->ref->relname, refname) == 0)
+#else
if (!strcmp(rte->refname, refname))
+#endif
return index;
index++;
}
foreach(et, rtable)
{
+ RangeTblEntry *rte_candidate = NULL;
RangeTblEntry *rte = lfirst(et);
/* only consider RTEs mentioned in FROM or UPDATE/DELETE */
if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
continue;
- if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
+ if (rte->ref->attrs != NULL)
{
- if (rte_result != NULL)
+ List *c;
+ foreach (c, rte->ref->attrs)
{
- if (!pstate->p_is_insert ||
- rte != pstate->p_target_rangetblentry)
- elog(ERROR, "Column '%s' is ambiguous", colname);
+ if (strcmp(strVal(lfirst(c)), colname) == 0)
+ {
+ if (rte_candidate != NULL)
+ elog(ERROR, "Column '%s' is ambiguous"
+ " (internal error)", colname);
+ rte_candidate = rte;
+ }
}
- else
- rte_result = rte;
}
+
+ /* Even if we have an attribute list in the RTE,
+ * look for the column here anyway. This is the only
+ * way we will find implicit columns like "oid".
+ * - thomas 2000-02-07
+ */
+ if ((rte_candidate == NULL)
+ && (get_attnum(rte->relid, colname) != InvalidAttrNumber))
+ {
+ rte_candidate = rte;
+ }
+
+ if (rte_candidate == NULL)
+ continue;
+
+ if (rte_result != NULL)
+ {
+ if (!pstate->p_is_insert ||
+ rte != pstate->p_target_rangetblentry)
+ elog(ERROR, "Column '%s' is ambiguous", colname);
+ }
+ else
+ rte_result = rte;
}
+
/* only allow correlated columns in WHERE clause */
if (pstate->p_in_where_clause && rte_result == NULL)
pstate = pstate->parentParseState;
RangeTblEntry *
addRangeTableEntry(ParseState *pstate,
char *relname,
- char *refname,
+ Attr *ref,
bool inh,
bool inFromCl,
bool inJoinSet)
{
- Relation relation;
- RangeTblEntry *rte;
- int sublevels_up;
+ Relation rel;
+ RangeTblEntry *rte;
+ int maxattrs;
+ int sublevels_up;
+ int varattno;
+ /* Look for an existing rte, if available... */
if (pstate != NULL)
{
- int rt_index = refnameRangeTablePosn(pstate, refname,
- &sublevels_up);
+ int rt_index = refnameRangeTablePosn(pstate, ref->relname,
+ &sublevels_up);
if (rt_index != 0 && (!inFromCl || sublevels_up == 0))
{
- if (!strcmp(refname, "*CURRENT*") || !strcmp(refname, "*NEW*"))
+ if (!strcmp(ref->relname, "*CURRENT*") || !strcmp(ref->relname, "*NEW*"))
return (RangeTblEntry *) nth(rt_index - 1, pstate->p_rtable);
- elog(ERROR, "Table name '%s' specified more than once", refname);
+ elog(ERROR, "Table name '%s' specified more than once", ref->relname);
}
}
rte = makeNode(RangeTblEntry);
- rte->relname = pstrdup(relname);
- rte->refname = pstrdup(refname);
+ rte->relname = relname;
+ rte->ref = ref;
/* Get the rel's OID. This access also ensures that we have an
* up-to-date relcache entry for the rel. We don't need to keep
* it open, however.
+ * Since this is open anyway, let's check that the number of column
+ * aliases is reasonable.
+ * - Thomas 2000-02-04
*/
- relation = heap_openr(relname, AccessShareLock);
- rte->relid = RelationGetRelid(relation);
- heap_close(relation, AccessShareLock);
+ rel = heap_openr(relname, AccessShareLock);
+ rte->relid = RelationGetRelid(rel);
+ maxattrs = RelationGetNumberOfAttributes(rel);
+ if (maxattrs < length(ref->attrs))
+ elog(ERROR, "Table '%s' has %d columns available but %d columns specified",
+ relname, maxattrs, length(ref->attrs));
+
+ /* fill in any unspecified alias columns */
+ for (varattno = length(ref->attrs); varattno < maxattrs; varattno++)
+ {
+ char *attrname;
+
+ attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+ ref->attrs = lappend(ref->attrs, makeString(attrname));
+ }
+ heap_close(rel, AccessShareLock);
/*
- * Flags: this RTE should be expanded to include descendant tables,
- * this RTE is in the FROM clause, this RTE should be included in
- * the planner's final join.
+ * Flags:
+ * - this RTE should be expanded to include descendant tables,
+ * - this RTE is in the FROM clause,
+ * - this RTE should be included in the planner's final join.
*/
rte->inh = inh;
rte->inFromCl = inFromCl;
return rte;
}
+/* expandTable()
+ * Populates an Attr with table name and column names
+ * This is similar to expandAll(), but does not create an RTE
+ * if it does not already exist.
+ * - thomas 2000-01-19
+ */
+Attr *
+expandTable(ParseState *pstate, char *refname, bool getaliases)
+{
+ Attr *attr;
+ RangeTblEntry *rte;
+ Relation rel;
+ int varattno,
+ maxattrs;
+
+ rte = refnameRangeTableEntry(pstate, refname);
+
+ if (getaliases && (rte != NULL) && (rte->ref != NULL)
+ && (length(rte->ref->attrs) > 0))
+ {
+ return rte->ref;
+ }
+
+ if (rte != NULL)
+ rel = heap_open(rte->relid, AccessShareLock);
+ else
+ rel = heap_openr(refname, AccessShareLock);
+
+ if (rel == NULL)
+ elog(ERROR, "Relation '%s' not found", refname);
+
+ maxattrs = RelationGetNumberOfAttributes(rel);
+
+ attr = makeAttr(refname, NULL);
+
+ for (varattno = 0; varattno < maxattrs; varattno++)
+ {
+ char *attrname;
+
+ attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+ attr->attrs = lappend(attr->attrs, makeString(attrname));
+ }
+
+ heap_close(rel, AccessShareLock);
+
+ return attr;
+}
+
/*
* expandAll -
* makes a list of attributes
*/
List *
-expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
+expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno)
{
- List *te_list = NIL;
- RangeTblEntry *rte;
- Relation rel;
- int varattno,
- maxattrs;
+ List *te_list = NIL;
+ RangeTblEntry *rte;
+ Relation rel;
+ int varattno,
+ maxattrs;
- rte = refnameRangeTableEntry(pstate, refname);
+ rte = refnameRangeTableEntry(pstate, ref->relname);
if (rte == NULL)
{
- rte = addRangeTableEntry(pstate, relname, refname,
+ rte = addRangeTableEntry(pstate, relname, ref,
FALSE, FALSE, TRUE);
#ifdef WARN_FROM
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
for (varattno = 0; varattno < maxattrs; varattno++)
{
- char *attrname;
- Var *varnode;
- TargetEntry *te = makeNode(TargetEntry);
+ char *attrname;
+ char *label;
+ Var *varnode;
+ TargetEntry *te = makeNode(TargetEntry);
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
- varnode = make_var(pstate, rte->relid, refname, attrname);
+
+ /* varattno is zero-based, so check that length() is always greater */
+ if (length(rte->ref->attrs) > varattno)
+ label = pstrdup(strVal(nth(varattno, rte->ref->attrs)));
+ else
+ label = attrname;
+ varnode = make_var(pstate, rte->relid, relname, attrname);
/*
* Even if the elements making up a set are complex, the set
te->resdom = makeResdom((AttrNumber) (*this_resno)++,
varnode->vartype,
varnode->vartypmod,
- attrname,
+ label,
(Index) 0,
(Oid) 0,
false);
if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
return i + 1;
- for (i = 0; i < SPECIALS; i++)
- if (!strcmp(special_attr[i].field, a))
- return special_attr[i].code;
+ if ((i = specialAttNum(a)) != InvalidAttrNumber)
+ return i;
/* on failure */
elog(ERROR, "Relation '%s' does not have attribute '%s'",
RelationGetRelationName(rd), a);
- return 0; /* lint */
+ return InvalidAttrNumber; /* lint */
}
+/* specialAttNum()
+ * Check attribute name to see if it is "special", e.g. "oid".
+ * - thomas 2000-02-07
+ */
+int
+specialAttNum(char *a)
+{
+ int i;
+
+ for (i = 0; i < SPECIALS; i++)
+ if (!strcmp(special_attr[i].field, a))
+ return special_attr[i].code;
+
+ return InvalidAttrNumber;
+}
+
+
/*
* Given range variable, return whether attribute of this name
* is a set.
*/
return rd->rd_att->attrs[attid - 1]->atttypid;
}
+
+
+
+
+
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.54 2000/01/26 05:56:42 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.55 2000/02/15 03:37:47 thomas Exp $
*
*-------------------------------------------------------------------------
*/
* Target item is a single '*', expand all tables
* (eg. SELECT * FROM emp)
*/
- p_target = nconc(p_target,
- ExpandAllTables(pstate));
+ if (pstate->p_shape != NULL)
+ {
+ List *s, *a;
+ int i;
+
+ Assert(length(pstate->p_shape) == length(pstate->p_alias));
+
+ s = pstate->p_shape;
+ a = pstate->p_alias;
+ for (i = 0; i < length(pstate->p_shape); i++)
+ {
+ TargetEntry *te;
+ char *colname;
+ Attr *shape = lfirst(s);
+ Attr *alias = lfirst(a);
+
+ Assert(IsA(shape, Attr) && IsA(alias, Attr));
+
+ colname = strVal(lfirst(alias->attrs));
+ te = transformTargetEntry(pstate, (Node *) shape,
+ NULL, colname, false);
+ p_target = lappend(p_target, te);
+ s = lnext(s);
+ a = lnext(a);
+ }
+ }
+ else
+ p_target = nconc(p_target,
+ ExpandAllTables(pstate));
}
else if (att->attrs != NIL &&
strcmp(strVal(lfirst(att->attrs)), "*") == 0)
* (eg. SELECT emp.*, dname FROM emp, dept)
*/
p_target = nconc(p_target,
- expandAll(pstate,
- att->relname,
- att->relname,
+ expandAll(pstate, att->relname,
+ makeAttr(att->relname, NULL),
&pstate->p_last_resno));
}
else
*/
if (indirection)
{
+#ifndef DISABLE_JOIN_SYNTAX
+ Attr *att = makeAttr(pstrdup(RelationGetRelationName(rd)), colname);
+#else
Attr *att = makeNode(Attr);
+#endif
Node *arrayBase;
ArrayRef *aref;
+#ifdef DISABLE_JOIN_SYNTAX
att->relname = pstrdup(RelationGetRelationName(rd));
att->attrs = lcons(makeString(colname), NIL);
+#endif
arrayBase = ParseNestedFuncOrColumn(pstate, att,
&pstate->p_last_resno,
EXPR_COLUMN_FIRST);
return cols;
}
-/*
- * ExpandAllTables -
- * turns '*' (in the target list) into a list of attributes
- * (of all relations in the range table)
+/* ExpandAllTables()
+ * Turns '*' (in the target list) into a list of attributes
+ * (of all relations in the range table)
*/
static List *
ExpandAllTables(ParseState *pstate)
/* SELECT *; */
if (rtable == NIL)
- elog(ERROR, "Wildcard with no tables specified.");
+ elog(ERROR, "Wildcard with no tables specified not allowed");
foreach(rt, rtable)
{
continue;
target = nconc(target,
- expandAll(pstate, rte->relname, rte->refname,
+ expandAll(pstate, rte->ref->relname, rte->ref,
&pstate->p_last_resno));
}
return target;
* out of its tuple
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.39 2000/01/15 22:43:24 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.40 2000/02/15 03:37:56 thomas Exp $
*
* This software is copyrighted by Jan Wieck - Hamburg.
*
continue;
rte = (RangeTblEntry *) lfirst(l);
- if (!strcmp(rte->refname, "*NEW*"))
+ if (!strcmp(rte->ref->relname, "*NEW*"))
continue;
- if (!strcmp(rte->refname, "*CURRENT*"))
+ if (!strcmp(rte->ref->relname, "*CURRENT*"))
continue;
rt_constonly = FALSE;
{
rte = (RangeTblEntry *) lfirst(l);
- if (!strcmp(rte->refname, "*NEW*"))
+ if (!strcmp(rte->ref->relname, "*NEW*"))
continue;
- if (!strcmp(rte->refname, "*CURRENT*"))
+ if (!strcmp(rte->ref->relname, "*CURRENT*"))
continue;
appendStringInfo(buf, sep);
appendStringInfo(buf, "%s%s",
quote_identifier(rte->relname),
inherit_marker(rte));
- if (strcmp(rte->relname, rte->refname) != 0)
+ if (strcmp(rte->relname, rte->ref->relname) != 0)
+ {
+ List *col;
appendStringInfo(buf, " %s",
- quote_identifier(rte->refname));
+ quote_identifier(rte->ref->relname));
+ appendStringInfo(buf, " (");
+ foreach (col, rte->ref->attrs)
+ {
+ if (col != lfirst(rte->ref->attrs))
+ appendStringInfo(buf, ", ");
+ appendStringInfo(buf, "%s", strVal(col));
+ }
+ }
}
}
}
continue;
rte = (RangeTblEntry *) lfirst(l);
- if (!strcmp(rte->refname, "*NEW*"))
+ if (!strcmp(rte->ref->relname, "*NEW*"))
continue;
- if (!strcmp(rte->refname, "*CURRENT*"))
+ if (!strcmp(rte->ref->relname, "*CURRENT*"))
continue;
rt_constonly = FALSE;
if (context->varprefix)
{
- if (!strcmp(rte->refname, "*NEW*"))
+ if (!strcmp(rte->ref->relname, "*NEW*"))
appendStringInfo(buf, "new.");
- else if (!strcmp(rte->refname, "*CURRENT*"))
+ else if (!strcmp(rte->ref->relname, "*CURRENT*"))
appendStringInfo(buf, "old.");
else
appendStringInfo(buf, "%s.",
- quote_identifier(rte->refname));
+ quote_identifier(rte->ref->relname));
}
appendStringInfo(buf, "%s",
quote_identifier(get_attribute_name(rte->relid,
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: makefuncs.h,v 1.22 2000/01/26 05:58:16 momjian Exp $
+ * $Id: makefuncs.h,v 1.23 2000/02/15 03:38:13 thomas Exp $
*
*-------------------------------------------------------------------------
*/
bool constisset,
bool constiscast);
+extern Attr *
+makeAttr(char *relname, char *attname);
+
#endif /* MAKEFUNC_H */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsenodes.h,v 1.97 2000/01/27 18:11:44 tgl Exp $
+ * $Id: parsenodes.h,v 1.98 2000/02/15 03:38:14 thomas Exp $
*
*-------------------------------------------------------------------------
*/
{
NodeTag type;
RelExpr *relExpr; /* the relation expression */
- char *name; /* the name to be referenced (optional) */
+ Attr *name; /* the name to be referenced (optional) */
} RangeVar;
/*
{
NodeTag type;
int jointype;
- RangeVar *larg;
- Node *rarg;
- List *quals;
+ bool isNatural; /* Natural join? Will need to shape table */
+ Node *larg; /* RangeVar or join expression */
+ Node *rarg; /* RangeVar or join expression */
+ Attr *alias; /* table and column aliases, if any */
+ List *quals; /* qualifiers on join, if any */
} JoinExpr;
{
NodeTag type;
char *relname; /* real name of the relation */
- char *refname; /* the reference name (as specified in the
- * FROM clause) */
+// char *refname; /* reference name (given in FROM clause) */
+#ifndef DISABLE_JOIN_SYNTAX
+ Attr *ref; /* reference names (given in FROM clause) */
+#endif
Oid relid; /* OID of the relation */
bool inh; /* inheritance requested? */
bool inFromCl; /* present in FROM clause */
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_clause.h,v 1.15 2000/01/27 18:11:47 tgl Exp $
+ * $Id: parse_clause.h,v 1.16 2000/02/15 03:38:28 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "parser/parse_node.h"
-extern void makeRangeTable(ParseState *pstate, List *frmList, Node **qual);
+extern void makeRangeTable(ParseState *pstate, List *frmList);
extern void setTargetTable(ParseState *pstate, char *relname);
-extern Node *transformWhereClause(ParseState *pstate, Node *where,
- Node *using);
+extern Node *transformWhereClause(ParseState *pstate, Node *where);
extern List *transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist);
extern List *transformSortClause(ParseState *pstate, List *orderlist,
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_node.h,v 1.17 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parse_node.h,v 1.18 2000/02/15 03:38:29 thomas Exp $
*
*-------------------------------------------------------------------------
*/
#include "nodes/parsenodes.h"
#include "utils/rel.h"
-/* state information used during parse analysis */
+/* State information used during parse analysis
+ * p_join_quals is a list of qualification expressions
+ * found in the FROM clause. Needs to be available later
+ * to merge with other qualifiers from the WHERE clause.
+ */
typedef struct ParseState
{
int p_last_resno;
bool p_in_where_clause;
Relation p_target_relation;
RangeTblEntry *p_target_rangetblentry;
+ List *p_shape;
+ List *p_alias;
+ Node *p_join_quals;
} ParseState;
extern ParseState *make_parsestate(ParseState *parentParseState);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parse_relation.h,v 1.14 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parse_relation.h,v 1.15 2000/02/15 03:38:29 thomas Exp $
*
*-------------------------------------------------------------------------
*/
extern RangeTblEntry *refnameRangeTableEntry(ParseState *pstate, char *refname);
extern int refnameRangeTablePosn(ParseState *pstate,
- char *refname, int *sublevels_up);
+ char *refname,
+ int *sublevels_up);
extern RangeTblEntry *colnameRangeTableEntry(ParseState *pstate, char *colname);
extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
- char *relname,
- char *refname,
- bool inh,
- bool inFromCl,
- bool inJoinSet);
-extern List *expandAll(ParseState *pstate, char *relname, char *refname,
- int *this_resno);
+ char *relname,
+ Attr *ref,
+ bool inh,
+ bool inFromCl,
+ bool inJoinSet);
+extern Attr *expandTable(ParseState *pstate, char *refname, bool getaliases);
+extern List *expandAll(ParseState *pstate, char *relname, Attr *ref,
+ int *this_resno);
extern int attnameAttNum(Relation rd, char *a);
+extern int specialAttNum(char *a);
extern bool attnameIsSet(Relation rd, char *name);
extern int attnumAttNelems(Relation rd, int attid);
extern Oid attnumTypeId(Relation rd, int attid);
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $Id: parsetree.h,v 1.8 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parsetree.h,v 1.9 2000/02/15 03:38:29 thomas Exp $
*
*-------------------------------------------------------------------------
*/
*/
#define rt_relname(rt_entry) \
- ((!strcmp(((rt_entry)->refname),"*CURRENT*") ||\
- !strcmp(((rt_entry)->refname),"*NEW*")) ? ((rt_entry)->refname) : \
+ ((!strcmp(((rt_entry)->ref->relname),"*CURRENT*") ||\
+ !strcmp(((rt_entry)->ref->relname),"*NEW*")) ? ((rt_entry)->ref->relname) : \
((char *)(rt_entry)->relname))
/*