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 89c20ce5fa70ec2023087dceeba0f4ff39bce5ef..2840e40633f5c63319bc405a6de8161c4e55f281 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 8406416b76516a9266a2db1a2cc5d886b10bcb7d..2b152b2fe5b0e7df8c90563035a1486ef343023e 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 8742b895dfd9091eea17305143ed44f3fc93b370..f4bb18762b805325048436507f9aea982bd6a86b 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 899885dc316e8cb4a5821b05f0095f71dac042fb..e3d1862f4e1fccbd4e8a0886cd576903187e6661 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 c5c9cb0782e7012dabf01c3905c644b7f0c6781f..adf0c7f1987c2ffe8dd28542ead1f778336c60f0 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 5888f49515e26d88b1ea989821a0bd1c2e8dc87e..3ddc8d6c98a518cc43c91cdd4fb1c321e98e2217 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 $
  *
  *-------------------------------------------------------------------------
  */
@@ -95,6 +95,17 @@ _equalExpr(Expr *a, Expr *b)
    return true;
 }
 
+static bool
+_equalAttr(Attr *a, Attr *b)
+{
+   if (!strcmp(a->relname, b->relname))
+       return false;
+   if (length(a->attrs) != length(b->attrs))
+       return false;
+
+   return equal(a->attrs, b->attrs);
+}
+
 static bool
 _equalVar(Var *a, Var *b)
 {
@@ -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 ab308fe31019941fe61447c261d03862817013f6..690da02de85f5ec10190b924a83102f2793d40a2 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 221a83d713e3319c69aac03089d14608bd2ef9d8..e42930ef87b64495ab60f12d0b998044eb39bf6d 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 8923510e1b43261b0d0441f762b8c4ceca2a6937..e4c35cc277fb9a4850e8b0ad2fbe69db9b4b3f2e 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 ffba95949ad8ffd2b3eb0abfd98d21596c1e1dc6..a84b829950f5140d7991a3ab54deaae34434c576 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 38db7def0b171bdcf989f2494ef85cce8385e139..7d56b603b85c1766676a8520a3ad8a2d7ff963e7 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 95005f166f164187d44e3c547b8ae70d2b664971..9a86cb23488dd051012213c8e522bdee6a70324b 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 53b4eec2cb6197f4cc2cc4ab8745e15481a519eb..664a0dfaaa57e2c652e48ec7506de7756239a8f7 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 a9dda032cdea516873692ed3b3e1b4e68f485d7c..5f7369af0078548142636ee91d9a556b87d5e5ad 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 3c23a29246d71e749c57f0ed7b2c4a88fc876a3e..afaa55e54f1f3c005081d44d69446c142e7a47a5 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 b22691fa3c2cfe2cf62e20194b3a5eb0732c4491..d0a3eb1edb421b2936a44c2ee9a4effc46f5241b 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 76e28fbfec9d4cabc7b0dfc805ffb51e31046417..365378f40720180f62627c1adf36d250246d44d9 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 96863179447dc66037c945865c3f86d73f571d15..06afc867903a051822d2e6903ef90f43f68c803a 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 4e72a7c029b3917e14af72303d997904058ffe32..02a3cd2de092b8e023ab462a227062670458c05b 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 653afe7058999e0d55166ccf70613cf259f25e20..9d00e1789e1cec855300e03266980208e275b37e 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 c4e31491604f556433878f6794fdde7ff162b5f6..d3c25345057a9407350800a37f01c6afcbc793ec 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 2b3c5339c61fbad9a8eacf04b0f4a2dd8bca4ca6..f934eb5e63a0c02a09730f0ae861c2377a40dcee 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 288e7f96b8d8174d5ab892202f1313f340167a6f..6eb47618c5e02ee14961e94ea4722291851ed187 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 235a02bc4c2680e54de07de7f471bef48635774c..58b8fc60fa49d6c8b0fcc5fd12f3f529ad70f7c1 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 4ba502ebaf359ff9fb1670745f6a6db7f7d39bb5..16641b530a2cb975e6ef65c8d2fbd29c3ae70c11 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 b9fe0b1b778a72d13f4014fec2836e74456244cc..5ba5db3f9d0af56cf260d9f574d77f3eed1d01c2 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 979ebf327e856696126cb0658f860ec78b58e104..3f5e09cc1df48a74d8b89fc3a55284a9eb1a21ac 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))
 
 /*