Commit a344a6e7 authored by Thomas G. Lockhart's avatar Thomas G. Lockhart

Carry column aliases from the parser frontend. Enables queries like

  SELECT a FROM t1 tx (a);
Allow join syntax, including queries like
  SELECT * FROM t1 NATURAL JOIN t2;
Update RTE structure to hold column aliases in an Attr structure.
parent 92c8437d
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * INTERFACE ROUTINES
...@@ -53,6 +53,7 @@ ...@@ -53,6 +53,7 @@
#include "optimizer/planmain.h" #include "optimizer/planmain.h"
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
#include "optimizer/var.h" #include "optimizer/var.h"
#include "nodes/makefuncs.h"
#include "parser/parse_clause.h" #include "parser/parse_clause.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
...@@ -1719,7 +1720,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin, ...@@ -1719,7 +1720,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
*/ */
rte = makeNode(RangeTblEntry); rte = makeNode(RangeTblEntry);
rte->relname = RelationGetRelationName(rel); rte->relname = RelationGetRelationName(rel);
rte->refname = RelationGetRelationName(rel); rte->ref = makeNode(Attr);
rte->ref->relname = RelationGetRelationName(rel);
rte->relid = RelationGetRelid(rel); rte->relid = RelationGetRelid(rel);
rte->inh = false; rte->inh = false;
rte->inFromCl = true; rte->inFromCl = true;
...@@ -1798,7 +1800,8 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin) ...@@ -1798,7 +1800,8 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
*/ */
rte = makeNode(RangeTblEntry); rte = makeNode(RangeTblEntry);
rte->relname = RelationGetRelationName(rel); rte->relname = RelationGetRelationName(rel);
rte->refname = RelationGetRelationName(rel); rte->ref = makeNode(Attr);
rte->ref->relname = RelationGetRelationName(rel);
rte->relid = RelationGetRelid(rel); rte->relid = RelationGetRelid(rel);
rte->inh = false; rte->inh = false;
rte->inFromCl = true; rte->inFromCl = true;
...@@ -1919,8 +1922,8 @@ AddRelationRawConstraints(Relation rel, ...@@ -1919,8 +1922,8 @@ AddRelationRawConstraints(Relation rel,
* its sole rangetable entry. We need a ParseState for transformExpr. * its sole rangetable entry. We need a ParseState for transformExpr.
*/ */
pstate = make_parsestate(NULL); pstate = make_parsestate(NULL);
makeRangeTable(pstate, NULL, NULL); makeRangeTable(pstate, NULL);
addRangeTableEntry(pstate, relname, relname, false, true, true); addRangeTableEntry(pstate, relname, makeAttr(relname, NULL), false, true, true);
/* /*
* Process column default expressions. * Process column default expressions.
......
...@@ -5,7 +5,7 @@ ...@@ -5,7 +5,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994-5, Regents of the University of California * 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 $
* *
*/ */
...@@ -230,12 +230,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) ...@@ -230,12 +230,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable); RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
appendStringInfo(str, " on "); appendStringInfo(str, " on ");
if (strcmp(rte->refname, rte->relname) != 0) if (strcmp(rte->ref->relname, rte->relname) != 0)
{ {
appendStringInfo(str, "%s ", appendStringInfo(str, "%s ",
stringStringInfo(rte->relname)); stringStringInfo(rte->relname));
} }
appendStringInfo(str, stringStringInfo(rte->refname)); appendStringInfo(str, stringStringInfo(rte->ref->relname));
} }
break; break;
case T_TidScan: case T_TidScan:
...@@ -244,12 +244,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es) ...@@ -244,12 +244,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
RangeTblEntry *rte = nth(((TidScan *) plan)->scan.scanrelid - 1, es->rtable); RangeTblEntry *rte = nth(((TidScan *) plan)->scan.scanrelid - 1, es->rtable);
appendStringInfo(str, " on "); appendStringInfo(str, " on ");
if (strcmp(rte->refname, rte->relname) != 0) if (strcmp(rte->ref->relname, rte->relname) != 0)
{ {
appendStringInfo(str, "%s ", appendStringInfo(str, "%s ",
stringStringInfo(rte->relname)); stringStringInfo(rte->relname));
} }
appendStringInfo(str, stringStringInfo(rte->refname)); appendStringInfo(str, stringStringInfo(rte->ref->relname));
} }
break; break;
default: default:
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include "catalog/heap.h" #include "catalog/heap.h"
#include "commands/creatinh.h" #include "commands/creatinh.h"
#include "commands/view.h" #include "commands/view.h"
#include "nodes/makefuncs.h"
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "parser/parse_type.h" #include "parser/parse_type.h"
#include "rewrite/rewriteDefine.h" #include "rewrite/rewriteDefine.h"
...@@ -225,9 +226,11 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse) ...@@ -225,9 +226,11 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
* create the 2 new range table entries and form the new range * create the 2 new range table entries and form the new range
* table... CURRENT first, then NEW.... * table... CURRENT first, then NEW....
*/ */
rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*", rt_entry1 = addRangeTableEntry(NULL, (char *) viewName,
makeAttr("*CURRENT*", NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*", rt_entry2 = addRangeTableEntry(NULL, (char *) viewName,
makeAttr("*NEW*", NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
new_rt = lcons(rt_entry2, old_rt); new_rt = lcons(rt_entry2, old_rt);
new_rt = lcons(rt_entry1, new_rt); new_rt = lcons(rt_entry1, new_rt);
......
...@@ -27,7 +27,7 @@ ...@@ -27,7 +27,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1508,7 +1508,8 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate) ...@@ -1508,7 +1508,8 @@ ExecRelCheck(Relation rel, HeapTuple tuple, EState *estate)
slot->ttc_buffer = InvalidBuffer; slot->ttc_buffer = InvalidBuffer;
slot->ttc_whichplan = -1; slot->ttc_whichplan = -1;
rte->relname = RelationGetRelationName(rel); rte->relname = RelationGetRelationName(rel);
rte->refname = rte->relname; rte->ref = makeNode(Attr);
rte->ref->relname = rte->relname;
rte->relid = RelationGetRelid(rel); rte->relid = RelationGetRelid(rel);
/* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */ /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
rtlist = lcons(rte, NIL); rtlist = lcons(rte, NIL);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -688,6 +688,18 @@ _copyVar(Var *from) ...@@ -688,6 +688,18 @@ _copyVar(Var *from)
return newnode; 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 * _copyOper
* ---------------- * ----------------
...@@ -1327,8 +1339,8 @@ _copyRangeTblEntry(RangeTblEntry *from) ...@@ -1327,8 +1339,8 @@ _copyRangeTblEntry(RangeTblEntry *from)
if (from->relname) if (from->relname)
newnode->relname = pstrdup(from->relname); newnode->relname = pstrdup(from->relname);
if (from->refname) if (from->ref)
newnode->refname = pstrdup(from->refname); Node_Copy(from, newnode, ref);
newnode->relid = from->relid; newnode->relid = from->relid;
newnode->inh = from->inh; newnode->inh = from->inh;
newnode->inFromCl = from->inFromCl; newnode->inFromCl = from->inFromCl;
...@@ -1571,6 +1583,9 @@ copyObject(void *from) ...@@ -1571,6 +1583,9 @@ copyObject(void *from)
case T_Var: case T_Var:
retval = _copyVar(from); retval = _copyVar(from);
break; break;
case T_Attr:
retval = _copyAttr(from);
break;
case T_Oper: case T_Oper:
retval = _copyOper(from); retval = _copyOper(from);
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -95,6 +95,17 @@ _equalExpr(Expr *a, Expr *b) ...@@ -95,6 +95,17 @@ _equalExpr(Expr *a, Expr *b)
return true; 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 static bool
_equalVar(Var *a, Var *b) _equalVar(Var *a, Var *b)
{ {
...@@ -633,14 +644,14 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b) ...@@ -633,14 +644,14 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
if (a->relname != b->relname) if (a->relname != b->relname)
return false; 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; return false;
} }
else else
{ {
if (a->refname != b->refname) if (a->ref != b->ref)
return false; return false;
} }
if (a->relid != b->relid) if (a->relid != b->relid)
...@@ -845,6 +856,9 @@ equal(void *a, void *b) ...@@ -845,6 +856,9 @@ equal(void *a, void *b)
case T_EState: case T_EState:
retval = _equalEState(a, b); retval = _equalEState(a, b);
break; break;
case T_Attr:
retval = _equalAttr(a, b);
break;
case T_Integer: case T_Integer:
case T_String: case T_String:
case T_Float: case T_Float:
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1013,8 +1013,19 @@ _freeRangeTblEntry(RangeTblEntry *node) ...@@ -1013,8 +1013,19 @@ _freeRangeTblEntry(RangeTblEntry *node)
{ {
if (node->relname) if (node->relname)
pfree(node->relname); pfree(node->relname);
if (node->refname) if (node->ref)
pfree(node->refname); freeObject(node->ref);
pfree(node);
}
static void
_freeAttr(Attr *node)
{
if (node->relname)
pfree(node->relname);
if (node->attrs)
freeObject(node->attrs);
pfree(node); pfree(node);
} }
...@@ -1308,6 +1319,9 @@ freeObject(void *node) ...@@ -1308,6 +1319,9 @@ freeObject(void *node)
case T_TypeCast: case T_TypeCast:
_freeTypeCast(node); _freeTypeCast(node);
break; break;
case T_Attr:
_freeAttr(node);
break;
/* /*
* VALUE NODES * VALUE NODES
...@@ -1332,3 +1346,10 @@ freeObject(void *node) ...@@ -1332,3 +1346,10 @@ freeObject(void *node)
break; break;
} }
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Creator functions in POSTGRES 4.2 are generated automatically. Most of * Creator functions in POSTGRES 4.2 are generated automatically. Most of
...@@ -141,3 +141,26 @@ makeConst(Oid consttype, ...@@ -141,3 +141,26 @@ makeConst(Oid consttype,
cnst->constiscast = constiscast; cnst->constiscast = constiscast;
return cnst; 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;
}
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 * NOTES
* Every (plan) node in POSTGRES has an associated "out" routine which * Every (plan) node in POSTGRES has an associated "out" routine which
...@@ -954,8 +954,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node) ...@@ -954,8 +954,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
{ {
appendStringInfo(str, " RTE :relname "); appendStringInfo(str, " RTE :relname ");
_outToken(str, node->relname); _outToken(str, node->relname);
appendStringInfo(str, " :refname "); appendStringInfo(str, " :ref ");
_outToken(str, node->refname); _outNode(str, node->ref);
appendStringInfo(str, appendStringInfo(str,
" :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s", " :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
node->relid, node->relid,
...@@ -1273,18 +1273,10 @@ _outIdent(StringInfo str, Ident *node) ...@@ -1273,18 +1273,10 @@ _outIdent(StringInfo str, Ident *node)
static void static void
_outAttr(StringInfo str, Attr *node) _outAttr(StringInfo str, Attr *node)
{ {
List *l; appendStringInfo(str, " ATTR :relname ");
appendStringInfo(str, " ATTR ");
_outToken(str, node->relname); _outToken(str, node->relname);
appendStringInfo(str, " ("); appendStringInfo(str, " :attrs ");
foreach(l, node->attrs) _outNode(str, node->attrs);
{
_outNode(str, lfirst(l));
if (lnext(l))
appendStringInfo(str, " ");
}
appendStringInfo(str, ")");
} }
static void static void
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -133,7 +133,7 @@ print_rt(List *rtable) ...@@ -133,7 +133,7 @@ print_rt(List *rtable)
RangeTblEntry *rte = lfirst(l); RangeTblEntry *rte = lfirst(l);
printf("%d\t%s(%s)\t%u\t%d\t%s\n", 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->inFromCl,
(rte->inh ? "inh" : "")); (rte->inh ? "inh" : ""));
i++; i++;
...@@ -175,8 +175,9 @@ print_expr(Node *expr, List *rtable) ...@@ -175,8 +175,9 @@ print_expr(Node *expr, List *rtable)
{ {
rt = rt_fetch(var->varno, rtable); rt = rt_fetch(var->varno, rtable);
relname = rt->relname; relname = rt->relname;
if (rt->refname) if (rt->ref)
relname = rt->refname; /* table renamed */ if (rt->ref->relname)
relname = rt->relname; /* table renamed */
attname = get_attname(rt->relid, var->varattno); attname = get_attname(rt->relid, var->varattno);
} }
break; break;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* Most of the read functions for plan nodes are tested. (In fact, they * Most of the read functions for plan nodes are tested. (In fact, they
...@@ -1322,6 +1322,51 @@ _readTargetEntry() ...@@ -1322,6 +1322,51 @@ _readTargetEntry()
return local_node; 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 * _readRangeTblEntry
* ---------------- * ----------------
...@@ -1342,12 +1387,8 @@ _readRangeTblEntry() ...@@ -1342,12 +1387,8 @@ _readRangeTblEntry()
else else
local_node->relname = debackslash(token, length); local_node->relname = debackslash(token, length);
token = lsptok(NULL, &length); /* eat :refname */ token = lsptok(NULL, &length); /* eat :ref */
token = lsptok(NULL, &length); /* get :refname */ local_node->ref = nodeRead(true);
if (length == 0)
local_node->refname = NULL;
else
local_node->refname = debackslash(token, length);
token = lsptok(NULL, &length); /* eat :relid */ token = lsptok(NULL, &length); /* eat :relid */
token = lsptok(NULL, &length); /* get :relid */ token = lsptok(NULL, &length); /* get :relid */
...@@ -1795,6 +1836,8 @@ parsePlanString(void) ...@@ -1795,6 +1836,8 @@ parsePlanString(void)
return_value = _readArray(); return_value = _readArray();
else if (length == 3 && strncmp(token, "VAR", length) == 0) else if (length == 3 && strncmp(token, "VAR", length) == 0)
return_value = _readVar(); return_value = _readVar();
else if (length == 4 && strncmp(token, "ATTR", length) == 0)
return_value = _readAttr();
else if (length == 5 && strncmp(token, "CONST", length) == 0) else if (length == 5 && strncmp(token, "CONST", length) == 0)
return_value = _readConst(); return_value = _readConst();
else if (length == 4 && strncmp(token, "FUNC", length) == 0) else if (length == 4 && strncmp(token, "FUNC", length) == 0)
...@@ -1843,6 +1886,14 @@ parsePlanString(void) ...@@ -1843,6 +1886,14 @@ parsePlanString(void)
return_value = _readCaseWhen(); return_value = _readCaseWhen();
else if (length == 7 && strncmp(token, "ROWMARK", length) == 0) else if (length == 7 && strncmp(token, "ROWMARK", length) == 0)
return_value = _readRowMark(); 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 else
elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token); elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -430,9 +430,9 @@ new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry) ...@@ -430,9 +430,9 @@ new_rangetable_entry(Oid new_relid, RangeTblEntry *old_entry)
RangeTblEntry *new_entry = copyObject(old_entry); RangeTblEntry *new_entry = copyObject(old_entry);
/* ??? someone tell me what the following is doing! - ay 11/94 */ /* ??? someone tell me what the following is doing! - ay 11/94 */
if (!strcmp(new_entry->refname, "*CURRENT*") || if (!strcmp(new_entry->ref->relname, "*CURRENT*") ||
!strcmp(new_entry->refname, "*NEW*")) !strcmp(new_entry->ref->relname, "*NEW*"))
new_entry->refname = get_rel_name(new_relid); new_entry->ref->relname = get_rel_name(new_relid);
else else
new_entry->relname = get_rel_name(new_relid); new_entry->relname = get_rel_name(new_relid);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * HISTORY
* AUTHOR DATE MAJOR EVENT * AUTHOR DATE MAJOR EVENT
...@@ -556,7 +556,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node, ...@@ -556,7 +556,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
elog(ERROR, "cache lookup of attribute %d in relation %u failed", elog(ERROR, "cache lookup of attribute %d in relation %u failed",
var->varattno, rte->relid); var->varattno, rte->relid);
elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query", elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
rte->refname, attname); rte->ref->relname, attname);
} }
} }
} }
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -239,13 +239,13 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt) ...@@ -239,13 +239,13 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
qry->commandType = CMD_DELETE; qry->commandType = CMD_DELETE;
/* set up a range table */ /* set up a range table */
makeRangeTable(pstate, NULL, NULL); makeRangeTable(pstate, NULL);
setTargetTable(pstate, stmt->relname); setTargetTable(pstate, stmt->relname);
qry->distinctClause = NIL; qry->distinctClause = NIL;
/* fix where clause */ /* fix where clause */
qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL); qry->qual = transformWhereClause(pstate, stmt->whereClause);
qry->rtable = pstate->p_rtable; qry->rtable = pstate->p_rtable;
qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL); qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
...@@ -266,7 +266,6 @@ static Query * ...@@ -266,7 +266,6 @@ static Query *
transformInsertStmt(ParseState *pstate, InsertStmt *stmt) transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
{ {
Query *qry = makeNode(Query); Query *qry = makeNode(Query);
Node *fromQual;
List *icolumns; List *icolumns;
List *attrnos; List *attrnos;
List *attnos; List *attnos;
...@@ -289,16 +288,16 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt) ...@@ -289,16 +288,16 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
*/ */
/* set up a range table --- note INSERT target is not in it yet */ /* 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->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. /* Initial processing of HAVING clause is just like WHERE clause.
* Additional work will be done in optimizer/plan/planner.c. * 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, qry->groupClause = transformGroupClause(pstate,
stmt->groupClause, stmt->groupClause,
...@@ -974,6 +973,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt) ...@@ -974,6 +973,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
* *
*/ */
if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL) if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
{
if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0) if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0)
transformFkeyGetPrimaryKey(fkconstraint); transformFkeyGetPrimaryKey(fkconstraint);
else if (pkey != NULL) else if (pkey != NULL)
...@@ -997,6 +997,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt) ...@@ -997,6 +997,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found", elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
fkconstraint->pktable_name); fkconstraint->pktable_name);
} }
}
/* /*
* Build a CREATE CONSTRAINT TRIGGER statement for the CHECK * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
...@@ -1207,7 +1208,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt) ...@@ -1207,7 +1208,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
qry->commandType = CMD_UTILITY; qry->commandType = CMD_UTILITY;
/* take care of the where clause */ /* 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->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable; stmt->rangetable = pstate->p_rtable;
...@@ -1231,7 +1233,8 @@ transformExtendStmt(ParseState *pstate, ExtendStmt *stmt) ...@@ -1231,7 +1233,8 @@ transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
qry->commandType = CMD_UTILITY; qry->commandType = CMD_UTILITY;
/* take care of the where clause */ /* 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->hasSubLinks = pstate->p_hasSubLinks;
stmt->rangetable = pstate->p_rtable; stmt->rangetable = pstate->p_rtable;
...@@ -1268,9 +1271,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1268,9 +1271,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
nothing_qry->commandType = CMD_NOTHING; nothing_qry->commandType = CMD_NOTHING;
addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*", addRangeTableEntry(pstate, stmt->object->relname,
makeAttr("*CURRENT*", NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
addRangeTableEntry(pstate, stmt->object->relname, "*NEW*", addRangeTableEntry(pstate, stmt->object->relname,
makeAttr("*NEW*", NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
nothing_qry->rtable = pstate->p_rtable; nothing_qry->rtable = pstate->p_rtable;
...@@ -1290,9 +1295,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1290,9 +1295,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
* NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW' * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
* equal to 2. * equal to 2.
*/ */
addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*", addRangeTableEntry(pstate, stmt->object->relname,
makeAttr("*CURRENT*", NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
addRangeTableEntry(pstate, stmt->object->relname, "*NEW*", addRangeTableEntry(pstate, stmt->object->relname,
makeAttr("*NEW*", NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
pstate->p_last_resno = 1; pstate->p_last_resno = 1;
...@@ -1306,7 +1313,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt) ...@@ -1306,7 +1313,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
} }
/* take care of the where clause */ /* 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->hasSubLinks = pstate->p_hasSubLinks;
qry->utilityStmt = (Node *) stmt; qry->utilityStmt = (Node *) stmt;
...@@ -1323,12 +1331,11 @@ static Query * ...@@ -1323,12 +1331,11 @@ static Query *
transformSelectStmt(ParseState *pstate, SelectStmt *stmt) transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
{ {
Query *qry = makeNode(Query); Query *qry = makeNode(Query);
Node *fromQual;
qry->commandType = CMD_SELECT; qry->commandType = CMD_SELECT;
/* set up a range table */ /* set up a range table */
makeRangeTable(pstate, stmt->fromClause, &fromQual); makeRangeTable(pstate, stmt->fromClause);
qry->into = stmt->into; qry->into = stmt->into;
qry->isTemp = stmt->istemp; qry->isTemp = stmt->istemp;
...@@ -1336,12 +1343,12 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt) ...@@ -1336,12 +1343,12 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
qry->targetList = transformTargetList(pstate, stmt->targetList); 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. /* Initial processing of HAVING clause is just like WHERE clause.
* Additional work will be done in optimizer/plan/planner.c. * 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, qry->groupClause = transformGroupClause(pstate,
stmt->groupClause, stmt->groupClause,
...@@ -1401,12 +1408,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt) ...@@ -1401,12 +1408,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
* the FROM clause is non-standard SQL syntax. We used to be able to * 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. * do this with REPLACE in POSTQUEL so we keep the feature.
*/ */
makeRangeTable(pstate, stmt->fromClause, NULL); makeRangeTable(pstate, stmt->fromClause);
setTargetTable(pstate, stmt->relname); setTargetTable(pstate, stmt->relname);
qry->targetList = transformTargetList(pstate, stmt->targetList); qry->targetList = transformTargetList(pstate, stmt->targetList);
qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL); qry->qual = transformWhereClause(pstate, stmt->whereClause);
qry->hasSubLinks = pstate->p_hasSubLinks; qry->hasSubLinks = pstate->p_hasSubLinks;
...@@ -1866,7 +1873,7 @@ transformForUpdate(Query *qry, List *forUpdate) ...@@ -1866,7 +1873,7 @@ transformForUpdate(Query *qry, List *forUpdate)
i = 1; i = 1;
foreach(l2, qry->rtable) foreach(l2, qry->rtable)
{ {
if (strcmp(((RangeTblEntry *) lfirst(l2))->refname, relname) == 0) if (strcmp(((RangeTblEntry *) lfirst(l2))->ref->relname, relname) == 0)
{ {
List *l3; List *l3;
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -111,7 +111,7 @@ check_ungrouped_columns_walker(Node *node, ...@@ -111,7 +111,7 @@ check_ungrouped_columns_walker(Node *node,
elog(ERROR, "cache lookup of attribute %d in relation %u failed", elog(ERROR, "cache lookup of attribute %d in relation %u failed",
var->varattno, rte->relid); var->varattno, rte->relid);
elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function", elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
rte->refname, attname); rte->ref->relname, attname);
} }
/* Otherwise, recurse. */ /* Otherwise, recurse. */
return expression_tree_walker(node, check_ungrouped_columns_walker, return expression_tree_walker(node, check_ungrouped_columns_walker,
......
...@@ -8,16 +8,17 @@ ...@@ -8,16 +8,17 @@
* *
* *
* IDENTIFICATION * 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 "postgres.h"
#include "access/heapam.h" #include "access/heapam.h"
#include "miscadmin.h"
#include "optimizer/tlist.h" #include "optimizer/tlist.h"
#include "parse.h" #include "parse.h"
#include "nodes/makefuncs.h"
#include "parser/parse_clause.h" #include "parser/parse_clause.h"
#include "parser/parse_coerce.h" #include "parser/parse_coerce.h"
#include "parser/parse_expr.h" #include "parser/parse_expr.h"
...@@ -25,7 +26,6 @@ ...@@ -25,7 +26,6 @@
#include "parser/parse_relation.h" #include "parser/parse_relation.h"
#include "parser/parse_target.h" #include "parser/parse_target.h"
#define ORDER_CLAUSE 0 #define ORDER_CLAUSE 0
#define GROUP_CLAUSE 1 #define GROUP_CLAUSE 1
#define DISTINCT_ON_CLAUSE 2 #define DISTINCT_ON_CLAUSE 2
...@@ -34,28 +34,26 @@ static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"}; ...@@ -34,28 +34,26 @@ static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node, static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
List *tlist, int clause); List *tlist, int clause);
static void parseFromClause(ParseState *pstate, List *frmList, Node **qual); static void parseFromClause(ParseState *pstate, List *frmList);
static char *transformTableEntry(ParseState *pstate, RangeVar *r); RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
static List *addTargetToSortList(TargetEntry *tle, List *sortlist, static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
List *targetlist, char *opname); List *targetlist, char *opname);
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList); static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
#ifdef ENABLE_OUTER_JOINS #ifndef DISABLE_OUTER_JOINS
static Node *transformUsingClause(ParseState *pstate, List *onList, static Node *transformUsingClause(ParseState *pstate, List *using, List *left, List *right);
char *lname, char *rname);
#endif #endif
/* /*
* makeRangeTable - * makeRangeTable -
* Build the initial range table from the FROM clause. * Build the initial range table from the FROM clause.
*/ */
void void
makeRangeTable(ParseState *pstate, List *frmList, Node **qual) makeRangeTable(ParseState *pstate, List *frmList)
{ {
/* Currently, nothing to do except this: */ /* Currently, nothing to do except this: */
parseFromClause(pstate, frmList, qual); parseFromClause(pstate, frmList);
} }
/* /*
...@@ -80,7 +78,8 @@ setTargetTable(ParseState *pstate, char *relname) ...@@ -80,7 +78,8 @@ setTargetTable(ParseState *pstate, char *relname)
if ((refnameRangeTablePosn(pstate, relname, &sublevels_up) == 0) if ((refnameRangeTablePosn(pstate, relname, &sublevels_up) == 0)
|| (sublevels_up != 0)) || (sublevels_up != 0))
rte = addRangeTableEntry(pstate, relname, relname, rte = addRangeTableEntry(pstate, relname,
makeAttr(relname, NULL),
FALSE, FALSE, FALSE); FALSE, FALSE, FALSE);
else else
rte = refnameRangeTableEntry(pstate, relname); rte = refnameRangeTableEntry(pstate, relname);
...@@ -94,40 +93,52 @@ setTargetTable(ParseState *pstate, char *relname) ...@@ -94,40 +93,52 @@ setTargetTable(ParseState *pstate, char *relname)
/* will close relation later, see analyze.c */ /* 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 * Node *
transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr) mergeInnerJoinQuals(ParseState *pstate, Node *clause);
Node *
mergeInnerJoinQuals(ParseState *pstate, Node *clause)
{ {
A_Expr *expr; A_Expr *expr = (A_Expr *) pstate->p_join_quals;
Node *qual;
if ((a_expr == NULL) && (o_expr == NULL)) if (expr == NULL)
return NULL; /* no qualifiers */ return clause;
if ((a_expr != NULL) && (o_expr != NULL)) if (clause != NULL)
{ {
A_Expr *a = makeNode(A_Expr); A_Expr *a = makeNode(A_Expr);
a->oper = AND; a->oper = AND;
a->opname = NULL; a->opname = NULL;
a->lexpr = o_expr; a->lexpr = (Node *) expr;
a->rexpr = a_expr; a->rexpr = clause;
expr = a; expr = a;
} }
else if (o_expr != NULL)
expr = (A_Expr *) o_expr; /* Make sure that we don't do this twice... */
else pstate->p_join_quals = NULL;
expr = (A_Expr *) a_expr;
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; 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; pstate->p_in_where_clause = false;
if (exprType(qual) != BOOLOID) if (exprType(qual) != BOOLOID)
...@@ -138,98 +149,259 @@ transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr) ...@@ -138,98 +149,259 @@ transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr)
return qual; return qual;
} }
#ifdef ENABLE_OUTER_JOINS #ifndef DISABLE_JOIN_SYNTAX
static Attr * char *
makeAttr(char *relname, char *attname) 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; Assert(IsA(val, String));
a->paramNo = NULL;
a->attrs = lcons(makeString(attname), NIL);
a->indirection = NULL;
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() /* transformUsingClause()
* Take an ON or USING clause from a join expression and expand if necessary. * Take an ON or USING clause from a join expression and expand if necessary.
*/ */
static Node * static Node *
transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname) transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *rightList)
{ {
A_Expr *expr = NULL; A_Expr *expr = NULL;
List *on; List *using;
Node *qual;
foreach(on, onList) foreach(using, usingList)
{ {
qual = lfirst(on); List *col;
A_Expr *e;
/* Attr *uattr = lfirst(using);
* Ident node means it is just a column name from a real USING Attr *lattr = NULL, *rattr = NULL;
* clause...
/* 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 *attr = lfirst(col);
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;
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; if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
a->opname = NULL; {
a->lexpr = (Node *) expr; rattr = attr;
a->rexpr = (Node *) e; break;
expr = a;
} }
else
expr = e;
} }
/* otherwise, we have an expression from an ON clause... */ Assert((lattr != NULL) && (rattr != NULL));
else
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->oper = AND;
a->opname = NULL; a->opname = NULL;
a->lexpr = (Node *) expr; a->lexpr = (Node *) expr;
a->rexpr = (Node *) qual; a->rexpr = (Node *) e;
expr = a; expr = a;
}
else
expr = (A_Expr *) qual;
} }
else
expr = e;
} }
return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
}
return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
} /* transformUsiongClause() */
#endif #endif
static char *
RangeTblEntry *
transformTableEntry(ParseState *pstate, RangeVar *r) transformTableEntry(ParseState *pstate, RangeVar *r)
{ {
RelExpr *baserel = r->relExpr; RelExpr *baserel = r->relExpr;
char *relname = baserel->relname; char *relname = baserel->relname;
char *refname = r->name; #if 0
char *refname;
List *columns;
#endif
RangeTblEntry *rte; 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; 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, * marks this entry to indicate it comes from the FROM clause. In SQL,
...@@ -242,11 +414,12 @@ transformTableEntry(ParseState *pstate, RangeVar *r) ...@@ -242,11 +414,12 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
* we expand * to foo.x. * we expand * to foo.x.
*/ */
rte = addRangeTableEntry(pstate, relname, refname, rte = addRangeTableEntry(pstate, relname, r->name,
baserel->inh, TRUE, TRUE); baserel->inh, TRUE, TRUE);
return refname; return rte;
} } /* transformTableEntry() */
/* /*
* parseFromClause - * parseFromClause -
...@@ -263,12 +436,13 @@ transformTableEntry(ParseState *pstate, RangeVar *r) ...@@ -263,12 +436,13 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
* - thomas 1998-12-16 * - thomas 1998-12-16
*/ */
static void 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) List *fl;
*qual = NULL;
foreach(fl, frmList) foreach(fl, frmList)
{ {
...@@ -285,60 +459,258 @@ parseFromClause(ParseState *pstate, List *frmList, Node **qual) ...@@ -285,60 +459,258 @@ parseFromClause(ParseState *pstate, List *frmList, Node **qual)
* eg. select * from foo f where f.x = 1; will generate wrong answer * eg. select * from foo f where f.x = 1; will generate wrong answer
* if we expand * to foo.x. * if we expand * to foo.x.
*/ */
/* Plain vanilla inner join, just like we've always had? */
if (IsA(n, RangeVar)) if (IsA(n, RangeVar))
{
transformTableEntry(pstate, (RangeVar *) n); transformTableEntry(pstate, (RangeVar *) n);
}
/* A newfangled join expression? */
else if (IsA(n, JoinExpr)) 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 if (j->alias != NULL)
char *lname = transformTableEntry(pstate, (RangeVar *) j->larg); elog(ERROR, "JOIN table aliases are not supported");
#endif /* nested join? then handle the left one first... */
char *rname; 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)) if (IsA(j->rarg, JoinExpr))
rname = transformTableEntry(pstate, (RangeVar *) j->rarg); {
// elog(ERROR, "Nested JOINs are not yet supported");
parseFromClause(pstate, lcons(j->rarg, NIL));
l_name = ((JoinExpr *)j->larg)->alias;
}
else 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) 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 * This is an inner join, so rip apart the join node and
* transform into a traditional FROM list. NATURAL JOIN * 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 * Need to generate a list of result columns to use for
* target list expansion and validation. Not doing this * target list expansion and validation.
* yet though!
*/ */
if (IsA(j->quals, List)) else if (IsA(j->quals, List))
j->quals = lcons(transformUsingClause(pstate, (List *) j->quals, lname, rname), NIL); {
/*
* 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) if (qual == NULL)
elog(ERROR, "JOIN/ON not supported in this context"); elog(ERROR, "JOIN/ON not supported in this context");
printf("Table aliases are %s\n", nodeToString(*aliasList));
#endif
#if 0
if (*qual == NULL) 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 else
{
elog(ERROR, "Multiple JOIN/ON clauses not handled (internal error)"); 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, * if we are transforming this node back into a FROM list,
* then we will need to replace the node with two nodes. * then we will need to replace the node with two nodes.
* Will need access to the previous list item to change * Will need access to the previous list item to change
* the link pointer to reference these new nodes. Try * the link pointer to reference these new nodes. Try
* accumulating and returning a new list. - thomas * accumulating and returning a new list.
* 1999-01-08 Not doing this yet though! * - thomas 1999-01-08 Not doing this yet though!
*/ */
} }
else if ((j->jointype == LEFT) else if ((j->jointype == LEFT)
|| (j->jointype == RIGHT) || (j->jointype == RIGHT)
|| (j->jointype == FULL)) || (j->jointype == FULL))
elog(ERROR, "OUTER JOIN is not implemented"); elog(ERROR, "OUTER JOIN is not yet supported");
else else
elog(ERROR, "Unrecognized JOIN clause; tag is %d (internal error)", elog(ERROR, "Unrecognized JOIN clause; tag is %d (internal error)",
j->jointype); j->jointype);
...@@ -350,7 +722,7 @@ parseFromClause(ParseState *pstate, List *frmList, Node **qual) ...@@ -350,7 +722,7 @@ parseFromClause(ParseState *pstate, List *frmList, Node **qual)
elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)" elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)"
"\n\t%s", nodeToString(n)); "\n\t%s", nodeToString(n));
} }
} } /* parseFromClause() */
/* /*
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -144,12 +144,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -144,12 +144,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
Node *rexpr = transformExpr(pstate, a->rexpr, precedence); Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
if (exprType(lexpr) != BOOLOID) if (exprType(lexpr) != BOOLOID)
elog(ERROR, "left-hand side of AND is type '%s', not bool", elog(ERROR, "left-hand side of AND is type '%s', not '%s'",
typeidTypeName(exprType(lexpr))); typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID));
if (exprType(rexpr) != BOOLOID) if (exprType(rexpr) != BOOLOID)
elog(ERROR, "right-hand side of AND is type '%s', not bool", elog(ERROR, "right-hand side of AND is type '%s', not '%s'",
typeidTypeName(exprType(rexpr))); typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
expr->typeOid = BOOLOID; expr->typeOid = BOOLOID;
expr->opType = AND_EXPR; expr->opType = AND_EXPR;
...@@ -164,11 +164,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -164,11 +164,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
Node *rexpr = transformExpr(pstate, a->rexpr, precedence); Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
if (exprType(lexpr) != BOOLOID) if (exprType(lexpr) != BOOLOID)
elog(ERROR, "left-hand side of OR is type '%s', not bool", elog(ERROR, "left-hand side of OR is type '%s', not '%s'",
typeidTypeName(exprType(lexpr))); typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID));
if (exprType(rexpr) != BOOLOID) if (exprType(rexpr) != BOOLOID)
elog(ERROR, "right-hand side of OR is type '%s', not bool", elog(ERROR, "right-hand side of OR is type '%s', not '%s'",
typeidTypeName(exprType(rexpr))); typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
expr->typeOid = BOOLOID; expr->typeOid = BOOLOID;
expr->opType = OR_EXPR; expr->opType = OR_EXPR;
expr->args = makeList(lexpr, rexpr, -1); expr->args = makeList(lexpr, rexpr, -1);
...@@ -181,8 +181,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -181,8 +181,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
Node *rexpr = transformExpr(pstate, a->rexpr, precedence); Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
if (exprType(rexpr) != BOOLOID) if (exprType(rexpr) != BOOLOID)
elog(ERROR, "argument to NOT is type '%s', not bool", elog(ERROR, "argument to NOT is type '%s', not '%s'",
typeidTypeName(exprType(rexpr))); typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
expr->typeOid = BOOLOID; expr->typeOid = BOOLOID;
expr->opType = NOT_EXPR; expr->opType = NOT_EXPR;
expr->args = makeList(rexpr, -1); expr->args = makeList(rexpr, -1);
...@@ -223,11 +223,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -223,11 +223,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
pstate->p_hasSubLinks = true; pstate->p_hasSubLinks = true;
qtrees = parse_analyze(lcons(sublink->subselect, NIL), pstate); qtrees = parse_analyze(lcons(sublink->subselect, NIL), pstate);
if (length(qtrees) != 1) if (length(qtrees) != 1)
elog(ERROR, "parser: bad query in subselect"); elog(ERROR, "Bad query in subselect");
qtree = (Query *) lfirst(qtrees); qtree = (Query *) lfirst(qtrees);
if (qtree->commandType != CMD_SELECT || if (qtree->commandType != CMD_SELECT ||
qtree->resultRelation != 0) qtree->resultRelation != 0)
elog(ERROR, "parser: bad query in subselect"); elog(ERROR, "Bad query in subselect");
sublink->subselect = (Node *) qtree; sublink->subselect = (Node *) qtree;
if (sublink->subLinkType == EXISTS_SUBLINK) if (sublink->subLinkType == EXISTS_SUBLINK)
...@@ -247,11 +247,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -247,11 +247,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
*/ */
if (tlist == NIL || if (tlist == NIL ||
((TargetEntry *) lfirst(tlist))->resdom->resjunk) ((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) while ((tlist = lnext(tlist)) != NIL)
{ {
if (! ((TargetEntry *) lfirst(tlist))->resdom->resjunk) 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. /* EXPR needs no lefthand or combining operator.
* These fields should be NIL already, but make sure. * These fields should be NIL already, but make sure.
...@@ -274,7 +274,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -274,7 +274,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
/* Combining operators other than =/<> is dubious... */ /* Combining operators other than =/<> is dubious... */
if (length(left_list) != 1 && if (length(left_list) != 1 &&
strcmp(op, "=") != 0 && strcmp(op, "<>") != 0) strcmp(op, "=") != 0 && strcmp(op, "<>") != 0)
elog(ERROR, "parser: '%s' is not usable for row comparison", elog(ERROR, "Row comparison cannot use '%s'",
op); op);
sublink->oper = NIL; sublink->oper = NIL;
...@@ -297,7 +297,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -297,7 +297,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
continue; continue;
if (left_list == NIL) if (left_list == NIL)
elog(ERROR, "parser: Subselect has too many fields."); elog(ERROR, "Subselect has too many fields");
lexpr = lfirst(left_list); lexpr = lfirst(left_list);
left_list = lnext(left_list); left_list = lnext(left_list);
...@@ -308,7 +308,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -308,7 +308,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
opform = (Form_pg_operator) GETSTRUCT(optup); opform = (Form_pg_operator) GETSTRUCT(optup);
if (opform->oprresult != BOOLOID) 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 */ newop = makeOper(oprid(optup),/* opno */
InvalidOid, /* opid */ InvalidOid, /* opid */
...@@ -318,7 +321,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -318,7 +321,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
sublink->oper = lappend(sublink->oper, newop); sublink->oper = lappend(sublink->oper, newop);
} }
if (left_list != NIL) if (left_list != NIL)
elog(ERROR, "parser: Subselect has too few fields."); elog(ERROR, "Subselect has too few fields");
} }
result = (Node *) expr; result = (Node *) expr;
break; break;
...@@ -430,7 +433,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -430,7 +433,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
} }
else else
{ {
elog(ERROR, "CASE/ELSE unable to convert to type %s", elog(ERROR, "CASE/ELSE unable to convert to type '%s'",
typeidTypeName(ptype)); typeidTypeName(ptype));
} }
} }
...@@ -457,7 +460,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -457,7 +460,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
} }
else else
{ {
elog(ERROR, "CASE/WHEN unable to convert to type %s", elog(ERROR, "CASE/WHEN unable to convert to type '%s'",
typeidTypeName(ptype)); typeidTypeName(ptype));
} }
} }
...@@ -519,8 +522,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence) ...@@ -519,8 +522,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
} }
default: default:
/* should not reach here */ /* should not reach here */
elog(ERROR, "transformExpr: does not know how to transform node %d", elog(ERROR, "transformExpr: does not know how to transform node %d"
nodeTag(expr)); " (internal error)", nodeTag(expr));
break; break;
} }
...@@ -566,18 +569,22 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence) ...@@ -566,18 +569,22 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL) if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
{ {
/* Convert it to a fully qualified Attr, and transform that */ /* 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); Attr *att = makeNode(Attr);
att->relname = rte->refname; att->relname = rte->refname;
att->paramNo = NULL; att->paramNo = NULL;
att->attrs = lcons(makeString(ident->name), NIL); att->attrs = lcons(makeString(ident->name), NIL);
#endif
att->indirection = ident->indirection; att->indirection = ident->indirection;
return transformAttr(pstate, att, precedence); return transformAttr(pstate, att, precedence);
} }
} }
if (result == NULL) if (result == NULL)
elog(ERROR, "attribute '%s' not found", ident->name); elog(ERROR, "Attribute '%s' not found", ident->name);
return result; return result;
} }
...@@ -631,7 +638,7 @@ exprType(Node *expr) ...@@ -631,7 +638,7 @@ exprType(Node *expr)
TargetEntry *tent; TargetEntry *tent;
if (! qtree || ! IsA(qtree, Query)) 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); tent = (TargetEntry *) lfirst(qtree->targetList);
type = tent->resdom->restype; type = tent->resdom->restype;
} }
...@@ -653,7 +660,7 @@ exprType(Node *expr) ...@@ -653,7 +660,7 @@ exprType(Node *expr)
type = UNKNOWNOID; type = UNKNOWNOID;
break; break;
default: 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)); nodeTag(expr));
break; break;
} }
...@@ -728,7 +735,7 @@ parser_typecast_constant(Value *expr, TypeName *typename) ...@@ -728,7 +735,7 @@ parser_typecast_constant(Value *expr, TypeName *typename)
break; break;
default: default:
elog(ERROR, elog(ERROR,
"parser_typecast_constant: cannot cast this expression to type '%s'", "Cannot cast this expression to type '%s'",
typename->name); typename->name);
} }
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -283,6 +283,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -283,6 +283,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel) if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
{ {
RangeTblEntry *rte; RangeTblEntry *rte;
AttrNumber attnum;
Ident *ident = (Ident *) first_arg; Ident *ident = (Ident *) first_arg;
/* /*
...@@ -293,7 +294,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -293,7 +294,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
rte = refnameRangeTableEntry(pstate, refname); rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL) if (rte == NULL)
{ {
rte = addRangeTableEntry(pstate, refname, refname, rte = addRangeTableEntry(pstate, refname,
makeAttr(refname, NULL),
FALSE, FALSE, TRUE); FALSE, FALSE, TRUE);
#ifdef WARN_FROM #ifdef WARN_FROM
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s", elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
...@@ -304,12 +306,53 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -304,12 +306,53 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
relname = rte->relname; relname = rte->relname;
relid = rte->relid; relid = rte->relid;
attnum = InvalidAttrNumber;
/* /*
* If the attr isn't a set, just make a var for it. If it is * 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. * 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, return (Node *) make_var(pstate,
relid, relid,
...@@ -474,7 +517,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -474,7 +517,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
rte = refnameRangeTableEntry(pstate, refname); rte = refnameRangeTableEntry(pstate, refname);
if (rte == NULL) if (rte == NULL)
{ {
rte = addRangeTableEntry(pstate, refname, refname, rte = addRangeTableEntry(pstate, refname,
makeAttr(refname, NULL),
FALSE, FALSE, TRUE); FALSE, FALSE, TRUE);
#ifdef WARN_FROM #ifdef WARN_FROM
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s", elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
...@@ -485,7 +529,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -485,7 +529,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
relname = rte->relname; 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 * for func(relname), the param to the function is the tuple
...@@ -593,7 +637,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs, ...@@ -593,7 +637,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
if (attisset) if (attisset)
{ {
if (!strcmp(funcname, "*")) if (!strcmp(funcname, "*"))
funcnode->func_tlist = expandAll(pstate, relname, refname, curr_resno); funcnode->func_tlist = expandAll(pstate, relname,
makeAttr(refname, NULL),
curr_resno);
else else
{ {
funcnode->func_tlist = setup_tlist(funcname, argrelid); funcnode->func_tlist = setup_tlist(funcname, argrelid);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -65,6 +65,39 @@ static char *attnum_type[SPECIALS] = { ...@@ -65,6 +65,39 @@ static char *attnum_type[SPECIALS] = {
"cid", "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 */ /* given refname, return a pointer to the range table entry */
RangeTblEntry * RangeTblEntry *
refnameRangeTableEntry(ParseState *pstate, char *refname) refnameRangeTableEntry(ParseState *pstate, char *refname)
...@@ -77,7 +110,11 @@ refnameRangeTableEntry(ParseState *pstate, char *refname) ...@@ -77,7 +110,11 @@ refnameRangeTableEntry(ParseState *pstate, char *refname)
{ {
RangeTblEntry *rte = lfirst(temp); RangeTblEntry *rte = lfirst(temp);
#ifndef DISABLE_JOIN_SYNTAX
if (strcmp(rte->ref->relname, refname) == 0)
#else
if (!strcmp(rte->refname, refname)) if (!strcmp(rte->refname, refname))
#endif
return rte; return rte;
} }
/* only allow correlated columns in WHERE clause */ /* only allow correlated columns in WHERE clause */
...@@ -106,7 +143,11 @@ refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up) ...@@ -106,7 +143,11 @@ refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up)
{ {
RangeTblEntry *rte = lfirst(temp); RangeTblEntry *rte = lfirst(temp);
#ifndef DISABLE_JOIN_SYNTAX
if (strcmp(rte->ref->relname, refname) == 0)
#else
if (!strcmp(rte->refname, refname)) if (!strcmp(rte->refname, refname))
#endif
return index; return index;
index++; index++;
} }
...@@ -143,24 +184,52 @@ colnameRangeTableEntry(ParseState *pstate, char *colname) ...@@ -143,24 +184,52 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
foreach(et, rtable) foreach(et, rtable)
{ {
RangeTblEntry *rte_candidate = NULL;
RangeTblEntry *rte = lfirst(et); RangeTblEntry *rte = lfirst(et);
/* only consider RTEs mentioned in FROM or UPDATE/DELETE */ /* only consider RTEs mentioned in FROM or UPDATE/DELETE */
if (!rte->inFromCl && rte != pstate->p_target_rangetblentry) if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
continue; 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 || if (strcmp(strVal(lfirst(c)), colname) == 0)
rte != pstate->p_target_rangetblentry) {
elog(ERROR, "Column '%s' is ambiguous", colname); 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 */ /* only allow correlated columns in WHERE clause */
if (pstate->p_in_where_clause && rte_result == NULL) if (pstate->p_in_where_clause && rte_result == NULL)
pstate = pstate->parentParseState; pstate = pstate->parentParseState;
...@@ -177,45 +246,65 @@ colnameRangeTableEntry(ParseState *pstate, char *colname) ...@@ -177,45 +246,65 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
RangeTblEntry * RangeTblEntry *
addRangeTableEntry(ParseState *pstate, addRangeTableEntry(ParseState *pstate,
char *relname, char *relname,
char *refname, Attr *ref,
bool inh, bool inh,
bool inFromCl, bool inFromCl,
bool inJoinSet) bool inJoinSet)
{ {
Relation relation; Relation rel;
RangeTblEntry *rte; RangeTblEntry *rte;
int sublevels_up; int maxattrs;
int sublevels_up;
int varattno;
/* Look for an existing rte, if available... */
if (pstate != NULL) if (pstate != NULL)
{ {
int rt_index = refnameRangeTablePosn(pstate, refname, int rt_index = refnameRangeTablePosn(pstate, ref->relname,
&sublevels_up); &sublevels_up);
if (rt_index != 0 && (!inFromCl || sublevels_up == 0)) 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); 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 = makeNode(RangeTblEntry);
rte->relname = pstrdup(relname); rte->relname = relname;
rte->refname = pstrdup(refname); rte->ref = ref;
/* Get the rel's OID. This access also ensures that we have an /* 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 * up-to-date relcache entry for the rel. We don't need to keep
* it open, however. * 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); rel = heap_openr(relname, AccessShareLock);
rte->relid = RelationGetRelid(relation); rte->relid = RelationGetRelid(rel);
heap_close(relation, AccessShareLock); 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, * Flags:
* this RTE is in the FROM clause, this RTE should be included in * - this RTE should be expanded to include descendant tables,
* the planner's final join. * - this RTE is in the FROM clause,
* - this RTE should be included in the planner's final join.
*/ */
rte->inh = inh; rte->inh = inh;
rte->inFromCl = inFromCl; rte->inFromCl = inFromCl;
...@@ -231,23 +320,71 @@ addRangeTableEntry(ParseState *pstate, ...@@ -231,23 +320,71 @@ addRangeTableEntry(ParseState *pstate,
return rte; 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 - * expandAll -
* makes a list of attributes * makes a list of attributes
*/ */
List * 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; List *te_list = NIL;
RangeTblEntry *rte; RangeTblEntry *rte;
Relation rel; Relation rel;
int varattno, int varattno,
maxattrs; maxattrs;
rte = refnameRangeTableEntry(pstate, refname); rte = refnameRangeTableEntry(pstate, ref->relname);
if (rte == NULL) if (rte == NULL)
{ {
rte = addRangeTableEntry(pstate, relname, refname, rte = addRangeTableEntry(pstate, relname, ref,
FALSE, FALSE, TRUE); FALSE, FALSE, TRUE);
#ifdef WARN_FROM #ifdef WARN_FROM
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s", elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
...@@ -262,12 +399,19 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno) ...@@ -262,12 +399,19 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
for (varattno = 0; varattno < maxattrs; varattno++) for (varattno = 0; varattno < maxattrs; varattno++)
{ {
char *attrname; char *attrname;
Var *varnode; char *label;
TargetEntry *te = makeNode(TargetEntry); Var *varnode;
TargetEntry *te = makeNode(TargetEntry);
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname)); 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 * Even if the elements making up a set are complex, the set
...@@ -277,7 +421,7 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno) ...@@ -277,7 +421,7 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
te->resdom = makeResdom((AttrNumber) (*this_resno)++, te->resdom = makeResdom((AttrNumber) (*this_resno)++,
varnode->vartype, varnode->vartype,
varnode->vartypmod, varnode->vartypmod,
attrname, label,
(Index) 0, (Index) 0,
(Oid) 0, (Oid) 0,
false); false);
...@@ -306,16 +450,32 @@ attnameAttNum(Relation rd, char *a) ...@@ -306,16 +450,32 @@ attnameAttNum(Relation rd, char *a)
if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
return i + 1; return i + 1;
for (i = 0; i < SPECIALS; i++) if ((i = specialAttNum(a)) != InvalidAttrNumber)
if (!strcmp(special_attr[i].field, a)) return i;
return special_attr[i].code;
/* on failure */ /* on failure */
elog(ERROR, "Relation '%s' does not have attribute '%s'", elog(ERROR, "Relation '%s' does not have attribute '%s'",
RelationGetRelationName(rd), a); 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 * Given range variable, return whether attribute of this name
* is a set. * is a set.
...@@ -372,3 +532,8 @@ attnumTypeId(Relation rd, int attid) ...@@ -372,3 +532,8 @@ attnumTypeId(Relation rd, int attid)
*/ */
return rd->rd_att->attrs[attid - 1]->atttypid; return rd->rd_att->attrs[attid - 1]->atttypid;
} }
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -105,8 +105,35 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -105,8 +105,35 @@ transformTargetList(ParseState *pstate, List *targetlist)
* Target item is a single '*', expand all tables * Target item is a single '*', expand all tables
* (eg. SELECT * FROM emp) * (eg. SELECT * FROM emp)
*/ */
p_target = nconc(p_target, if (pstate->p_shape != NULL)
ExpandAllTables(pstate)); {
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 && else if (att->attrs != NIL &&
strcmp(strVal(lfirst(att->attrs)), "*") == 0) strcmp(strVal(lfirst(att->attrs)), "*") == 0)
...@@ -116,9 +143,8 @@ transformTargetList(ParseState *pstate, List *targetlist) ...@@ -116,9 +143,8 @@ transformTargetList(ParseState *pstate, List *targetlist)
* (eg. SELECT emp.*, dname FROM emp, dept) * (eg. SELECT emp.*, dname FROM emp, dept)
*/ */
p_target = nconc(p_target, p_target = nconc(p_target,
expandAll(pstate, expandAll(pstate, att->relname,
att->relname, makeAttr(att->relname, NULL),
att->relname,
&pstate->p_last_resno)); &pstate->p_last_resno));
} }
else else
...@@ -192,12 +218,18 @@ updateTargetListEntry(ParseState *pstate, ...@@ -192,12 +218,18 @@ updateTargetListEntry(ParseState *pstate,
*/ */
if (indirection) if (indirection)
{ {
#ifndef DISABLE_JOIN_SYNTAX
Attr *att = makeAttr(pstrdup(RelationGetRelationName(rd)), colname);
#else
Attr *att = makeNode(Attr); Attr *att = makeNode(Attr);
#endif
Node *arrayBase; Node *arrayBase;
ArrayRef *aref; ArrayRef *aref;
#ifdef DISABLE_JOIN_SYNTAX
att->relname = pstrdup(RelationGetRelationName(rd)); att->relname = pstrdup(RelationGetRelationName(rd));
att->attrs = lcons(makeString(colname), NIL); att->attrs = lcons(makeString(colname), NIL);
#endif
arrayBase = ParseNestedFuncOrColumn(pstate, att, arrayBase = ParseNestedFuncOrColumn(pstate, att,
&pstate->p_last_resno, &pstate->p_last_resno,
EXPR_COLUMN_FIRST); EXPR_COLUMN_FIRST);
...@@ -355,10 +387,9 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos) ...@@ -355,10 +387,9 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
return cols; return cols;
} }
/* /* ExpandAllTables()
* ExpandAllTables - * Turns '*' (in the target list) into a list of attributes
* turns '*' (in the target list) into a list of attributes * (of all relations in the range table)
* (of all relations in the range table)
*/ */
static List * static List *
ExpandAllTables(ParseState *pstate) ExpandAllTables(ParseState *pstate)
...@@ -378,7 +409,7 @@ ExpandAllTables(ParseState *pstate) ...@@ -378,7 +409,7 @@ ExpandAllTables(ParseState *pstate)
/* SELECT *; */ /* SELECT *; */
if (rtable == NIL) if (rtable == NIL)
elog(ERROR, "Wildcard with no tables specified."); elog(ERROR, "Wildcard with no tables specified not allowed");
foreach(rt, rtable) foreach(rt, rtable)
{ {
...@@ -393,7 +424,7 @@ ExpandAllTables(ParseState *pstate) ...@@ -393,7 +424,7 @@ ExpandAllTables(ParseState *pstate)
continue; continue;
target = nconc(target, target = nconc(target,
expandAll(pstate, rte->relname, rte->refname, expandAll(pstate, rte->ref->relname, rte->ref,
&pstate->p_last_resno)); &pstate->p_last_resno));
} }
return target; return target;
......
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
* out of its tuple * out of its tuple
* *
* IDENTIFICATION * 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. * This software is copyrighted by Jan Wieck - Hamburg.
* *
...@@ -922,9 +922,9 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -922,9 +922,9 @@ get_select_query_def(Query *query, deparse_context *context)
continue; continue;
rte = (RangeTblEntry *) lfirst(l); rte = (RangeTblEntry *) lfirst(l);
if (!strcmp(rte->refname, "*NEW*")) if (!strcmp(rte->ref->relname, "*NEW*"))
continue; continue;
if (!strcmp(rte->refname, "*CURRENT*")) if (!strcmp(rte->ref->relname, "*CURRENT*"))
continue; continue;
rt_constonly = FALSE; rt_constonly = FALSE;
...@@ -980,10 +980,10 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -980,10 +980,10 @@ get_select_query_def(Query *query, deparse_context *context)
{ {
rte = (RangeTblEntry *) lfirst(l); rte = (RangeTblEntry *) lfirst(l);
if (!strcmp(rte->refname, "*NEW*")) if (!strcmp(rte->ref->relname, "*NEW*"))
continue; continue;
if (!strcmp(rte->refname, "*CURRENT*")) if (!strcmp(rte->ref->relname, "*CURRENT*"))
continue; continue;
appendStringInfo(buf, sep); appendStringInfo(buf, sep);
...@@ -991,9 +991,19 @@ get_select_query_def(Query *query, deparse_context *context) ...@@ -991,9 +991,19 @@ get_select_query_def(Query *query, deparse_context *context)
appendStringInfo(buf, "%s%s", appendStringInfo(buf, "%s%s",
quote_identifier(rte->relname), quote_identifier(rte->relname),
inherit_marker(rte)); inherit_marker(rte));
if (strcmp(rte->relname, rte->refname) != 0) if (strcmp(rte->relname, rte->ref->relname) != 0)
{
List *col;
appendStringInfo(buf, " %s", 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));
}
}
} }
} }
} }
...@@ -1071,9 +1081,9 @@ get_insert_query_def(Query *query, deparse_context *context) ...@@ -1071,9 +1081,9 @@ get_insert_query_def(Query *query, deparse_context *context)
continue; continue;
rte = (RangeTblEntry *) lfirst(l); rte = (RangeTblEntry *) lfirst(l);
if (!strcmp(rte->refname, "*NEW*")) if (!strcmp(rte->ref->relname, "*NEW*"))
continue; continue;
if (!strcmp(rte->refname, "*CURRENT*")) if (!strcmp(rte->ref->relname, "*CURRENT*"))
continue; continue;
rt_constonly = FALSE; rt_constonly = FALSE;
...@@ -1241,13 +1251,13 @@ get_rule_expr(Node *node, deparse_context *context) ...@@ -1241,13 +1251,13 @@ get_rule_expr(Node *node, deparse_context *context)
if (context->varprefix) if (context->varprefix)
{ {
if (!strcmp(rte->refname, "*NEW*")) if (!strcmp(rte->ref->relname, "*NEW*"))
appendStringInfo(buf, "new."); appendStringInfo(buf, "new.");
else if (!strcmp(rte->refname, "*CURRENT*")) else if (!strcmp(rte->ref->relname, "*CURRENT*"))
appendStringInfo(buf, "old."); appendStringInfo(buf, "old.");
else else
appendStringInfo(buf, "%s.", appendStringInfo(buf, "%s.",
quote_identifier(rte->refname)); quote_identifier(rte->ref->relname));
} }
appendStringInfo(buf, "%s", appendStringInfo(buf, "%s",
quote_identifier(get_attribute_name(rte->relid, quote_identifier(get_attribute_name(rte->relid,
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -46,4 +46,7 @@ extern Const *makeConst(Oid consttype, ...@@ -46,4 +46,7 @@ extern Const *makeConst(Oid consttype,
bool constisset, bool constisset,
bool constiscast); bool constiscast);
extern Attr *
makeAttr(char *relname, char *attname);
#endif /* MAKEFUNC_H */ #endif /* MAKEFUNC_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -1031,7 +1031,7 @@ typedef struct RangeVar ...@@ -1031,7 +1031,7 @@ typedef struct RangeVar
{ {
NodeTag type; NodeTag type;
RelExpr *relExpr; /* the relation expression */ RelExpr *relExpr; /* the relation expression */
char *name; /* the name to be referenced (optional) */ Attr *name; /* the name to be referenced (optional) */
} RangeVar; } RangeVar;
/* /*
...@@ -1064,9 +1064,11 @@ typedef struct JoinExpr ...@@ -1064,9 +1064,11 @@ typedef struct JoinExpr
{ {
NodeTag type; NodeTag type;
int jointype; int jointype;
RangeVar *larg; bool isNatural; /* Natural join? Will need to shape table */
Node *rarg; Node *larg; /* RangeVar or join expression */
List *quals; Node *rarg; /* RangeVar or join expression */
Attr *alias; /* table and column aliases, if any */
List *quals; /* qualifiers on join, if any */
} JoinExpr; } JoinExpr;
...@@ -1122,8 +1124,10 @@ typedef struct RangeTblEntry ...@@ -1122,8 +1124,10 @@ typedef struct RangeTblEntry
{ {
NodeTag type; NodeTag type;
char *relname; /* real name of the relation */ char *relname; /* real name of the relation */
char *refname; /* the reference name (as specified in the // char *refname; /* reference name (given in FROM clause) */
* FROM clause) */ #ifndef DISABLE_JOIN_SYNTAX
Attr *ref; /* reference names (given in FROM clause) */
#endif
Oid relid; /* OID of the relation */ Oid relid; /* OID of the relation */
bool inh; /* inheritance requested? */ bool inh; /* inheritance requested? */
bool inFromCl; /* present in FROM clause */ bool inFromCl; /* present in FROM clause */
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,10 +16,9 @@ ...@@ -16,10 +16,9 @@
#include "parser/parse_node.h" #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 void setTargetTable(ParseState *pstate, char *relname);
extern Node *transformWhereClause(ParseState *pstate, Node *where, extern Node *transformWhereClause(ParseState *pstate, Node *where);
Node *using);
extern List *transformGroupClause(ParseState *pstate, List *grouplist, extern List *transformGroupClause(ParseState *pstate, List *grouplist,
List *targetlist); List *targetlist);
extern List *transformSortClause(ParseState *pstate, List *orderlist, extern List *transformSortClause(ParseState *pstate, List *orderlist,
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -16,7 +16,11 @@ ...@@ -16,7 +16,11 @@
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "utils/rel.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 typedef struct ParseState
{ {
int p_last_resno; int p_last_resno;
...@@ -30,6 +34,9 @@ typedef struct ParseState ...@@ -30,6 +34,9 @@ typedef struct ParseState
bool p_in_where_clause; bool p_in_where_clause;
Relation p_target_relation; Relation p_target_relation;
RangeTblEntry *p_target_rangetblentry; RangeTblEntry *p_target_rangetblentry;
List *p_shape;
List *p_alias;
Node *p_join_quals;
} ParseState; } ParseState;
extern ParseState *make_parsestate(ParseState *parentParseState); extern ParseState *make_parsestate(ParseState *parentParseState);
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -18,17 +18,20 @@ ...@@ -18,17 +18,20 @@
extern RangeTblEntry *refnameRangeTableEntry(ParseState *pstate, char *refname); extern RangeTblEntry *refnameRangeTableEntry(ParseState *pstate, char *refname);
extern int refnameRangeTablePosn(ParseState *pstate, extern int refnameRangeTablePosn(ParseState *pstate,
char *refname, int *sublevels_up); char *refname,
int *sublevels_up);
extern RangeTblEntry *colnameRangeTableEntry(ParseState *pstate, char *colname); extern RangeTblEntry *colnameRangeTableEntry(ParseState *pstate, char *colname);
extern RangeTblEntry *addRangeTableEntry(ParseState *pstate, extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
char *relname, char *relname,
char *refname, Attr *ref,
bool inh, bool inh,
bool inFromCl, bool inFromCl,
bool inJoinSet); bool inJoinSet);
extern List *expandAll(ParseState *pstate, char *relname, char *refname, extern Attr *expandTable(ParseState *pstate, char *refname, bool getaliases);
int *this_resno); extern List *expandAll(ParseState *pstate, char *relname, Attr *ref,
int *this_resno);
extern int attnameAttNum(Relation rd, char *a); extern int attnameAttNum(Relation rd, char *a);
extern int specialAttNum(char *a);
extern bool attnameIsSet(Relation rd, char *name); extern bool attnameIsSet(Relation rd, char *name);
extern int attnumAttNelems(Relation rd, int attid); extern int attnumAttNelems(Relation rd, int attid);
extern Oid attnumTypeId(Relation rd, int attid); extern Oid attnumTypeId(Relation rd, int attid);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* Portions Copyright (c) 1996-2000, PostgreSQL, Inc * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
* Portions Copyright (c) 1994, Regents of the University of California * 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 $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -39,8 +39,8 @@ ...@@ -39,8 +39,8 @@
*/ */
#define rt_relname(rt_entry) \ #define rt_relname(rt_entry) \
((!strcmp(((rt_entry)->refname),"*CURRENT*") ||\ ((!strcmp(((rt_entry)->ref->relname),"*CURRENT*") ||\
!strcmp(((rt_entry)->refname),"*NEW*")) ? ((rt_entry)->refname) : \ !strcmp(((rt_entry)->ref->relname),"*NEW*")) ? ((rt_entry)->ref->relname) : \
((char *)(rt_entry)->relname)) ((char *)(rt_entry)->relname))
/* /*
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment