Carry column aliases from the parser frontend. Enables queries like
SELECT a FROM t1 tx (a); Allow join syntax, including queries like SELECT * FROM t1 NATURAL JOIN t2; Update RTE structure to hold column aliases in an Attr structure.
This commit is contained in:
parent
92c8437d8d
commit
a344a6e7b5
@ -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.
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
||||
a->relname = relname;
|
||||
a->paramNo = NULL;
|
||||
a->attrs = lcons(makeString(attname), NIL);
|
||||
a->indirection = NULL;
|
||||
Assert(length(attr->attrs) == 1);
|
||||
|
||||
return a;
|
||||
val = lfirst(attr->attrs);
|
||||
|
||||
Assert(IsA(val, String));
|
||||
|
||||
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);
|
||||
Attr *attr = lfirst(col);
|
||||
|
||||
e->oper = OP;
|
||||
e->opname = "=";
|
||||
e->lexpr = (Node *) lattr;
|
||||
e->rexpr = (Node *) rattr;
|
||||
|
||||
if (expr != NULL)
|
||||
if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
|
||||
{
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
|
||||
a->oper = AND;
|
||||
a->opname = NULL;
|
||||
a->lexpr = (Node *) expr;
|
||||
a->rexpr = (Node *) e;
|
||||
expr = a;
|
||||
lattr = attr;
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (col, rightList)
|
||||
{
|
||||
Attr *attr = lfirst(col);
|
||||
|
||||
if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
|
||||
{
|
||||
rattr = attr;
|
||||
break;
|
||||
}
|
||||
else
|
||||
expr = e;
|
||||
}
|
||||
|
||||
/* otherwise, we have an expression from an ON clause... */
|
||||
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)
|
||||
{
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
|
||||
a->oper = AND;
|
||||
a->opname = NULL;
|
||||
a->lexpr = (Node *) expr;
|
||||
a->rexpr = (Node *) e;
|
||||
expr = a;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (expr != NULL)
|
||||
{
|
||||
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;
|
||||
}
|
||||
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;
|
||||
|
||||
if (IsA((Node *) j->rarg, RangeVar))
|
||||
rname = transformTableEntry(pstate, (RangeVar *) j->rarg);
|
||||
/* 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
|
||||
elog(ERROR, "Nested JOINs are not yet supported");
|
||||
{
|
||||
Assert(IsA(j->larg, RangeVar));
|
||||
l_rte = transformTableEntry(pstate, (RangeVar *) j->larg);
|
||||
l_name = expandTable(pstate, l_rte->ref->relname, TRUE);
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
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() */
|
||||
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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,
|
||||
|
@ -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 */
|
||||
|
@ -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 */
|
||||
|
@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,10 +16,9 @@
|
||||
|
||||
#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,
|
||||
|
@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -16,7 +16,11 @@
|
||||
#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);
|
||||
|
@ -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 $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@ -18,17 +18,20 @@
|
||||
|
||||
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);
|
||||
|
@ -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))
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user