OSDN Git Service

Carry column aliases from the parser frontend. Enables queries like
authorThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 15 Feb 2000 03:38:29 +0000 (03:38 +0000)
committerThomas G. Lockhart <lockhart@fourpalms.org>
Tue, 15 Feb 2000 03:38:29 +0000 (03:38 +0000)
  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.

27 files changed:
src/backend/catalog/heap.c
src/backend/commands/explain.c
src/backend/commands/view.c
src/backend/executor/execMain.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/freefuncs.c
src/backend/nodes/makefuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/print.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/prep/prepunion.c
src/backend/optimizer/util/clauses.c
src/backend/parser/analyze.c
src/backend/parser/parse_agg.c
src/backend/parser/parse_clause.c
src/backend/parser/parse_expr.c
src/backend/parser/parse_func.c
src/backend/parser/parse_relation.c
src/backend/parser/parse_target.c
src/backend/utils/adt/ruleutils.c
src/include/nodes/makefuncs.h
src/include/nodes/parsenodes.h
src/include/parser/parse_clause.h
src/include/parser/parse_node.h
src/include/parser/parse_relation.h
src/include/parser/parsetree.h

index 89c20ce..2840e40 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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
@@ -53,6 +53,7 @@
 #include "optimizer/planmain.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
+#include "nodes/makefuncs.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_expr.h"
 #include "parser/parse_relation.h"
@@ -1719,7 +1720,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum, char *adbin,
         */
        rte = makeNode(RangeTblEntry);
        rte->relname = RelationGetRelationName(rel);
-       rte->refname = RelationGetRelationName(rel);
+       rte->ref = makeNode(Attr);
+       rte->ref->relname = RelationGetRelationName(rel);
        rte->relid = RelationGetRelid(rel);
        rte->inh = false;
        rte->inFromCl = true;
@@ -1798,7 +1800,8 @@ StoreRelCheck(Relation rel, char *ccname, char *ccbin)
         */
        rte = makeNode(RangeTblEntry);
        rte->relname = RelationGetRelationName(rel);
-       rte->refname = RelationGetRelationName(rel);
+       rte->ref = makeNode(Attr);
+       rte->ref->relname = RelationGetRelationName(rel);
        rte->relid = RelationGetRelid(rel);
        rte->inh = false;
        rte->inFromCl = true;
@@ -1919,8 +1922,8 @@ AddRelationRawConstraints(Relation rel,
         * its sole rangetable entry.  We need a ParseState for transformExpr.
         */
        pstate = make_parsestate(NULL);
-       makeRangeTable(pstate, NULL, NULL);
-       addRangeTableEntry(pstate, relname, relname, false, true, true);
+       makeRangeTable(pstate, NULL);
+       addRangeTableEntry(pstate, relname, makeAttr(relname, NULL), false, true, true);
 
        /*
         * Process column default expressions.
index 8406416..2b152b2 100644 (file)
@@ -5,7 +5,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
- *       $Id: explain.c,v 1.52 2000/01/26 05:56:13 momjian Exp $
+ *       $Id: explain.c,v 1.53 2000/02/15 03:36:39 thomas Exp $
  *
  */
 
@@ -230,12 +230,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
                                RangeTblEntry *rte = nth(((Scan *) plan)->scanrelid - 1, es->rtable);
 
                                appendStringInfo(str, " on ");
-                               if (strcmp(rte->refname, rte->relname) != 0)
+                               if (strcmp(rte->ref->relname, rte->relname) != 0)
                                {
                                        appendStringInfo(str, "%s ",
                                                                         stringStringInfo(rte->relname));
                                }
-                               appendStringInfo(str, stringStringInfo(rte->refname));
+                               appendStringInfo(str, stringStringInfo(rte->ref->relname));
                        }
                        break;
                case T_TidScan:
@@ -244,12 +244,12 @@ explain_outNode(StringInfo str, Plan *plan, int indent, ExplainState *es)
                                RangeTblEntry *rte = nth(((TidScan *) plan)->scan.scanrelid - 1, es->rtable);
 
                                appendStringInfo(str, " on ");
-                               if (strcmp(rte->refname, rte->relname) != 0)
+                               if (strcmp(rte->ref->relname, rte->relname) != 0)
                                {
                                        appendStringInfo(str, "%s ",
                                                                         stringStringInfo(rte->relname));
                                }
-                               appendStringInfo(str, stringStringInfo(rte->refname));
+                               appendStringInfo(str, stringStringInfo(rte->ref->relname));
                        }
                        break;
                default:
index 8742b89..f4bb187 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: view.c,v 1.41 2000/01/26 05:56:14 momjian Exp $
+ *     $Id: view.c,v 1.42 2000/02/15 03:36:39 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -17,6 +17,7 @@
 #include "catalog/heap.h"
 #include "commands/creatinh.h"
 #include "commands/view.h"
+#include "nodes/makefuncs.h"
 #include "parser/parse_relation.h"
 #include "parser/parse_type.h"
 #include "rewrite/rewriteDefine.h"
@@ -225,9 +226,11 @@ UpdateRangeTableOfViewParse(char *viewName, Query *viewParse)
         * create the 2 new range table entries and form the new range
         * table... CURRENT first, then NEW....
         */
-       rt_entry1 = addRangeTableEntry(NULL, (char *) viewName, "*CURRENT*",
+       rt_entry1 = addRangeTableEntry(NULL, (char *) viewName,
+                                                                  makeAttr("*CURRENT*", NULL),
                                                                   FALSE, FALSE, FALSE);
-       rt_entry2 = addRangeTableEntry(NULL, (char *) viewName, "*NEW*",
+       rt_entry2 = addRangeTableEntry(NULL, (char *) viewName,
+                                                                  makeAttr("*NEW*", NULL),
                                                                   FALSE, FALSE, FALSE);
        new_rt = lcons(rt_entry2, old_rt);
        new_rt = lcons(rt_entry1, new_rt);
index 899885d..e3d1862 100644 (file)
@@ -27,7 +27,7 @@
  *
  *
  * 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)
        slot->ttc_buffer = InvalidBuffer;
        slot->ttc_whichplan = -1;
        rte->relname = RelationGetRelationName(rel);
-       rte->refname = rte->relname;
+       rte->ref = makeNode(Attr);
+       rte->ref->relname = rte->relname;
        rte->relid = RelationGetRelid(rel);
        /* inh, inFromCl, inJoinSet, skipAcl won't be used, leave them zero */
        rtlist = lcons(rte, NIL);
index c5c9cb0..adf0c7f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
        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
  * ----------------
@@ -1327,8 +1339,8 @@ _copyRangeTblEntry(RangeTblEntry *from)
 
        if (from->relname)
                newnode->relname = pstrdup(from->relname);
-       if (from->refname)
-               newnode->refname = pstrdup(from->refname);
+       if (from->ref)
+               Node_Copy(from, newnode, ref);
        newnode->relid = from->relid;
        newnode->inh = from->inh;
        newnode->inFromCl = from->inFromCl;
@@ -1571,6 +1583,9 @@ copyObject(void *from)
                case T_Var:
                        retval = _copyVar(from);
                        break;
+               case T_Attr:
+                       retval = _copyAttr(from);
+                       break;
                case T_Oper:
                        retval = _copyOper(from);
                        break;
index 5888f49..3ddc8d6 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -96,6 +96,17 @@ _equalExpr(Expr *a, Expr *b)
 }
 
 static bool
+_equalAttr(Attr *a, Attr *b)
+{
+       if (!strcmp(a->relname, b->relname))
+               return false;
+       if (length(a->attrs) != length(b->attrs))
+               return false;
+
+       return equal(a->attrs, b->attrs);
+}
+
+static bool
 _equalVar(Var *a, Var *b)
 {
        if (a->varno != b->varno)
@@ -633,14 +644,14 @@ _equalRangeTblEntry(RangeTblEntry *a, RangeTblEntry *b)
                if (a->relname != b->relname)
                        return false;
        }
-       if (a->refname && b->refname)
+       if (a->ref && b->ref)
        {
-               if (strcmp(a->refname, b->refname) != 0)
+               if (! equal(a->ref, b->ref))
                        return false;
        }
        else
        {
-               if (a->refname != b->refname)
+               if (a->ref != b->ref)
                        return false;
        }
        if (a->relid != b->relid)
@@ -845,6 +856,9 @@ equal(void *a, void *b)
                case T_EState:
                        retval = _equalEState(a, b);
                        break;
+               case T_Attr:
+                       retval = _equalAttr(a, b);
+                       break;
                case T_Integer:
                case T_String:
                case T_Float:
index ab308fe..690da02 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
 {
        if (node->relname)
                pfree(node->relname);
-       if (node->refname)
-               pfree(node->refname);
+       if (node->ref)
+               freeObject(node->ref);
+
+       pfree(node);
+}
+
+static void
+_freeAttr(Attr *node)
+{
+       if (node->relname)
+               pfree(node->relname);
+       if (node->attrs)
+               freeObject(node->attrs);
 
        pfree(node);
 }
@@ -1308,6 +1319,9 @@ freeObject(void *node)
                case T_TypeCast:
                        _freeTypeCast(node);
                        break;
+               case T_Attr:
+                       _freeAttr(node);
+                       break;
 
                        /*
                         * VALUE NODES
@@ -1332,3 +1346,10 @@ freeObject(void *node)
                        break;
        }
 }
+
+
+
+
+
+
+
index 221a83d..e42930e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.19 2000/01/26 05:56:31 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/makefuncs.c,v 1.20 2000/02/15 03:37:09 thomas Exp $
  *
  * NOTES
  *       Creator functions in POSTGRES 4.2 are generated automatically. Most of
@@ -141,3 +141,26 @@ makeConst(Oid consttype,
        cnst->constiscast = constiscast;
        return cnst;
 }
+
+/*
+ * makeAttr -
+ *       creates an Attr node
+ */
+Attr *
+makeAttr(char *relname, char *attname)
+{
+       Attr       *a = makeNode(Attr);
+
+       a->relname = pstrdup(relname);
+       a->paramNo = NULL;
+       if (attname != NULL)
+               a->attrs = lcons(makeString(pstrdup(attname)), NIL);
+       a->indirection = NULL;
+
+       return a;
+}
+
+
+
+
+
index 8923510..e4c35cc 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.106 2000/02/07 04:40:57 tgl Exp $
+ *     $Header: /cvsroot/pgsql/src/backend/nodes/outfuncs.c,v 1.107 2000/02/15 03:37:09 thomas Exp $
  *
  * NOTES
  *       Every (plan) node in POSTGRES has an associated "out" routine which
