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