@@ -954,8 +954,8 @@ _outRangeTblEntry(StringInfo str, RangeTblEntry *node)
 {
        appendStringInfo(str, " RTE :relname ");
        _outToken(str, node->relname);
-       appendStringInfo(str, " :refname ");
-       _outToken(str, node->refname);
+       appendStringInfo(str, " :ref ");
+       _outNode(str, node->ref);
        appendStringInfo(str,
                                         " :relid %u :inh %s :inFromCl %s :inJoinSet %s :skipAcl %s",
                                         node->relid,
@@ -1273,18 +1273,10 @@ _outIdent(StringInfo str, Ident *node)
 static void
 _outAttr(StringInfo str, Attr *node)
 {
-       List       *l;
-
-       appendStringInfo(str, " ATTR ");
+       appendStringInfo(str, " ATTR :relname ");
        _outToken(str, node->relname);
-       appendStringInfo(str, " (");
-       foreach(l, node->attrs)
-       {
-               _outNode(str, lfirst(l));
-               if (lnext(l))
-                       appendStringInfo(str, " ");
-       }
-       appendStringInfo(str, ")");
+       appendStringInfo(str, " :attrs ");
+       _outNode(str, node->attrs);
 }
 
 static void
index ffba959..a84b829 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.35 2000/01/26 05:56:32 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/print.c,v 1.36 2000/02/15 03:37:09 thomas Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -133,7 +133,7 @@ print_rt(List *rtable)
                RangeTblEntry *rte = lfirst(l);
 
                printf("%d\t%s(%s)\t%u\t%d\t%s\n",
-                          i, rte->relname, rte->refname, rte->relid,
+                          i, rte->relname, rte->ref->relname, rte->relid,
                           rte->inFromCl,
                           (rte->inh ? "inh" : ""));
                i++;
@@ -175,8 +175,9 @@ print_expr(Node *expr, List *rtable)
                                {
                                        rt = rt_fetch(var->varno, rtable);
                                        relname = rt->relname;
-                                       if (rt->refname)
-                                               relname = rt->refname;  /* table renamed */
+                                       if (rt->ref)
+                                               if (rt->ref->relname)
+                                               relname = rt->relname;  /* table renamed */
                                        attname = get_attname(rt->relid, var->varattno);
                                }
                                break;
index 38db7de..7d56b60 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.82 2000/02/07 04:40:57 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/nodes/readfuncs.c,v 1.83 2000/02/15 03:37:09 thomas Exp $
  *
  * NOTES
  *       Most of the read functions for plan nodes are tested. (In fact, they
@@ -1322,6 +1322,51 @@ _readTargetEntry()
        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
  * ----------------
@@ -1342,12 +1387,8 @@ _readRangeTblEntry()
        else
                local_node->relname = debackslash(token, length);
 
-       token = lsptok(NULL, &length);          /* eat :refname */
-       token = lsptok(NULL, &length);          /* get :refname */
-       if (length == 0)
-               local_node->refname = NULL;
-       else
-               local_node->refname = debackslash(token, length);
+       token = lsptok(NULL, &length);          /* eat :ref */
+       local_node->ref = nodeRead(true);
 
        token = lsptok(NULL, &length);          /* eat :relid */
        token = lsptok(NULL, &length);          /* get :relid */
@@ -1795,6 +1836,8 @@ parsePlanString(void)
                return_value = _readArray();
        else if (length == 3 && strncmp(token, "VAR", length) == 0)
                return_value = _readVar();
+       else if (length == 4 && strncmp(token, "ATTR", length) == 0)
+               return_value = _readAttr();
        else if (length == 5 && strncmp(token, "CONST", length) == 0)
                return_value = _readConst();
        else if (length == 4 && strncmp(token, "FUNC", length) == 0)
@@ -1843,6 +1886,14 @@ parsePlanString(void)
                return_value = _readCaseWhen();
        else if (length == 7 && strncmp(token, "ROWMARK", length) == 0)
                return_value = _readRowMark();
+#if 0
+       else if (length == 1 && strncmp(token, "{", length) == 0)
+       {
+               /* raw list (of strings?) found in Attr structure - thomas 2000-02-09 */
+               return_value = nodeRead(true);
+               token = lsptok(NULL, &length);  /* eat trailing brace */
+       }
+#endif
        else
                elog(ERROR, "badly formatted planstring \"%.10s\"...\n", token);
 
index 95005f1..9a86cb2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
        RangeTblEntry *new_entry = copyObject(old_entry);
 
        /* ??? someone tell me what the following is doing! - ay 11/94 */
-       if (!strcmp(new_entry->refname, "*CURRENT*") ||
-               !strcmp(new_entry->refname, "*NEW*"))
-               new_entry->refname = get_rel_name(new_relid);
+       if (!strcmp(new_entry->ref->relname, "*CURRENT*") ||
+               !strcmp(new_entry->ref->relname, "*NEW*"))
+               new_entry->ref->relname = get_rel_name(new_relid);
        else
                new_entry->relname = get_rel_name(new_relid);
 
index 53b4eec..664a0df 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.58 2000/01/26 05:56:40 momjian Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v 1.59 2000/02/15 03:37:36 thomas Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -556,7 +556,7 @@ check_subplans_for_ungrouped_vars_walker(Node *node,
                                        elog(ERROR, "cache lookup of attribute %d in relation %u failed",
                                                 var->varattno, rte->relid);
                                elog(ERROR, "Sub-SELECT uses un-GROUPed attribute %s.%s from outer query",
-                                        rte->refname, attname);
+                                        rte->ref->relname, attname);
                        }
                }
        }
index a9dda03..5f7369a 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $Id: analyze.c,v 1.136 2000/02/05 00:20:38 wieck Exp $
+ *     $Id: analyze.c,v 1.137 2000/02/15 03:37:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -239,13 +239,13 @@ transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
        qry->commandType = CMD_DELETE;
 
        /* set up a range table */
-       makeRangeTable(pstate, NULL, NULL);
+       makeRangeTable(pstate, NULL);
        setTargetTable(pstate, stmt->relname);
 
        qry->distinctClause = NIL;
 
        /* fix where clause */
-       qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);
+       qry->qual = transformWhereClause(pstate, stmt->whereClause);
 
        qry->rtable = pstate->p_rtable;
        qry->resultRelation = refnameRangeTablePosn(pstate, stmt->relname, NULL);
@@ -266,7 +266,6 @@ static Query *
 transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
 {
        Query      *qry = makeNode(Query);
-       Node       *fromQual;
        List       *icolumns;
        List       *attrnos;
        List       *attnos;
@@ -289,16 +288,16 @@ transformInsertStmt(ParseState *pstate, InsertStmt *stmt)
         */
 
        /* set up a range table --- note INSERT target is not in it yet */
-       makeRangeTable(pstate, stmt->fromClause, &fromQual);
+       makeRangeTable(pstate, stmt->fromClause);
 
        qry->targetList = transformTargetList(pstate, stmt->targetList);
 
-       qry->qual = transformWhereClause(pstate, stmt->whereClause, fromQual);
+       qry->qual = transformWhereClause(pstate, stmt->whereClause);
 
        /* Initial processing of HAVING clause is just like WHERE clause.
         * Additional work will be done in optimizer/plan/planner.c.
         */
-       qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);
+       qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
 
        qry->groupClause = transformGroupClause(pstate,
                                                                                        stmt->groupClause,
@@ -974,6 +973,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                         *
                         */
                        if (fkconstraint->fk_attrs != NIL && fkconstraint->pk_attrs == NIL)
+                       {
                                if (strcmp(fkconstraint->pktable_name, stmt->relname) != 0)
                                        transformFkeyGetPrimaryKey(fkconstraint);
                                else if (pkey != NULL) 
@@ -997,6 +997,7 @@ transformCreateStmt(ParseState *pstate, CreateStmt *stmt)
                                        elog(ERROR, "PRIMARY KEY for referenced table \"%s\" not found",
                                                fkconstraint->pktable_name);
                                }
+                       }
 
                        /*
                         * Build a CREATE CONSTRAINT TRIGGER statement for the CHECK
@@ -1207,7 +1208,8 @@ transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
        qry->commandType = CMD_UTILITY;
 
        /* take care of the where clause */
-       stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
+       stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+
        qry->hasSubLinks = pstate->p_hasSubLinks;
 
        stmt->rangetable = pstate->p_rtable;
@@ -1231,7 +1233,8 @@ transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
        qry->commandType = CMD_UTILITY;
 
        /* take care of the where clause */
-       stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
+       stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+
        qry->hasSubLinks = pstate->p_hasSubLinks;
 
        stmt->rangetable = pstate->p_rtable;
@@ -1268,9 +1271,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
 
                nothing_qry->commandType = CMD_NOTHING;
 
-               addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+               addRangeTableEntry(pstate, stmt->object->relname,
+                                                  makeAttr("*CURRENT*", NULL),
                                                   FALSE, FALSE, FALSE);
-               addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+               addRangeTableEntry(pstate, stmt->object->relname,
+                                                  makeAttr("*NEW*", NULL),
                                                   FALSE, FALSE, FALSE);
 
                nothing_qry->rtable = pstate->p_rtable;
@@ -1290,9 +1295,11 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
                 * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
                 * equal to 2.
                 */
-               addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+               addRangeTableEntry(pstate, stmt->object->relname,
+                                                  makeAttr("*CURRENT*", NULL),
                                                   FALSE, FALSE, FALSE);
-               addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+               addRangeTableEntry(pstate, stmt->object->relname,
+                                                  makeAttr("*NEW*", NULL),
                                                   FALSE, FALSE, FALSE);
 
                pstate->p_last_resno = 1;
@@ -1306,7 +1313,8 @@ transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
        }
 
        /* take care of the where clause */
-       stmt->whereClause = transformWhereClause(pstate, stmt->whereClause, NULL);
+       stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+
        qry->hasSubLinks = pstate->p_hasSubLinks;
 
        qry->utilityStmt = (Node *) stmt;
@@ -1323,12 +1331,11 @@ static Query *
 transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 {
        Query      *qry = makeNode(Query);
-       Node       *fromQual;
 
        qry->commandType = CMD_SELECT;
 
        /* set up a range table */
-       makeRangeTable(pstate, stmt->fromClause, &fromQual);
+       makeRangeTable(pstate, stmt->fromClause);
 
        qry->into = stmt->into;
        qry->isTemp = stmt->istemp;
@@ -1336,12 +1343,12 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
 
        qry->targetList = transformTargetList(pstate, stmt->targetList);
 
-       qry->qual = transformWhereClause(pstate, stmt->whereClause, fromQual);
+       qry->qual = transformWhereClause(pstate, stmt->whereClause);
 
        /* Initial processing of HAVING clause is just like WHERE clause.
         * Additional work will be done in optimizer/plan/planner.c.
         */
-       qry->havingQual = transformWhereClause(pstate, stmt->havingClause, NULL);
+       qry->havingQual = transformWhereClause(pstate, stmt->havingClause);
 
        qry->groupClause = transformGroupClause(pstate,
                                                                                        stmt->groupClause,
@@ -1401,12 +1408,12 @@ transformUpdateStmt(ParseState *pstate, UpdateStmt *stmt)
         * the FROM clause is non-standard SQL syntax. We used to be able to
         * do this with REPLACE in POSTQUEL so we keep the feature.
         */
-       makeRangeTable(pstate, stmt->fromClause, NULL);
+       makeRangeTable(pstate, stmt->fromClause);
        setTargetTable(pstate, stmt->relname);
 
        qry->targetList = transformTargetList(pstate, stmt->targetList);
 
-       qry->qual = transformWhereClause(pstate, stmt->whereClause, NULL);
+       qry->qual = transformWhereClause(pstate, stmt->whereClause);
 
        qry->hasSubLinks = pstate->p_hasSubLinks;
 
@@ -1866,7 +1873,7 @@ transformForUpdate(Query *qry, List *forUpdate)
                i = 1;
                foreach(l2, qry->rtable)
                {
-                       if (strcmp(((RangeTblEntry *) lfirst(l2))->refname, relname) == 0)
+                       if (strcmp(((RangeTblEntry *) lfirst(l2))->ref->relname, relname) == 0)
                        {
                                List       *l3;
 
index 3c23a29..afaa55e 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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,
                        elog(ERROR, "cache lookup of attribute %d in relation %u failed",
                                 var->varattno, rte->relid);
                elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
-                        rte->refname, attname);
+                        rte->ref->relname, attname);
        }
        /* Otherwise, recurse. */
        return expression_tree_walker(node, check_ungrouped_columns_walker,
index b22691f..d0a3eb1 100644 (file)
@@ -8,16 +8,17 @@
  *
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.51 2000/01/27 18:11:35 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.52 2000/02/15 03:37:47 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "postgres.h"
-
 #include "access/heapam.h"
+#include "miscadmin.h"
 #include "optimizer/tlist.h"
 #include "parse.h"
+#include "nodes/makefuncs.h"
 #include "parser/parse_clause.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
@@ -25,7 +26,6 @@
 #include "parser/parse_relation.h"
 #include "parser/parse_target.h"
 
-
 #define ORDER_CLAUSE 0
 #define GROUP_CLAUSE 1
 #define DISTINCT_ON_CLAUSE 2
@@ -34,28 +34,26 @@ static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};
 
 static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
                                                                                List *tlist, int clause);
-static void parseFromClause(ParseState *pstate, List *frmList, Node **qual);
-static char    *transformTableEntry(ParseState *pstate, RangeVar *r);
+static void parseFromClause(ParseState *pstate, List *frmList);
+RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
 static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
                                                                 List *targetlist, char *opname);
 static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
 
-#ifdef ENABLE_OUTER_JOINS
-static Node *transformUsingClause(ParseState *pstate, List *onList,
-                                                                 char *lname, char *rname);
+#ifndef DISABLE_OUTER_JOINS
+static Node *transformUsingClause(ParseState *pstate, List *using, List *left, List *right);
 #endif
 
 
-
 /*
  * makeRangeTable -
  *       Build the initial range table from the FROM clause.
  */
 void
-makeRangeTable(ParseState *pstate, List *frmList, Node **qual)
+makeRangeTable(ParseState *pstate, List *frmList)
 {
        /* Currently, nothing to do except this: */
-       parseFromClause(pstate, frmList, qual);
+       parseFromClause(pstate, frmList);
 }
 
 /*
@@ -80,7 +78,8 @@ setTargetTable(ParseState *pstate, char *relname)
 
        if ((refnameRangeTablePosn(pstate, relname, &sublevels_up) == 0)
                || (sublevels_up != 0))
-               rte = addRangeTableEntry(pstate, relname, relname,
+               rte = addRangeTableEntry(pstate, relname,
+                                                                makeAttr(relname, NULL),
                                                                 FALSE, FALSE, FALSE);
        else
                rte = refnameRangeTableEntry(pstate, relname);
@@ -94,40 +93,52 @@ setTargetTable(ParseState *pstate, char *relname)
        /* will close relation later, see analyze.c */
 }
 
-/*
- * transformWhereClause -
- *       transforms the qualification and make sure it is of type Boolean
- *
- * Now accept an additional argument, which is a qualification derived
- * from the JOIN/ON or JOIN/USING syntax.
- * - thomas 1998-12-16
- */
+
 Node *
-transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr)
+mergeInnerJoinQuals(ParseState *pstate, Node *clause);
+
+Node *
+mergeInnerJoinQuals(ParseState *pstate, Node *clause)
 {
-       A_Expr     *expr;
-       Node       *qual;
+       A_Expr     *expr = (A_Expr *) pstate->p_join_quals;
 
-       if ((a_expr == NULL) && (o_expr == NULL))
-               return NULL;                    /* no qualifiers */
+       if (expr == NULL)
+               return clause;
 
-       if ((a_expr != NULL) && (o_expr != NULL))
+       if (clause != NULL)
        {
                A_Expr     *a = makeNode(A_Expr);
 
                a->oper = AND;
                a->opname = NULL;
-               a->lexpr = o_expr;
-               a->rexpr = a_expr;
+               a->lexpr = (Node *) expr;
+               a->rexpr = clause;
                expr = a;
        }
-       else if (o_expr != NULL)
-               expr = (A_Expr *) o_expr;
-       else
-               expr = (A_Expr *) a_expr;
+
+       /* Make sure that we don't do this twice... */
+       pstate->p_join_quals = NULL;
+
+       return (Node *) expr;
+} /* mergeInnerJoinQuals() */
+
+/*
+ * transformWhereClause -
+ *       transforms the qualification and make sure it is of type Boolean
+ */
+Node *
+transformWhereClause(ParseState *pstate, Node *clause)
+{
+       Node       *qual;
+
+       if (pstate->p_join_quals != NULL)
+               clause = mergeInnerJoinQuals(pstate, clause);
+
+       if (clause == NULL)
+               return NULL;
 
        pstate->p_in_where_clause = true;
-       qual = transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST);
+       qual = transformExpr(pstate, clause, EXPR_COLUMN_FIRST);
        pstate->p_in_where_clause = false;
 
        if (exprType(qual) != BOOLOID)
@@ -138,98 +149,259 @@ transformWhereClause(ParseState *pstate, Node *a_expr, Node *o_expr)
        return qual;
 }
 
-#ifdef ENABLE_OUTER_JOINS
-static Attr *
-makeAttr(char *relname, char *attname)
+#ifndef DISABLE_JOIN_SYNTAX
+char *
+AttrString(Attr *attr);
+
+char *
+AttrString(Attr *attr)
 {
-       Attr       *a = makeNode(Attr);
+       Value *val;
+
+       Assert(length(attr->attrs) == 1);
+
+       val = lfirst(attr->attrs);
 
-       a->relname = relname;
-       a->paramNo = NULL;
-       a->attrs = lcons(makeString(attname), NIL);
-       a->indirection = NULL;
+       Assert(IsA(val, String));
 
-       return a;
+       return strVal(val);
+}
+
+List *
+ListTableAsAttrs(ParseState *pstate, char *table);
+List *
+ListTableAsAttrs(ParseState *pstate, char *table)
+{
+       List *rlist = NULL;
+       List *col;
+
+       Attr *attr = expandTable(pstate, table, TRUE);
+       foreach(col, attr->attrs)
+       {
+               Attr *a;
+               a = makeAttr(table, strVal((Value *) col));
+               rlist = lappend(rlist, a);
+       }
+
+       return rlist;
+}
+
+List *
+makeUniqueAttrList(List *candidates, List *idents);
+List *
+makeUniqueAttrList(List *attrs, List *filter)
+{
+       List *result = NULL;
+       List *candidate;
+
+       foreach(candidate, attrs)
+       {
+               List *fmember;
+               bool match = FALSE;
+//             char *field;
+               Attr *cattr = lfirst(candidate);
+
+               Assert(IsA(cattr, Attr));
+               Assert(length(cattr->attrs) == 1);
+
+//             field = strVal(lfirst(ccol));
+//             bool match = FALSE;
+
+               foreach(fmember, filter)
+               {
+                       Attr *fattr = lfirst(fmember);
+                       Assert(IsA(fattr, Attr));
+                       Assert(length(fattr->attrs) == 1);
+
+                       if (strcmp(strVal(lfirst(cattr->attrs)), strVal(lfirst(fattr->attrs))) == 0)
+                       {
+                               match = TRUE;
+                               break;
+                       }
+               }
+
+               if (!match)
+                       result = lappend(result, cattr);
+       }
+
+       return result;
+}
+
+List *
+makeAttrList(Attr *attr);
+
+List *
+makeAttrList(Attr *attr)
+{
+       List *result = NULL;
+
+       char *name = attr->relname;
+       List *col;
+
+       foreach (col, attr->attrs)
+       {
+               Attr *newattr = makeAttr(name, strVal((Value *) lfirst(col)));
+
+               result = lappend(result, newattr);
+       }
+
+       return result;
+}
+
+/* ExpandAttrs()
+ * Take an existing attribute node and return a list of attribute nodes
+ * with one attribute name per node.
+ */
+List *
+ExpandAttrs(Attr *attr);
+List *
+ExpandAttrs(Attr *attr)
+{
+       List *col;
+       char *relname = attr->relname;
+       List *rlist = NULL;
+
+       Assert(attr != NULL);
+
+       if ((attr->attrs == NULL) || (length(attr->attrs) <= 1))
+               return lcons(attr, NIL);
+
+       foreach(col, attr->attrs)
+       {
+               Attr *attr = lfirst(col);
+
+               rlist = lappend(rlist, makeAttr(relname, AttrString(attr)));
+       }
+
+       return rlist;
 }
-#endif
 
-#ifdef ENABLE_OUTER_JOINS
 /* transformUsingClause()
  * Take an ON or USING clause from a join expression and expand if necessary.
  */
 static Node *
-transformUsingClause(ParseState *pstate, List *onList, char *lname, char *rname)
+transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *rightList)
 {
        A_Expr     *expr = NULL;
-       List       *on;
-       Node       *qual;
+       List       *using;
 
-       foreach(on, onList)
+       foreach(using, usingList)
        {
-               qual = lfirst(on);
+               List *col;
+               A_Expr *e;
 
-               /*
-                * Ident node means it is just a column name from a real USING
-                * clause...
+               Attr *uattr = lfirst(using);
+               Attr *lattr = NULL, *rattr = NULL;
+
+               /* find the first instances of this column in the shape list
+                * and the last table in the shape list...
                 */
-               if (IsA(qual, Ident))
+               foreach (col, leftList)
                {
-                       Ident      *i = (Ident *) qual;
-                       Attr       *lattr = makeAttr(lname, i->name);
-                       Attr       *rattr = makeAttr(rname, i->name);
-                       A_Expr     *e = makeNode(A_Expr);
-
-                       e->oper = OP;
-                       e->opname = "=";
-                       e->lexpr = (Node *) lattr;
-                       e->rexpr = (Node *) rattr;
+                       Attr *attr = lfirst(col);
 
-                       if (expr != NULL)
+                       if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
                        {
-                               A_Expr     *a = makeNode(A_Expr);
+                               lattr = attr;
+                               break;
+                       }
+               }
+               foreach (col, rightList)
+               {
+                       Attr *attr = lfirst(col);
 
-                               a->oper = AND;
-                               a->opname = NULL;
-                               a->lexpr = (Node *) expr;
-                               a->rexpr = (Node *) e;
-                               expr = a;
+                       if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
+                       {
+                               rattr = attr;
+                               break;
                        }
-                       else
-                               expr = e;
                }
 
-               /* otherwise, we have an expression from an ON clause... */
-               else
+               Assert((lattr != NULL) && (rattr != NULL));
+
+               e = makeNode(A_Expr);
+               e->oper = OP;
+               e->opname = "=";
+               e->lexpr = (Node *) lattr;
+               e->rexpr = (Node *) rattr;
+
+               if (expr != NULL)
                {
-                       if (expr != NULL)
-                       {
-                               A_Expr     *a = makeNode(A_Expr);
+                       A_Expr     *a = makeNode(A_Expr);
 
-                               a->oper = AND;
-                               a->opname = NULL;
-                               a->lexpr = (Node *) expr;
-                               a->rexpr = (Node *) qual;
-                               expr = a;
-                       }
-                       else
-                               expr = (A_Expr *) qual;
+                       a->oper = AND;
+                       a->opname = NULL;
+                       a->lexpr = (Node *) expr;
+                       a->rexpr = (Node *) e;
+                       expr = a;
                }
+               else
+                       expr = e;
        }
-       return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
-}
 
+       return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
+} /* transformUsiongClause() */
 #endif
 
-static char *
+
+RangeTblEntry *
 transformTableEntry(ParseState *pstate, RangeVar *r)
 {
        RelExpr    *baserel = r->relExpr;
        char       *relname = baserel->relname;
-       char       *refname = r->name;
+#if 0
+       char       *refname;
+       List       *columns;
+#endif
        RangeTblEntry *rte;
 
-       if (refname == NULL)
+#if 0
+       if (r->name != NULL)
+               refname = r->name->relname;
+       else
+               refname = NULL;
+
+       columns = ListTableAsAttrs(pstate, relname);
+
+       /* alias might be specified... */
+       if (r->name != NULL)
+       {
+#ifndef DISABLE_JOIN_SYNTAX
+               if (length(columns) > 0)
+               {
+                       if (length(r->name->attrs) > 0)
+                       {
+                               if (length(columns) != length(r->name->attrs))
+                                       elog(ERROR, "'%s' has %d columns but %d %s specified",
+                                                relname, length(columns), length(r->name->attrs),
+                                                ((length(r->name->attrs) != 1)? "aliases": "alias"));
+
+                               aliasList = nconc(aliasList, r->name->attrs);
+                       }
+                       else
+                       {
+                               r->name->attrs = columns;
+
+                               aliasList = nconc(aliasList, r->name->attrs);
+                       }
+               }
+               else
+               {
+                       elog(NOTICE, "transformTableEntry: column aliases not handled (internal error)");
+               }
+#else
+               elog(ERROR, "Column aliases not yet supported");
+#endif
+       }
+       else
+       {
                refname = relname;
+               aliasList = nconc(aliasList, columns);
+       }
+#endif
+
+       if (r->name == NULL)
+               r->name = makeAttr(relname, NULL);
 
        /*
         * marks this entry to indicate it comes from the FROM clause. In SQL,
@@ -242,11 +414,12 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
         * we expand * to foo.x.
         */
 
-       rte = addRangeTableEntry(pstate, relname, refname,
+       rte = addRangeTableEntry(pstate, relname, r->name,
                                                         baserel->inh, TRUE, TRUE);
 
-       return refname;
-}
+       return rte;
+} /* transformTableEntry() */
+
 
 /*
  * parseFromClause -
@@ -263,12 +436,13 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
  * - thomas 1998-12-16
  */
 static void
-parseFromClause(ParseState *pstate, List *frmList, Node **qual)
+parseFromClause(ParseState *pstate, List *frmList)
 {
-       List       *fl;
+//     List *shape, *alias;
+//     Node **qual;
+//     char *lname, *rname;
 
-       if (qual != NULL)
-               *qual = NULL;
+       List *fl;
 
        foreach(fl, frmList)
        {
@@ -285,60 +459,258 @@ parseFromClause(ParseState *pstate, List *frmList, Node **qual)
                 * eg. select * from foo f where f.x = 1; will generate wrong answer
                 * if we expand * to foo.x.
                 */
+
+               /* Plain vanilla inner join, just like we've always had? */
                if (IsA(n, RangeVar))
+               {
                        transformTableEntry(pstate, (RangeVar *) n);
+               }
+
+               /* A newfangled join expression? */
                else if (IsA(n, JoinExpr))
                {
-                       JoinExpr   *j = (JoinExpr *) n;
+#ifndef DISABLE_JOIN_SYNTAX
+//                     char                       *lname, *rname;
+                       RangeTblEntry      *l_rte, *r_rte;
+                       Attr                       *l_name, *r_name;
+                       JoinExpr *j = (JoinExpr *) n;
 
-#ifdef ENABLE_OUTER_JOINS
-                       char       *lname = transformTableEntry(pstate, (RangeVar *) j->larg);
+                       if (j->alias != NULL)
+                               elog(ERROR, "JOIN table aliases are not supported");
 
-#endif
-                       char       *rname;
+                       /* nested join? then handle the left one first... */
+                       if (IsA(j->larg, JoinExpr))
+                       {
+                               parseFromClause(pstate, lcons(j->larg, NIL));
+                               l_name = ((JoinExpr *)j->larg)->alias;
+                       }
+                       else
+                       {
+                               Assert(IsA(j->larg, RangeVar));
+                               l_rte = transformTableEntry(pstate, (RangeVar *) j->larg);
+                               l_name = expandTable(pstate, l_rte->ref->relname, TRUE);
+                       }
 
-                       if (IsA((Node *) j->rarg, RangeVar))
-                               rname = transformTableEntry(pstate, (RangeVar *) j->rarg);
+                       if (IsA(j->rarg, JoinExpr))
+                       {
+//                             elog(ERROR, "Nested JOINs are not yet supported");
+                               parseFromClause(pstate, lcons(j->rarg, NIL));
+                               l_name = ((JoinExpr *)j->larg)->alias;
+                       }
                        else
-                               elog(ERROR, "Nested JOINs are not yet supported");
+                       {
+                               Assert(IsA(j->rarg, RangeVar));
+                               r_rte = transformTableEntry(pstate, (RangeVar *) j->rarg);
+                               r_name = expandTable(pstate, r_rte->ref->relname, TRUE);
+                       }
+
+                       /* Natural join does not explicitly specify columns; must generate columns to join.
+                        * Need to run through the list of columns from each table or join result
+                        * and match up the column names. Use the first table, and check every
+                        * column in the second table for a match.
+                        */
+                       if (j->isNatural)
+                       {
+                               List *lx, *rx;
+                               List *rlist = NULL;
+
+                               foreach(lx, l_name->attrs)
+                               {
+                                       Ident *id = NULL;
+                                       Value *l_col = lfirst(lx);
+                                       Assert(IsA(l_col, String));
+
+                                       foreach(rx, r_name->attrs)
+                                       {
+                                               Value *r_col = lfirst(rx);
+                                               Assert(IsA(r_col, String));
+
+//                                             if (equal(l_col, r_col))
+                                               if (strcmp(strVal(l_col), strVal(r_col)) == 0)
+                                               {
+                                                       id = (Ident *) makeNode(Ident);
+                                                       id->name = strVal(l_col);
+                                                       break;
+                                               }
+                                       }
+
+                                       /* right column matched? then keep as join column... */
+                                       if (id != NULL)
+                                               rlist = lappend(rlist, id);
+                               }
+                               j->quals = rlist;
+
+                               printf("NATURAL JOIN columns are %s\n", nodeToString(rlist));
+                       }
 
-#ifdef ENABLE_OUTER_JOINS
                        if (j->jointype == INNER_P)
                        {
+                               /* CROSS JOIN */
+                               if (j->quals == NULL)
+                               {
+                                       printf("CROSS JOIN...\n");
+                               }
 
-                               /*
+                               /* JOIN/USING
                                 * This is an inner join, so rip apart the join node and
                                 * transform into a traditional FROM list. NATURAL JOIN
-                                * and USING clauses both change the shape of the result.
+                                * and JOIN USING both change the shape of the result.
                                 * Need to generate a list of result columns to use for
-                                * target list expansion and validation. Not doing this
-                                * yet though!
+                                * target list expansion and validation.
                                 */
-                               if (IsA(j->quals, List))
-                                       j->quals = lcons(transformUsingClause(pstate, (List *) j->quals, lname, rname), NIL);
+                               else if (IsA(j->quals, List))
+                               {
+                                       /*
+                                        * List of Ident nodes means column names from a real USING
+                                        * clause. Determine the shape of the joined table.
+                                        */
+//                                     List *ltable, *rtable;
+                                       List *ucols, *ucol;
+                                       List *shape = NULL;
+                                       List *alias = NULL;
+                                       List *l_shape, *r_shape;
+
+                                       List *l_cols = makeAttrList(l_name);
+                                       List *r_cols = makeAttrList(r_name);
+
+                                       printf("USING input tables are:\n %s\n %s\n",
+                                                  nodeToString(l_name), nodeToString(r_name));
+
+                                       printf("USING expanded tables are:\n %s\n %s\n",
+                                                  nodeToString(l_cols), nodeToString(r_cols));
+
+                                       /* Columns from the USING clause... */
+                                       ucols = (List *)j->quals;
+                                       foreach(ucol, ucols)
+                                       {
+                                               List *col;
+                                               Attr *l_attr = NULL, *r_attr = NULL;
+                                               Ident *id = lfirst(ucol);
+
+                                               Attr *attr = makeAttr("", id->name);
+
+                                               foreach(col, l_cols)
+                                               {
+                                                       attr = lfirst(col);
+                                                       if (strcmp(AttrString(attr), id->name) == 0)
+                                                       {
+                                                               l_attr = attr;
+                                                               break;
+                                                       }
+                                               }
+
+                                               foreach(col, r_cols)
+                                               {
+                                                       attr = lfirst(col);
+                                                       if (strcmp(AttrString(attr), id->name) == 0)
+                                                       {
+                                                               r_attr = attr;
+                                                               break;
+                                                       }
+                                               }
+
+                                               if (l_attr == NULL)
+                                                       elog(ERROR, "USING column '%s' not found in table '%s'",
+                                                                id->name, l_name->relname);
+                                               if (r_attr == NULL)
+                                                       elog(ERROR, "USING column '%s' not found in table '%s'",
+                                                                id->name, r_name->relname);
+
+                                               shape = lappend(shape, l_attr);
+                                               alias = lappend(alias, makeAttr("", AttrString(l_attr)));
+                                       }
+                                       printf("JOIN/USING join columns are %s\n", nodeToString(shape));
+
+                                       /* Remaining columns from the left side... */
+                                       l_shape = makeUniqueAttrList(makeAttrList(l_name), shape);
 
+                                       printf("JOIN/USING left columns are %s\n", nodeToString(l_shape));
+
+                                       r_shape = makeUniqueAttrList(makeAttrList(r_name), shape);
+
+                                       printf("JOIN/USING right columns are %s\n", nodeToString(r_shape));
+
+                                       printf("JOIN/USING input quals are %s\n", nodeToString(j->quals));
+
+                                       j->quals = (List *) transformUsingClause(pstate, shape, l_cols, r_cols);
+
+                                       printf("JOIN/USING transformed quals are %s\n", nodeToString(j->quals));
+
+                                       alias = nconc(nconc(alias, listCopy(l_shape)), listCopy(r_shape));
+                                       shape = nconc(nconc(shape, l_shape), r_shape);
+
+                                       printf("JOIN/USING shaped table is %s\n", nodeToString(shape));
+                                       printf("JOIN/USING alias list is %s\n", nodeToString(alias));
+
+                                       pstate->p_shape = shape;
+                                       pstate->p_alias = alias;
+                               }
+
+                               /* otherwise, must be an expression from an ON clause... */
+                               else
+                               {
+                                       j->quals = (List *) lcons(j->quals, NIL);
+                               }
+
+                               pstate->p_join_quals = (Node *) j->quals;
+
+#if 0
                                if (qual == NULL)
                                        elog(ERROR, "JOIN/ON not supported in this context");
 
+                               printf("Table aliases are %s\n", nodeToString(*aliasList));
+#endif
+
+#if 0
                                if (*qual == NULL)
-                                       *qual = lfirst(j->quals);
+                               {
+#endif
+
+#if 0
+                                       /* merge qualified join clauses... */
+                               if (j->quals != NULL)
+                               {
+                                       if (*qual != NULL)
+                                       {
+                                               A_Expr     *a = makeNode(A_Expr);
+
+                                               a->oper = AND;
+                                               a->opname = NULL;
+                                               a->lexpr = (Node *) *qual;
+                                               a->rexpr = (Node *) j->quals;
+
+                                               *qual = (Node *)a;
+                                       }
+                                       else
+                                       {
+                                               *qual = (Node *)j->quals;
+                                       }
+                               }
+#endif
+
+#if 0
+                               }
                                else
+                               {
                                        elog(ERROR, "Multiple JOIN/ON clauses not handled (internal error)");
+                                       *qual = lappend(*qual, j->quals);
+                               }
+#endif
 
                                /*
                                 * if we are transforming this node back into a FROM list,
                                 * then we will need to replace the node with two nodes.
                                 * Will need access to the previous list item to change
                                 * the link pointer to reference these new nodes. Try
-                                * accumulating and returning a new list. - thomas
-                                * 1999-01-08 Not doing this yet though!
+                                * accumulating and returning a new list.
+                                * - thomas 1999-01-08 Not doing this yet though!
                                 */
 
                        }
                        else if ((j->jointype == LEFT)
                                         || (j->jointype == RIGHT)
                                         || (j->jointype == FULL))
-                               elog(ERROR, "OUTER JOIN is not implemented");
+                               elog(ERROR, "OUTER JOIN is not yet supported");
                        else
                                elog(ERROR, "Unrecognized JOIN clause; tag is %d (internal error)",
                                         j->jointype);
@@ -350,7 +722,7 @@ parseFromClause(ParseState *pstate, List *frmList, Node **qual)
                        elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)"
                                 "\n\t%s", nodeToString(n));
        }
-}
+} /* parseFromClause() */
 
 
 /*
index 76e28fb..365378f 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
                                                        Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
 
                                                        if (exprType(lexpr) != BOOLOID)
-                                                               elog(ERROR, "left-hand side of AND is type '%s', not bool",
-                                                                        typeidTypeName(exprType(lexpr)));
+                                                               elog(ERROR, "left-hand side of AND is type '%s', not '%s'",
+                                                                        typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID));
 
                                                        if (exprType(rexpr) != BOOLOID)
-                                                               elog(ERROR, "right-hand side of AND is type '%s', not bool",
-                                                                        typeidTypeName(exprType(rexpr)));
+                                                               elog(ERROR, "right-hand side of AND is type '%s', not '%s'",
+                                                                        typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
 
                                                        expr->typeOid = BOOLOID;
                                                        expr->opType = AND_EXPR;
@@ -164,11 +164,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                        Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
 
                                                        if (exprType(lexpr) != BOOLOID)
-                                                               elog(ERROR, "left-hand side of OR is type '%s', not bool",
-                                                                        typeidTypeName(exprType(lexpr)));
+                                                               elog(ERROR, "left-hand side of OR is type '%s', not '%s'",
+                                                                        typeidTypeName(exprType(lexpr)), typeidTypeName(BOOLOID));
                                                        if (exprType(rexpr) != BOOLOID)
-                                                               elog(ERROR, "right-hand side of OR is type '%s', not bool",
-                                                                        typeidTypeName(exprType(rexpr)));
+                                                               elog(ERROR, "right-hand side of OR is type '%s', not '%s'",
+                                                                        typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
                                                        expr->typeOid = BOOLOID;
                                                        expr->opType = OR_EXPR;
                                                        expr->args = makeList(lexpr, rexpr, -1);
@@ -181,8 +181,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                        Node       *rexpr = transformExpr(pstate, a->rexpr, precedence);
 
                                                        if (exprType(rexpr) != BOOLOID)
-                                                               elog(ERROR, "argument to NOT is type '%s', not bool",
-                                                                        typeidTypeName(exprType(rexpr)));
+                                                               elog(ERROR, "argument to NOT is type '%s', not '%s'",
+                                                                        typeidTypeName(exprType(rexpr)), typeidTypeName(BOOLOID));
                                                        expr->typeOid = BOOLOID;
                                                        expr->opType = NOT_EXPR;
                                                        expr->args = makeList(rexpr, -1);
@@ -223,11 +223,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                pstate->p_hasSubLinks = true;
                                qtrees = parse_analyze(lcons(sublink->subselect, NIL), pstate);
                                if (length(qtrees) != 1)
-                                       elog(ERROR, "parser: bad query in subselect");
+                                       elog(ERROR, "Bad query in subselect");
                                qtree = (Query *) lfirst(qtrees);
                                if (qtree->commandType != CMD_SELECT ||
                                        qtree->resultRelation != 0)
-                                       elog(ERROR, "parser: bad query in subselect");
+                                       elog(ERROR, "Bad query in subselect");
                                sublink->subselect = (Node *) qtree;
 
                                if (sublink->subLinkType == EXISTS_SUBLINK)
@@ -247,11 +247,11 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                         */
                                        if (tlist == NIL ||
                                                ((TargetEntry *) lfirst(tlist))->resdom->resjunk)
-                                               elog(ERROR, "parser: subselect must have a field");
+                                               elog(ERROR, "Subselect must have a field");
                                        while ((tlist = lnext(tlist)) != NIL)
                                        {
                                                if (! ((TargetEntry *) lfirst(tlist))->resdom->resjunk)
-                                                       elog(ERROR, "parser: subselect must have only one field");
+                                                       elog(ERROR, "Subselect must have only one field");
                                        }
                                        /* EXPR needs no lefthand or combining operator.
                                         * These fields should be NIL already, but make sure.
@@ -274,7 +274,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                        /* Combining operators other than =/<> is dubious... */
                                        if (length(left_list) != 1 &&
                                                strcmp(op, "=") != 0 && strcmp(op, "<>") != 0)
-                                               elog(ERROR, "parser: '%s' is not usable for row comparison",
+                                               elog(ERROR, "Row comparison cannot use '%s'",
                                                         op);
 
                                        sublink->oper = NIL;
@@ -297,7 +297,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                        continue;
 
                                                if (left_list == NIL)
-                                                       elog(ERROR, "parser: Subselect has too many fields.");
+                                                       elog(ERROR, "Subselect has too many fields");
                                                lexpr = lfirst(left_list);
                                                left_list = lnext(left_list);
 
@@ -308,7 +308,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                opform = (Form_pg_operator) GETSTRUCT(optup);
 
                                                if (opform->oprresult != BOOLOID)
-                                                       elog(ERROR, "parser: '%s' must return 'bool' to be used with quantified predicate subquery", op);
+                                                       elog(ERROR, "'%s' result type of '%s' must return '%s'"
+                                                                " to be used with quantified predicate subquery",
+                                                                op, typeidTypeName(opform->oprresult),
+                                                                typeidTypeName(BOOLOID));
 
                                                newop = makeOper(oprid(optup),/* opno */
                                                                                 InvalidOid, /* opid */
@@ -318,7 +321,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                sublink->oper = lappend(sublink->oper, newop);
                                        }
                                        if (left_list != NIL)
-                                               elog(ERROR, "parser: Subselect has too few fields.");
+                                               elog(ERROR, "Subselect has too few fields");
                                }
                                result = (Node *) expr;
                                break;
@@ -430,7 +433,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                        }
                                        else
                                        {
-                                               elog(ERROR, "CASE/ELSE unable to convert to type %s",
+                                               elog(ERROR, "CASE/ELSE unable to convert to type '%s'",
                                                         typeidTypeName(ptype));
                                        }
                                }
@@ -457,7 +460,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                                                }
                                                else
                                                {
-                                                       elog(ERROR, "CASE/WHEN unable to convert to type %s",
+                                                       elog(ERROR, "CASE/WHEN unable to convert to type '%s'",
                                                                 typeidTypeName(ptype));
                                                }
                                        }
@@ -519,8 +522,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
                        }
                default:
                        /* should not reach here */
-                       elog(ERROR, "transformExpr: does not know how to transform node %d",
-                                nodeTag(expr));
+                       elog(ERROR, "transformExpr: does not know how to transform node %d"
+                                " (internal error)", nodeTag(expr));
                        break;
        }
 
@@ -566,18 +569,22 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
                if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
                {
                        /* Convert it to a fully qualified Attr, and transform that */
+#ifndef DISABLE_JOIN_SYNTAX
+                       Attr       *att = makeAttr(rte->ref->relname, ident->name);
+#else
                        Attr       *att = makeNode(Attr);
 
                        att->relname = rte->refname;
                        att->paramNo = NULL;
                        att->attrs = lcons(makeString(ident->name), NIL);
+#endif
                        att->indirection = ident->indirection;
                        return transformAttr(pstate, att, precedence);
                }
        }
 
        if (result == NULL)
-               elog(ERROR, "attribute '%s' not found", ident->name);
+               elog(ERROR, "Attribute '%s' not found", ident->name);
 
        return result;
 }
@@ -631,7 +638,7 @@ exprType(Node *expr)
                                        TargetEntry *tent;
 
                                        if (! qtree || ! IsA(qtree, Query))
-                                               elog(ERROR, "exprType: can't get type for untransformed sublink");
+                                               elog(ERROR, "Cannot get type for untransformed sublink");
                                        tent = (TargetEntry *) lfirst(qtree->targetList);
                                        type = tent->resdom->restype;
                                }
@@ -653,7 +660,7 @@ exprType(Node *expr)
                        type = UNKNOWNOID;
                        break;
                default:
-                       elog(ERROR, "exprType: don't know how to get type for %d node",
+                       elog(ERROR, "Do not know how to get type for %d node",
                                 nodeTag(expr));
                        break;
        }
@@ -728,7 +735,7 @@ parser_typecast_constant(Value *expr, TypeName *typename)
                        break;
                default:
                        elog(ERROR,
-                                "parser_typecast_constant: cannot cast this expression to type '%s'",
+                                "Cannot cast this expression to type '%s'",
                                 typename->name);
        }
 
index 9686317..06afc86 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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,
                if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
                {
                        RangeTblEntry *rte;
+                       AttrNumber attnum;
                        Ident      *ident = (Ident *) first_arg;
 
                        /*
@@ -293,7 +294,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                        rte = refnameRangeTableEntry(pstate, refname);
                        if (rte == NULL)
                        {
-                               rte = addRangeTableEntry(pstate, refname, refname,
+                               rte = addRangeTableEntry(pstate, refname,
+                                                                                makeAttr(refname, NULL),
                                                                                 FALSE, FALSE, TRUE);
 #ifdef WARN_FROM
                                elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
@@ -304,12 +306,53 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 
                        relname = rte->relname;
                        relid = rte->relid;
+                       attnum = InvalidAttrNumber;
 
                        /*
                         * If the attr isn't a set, just make a var for it.  If it is
                         * a set, treat it like a function and drop through.
+                        * Look through the explicit column list first, since we
+                        * now allow column aliases.
+                        * - thomas 2000-02-07
                         */
-                       if (get_attnum(relid, funcname) != InvalidAttrNumber)
+                       if (rte->ref->attrs != NULL)
+                       {
+                               List   *c;
+                               /* start counting attributes/columns from one.
+                                * zero is reserved for InvalidAttrNumber.
+                                * - thomas 2000-01-27
+                                */
+                               int             i = 1;
+                               foreach (c, rte->ref->attrs)
+                               {
+                                       char *colname = strVal(lfirst(c));
+                                       /* found a match? */
+                                       if (strcmp(colname, funcname) == 0)
+                                       {
+                                               char *basename = get_attname(relid, i);
+
+                                               if (basename != NULL)
+                                               {
+                                                       funcname = basename;
+                                                       attnum = i;
+                                               }
+                                               /* attnum was initialized to InvalidAttrNumber
+                                                * earlier, so no need to reset it if the
+                                                * above test fails. - thomas 2000-02-07
+                                                */
+                                               break;
+                                       }
+                                       i++;
+                               }
+                               if (attnum == InvalidAttrNumber)
+                                       attnum = specialAttNum(funcname);
+                       }
+                       else
+                       {
+                               attnum = get_attnum(relid, funcname);
+                       }
+
+                       if (attnum != InvalidAttrNumber)
                        {
                                return (Node *) make_var(pstate,
                                                                                 relid,
@@ -474,7 +517,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
                        rte = refnameRangeTableEntry(pstate, refname);
                        if (rte == NULL)
                        {
-                               rte = addRangeTableEntry(pstate, refname, refname,
+                               rte = addRangeTableEntry(pstate, refname,
+                                                                                makeAttr(refname, NULL),
                                                                                 FALSE, FALSE, TRUE);
 #ifdef WARN_FROM
                                elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
@@ -485,7 +529,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
 
                        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
@@ -593,7 +637,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
        if (attisset)
        {
                if (!strcmp(funcname, "*"))
-                       funcnode->func_tlist = expandAll(pstate, relname, refname, curr_resno);
+                       funcnode->func_tlist = expandAll(pstate, relname,
+                                                                                        makeAttr(refname, NULL),
+                                                                                        curr_resno);
                else
                {
                        funcnode->func_tlist = setup_tlist(funcname, argrelid);
index 4e72a7c..02a3cd2 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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] = {
        "cid",
 };
 
+/* refnameRangeTableEntries()
+ * Given refname, return a list of range table entries
+ * This is possible with JOIN syntax, where tables in a join
+ * acquire the same reference name
+ * - thomas 2000-01-20
+ */
+List *
+refnameRangeTableEntries(ParseState *pstate, char *refname);
+
+List *
+refnameRangeTableEntries(ParseState *pstate, char *refname)
+{
+       List       *rteList = NULL;
+       List       *temp;
+
+       while (pstate != NULL)
+       {
+               foreach(temp, pstate->p_rtable)
+               {
+                       RangeTblEntry *rte = lfirst(temp);
+
+                       if (strcmp(rte->ref->relname, refname) == 0)
+                               rteList = lappend(rteList, rte);
+               }
+               /* only allow correlated columns in WHERE clause */
+               if (pstate->p_in_where_clause)
+                       pstate = pstate->parentParseState;
+               else
+                       break;
+       }
+       return rteList;
+}
+
 /* given refname, return a pointer to the range table entry */
 RangeTblEntry *
 refnameRangeTableEntry(ParseState *pstate, char *refname)
@@ -77,7 +110,11 @@ refnameRangeTableEntry(ParseState *pstate, char *refname)
                {
                        RangeTblEntry *rte = lfirst(temp);
 
+#ifndef DISABLE_JOIN_SYNTAX
+                       if (strcmp(rte->ref->relname, refname) == 0)
+#else
                        if (!strcmp(rte->refname, refname))
+#endif
                                return rte;
                }
                /* only allow correlated columns in WHERE clause */
@@ -106,7 +143,11 @@ refnameRangeTablePosn(ParseState *pstate, char *refname, int *sublevels_up)
                {
                        RangeTblEntry *rte = lfirst(temp);
 
+#ifndef DISABLE_JOIN_SYNTAX
+                       if (strcmp(rte->ref->relname, refname) == 0)
+#else
                        if (!strcmp(rte->refname, refname))
+#endif
                                return index;
                        index++;
                }
@@ -143,24 +184,52 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
 
                foreach(et, rtable)
                {
+                       RangeTblEntry *rte_candidate = NULL;
                        RangeTblEntry *rte = lfirst(et);
 
                        /* only consider RTEs mentioned in FROM or UPDATE/DELETE */
                        if (!rte->inFromCl && rte != pstate->p_target_rangetblentry)
                                continue;
 
-                       if (get_attnum(rte->relid, colname) != InvalidAttrNumber)
+                       if (rte->ref->attrs != NULL)
                        {
-                               if (rte_result != NULL)
+                               List *c;
+                               foreach (c, rte->ref->attrs)
                                {
-                                       if (!pstate->p_is_insert ||
-                                               rte != pstate->p_target_rangetblentry)
-                                               elog(ERROR, "Column '%s' is ambiguous", colname);
+                                       if (strcmp(strVal(lfirst(c)), colname) == 0)
+                                       {
+                                               if (rte_candidate != NULL)
+                                                       elog(ERROR, "Column '%s' is ambiguous"
+                                                                " (internal error)", colname);
+                                               rte_candidate = rte;
+                                       }
                                }
-                               else
-                                       rte_result = rte;
                        }
+
+                       /* Even if we have an attribute list in the RTE,
+                        * look for the column here anyway. This is the only
+                        * way we will find implicit columns like "oid".
+                        * - thomas 2000-02-07
+                        */
+                       if ((rte_candidate == NULL)
+                               && (get_attnum(rte->relid, colname) != InvalidAttrNumber))
+                       {
+                               rte_candidate = rte;
+                       }
+
+                       if (rte_candidate == NULL)
+                               continue;
+
+                       if (rte_result != NULL)
+                       {
+                               if (!pstate->p_is_insert ||
+                                       rte != pstate->p_target_rangetblentry)
+                                       elog(ERROR, "Column '%s' is ambiguous", colname);
+                       }
+                       else
+                               rte_result = rte;
                }
+
                /* only allow correlated columns in WHERE clause */
                if (pstate->p_in_where_clause && rte_result == NULL)
                        pstate = pstate->parentParseState;
@@ -177,45 +246,65 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
 RangeTblEntry *
 addRangeTableEntry(ParseState *pstate,
                                   char *relname,
-                                  char *refname,
+                                  Attr *ref,
                                   bool inh,
                                   bool inFromCl,
                                   bool inJoinSet)
 {
-       Relation        relation;
-       RangeTblEntry *rte;
-       int                     sublevels_up;
+       Relation                rel;
+       RangeTblEntry  *rte;
+       int                             maxattrs;
+       int                             sublevels_up;
+       int                             varattno;
 
+       /* Look for an existing rte, if available... */
        if (pstate != NULL)
        {
-               int                     rt_index = refnameRangeTablePosn(pstate, refname,
-                                                                                                        &sublevels_up);
+               int rt_index = refnameRangeTablePosn(pstate, ref->relname,
+                                                                                        &sublevels_up);
 
                if (rt_index != 0 && (!inFromCl || sublevels_up == 0))
                {
-                       if (!strcmp(refname, "*CURRENT*") || !strcmp(refname, "*NEW*"))
+                       if (!strcmp(ref->relname, "*CURRENT*") || !strcmp(ref->relname, "*NEW*"))
                                return (RangeTblEntry *) nth(rt_index - 1, pstate->p_rtable);
-                       elog(ERROR, "Table name '%s' specified more than once", refname);
+                       elog(ERROR, "Table name '%s' specified more than once", ref->relname);
                }
        }
 
        rte = makeNode(RangeTblEntry);
 
-       rte->relname = pstrdup(relname);
-       rte->refname = pstrdup(refname);
+       rte->relname = relname;
+       rte->ref = ref;
 
        /* Get the rel's OID.  This access also ensures that we have an
         * up-to-date relcache entry for the rel.  We don't need to keep
         * it open, however.
+        * Since this is open anyway, let's check that the number of column
+        * aliases is reasonable.
+        * - Thomas 2000-02-04
         */
-       relation = heap_openr(relname, AccessShareLock);
-       rte->relid = RelationGetRelid(relation);
-       heap_close(relation, AccessShareLock);
+       rel = heap_openr(relname, AccessShareLock);
+       rte->relid = RelationGetRelid(rel);
+       maxattrs = RelationGetNumberOfAttributes(rel);
+       if (maxattrs < length(ref->attrs))
+               elog(ERROR, "Table '%s' has %d columns available but %d columns specified",
+                        relname, maxattrs, length(ref->attrs));
+
+       /* fill in any unspecified alias columns */
+       for (varattno = length(ref->attrs); varattno < maxattrs; varattno++)
+       {
+               char       *attrname;
+
+               attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+               ref->attrs = lappend(ref->attrs, makeString(attrname));
+       }
+       heap_close(rel, AccessShareLock);
 
        /*
-        * Flags: this RTE should be expanded to include descendant tables,
-        * this RTE is in the FROM clause, this RTE should be included in
-        * the planner's final join.
+        * Flags:
+        * - this RTE should be expanded to include descendant tables,
+        * - this RTE is in the FROM clause,
+        * - this RTE should be included in the planner's final join.
         */
        rte->inh = inh;
        rte->inFromCl = inFromCl;
@@ -231,23 +320,71 @@ addRangeTableEntry(ParseState *pstate,
        return rte;
 }
 
+/* expandTable()
+ * Populates an Attr with table name and column names
+ * This is similar to expandAll(), but does not create an RTE
+ * if it does not already exist.
+ * - thomas 2000-01-19
+ */
+Attr *
+expandTable(ParseState *pstate, char *refname, bool getaliases)
+{
+       Attr                       *attr;
+       RangeTblEntry      *rte;
+       Relation                        rel;
+       int                     varattno,
+                               maxattrs;
+
+       rte = refnameRangeTableEntry(pstate, refname);
+
+       if (getaliases && (rte != NULL) && (rte->ref != NULL)
+               && (length(rte->ref->attrs) > 0))
+       {
+               return rte->ref;
+       }
+
+       if (rte != NULL)
+               rel = heap_open(rte->relid, AccessShareLock);
+       else
+               rel = heap_openr(refname, AccessShareLock);
+
+       if (rel == NULL)
+               elog(ERROR, "Relation '%s' not found", refname);
+
+       maxattrs = RelationGetNumberOfAttributes(rel);
+
+       attr = makeAttr(refname, NULL);
+
+       for (varattno = 0; varattno < maxattrs; varattno++)
+       {
+               char       *attrname;
+
+               attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
+               attr->attrs = lappend(attr->attrs, makeString(attrname));
+       }
+
+       heap_close(rel, AccessShareLock);
+
+       return attr;
+}
+
 /*
  * expandAll -
  *       makes a list of attributes
  */
 List *
-expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
+expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno)
 {
-       List       *te_list = NIL;
-       RangeTblEntry *rte;
-       Relation        rel;
-       int                     varattno,
-                               maxattrs;
+       List               *te_list = NIL;
+       RangeTblEntry  *rte;
+       Relation                rel;
+       int                             varattno,
+                                       maxattrs;
 
-       rte = refnameRangeTableEntry(pstate, refname);
+       rte = refnameRangeTableEntry(pstate, ref->relname);
        if (rte == NULL)
        {
-               rte = addRangeTableEntry(pstate, relname, refname,
+               rte = addRangeTableEntry(pstate, relname, ref,
                                                                 FALSE, FALSE, TRUE);
 #ifdef WARN_FROM
                elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
@@ -262,12 +399,19 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
 
        for (varattno = 0; varattno < maxattrs; varattno++)
        {
-               char       *attrname;
-               Var                *varnode;
-               TargetEntry *te = makeNode(TargetEntry);
+               char               *attrname;
+               char               *label;
+               Var                        *varnode;
+               TargetEntry        *te = makeNode(TargetEntry);
 
                attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
-               varnode = make_var(pstate, rte->relid, refname, attrname);
+
+               /* varattno is zero-based, so check that length() is always greater */
+               if (length(rte->ref->attrs) > varattno)
+                       label = pstrdup(strVal(nth(varattno, rte->ref->attrs)));
+               else
+                       label = attrname;
+               varnode = make_var(pstate, rte->relid, relname, attrname);
 
                /*
                 * Even if the elements making up a set are complex, the set
@@ -277,7 +421,7 @@ expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno)
                te->resdom = makeResdom((AttrNumber) (*this_resno)++,
                                                                varnode->vartype,
                                                                varnode->vartypmod,
-                                                               attrname,
+                                                               label,
                                                                (Index) 0,
                                                                (Oid) 0,
                                                                false);
@@ -306,16 +450,32 @@ attnameAttNum(Relation rd, char *a)
                if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a))
                        return i + 1;
 
-       for (i = 0; i < SPECIALS; i++)
-               if (!strcmp(special_attr[i].field, a))
-                       return special_attr[i].code;
+       if ((i = specialAttNum(a)) != InvalidAttrNumber)
+               return i;
 
        /* on failure */
        elog(ERROR, "Relation '%s' does not have attribute '%s'",
                 RelationGetRelationName(rd), a);
-       return 0;                                       /* lint */
+       return InvalidAttrNumber;               /* lint */
 }
 
+/* specialAttNum()
+ * Check attribute name to see if it is "special", e.g. "oid".
+ * - thomas 2000-02-07
+ */
+int
+specialAttNum(char *a)
+{
+       int                     i;
+
+       for (i = 0; i < SPECIALS; i++)
+               if (!strcmp(special_attr[i].field, a))
+                       return special_attr[i].code;
+
+       return InvalidAttrNumber;
+}
+
+
 /*
  * Given range variable, return whether attribute of this name
  * is a set.
@@ -372,3 +532,8 @@ attnumTypeId(Relation rd, int attid)
         */
        return rd->rd_att->attrs[attid - 1]->atttypid;
 }
+
+
+
+
+
index 653afe7..9d00e17 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * 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)
                                 * Target item is a single '*', expand all tables
                                 * (eg. SELECT * FROM emp)
                                 */
-                               p_target = nconc(p_target,
-                                                                ExpandAllTables(pstate));
+                               if (pstate->p_shape != NULL)
+                               {
+                                       List *s, *a;
+                                       int i;
+
+                                       Assert(length(pstate->p_shape) == length(pstate->p_alias));
+
+                                       s = pstate->p_shape;
+                                       a = pstate->p_alias;
+                                       for (i = 0; i < length(pstate->p_shape); i++)
+                                       {
+                                               TargetEntry        *te;
+                                               char               *colname;
+                                               Attr *shape = lfirst(s);
+                                               Attr *alias = lfirst(a);
+
+                                               Assert(IsA(shape, Attr) && IsA(alias, Attr));
+
+                                               colname = strVal(lfirst(alias->attrs));
+                                               te = transformTargetEntry(pstate, (Node *) shape,
+                                                                                                 NULL, colname, false);
+                                               p_target = lappend(p_target, te);
+                                               s = lnext(s);
+                                               a = lnext(a);
+                                       }
+                               }
+                               else
+                                       p_target = nconc(p_target,
+                                                                        ExpandAllTables(pstate));
                        }
                        else if (att->attrs != NIL &&
                                         strcmp(strVal(lfirst(att->attrs)), "*") == 0)
@@ -116,9 +143,8 @@ transformTargetList(ParseState *pstate, List *targetlist)
                                 * (eg. SELECT emp.*, dname FROM emp, dept)
                                 */
                                p_target = nconc(p_target,
-                                                                expandAll(pstate,
-                                                                                  att->relname,
-                                                                                  att->relname,
+                                                                expandAll(pstate, att->relname,
+                                                                                  makeAttr(att->relname, NULL),
                                                                                   &pstate->p_last_resno));
                        }
                        else
@@ -192,12 +218,18 @@ updateTargetListEntry(ParseState *pstate,
         */
        if (indirection)
        {
+#ifndef DISABLE_JOIN_SYNTAX
+               Attr       *att = makeAttr(pstrdup(RelationGetRelationName(rd)), colname);
+#else
                Attr       *att = makeNode(Attr);
+#endif
                Node       *arrayBase;
                ArrayRef   *aref;
 
+#ifdef DISABLE_JOIN_SYNTAX
                att->relname = pstrdup(RelationGetRelationName(rd));
                att->attrs = lcons(makeString(colname), NIL);
+#endif
                arrayBase = ParseNestedFuncOrColumn(pstate, att,
                                                                                        &pstate->p_last_resno,
                                                                                        EXPR_COLUMN_FIRST);
@@ -355,10 +387,9 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
        return cols;
 }
 
-/*
- * ExpandAllTables -
- *       turns '*' (in the target list) into a list of attributes
- *        (of all relations in the range table)
+/* ExpandAllTables()
+ * Turns '*' (in the target list) into a list of attributes
+ * (of all relations in the range table)
  */
 static List *
 ExpandAllTables(ParseState *pstate)
@@ -378,7 +409,7 @@ ExpandAllTables(ParseState *pstate)
 
        /* SELECT *; */
        if (rtable == NIL)
-               elog(ERROR, "Wildcard with no tables specified.");
+               elog(ERROR, "Wildcard with no tables specified not allowed");
 
        foreach(rt, rtable)
        {
@@ -393,7 +424,7 @@ ExpandAllTables(ParseState *pstate)
                        continue;
 
                target = nconc(target,
-                                          expandAll(pstate, rte->relname, rte->refname,
+                                          expandAll(pstate, rte->ref->relname, rte->ref,
                                                                 &pstate->p_last_resno));
        }
        return target;
index c4e3149..d3c2534 100644 (file)
@@ -3,7 +3,7 @@
  *                       out of its tuple
  *
  * IDENTIFICATION
- *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.39 2000/01/15 22:43:24 tgl Exp $
+ *       $Header: /cvsroot/pgsql/src/backend/utils/adt/ruleutils.c,v 1.40 2000/02/15 03:37:56 thomas Exp $
  *
  *       This software is copyrighted by Jan Wieck - Hamburg.
  *
@@ -922,9 +922,9 @@ get_select_query_def(Query *query, deparse_context *context)
                        continue;
 
                rte = (RangeTblEntry *) lfirst(l);
-               if (!strcmp(rte->refname, "*NEW*"))
+               if (!strcmp(rte->ref->relname, "*NEW*"))
                        continue;
-               if (!strcmp(rte->refname, "*CURRENT*"))
+               if (!strcmp(rte->ref->relname, "*CURRENT*"))
                        continue;
 
                rt_constonly = FALSE;
@@ -980,10 +980,10 @@ get_select_query_def(Query *query, deparse_context *context)
                        {
                                rte = (RangeTblEntry *) lfirst(l);
 
-                               if (!strcmp(rte->refname, "*NEW*"))
+                               if (!strcmp(rte->ref->relname, "*NEW*"))
                                        continue;
 
-                               if (!strcmp(rte->refname, "*CURRENT*"))
+                               if (!strcmp(rte->ref->relname, "*CURRENT*"))
                                        continue;
 
                                appendStringInfo(buf, sep);
@@ -991,9 +991,19 @@ get_select_query_def(Query *query, deparse_context *context)
                                appendStringInfo(buf, "%s%s",
                                                                 quote_identifier(rte->relname),
                                                                 inherit_marker(rte));
-                               if (strcmp(rte->relname, rte->refname) != 0)
+                               if (strcmp(rte->relname, rte->ref->relname) != 0)
+                               {
+                                       List *col;
                                        appendStringInfo(buf, " %s",
-                                                                        quote_identifier(rte->refname));
+                                                                        quote_identifier(rte->ref->relname));
+                                       appendStringInfo(buf, " (");
+                                       foreach (col, rte->ref->attrs)
+                                       {
+                                               if (col != lfirst(rte->ref->attrs))
+                                                       appendStringInfo(buf, ", ");
+                                               appendStringInfo(buf, "%s", strVal(col));
+                                       }
+                               }
                        }
                }
        }
@@ -1071,9 +1081,9 @@ get_insert_query_def(Query *query, deparse_context *context)
                        continue;
 
                rte = (RangeTblEntry *) lfirst(l);
-               if (!strcmp(rte->refname, "*NEW*"))
+               if (!strcmp(rte->ref->relname, "*NEW*"))
                        continue;
-               if (!strcmp(rte->refname, "*CURRENT*"))
+               if (!strcmp(rte->ref->relname, "*CURRENT*"))
                        continue;
 
                rt_constonly = FALSE;
@@ -1241,13 +1251,13 @@ get_rule_expr(Node *node, deparse_context *context)
 
                                if (context->varprefix)
                                {
-                                       if (!strcmp(rte->refname, "*NEW*"))
+                                       if (!strcmp(rte->ref->relname, "*NEW*"))
                                                appendStringInfo(buf, "new.");
-                                       else if (!strcmp(rte->refname, "*CURRENT*"))
+                                       else if (!strcmp(rte->ref->relname, "*CURRENT*"))
                                                appendStringInfo(buf, "old.");
                                        else
                                                appendStringInfo(buf, "%s.",
-                                                                                quote_identifier(rte->refname));
+                                                                                quote_identifier(rte->ref->relname));
                                }
                                appendStringInfo(buf, "%s",
                                                quote_identifier(get_attribute_name(rte->relid,
index 2b3c533..f934eb5 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: makefuncs.h,v 1.22 2000/01/26 05:58:16 momjian Exp $
+ * $Id: makefuncs.h,v 1.23 2000/02/15 03:38:13 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,4 +46,7 @@ extern Const *makeConst(Oid consttype,
                  bool constisset,
                  bool constiscast);
 
+extern Attr *
+makeAttr(char *relname, char *attname);
+
 #endif  /* MAKEFUNC_H */
index 288e7f9..6eb4761 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsenodes.h,v 1.97 2000/01/27 18:11:44 tgl Exp $
+ * $Id: parsenodes.h,v 1.98 2000/02/15 03:38:14 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1031,7 +1031,7 @@ typedef struct RangeVar
 {
        NodeTag         type;
        RelExpr    *relExpr;            /* the relation expression */
-       char       *name;                       /* the name to be referenced (optional) */
+       Attr       *name;                       /* the name to be referenced (optional) */
 } RangeVar;
 
 /*
@@ -1064,9 +1064,11 @@ typedef struct JoinExpr
 {
        NodeTag         type;
        int                     jointype;
-       RangeVar   *larg;
-       Node       *rarg;
-       List       *quals;
+       bool            isNatural;              /* Natural join? Will need to shape table */
+       Node       *larg;                       /* RangeVar or join expression */
+       Node       *rarg;                       /* RangeVar or join expression */
+       Attr       *alias;                      /* table and column aliases, if any */
+       List       *quals;                      /* qualifiers on join, if any */
 } JoinExpr;
 
 
@@ -1122,8 +1124,10 @@ typedef struct RangeTblEntry
 {
        NodeTag         type;
        char       *relname;            /* real name of the relation */
-       char       *refname;            /* the reference name (as specified in the
-                                                                * FROM clause) */
+//     char       *refname;            /* reference name (given in FROM clause) */
+#ifndef DISABLE_JOIN_SYNTAX
+       Attr       *ref;                        /* reference names (given in FROM clause) */
+#endif
        Oid                     relid;                  /* OID of the relation */
        bool            inh;                    /* inheritance requested? */
        bool            inFromCl;               /* present in FROM clause */
index 235a02b..58b8fc6 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_clause.h,v 1.15 2000/01/27 18:11:47 tgl Exp $
+ * $Id: parse_clause.h,v 1.16 2000/02/15 03:38:28 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 #include "parser/parse_node.h"
 
-extern void makeRangeTable(ParseState *pstate, List *frmList, Node **qual);
+extern void makeRangeTable(ParseState *pstate, List *frmList);
 extern void setTargetTable(ParseState *pstate, char *relname);
-extern Node *transformWhereClause(ParseState *pstate, Node *where,
-                                                                 Node *using);
+extern Node *transformWhereClause(ParseState *pstate, Node *where);
 extern List *transformGroupClause(ParseState *pstate, List *grouplist,
                                                                  List *targetlist);
 extern List *transformSortClause(ParseState *pstate, List *orderlist,
index 4ba502e..16641b5 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_node.h,v 1.17 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parse_node.h,v 1.18 2000/02/15 03:38:29 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "nodes/parsenodes.h"
 #include "utils/rel.h"
 
-/* state information used during parse analysis */
+/* State information used during parse analysis
+ * p_join_quals is a list of qualification expressions
+ * found in the FROM clause. Needs to be available later
+ * to merge with other qualifiers from the WHERE clause.
+ */
 typedef struct ParseState
 {
        int                     p_last_resno;
@@ -30,6 +34,9 @@ typedef struct ParseState
        bool            p_in_where_clause;
        Relation        p_target_relation;
        RangeTblEntry *p_target_rangetblentry;
+       List       *p_shape;
+       List       *p_alias;
+       Node       *p_join_quals;
 } ParseState;
 
 extern ParseState *make_parsestate(ParseState *parentParseState);
index b9fe0b1..5ba5db3 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parse_relation.h,v 1.14 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parse_relation.h,v 1.15 2000/02/15 03:38:29 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
 
 extern RangeTblEntry *refnameRangeTableEntry(ParseState *pstate, char *refname);
 extern int refnameRangeTablePosn(ParseState *pstate,
-                                         char *refname, int *sublevels_up);
+                                                                char *refname,
+                                                                int *sublevels_up);
 extern RangeTblEntry *colnameRangeTableEntry(ParseState *pstate, char *colname);
 extern RangeTblEntry *addRangeTableEntry(ParseState *pstate,
-                                  char *relname,
-                                  char *refname,
-                                  bool inh,
-                                  bool inFromCl,
-                                  bool inJoinSet);
-extern List *expandAll(ParseState *pstate, char *relname, char *refname,
-                 int *this_resno);
+                                                                                char *relname,
+                                                                                Attr *ref,
+                                                                                bool inh,
+                                                                                bool inFromCl,
+                                                                                bool inJoinSet);
+extern Attr *expandTable(ParseState *pstate, char *refname, bool getaliases);
+extern List *expandAll(ParseState *pstate, char *relname, Attr *ref,
+                                          int *this_resno);
 extern int     attnameAttNum(Relation rd, char *a);
+extern int     specialAttNum(char *a);
 extern bool attnameIsSet(Relation rd, char *name);
 extern int     attnumAttNelems(Relation rd, int attid);
 extern Oid     attnumTypeId(Relation rd, int attid);
index 979ebf3..3f5e09c 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2000, PostgreSQL, Inc
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: parsetree.h,v 1.8 2000/01/26 05:58:27 momjian Exp $
+ * $Id: parsetree.h,v 1.9 2000/02/15 03:38:29 thomas Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -39,8 +39,8 @@
  */
 
 #define rt_relname(rt_entry) \
-         ((!strcmp(((rt_entry)->refname),"*CURRENT*") ||\
-               !strcmp(((rt_entry)->refname),"*NEW*")) ? ((rt_entry)->refname) : \
+         ((!strcmp(((rt_entry)->ref->relname),"*CURRENT*") ||\
+               !strcmp(((rt_entry)->ref->relname),"*NEW*")) ? ((rt_entry)->ref->relname) : \
                ((char *)(rt_entry)->relname))
 
 /*