mirror of
https://github.com/postgres/postgres.git
synced 2025-11-10 17:42:29 +03:00
Ye-old pgindent run. Same 4-space tabs.
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.70 2000/04/07 13:39:34 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.71 2000/04/12 17:15:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -227,7 +227,7 @@ static ScanKeyword ScanKeywords[] = {
|
||||
{"stdin", STDIN},
|
||||
{"stdout", STDOUT},
|
||||
{"substring", SUBSTRING},
|
||||
{"sysid", SYSID},
|
||||
{"sysid", SYSID},
|
||||
{"table", TABLE},
|
||||
{"temp", TEMP},
|
||||
{"temporary", TEMPORARY},
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.36 2000/03/17 02:36:17 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_agg.c,v 1.37 2000/04/12 17:15:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -24,15 +24,16 @@
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
typedef struct {
|
||||
typedef struct
|
||||
{
|
||||
ParseState *pstate;
|
||||
List *groupClauses;
|
||||
} check_ungrouped_columns_context;
|
||||
|
||||
static void check_ungrouped_columns(Node *node, ParseState *pstate,
|
||||
List *groupClauses);
|
||||
List *groupClauses);
|
||||
static bool check_ungrouped_columns_walker(Node *node,
|
||||
check_ungrouped_columns_context *context);
|
||||
check_ungrouped_columns_context *context);
|
||||
|
||||
/*
|
||||
* check_ungrouped_columns -
|
||||
@@ -46,7 +47,7 @@ static bool check_ungrouped_columns_walker(Node *node,
|
||||
*
|
||||
* NOTE: in the case of a SubLink, expression_tree_walker does not descend
|
||||
* into the subquery. This means we will fail to detect ungrouped columns
|
||||
* that appear as outer-level variables within a subquery. That case seems
|
||||
* that appear as outer-level variables within a subquery. That case seems
|
||||
* unreasonably hard to handle here. Instead, we expect the planner to check
|
||||
* for ungrouped columns after it's found all the outer-level references
|
||||
* inside the subquery and converted them into a list of parameters for the
|
||||
@@ -56,7 +57,7 @@ static void
|
||||
check_ungrouped_columns(Node *node, ParseState *pstate,
|
||||
List *groupClauses)
|
||||
{
|
||||
check_ungrouped_columns_context context;
|
||||
check_ungrouped_columns_context context;
|
||||
|
||||
context.pstate = pstate;
|
||||
context.groupClauses = groupClauses;
|
||||
@@ -71,13 +72,16 @@ check_ungrouped_columns_walker(Node *node,
|
||||
|
||||
if (node == NULL)
|
||||
return false;
|
||||
if (IsA(node, Const) || IsA(node, Param))
|
||||
if (IsA(node, Const) ||IsA(node, Param))
|
||||
return false; /* constants are always acceptable */
|
||||
|
||||
/*
|
||||
* If we find an aggregate function, do not recurse into its arguments.
|
||||
* If we find an aggregate function, do not recurse into its
|
||||
* arguments.
|
||||
*/
|
||||
if (IsA(node, Aggref))
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Check to see if subexpression as a whole matches any GROUP BY item.
|
||||
* We need to do this at every recursion level so that we recognize
|
||||
@@ -88,17 +92,19 @@ check_ungrouped_columns_walker(Node *node,
|
||||
if (equal(node, lfirst(gl)))
|
||||
return false; /* acceptable, do not descend more */
|
||||
}
|
||||
|
||||
/*
|
||||
* If we have an ungrouped Var, we have a failure --- unless it is an
|
||||
* outer-level Var. In that case it's a constant as far as this query
|
||||
* level is concerned, and we can accept it. (If it's ungrouped as far
|
||||
* as the upper query is concerned, that's someone else's problem...)
|
||||
* level is concerned, and we can accept it. (If it's ungrouped as
|
||||
* far as the upper query is concerned, that's someone else's
|
||||
* problem...)
|
||||
*/
|
||||
if (IsA(node, Var))
|
||||
{
|
||||
Var *var = (Var *) node;
|
||||
RangeTblEntry *rte;
|
||||
char *attname;
|
||||
Var *var = (Var *) node;
|
||||
RangeTblEntry *rte;
|
||||
char *attname;
|
||||
|
||||
if (var->varlevelsup > 0)
|
||||
return false; /* outer-level Var is acceptable */
|
||||
@@ -107,7 +113,7 @@ check_ungrouped_columns_walker(Node *node,
|
||||
(int) var->varno <= length(context->pstate->p_rtable));
|
||||
rte = rt_fetch(var->varno, context->pstate->p_rtable);
|
||||
attname = get_attname(rte->relid, var->varattno);
|
||||
if (! attname)
|
||||
if (!attname)
|
||||
elog(ERROR, "cache lookup of attribute %d in relation %u failed",
|
||||
var->varattno, rte->relid);
|
||||
elog(ERROR, "Attribute %s.%s must be GROUPed or used in an aggregate function",
|
||||
@@ -139,9 +145,9 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
|
||||
/*
|
||||
* Aggregates must never appear in WHERE clauses. (Note this check
|
||||
* should appear first to deliver an appropriate error message;
|
||||
* otherwise we are likely to complain about some innocent variable
|
||||
* in the target list, which is outright misleading if the problem
|
||||
* is in WHERE.)
|
||||
* otherwise we are likely to complain about some innocent variable in
|
||||
* the target list, which is outright misleading if the problem is in
|
||||
* WHERE.)
|
||||
*/
|
||||
if (contain_agg_clause(qry->qual))
|
||||
elog(ERROR, "Aggregates not allowed in WHERE clause");
|
||||
@@ -149,14 +155,14 @@ parseCheckAggregates(ParseState *pstate, Query *qry)
|
||||
/*
|
||||
* No aggregates allowed in GROUP BY clauses, either.
|
||||
*
|
||||
* While we are at it, build a list of the acceptable GROUP BY expressions
|
||||
* for use by check_ungrouped_columns() (this avoids repeated scans of the
|
||||
* targetlist within the recursive routine...)
|
||||
* While we are at it, build a list of the acceptable GROUP BY
|
||||
* expressions for use by check_ungrouped_columns() (this avoids
|
||||
* repeated scans of the targetlist within the recursive routine...)
|
||||
*/
|
||||
foreach(tl, qry->groupClause)
|
||||
{
|
||||
GroupClause *grpcl = lfirst(tl);
|
||||
Node *expr;
|
||||
Node *expr;
|
||||
|
||||
expr = get_sortgroupclause_expr(grpcl, qry->targetList);
|
||||
if (contain_agg_clause(expr))
|
||||
@@ -198,16 +204,16 @@ ParseAgg(ParseState *pstate, char *aggname, Oid basetype,
|
||||
/*
|
||||
* There used to be a really ugly hack for count(*) here.
|
||||
*
|
||||
* It's gone. Now, the grammar transforms count(*) into count(1),
|
||||
* which does the right thing. (It didn't use to do the right thing,
|
||||
* because the optimizer had the wrong ideas about semantics of queries
|
||||
* without explicit variables. Fixed as of Oct 1999 --- tgl.)
|
||||
* It's gone. Now, the grammar transforms count(*) into count(1), which
|
||||
* does the right thing. (It didn't use to do the right thing,
|
||||
* because the optimizer had the wrong ideas about semantics of
|
||||
* queries without explicit variables. Fixed as of Oct 1999 --- tgl.)
|
||||
*
|
||||
* Since "1" never evaluates as null, we currently have no need of
|
||||
* the "usenulls" flag, but it should be kept around; in fact, we should
|
||||
* Since "1" never evaluates as null, we currently have no need of the
|
||||
* "usenulls" flag, but it should be kept around; in fact, we should
|
||||
* extend the pg_aggregate table to let usenulls be specified as an
|
||||
* attribute of user-defined aggregates. In the meantime, usenulls
|
||||
* is just always set to "false".
|
||||
* attribute of user-defined aggregates. In the meantime, usenulls is
|
||||
* just always set to "false".
|
||||
*/
|
||||
|
||||
aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.58 2000/03/23 07:38:30 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_clause.c,v 1.59 2000/04/12 17:15:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -33,15 +33,16 @@
|
||||
static char *clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};
|
||||
|
||||
static TargetEntry *findTargetlistEntry(ParseState *pstate, Node *node,
|
||||
List *tlist, int clause);
|
||||
List *tlist, int clause);
|
||||
static void parseFromClause(ParseState *pstate, List *frmList);
|
||||
RangeTblEntry *transformTableEntry(ParseState *pstate, RangeVar *r);
|
||||
static List *addTargetToSortList(TargetEntry *tle, List *sortlist,
|
||||
List *targetlist, char *opname);
|
||||
List *targetlist, char *opname);
|
||||
static bool exprIsInSortList(Node *expr, List *sortList, List *targetList);
|
||||
|
||||
#ifndef DISABLE_OUTER_JOINS
|
||||
static Node *transformUsingClause(ParseState *pstate, List *using, List *left, List *right);
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -63,8 +64,8 @@ makeRangeTable(ParseState *pstate, List *frmList)
|
||||
*
|
||||
* Note that the target is not marked as either inFromCl or inJoinSet.
|
||||
* For INSERT, we don't want the target to be joined to; it's a
|
||||
* destination of tuples, not a source. For UPDATE/DELETE, we do
|
||||
* need to scan or join the target. This will happen without the
|
||||
* destination of tuples, not a source. For UPDATE/DELETE, we do
|
||||
* need to scan or join the target. This will happen without the
|
||||
* inJoinSet flag because the planner's preprocess_targetlist()
|
||||
* adds the destination's CTID attribute to the targetlist, and
|
||||
* therefore the destination will be a referenced table even if
|
||||
@@ -94,7 +95,7 @@ setTargetTable(ParseState *pstate, char *relname)
|
||||
|
||||
|
||||
Node *
|
||||
mergeInnerJoinQuals(ParseState *pstate, Node *clause);
|
||||
mergeInnerJoinQuals(ParseState *pstate, Node *clause);
|
||||
|
||||
Node *
|
||||
mergeInnerJoinQuals(ParseState *pstate, Node *clause)
|
||||
@@ -119,7 +120,7 @@ mergeInnerJoinQuals(ParseState *pstate, Node *clause)
|
||||
pstate->p_join_quals = NULL;
|
||||
|
||||
return (Node *) expr;
|
||||
} /* mergeInnerJoinQuals() */
|
||||
} /* mergeInnerJoinQuals() */
|
||||
|
||||
/*
|
||||
* transformWhereClause -
|
||||
@@ -150,12 +151,12 @@ transformWhereClause(ParseState *pstate, Node *clause)
|
||||
|
||||
#ifndef DISABLE_JOIN_SYNTAX
|
||||
char *
|
||||
AttrString(Attr *attr);
|
||||
AttrString(Attr *attr);
|
||||
|
||||
char *
|
||||
AttrString(Attr *attr)
|
||||
{
|
||||
Value *val;
|
||||
Value *val;
|
||||
|
||||
Assert(length(attr->attrs) == 1);
|
||||
|
||||
@@ -167,17 +168,18 @@ AttrString(Attr *attr)
|
||||
}
|
||||
|
||||
List *
|
||||
ListTableAsAttrs(ParseState *pstate, char *table);
|
||||
ListTableAsAttrs(ParseState *pstate, char *table);
|
||||
List *
|
||||
ListTableAsAttrs(ParseState *pstate, char *table)
|
||||
{
|
||||
Attr *attr = expandTable(pstate, table, TRUE);
|
||||
List *rlist = NIL;
|
||||
List *col;
|
||||
Attr *attr = expandTable(pstate, table, TRUE);
|
||||
List *rlist = NIL;
|
||||
List *col;
|
||||
|
||||
foreach(col, attr->attrs)
|
||||
{
|
||||
Attr *a = makeAttr(table, strVal((Value *) lfirst(col)));
|
||||
Attr *a = makeAttr(table, strVal((Value *) lfirst(col)));
|
||||
|
||||
rlist = lappend(rlist, a);
|
||||
}
|
||||
|
||||
@@ -185,25 +187,26 @@ ListTableAsAttrs(ParseState *pstate, char *table)
|
||||
}
|
||||
|
||||
List *
|
||||
makeUniqueAttrList(List *candidates, List *idents);
|
||||
makeUniqueAttrList(List *candidates, List *idents);
|
||||
List *
|
||||
makeUniqueAttrList(List *attrs, List *filter)
|
||||
{
|
||||
List *result = NULL;
|
||||
List *candidate;
|
||||
List *result = NULL;
|
||||
List *candidate;
|
||||
|
||||
foreach(candidate, attrs)
|
||||
{
|
||||
List *fmember;
|
||||
bool match = FALSE;
|
||||
Attr *cattr = lfirst(candidate);
|
||||
List *fmember;
|
||||
bool match = FALSE;
|
||||
Attr *cattr = lfirst(candidate);
|
||||
|
||||
Assert(IsA(cattr, Attr));
|
||||
Assert(length(cattr->attrs) == 1);
|
||||
|
||||
foreach(fmember, filter)
|
||||
{
|
||||
Attr *fattr = lfirst(fmember);
|
||||
Attr *fattr = lfirst(fmember);
|
||||
|
||||
Assert(IsA(fattr, Attr));
|
||||
Assert(length(fattr->attrs) == 1);
|
||||
|
||||
@@ -222,19 +225,19 @@ makeUniqueAttrList(List *attrs, List *filter)
|
||||
}
|
||||
|
||||
List *
|
||||
makeAttrList(Attr *attr);
|
||||
makeAttrList(Attr *attr);
|
||||
|
||||
List *
|
||||
makeAttrList(Attr *attr)
|
||||
{
|
||||
List *result = NULL;
|
||||
List *result = NULL;
|
||||
|
||||
char *name = attr->relname;
|
||||
List *col;
|
||||
char *name = attr->relname;
|
||||
List *col;
|
||||
|
||||
foreach (col, attr->attrs)
|
||||
foreach(col, attr->attrs)
|
||||
{
|
||||
Attr *newattr = makeAttr(name, strVal((Value *) lfirst(col)));
|
||||
Attr *newattr = makeAttr(name, strVal((Value *) lfirst(col)));
|
||||
|
||||
result = lappend(result, newattr);
|
||||
}
|
||||
@@ -247,13 +250,13 @@ makeAttrList(Attr *attr)
|
||||
* with one attribute name per node.
|
||||
*/
|
||||
List *
|
||||
ExpandAttrs(Attr *attr);
|
||||
ExpandAttrs(Attr *attr);
|
||||
List *
|
||||
ExpandAttrs(Attr *attr)
|
||||
{
|
||||
List *col;
|
||||
char *relname = attr->relname;
|
||||
List *rlist = NULL;
|
||||
List *col;
|
||||
char *relname = attr->relname;
|
||||
List *rlist = NULL;
|
||||
|
||||
Assert(attr != NULL);
|
||||
|
||||
@@ -262,7 +265,7 @@ ExpandAttrs(Attr *attr)
|
||||
|
||||
foreach(col, attr->attrs)
|
||||
{
|
||||
Attr *attr = lfirst(col);
|
||||
Attr *attr = lfirst(col);
|
||||
|
||||
rlist = lappend(rlist, makeAttr(relname, AttrString(attr)));
|
||||
}
|
||||
@@ -281,18 +284,20 @@ transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *
|
||||
|
||||
foreach(using, usingList)
|
||||
{
|
||||
List *col;
|
||||
A_Expr *e;
|
||||
List *col;
|
||||
A_Expr *e;
|
||||
|
||||
Attr *uattr = lfirst(using);
|
||||
Attr *lattr = NULL, *rattr = NULL;
|
||||
Attr *uattr = lfirst(using);
|
||||
Attr *lattr = NULL,
|
||||
*rattr = NULL;
|
||||
|
||||
/* find the first instances of this column in the shape list
|
||||
* and the last table in the shape list...
|
||||
/*
|
||||
* find the first instances of this column in the shape list and
|
||||
* the last table in the shape list...
|
||||
*/
|
||||
foreach (col, leftList)
|
||||
foreach(col, leftList)
|
||||
{
|
||||
Attr *attr = lfirst(col);
|
||||
Attr *attr = lfirst(col);
|
||||
|
||||
if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
|
||||
{
|
||||
@@ -300,9 +305,9 @@ transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *
|
||||
break;
|
||||
}
|
||||
}
|
||||
foreach (col, rightList)
|
||||
foreach(col, rightList)
|
||||
{
|
||||
Attr *attr = lfirst(col);
|
||||
Attr *attr = lfirst(col);
|
||||
|
||||
if (strcmp(AttrString(attr), AttrString(uattr)) == 0)
|
||||
{
|
||||
@@ -334,7 +339,8 @@ transformUsingClause(ParseState *pstate, List *usingList, List *leftList, List *
|
||||
}
|
||||
|
||||
return ((Node *) transformExpr(pstate, (Node *) expr, EXPR_COLUMN_FIRST));
|
||||
} /* transformUsiongClause() */
|
||||
} /* transformUsiongClause() */
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -343,9 +349,11 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
|
||||
{
|
||||
RelExpr *baserel = r->relExpr;
|
||||
char *relname = baserel->relname;
|
||||
|
||||
#if 0
|
||||
char *refname;
|
||||
List *columns;
|
||||
|
||||
#endif
|
||||
RangeTblEntry *rte;
|
||||
|
||||
@@ -368,7 +376,7 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
|
||||
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"));
|
||||
((length(r->name->attrs) != 1) ? "aliases" : "alias"));
|
||||
|
||||
aliasList = nconc(aliasList, r->name->attrs);
|
||||
}
|
||||
@@ -380,9 +388,7 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(NOTICE, "transformTableEntry: column aliases not handled (internal error)");
|
||||
}
|
||||
#else
|
||||
elog(ERROR, "Column aliases not yet supported");
|
||||
#endif
|
||||
@@ -412,7 +418,7 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
|
||||
baserel->inh, TRUE, TRUE);
|
||||
|
||||
return rte;
|
||||
} /* transformTableEntry() */
|
||||
} /* transformTableEntry() */
|
||||
|
||||
|
||||
/*
|
||||
@@ -432,7 +438,7 @@ transformTableEntry(ParseState *pstate, RangeVar *r)
|
||||
static void
|
||||
parseFromClause(ParseState *pstate, List *frmList)
|
||||
{
|
||||
List *fl;
|
||||
List *fl;
|
||||
|
||||
foreach(fl, frmList)
|
||||
{
|
||||
@@ -452,17 +458,17 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
|
||||
/* Plain vanilla inner join, just like we've always had? */
|
||||
if (IsA(n, RangeVar))
|
||||
{
|
||||
transformTableEntry(pstate, (RangeVar *) n);
|
||||
}
|
||||
|
||||
/* A newfangled join expression? */
|
||||
else if (IsA(n, JoinExpr))
|
||||
{
|
||||
#ifndef DISABLE_JOIN_SYNTAX
|
||||
RangeTblEntry *l_rte, *r_rte;
|
||||
Attr *l_name, *r_name = NULL;
|
||||
JoinExpr *j = (JoinExpr *) n;
|
||||
RangeTblEntry *l_rte,
|
||||
*r_rte;
|
||||
Attr *l_name,
|
||||
*r_name = NULL;
|
||||
JoinExpr *j = (JoinExpr *) n;
|
||||
|
||||
if (j->alias != NULL)
|
||||
elog(ERROR, "JOIN table aliases are not supported");
|
||||
@@ -471,7 +477,7 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
if (IsA(j->larg, JoinExpr))
|
||||
{
|
||||
parseFromClause(pstate, lcons(j->larg, NIL));
|
||||
l_name = ((JoinExpr *)j->larg)->alias;
|
||||
l_name = ((JoinExpr *) j->larg)->alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -483,7 +489,7 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
if (IsA(j->rarg, JoinExpr))
|
||||
{
|
||||
parseFromClause(pstate, lcons(j->rarg, NIL));
|
||||
l_name = ((JoinExpr *)j->larg)->alias;
|
||||
l_name = ((JoinExpr *) j->larg)->alias;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -492,25 +498,30 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
r_name = expandTable(pstate, r_rte->eref->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.
|
||||
/*
|
||||
* 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;
|
||||
List *lx,
|
||||
*rx;
|
||||
List *rlist = NULL;
|
||||
|
||||
foreach(lx, l_name->attrs)
|
||||
{
|
||||
Ident *id = NULL;
|
||||
Value *l_col = lfirst(lx);
|
||||
Ident *id = NULL;
|
||||
Value *l_col = lfirst(lx);
|
||||
|
||||
Assert(IsA(l_col, String));
|
||||
|
||||
foreach(rx, r_name->attrs)
|
||||
{
|
||||
Value *r_col = lfirst(rx);
|
||||
Value *r_col = lfirst(rx);
|
||||
|
||||
Assert(IsA(r_col, String));
|
||||
|
||||
if (strcmp(strVal(l_col), strVal(r_col)) == 0)
|
||||
@@ -534,30 +545,32 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
{
|
||||
/* CROSS JOIN */
|
||||
if (j->quals == NULL)
|
||||
{
|
||||
printf("CROSS JOIN...\n");
|
||||
}
|
||||
|
||||
/* JOIN/USING
|
||||
* This is an inner join, so rip apart the join node and
|
||||
* transform into a traditional FROM list. NATURAL JOIN
|
||||
* and JOIN USING both change the shape of the result.
|
||||
* Need to generate a list of result columns to use for
|
||||
* target list expansion and validation.
|
||||
/*
|
||||
* JOIN/USING This is an inner join, so rip apart the join
|
||||
* node and transform into a traditional FROM list.
|
||||
* NATURAL JOIN and JOIN USING both change the shape of
|
||||
* the result. Need to generate a list of result columns
|
||||
* to use for target list expansion and validation.
|
||||
*/
|
||||
else if (IsA(j->quals, List))
|
||||
{
|
||||
/*
|
||||
* List of Ident nodes means column names from a real USING
|
||||
* clause. Determine the shape of the joined table.
|
||||
*/
|
||||
List *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);
|
||||
/*
|
||||
* List of Ident nodes means column names from a real
|
||||
* USING clause. Determine the shape of the joined
|
||||
* table.
|
||||
*/
|
||||
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));
|
||||
@@ -566,14 +579,15 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
nodeToString(l_cols), nodeToString(r_cols));
|
||||
|
||||
/* Columns from the USING clause... */
|
||||
ucols = (List *)j->quals;
|
||||
ucols = (List *) j->quals;
|
||||
foreach(ucol, ucols)
|
||||
{
|
||||
List *col;
|
||||
Attr *l_attr = NULL, *r_attr = NULL;
|
||||
Ident *id = lfirst(ucol);
|
||||
List *col;
|
||||
Attr *l_attr = NULL,
|
||||
*r_attr = NULL;
|
||||
Ident *id = lfirst(ucol);
|
||||
|
||||
Attr *attr = makeAttr("", id->name);
|
||||
Attr *attr = makeAttr("", id->name);
|
||||
|
||||
foreach(col, l_cols)
|
||||
{
|
||||
@@ -634,9 +648,7 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
|
||||
/* otherwise, must be an expression from an ON clause... */
|
||||
else
|
||||
{
|
||||
j->quals = (List *) lcons(j->quals, NIL);
|
||||
}
|
||||
|
||||
pstate->p_join_quals = (Node *) j->quals;
|
||||
|
||||
@@ -654,24 +666,22 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
|
||||
#if 0
|
||||
/* merge qualified join clauses... */
|
||||
if (j->quals != NULL)
|
||||
{
|
||||
if (*qual != NULL)
|
||||
if (j->quals != NULL)
|
||||
{
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
if (*qual != NULL)
|
||||
{
|
||||
A_Expr *a = makeNode(A_Expr);
|
||||
|
||||
a->oper = AND;
|
||||
a->opname = NULL;
|
||||
a->lexpr = (Node *) *qual;
|
||||
a->rexpr = (Node *) j->quals;
|
||||
a->oper = AND;
|
||||
a->opname = NULL;
|
||||
a->lexpr = (Node *) *qual;
|
||||
a->rexpr = (Node *) j->quals;
|
||||
|
||||
*qual = (Node *)a;
|
||||
*qual = (Node *) a;
|
||||
}
|
||||
else
|
||||
*qual = (Node *) j->quals;
|
||||
}
|
||||
else
|
||||
{
|
||||
*qual = (Node *)j->quals;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if 0
|
||||
@@ -688,8 +698,8 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
* then we will need to replace the node with two nodes.
|
||||
* Will need access to the previous list item to change
|
||||
* the link pointer to reference these new nodes. Try
|
||||
* accumulating and returning a new list.
|
||||
* - thomas 1999-01-08 Not doing this yet though!
|
||||
* accumulating and returning a new list. - thomas
|
||||
* 1999-01-08 Not doing this yet though!
|
||||
*/
|
||||
|
||||
}
|
||||
@@ -708,7 +718,7 @@ parseFromClause(ParseState *pstate, List *frmList)
|
||||
elog(ERROR, "parseFromClause: unexpected FROM clause node (internal error)"
|
||||
"\n\t%s", nodeToString(n));
|
||||
}
|
||||
} /* parseFromClause() */
|
||||
} /* parseFromClause() */
|
||||
|
||||
|
||||
/*
|
||||
@@ -733,17 +743,17 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
* Handle two special cases as mandated by the SQL92 spec:
|
||||
*
|
||||
* 1. Bare ColumnName (no qualifier or subscripts)
|
||||
* For a bare identifier, we search for a matching column name
|
||||
* in the existing target list. Multiple matches are an error
|
||||
* For a bare identifier, we search for a matching column name
|
||||
* in the existing target list. Multiple matches are an error
|
||||
* unless they refer to identical values; for example,
|
||||
* we allow SELECT a, a FROM table ORDER BY a
|
||||
* but not SELECT a AS b, b FROM table ORDER BY b
|
||||
* we allow SELECT a, a FROM table ORDER BY a
|
||||
* but not SELECT a AS b, b FROM table ORDER BY b
|
||||
* If no match is found, we fall through and treat the identifier
|
||||
* as an expression.
|
||||
* For GROUP BY, it is incorrect to match the grouping item against
|
||||
* targetlist entries: according to SQL92, an identifier in GROUP BY
|
||||
* is a reference to a column name exposed by FROM, not to a target
|
||||
* list column. However, many implementations (including pre-7.0
|
||||
* list column. However, many implementations (including pre-7.0
|
||||
* PostgreSQL) accept this anyway. So for GROUP BY, we look first
|
||||
* to see if the identifier matches any FROM column name, and only
|
||||
* try for a targetlist name if it doesn't. This ensures that we
|
||||
@@ -768,19 +778,21 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
* an expression.
|
||||
*----------
|
||||
*/
|
||||
if (IsA(node, Ident) && ((Ident *) node)->indirection == NIL)
|
||||
if (IsA(node, Ident) &&((Ident *) node)->indirection == NIL)
|
||||
{
|
||||
char *name = ((Ident *) node)->name;
|
||||
|
||||
if (clause == GROUP_CLAUSE)
|
||||
{
|
||||
|
||||
/*
|
||||
* In GROUP BY, we must prefer a match against a FROM-clause
|
||||
* column to one against the targetlist. Look to see if there is
|
||||
* a matching column. If so, fall through to let transformExpr()
|
||||
* do the rest. NOTE: if name could refer ambiguously to more
|
||||
* than one column name exposed by FROM, colnameRangeTableEntry
|
||||
* will elog(ERROR). That's just what we want here.
|
||||
* column to one against the targetlist. Look to see if there
|
||||
* is a matching column. If so, fall through to let
|
||||
* transformExpr() do the rest. NOTE: if name could refer
|
||||
* ambiguously to more than one column name exposed by FROM,
|
||||
* colnameRangeTableEntry will elog(ERROR). That's just what
|
||||
* we want here.
|
||||
*/
|
||||
if (colnameRangeTableEntry(pstate, name) != NULL)
|
||||
name = NULL;
|
||||
@@ -798,7 +810,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
{
|
||||
if (target_result != NULL)
|
||||
{
|
||||
if (! equal(target_result->expr, tle->expr))
|
||||
if (!equal(target_result->expr, tle->expr))
|
||||
elog(ERROR, "%s '%s' is ambiguous",
|
||||
clauseText[clause], name);
|
||||
}
|
||||
@@ -808,7 +820,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
}
|
||||
}
|
||||
if (target_result != NULL)
|
||||
return target_result; /* return the first match */
|
||||
return target_result; /* return the first match */
|
||||
}
|
||||
}
|
||||
if (IsA(node, A_Const))
|
||||
@@ -817,7 +829,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
int targetlist_pos = 0;
|
||||
int target_pos;
|
||||
|
||||
if (! IsA(val, Integer))
|
||||
if (!IsA(val, Integer))
|
||||
elog(ERROR, "Non-integer constant in %s", clauseText[clause]);
|
||||
target_pos = intVal(val);
|
||||
foreach(tl, tlist)
|
||||
@@ -828,7 +840,7 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
if (!resnode->resjunk)
|
||||
{
|
||||
if (++targetlist_pos == target_pos)
|
||||
return tle; /* return the unique match */
|
||||
return tle; /* return the unique match */
|
||||
}
|
||||
}
|
||||
elog(ERROR, "%s position %d is not in target list",
|
||||
@@ -836,12 +848,12 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
}
|
||||
|
||||
/*
|
||||
* Otherwise, we have an expression (this is a Postgres extension
|
||||
* not found in SQL92). Convert the untransformed node to a
|
||||
* transformed expression, and search for a match in the tlist.
|
||||
* NOTE: it doesn't really matter whether there is more than one
|
||||
* match. Also, we are willing to match a resjunk target here,
|
||||
* though the above cases must ignore resjunk targets.
|
||||
* Otherwise, we have an expression (this is a Postgres extension not
|
||||
* found in SQL92). Convert the untransformed node to a transformed
|
||||
* expression, and search for a match in the tlist. NOTE: it doesn't
|
||||
* really matter whether there is more than one match. Also, we are
|
||||
* willing to match a resjunk target here, though the above cases must
|
||||
* ignore resjunk targets.
|
||||
*/
|
||||
expr = transformExpr(pstate, node, EXPR_COLUMN_FIRST);
|
||||
|
||||
@@ -855,8 +867,8 @@ findTargetlistEntry(ParseState *pstate, Node *node, List *tlist, int clause)
|
||||
|
||||
/*
|
||||
* If no matches, construct a new target entry which is appended to
|
||||
* the end of the target list. This target is given resjunk = TRUE
|
||||
* so that it will not be projected into the final tuple.
|
||||
* the end of the target list. This target is given resjunk = TRUE so
|
||||
* that it will not be projected into the final tuple.
|
||||
*/
|
||||
target_result = transformTargetEntry(pstate, node, expr, NULL, true);
|
||||
lappend(tlist, target_result);
|
||||
@@ -884,7 +896,7 @@ transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
|
||||
targetlist, GROUP_CLAUSE);
|
||||
|
||||
/* avoid making duplicate grouplist entries */
|
||||
if (! exprIsInSortList(tle->expr, glist, targetlist))
|
||||
if (!exprIsInSortList(tle->expr, glist, targetlist))
|
||||
{
|
||||
GroupClause *grpcl = makeNode(GroupClause);
|
||||
|
||||
@@ -915,8 +927,8 @@ transformSortClause(ParseState *pstate,
|
||||
|
||||
foreach(olitem, orderlist)
|
||||
{
|
||||
SortGroupBy *sortby = lfirst(olitem);
|
||||
TargetEntry *tle;
|
||||
SortGroupBy *sortby = lfirst(olitem);
|
||||
TargetEntry *tle;
|
||||
|
||||
tle = findTargetlistEntry(pstate, sortby->node,
|
||||
targetlist, ORDER_CLAUSE);
|
||||
@@ -933,7 +945,7 @@ transformSortClause(ParseState *pstate,
|
||||
* transform a DISTINCT or DISTINCT ON clause
|
||||
*
|
||||
* Since we may need to add items to the query's sortClause list, that list
|
||||
* is passed by reference. We might also need to add items to the query's
|
||||
* is passed by reference. We might also need to add items to the query's
|
||||
* targetlist, but we assume that cannot be empty initially, so we can
|
||||
* lappend to it even though the pointer is passed by value.
|
||||
*/
|
||||
@@ -955,10 +967,10 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
|
||||
|
||||
/*
|
||||
* All non-resjunk elements from target list that are not already
|
||||
* in the sort list should be added to it. (We don't really care
|
||||
* in the sort list should be added to it. (We don't really care
|
||||
* what order the DISTINCT fields are checked in, so we can leave
|
||||
* the user's ORDER BY spec alone, and just add additional sort keys
|
||||
* to it to ensure that all targetlist items get sorted.)
|
||||
* the user's ORDER BY spec alone, and just add additional sort
|
||||
* keys to it to ensure that all targetlist items get sorted.)
|
||||
*/
|
||||
*sortClause = addAllTargetsToSortList(*sortClause, targetlist);
|
||||
|
||||
@@ -966,8 +978,8 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
|
||||
* Now, DISTINCT list consists of all non-resjunk sortlist items.
|
||||
* Actually, all the sortlist items had better be non-resjunk!
|
||||
* Otherwise, user wrote SELECT DISTINCT with an ORDER BY item
|
||||
* that does not appear anywhere in the SELECT targetlist, and
|
||||
* we can't implement that with only one sorting pass...
|
||||
* that does not appear anywhere in the SELECT targetlist, and we
|
||||
* can't implement that with only one sorting pass...
|
||||
*/
|
||||
foreach(slitem, *sortClause)
|
||||
{
|
||||
@@ -988,11 +1000,12 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
|
||||
* If the user writes both DISTINCT ON and ORDER BY, then the two
|
||||
* expression lists must match (until one or the other runs out).
|
||||
* Otherwise the ORDER BY requires a different sort order than the
|
||||
* DISTINCT does, and we can't implement that with only one sort pass
|
||||
* (and if we do two passes, the results will be rather unpredictable).
|
||||
* However, it's OK to have more DISTINCT ON expressions than ORDER BY
|
||||
* expressions; we can just add the extra DISTINCT values to the sort
|
||||
* list, much as we did above for ordinary DISTINCT fields.
|
||||
* DISTINCT does, and we can't implement that with only one sort
|
||||
* pass (and if we do two passes, the results will be rather
|
||||
* unpredictable). However, it's OK to have more DISTINCT ON
|
||||
* expressions than ORDER BY expressions; we can just add the
|
||||
* extra DISTINCT values to the sort list, much as we did above
|
||||
* for ordinary DISTINCT fields.
|
||||
*
|
||||
* Actually, it'd be OK for the common prefixes of the two lists to
|
||||
* match in any order, but implementing that check seems like more
|
||||
@@ -1020,7 +1033,9 @@ transformDistinctClause(ParseState *pstate, List *distinctlist,
|
||||
{
|
||||
*sortClause = addTargetToSortList(tle, *sortClause,
|
||||
targetlist, NULL);
|
||||
/* Probably, the tle should always have been added at the
|
||||
|
||||
/*
|
||||
* Probably, the tle should always have been added at the
|
||||
* end of the sort list ... but search to be safe.
|
||||
*/
|
||||
foreach(slitem, *sortClause)
|
||||
@@ -1059,7 +1074,7 @@ addAllTargetsToSortList(List *sortlist, List *targetlist)
|
||||
{
|
||||
TargetEntry *tle = (TargetEntry *) lfirst(i);
|
||||
|
||||
if (! tle->resdom->resjunk)
|
||||
if (!tle->resdom->resjunk)
|
||||
sortlist = addTargetToSortList(tle, sortlist, targetlist, NULL);
|
||||
}
|
||||
return sortlist;
|
||||
@@ -1078,7 +1093,7 @@ addTargetToSortList(TargetEntry *tle, List *sortlist, List *targetlist,
|
||||
char *opname)
|
||||
{
|
||||
/* avoid making duplicate sortlist entries */
|
||||
if (! exprIsInSortList(tle->expr, sortlist, targetlist))
|
||||
if (!exprIsInSortList(tle->expr, sortlist, targetlist))
|
||||
{
|
||||
SortClause *sortcl = makeNode(SortClause);
|
||||
|
||||
@@ -1109,14 +1124,14 @@ assignSortGroupRef(TargetEntry *tle, List *tlist)
|
||||
Index maxRef;
|
||||
List *l;
|
||||
|
||||
if (tle->resdom->ressortgroupref) /* already has one? */
|
||||
if (tle->resdom->ressortgroupref) /* already has one? */
|
||||
return tle->resdom->ressortgroupref;
|
||||
|
||||
/* easiest way to pick an unused refnumber: max used + 1 */
|
||||
maxRef = 0;
|
||||
foreach(l, tlist)
|
||||
{
|
||||
Index ref = ((TargetEntry *) lfirst(l))->resdom->ressortgroupref;
|
||||
Index ref = ((TargetEntry *) lfirst(l))->resdom->ressortgroupref;
|
||||
|
||||
if (ref > maxRef)
|
||||
maxRef = ref;
|
||||
@@ -1250,4 +1265,5 @@ transformUnionClause(List *unionClause, List *targetlist)
|
||||
else
|
||||
return NIL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.41 2000/04/08 19:29:40 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_coerce.c,v 2.42 2000/04/12 17:15:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -47,21 +47,22 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
}
|
||||
else if (inputTypeId == UNKNOWNOID && IsA(node, Const))
|
||||
{
|
||||
|
||||
/*
|
||||
* Input is a string constant with previously undetermined type.
|
||||
* Apply the target type's typinput function to it to produce
|
||||
* a constant of the target type.
|
||||
* Apply the target type's typinput function to it to produce a
|
||||
* constant of the target type.
|
||||
*
|
||||
* NOTE: this case cannot be folded together with the other
|
||||
* constant-input case, since the typinput function does not
|
||||
* necessarily behave the same as a type conversion function.
|
||||
* For example, int4's typinput function will reject "1.2",
|
||||
* whereas float-to-int type conversion will round to integer.
|
||||
* necessarily behave the same as a type conversion function. For
|
||||
* example, int4's typinput function will reject "1.2", whereas
|
||||
* float-to-int type conversion will round to integer.
|
||||
*
|
||||
* XXX if the typinput function is not cachable, we really ought
|
||||
* to postpone evaluation of the function call until runtime.
|
||||
* But there is no way to represent a typinput function call as
|
||||
* an expression tree, because C-string values are not Datums.
|
||||
* XXX if the typinput function is not cachable, we really ought to
|
||||
* postpone evaluation of the function call until runtime. But
|
||||
* there is no way to represent a typinput function call as an
|
||||
* expression tree, because C-string values are not Datums.
|
||||
*/
|
||||
Const *con = (Const *) node;
|
||||
Const *newcon = makeNode(Const);
|
||||
@@ -73,10 +74,11 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
newcon->constisnull = con->constisnull;
|
||||
newcon->constisset = false;
|
||||
|
||||
if (! con->constisnull)
|
||||
if (!con->constisnull)
|
||||
{
|
||||
/* We know the source constant is really of type 'text' */
|
||||
char *val = textout((text *) con->constvalue);
|
||||
|
||||
newcon->constvalue = stringTypeDatum(targetType, val, atttypmod);
|
||||
pfree(val);
|
||||
}
|
||||
@@ -85,15 +87,17 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
}
|
||||
else if (IS_BINARY_COMPATIBLE(inputTypeId, targetTypeId))
|
||||
{
|
||||
|
||||
/*
|
||||
* We don't really need to do a conversion, but we do need to attach
|
||||
* a RelabelType node so that the expression will be seen to have
|
||||
* the intended type when inspected by higher-level code.
|
||||
* We don't really need to do a conversion, but we do need to
|
||||
* attach a RelabelType node so that the expression will be seen
|
||||
* to have the intended type when inspected by higher-level code.
|
||||
*/
|
||||
RelabelType *relabel = makeNode(RelabelType);
|
||||
|
||||
relabel->arg = node;
|
||||
relabel->resulttype = targetTypeId;
|
||||
|
||||
/*
|
||||
* XXX could we label result with exprTypmod(node) instead of
|
||||
* default -1 typmod, to save a possible length-coercion later?
|
||||
@@ -111,11 +115,12 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Otherwise, find the appropriate type conversion function
|
||||
* (caller should have determined that there is one), and
|
||||
* generate an expression tree representing run-time
|
||||
* application of the conversion function.
|
||||
* (caller should have determined that there is one), and generate
|
||||
* an expression tree representing run-time application of the
|
||||
* conversion function.
|
||||
*/
|
||||
FuncCall *n = makeNode(FuncCall);
|
||||
Type targetType = typeidType(targetTypeId);
|
||||
@@ -135,20 +140,20 @@ coerce_type(ParseState *pstate, Node *node, Oid inputTypeId,
|
||||
|
||||
/*
|
||||
* If the input is a constant, apply the type conversion function
|
||||
* now instead of delaying to runtime. (We could, of course,
|
||||
* just leave this to be done during planning/optimization;
|
||||
* but it's a very frequent special case, and we save cycles
|
||||
* in the rewriter if we fold the expression now.)
|
||||
* now instead of delaying to runtime. (We could, of course, just
|
||||
* leave this to be done during planning/optimization; but it's a
|
||||
* very frequent special case, and we save cycles in the rewriter
|
||||
* if we fold the expression now.)
|
||||
*
|
||||
* Note that no folding will occur if the conversion function is
|
||||
* not marked 'iscachable'.
|
||||
* Note that no folding will occur if the conversion function is not
|
||||
* marked 'iscachable'.
|
||||
*
|
||||
* HACK: if constant is NULL, don't fold it here. This is needed
|
||||
* by make_subplan(), which calls this routine on placeholder Const
|
||||
* nodes that mustn't be collapsed. (It'd be a lot cleaner to make
|
||||
* a separate node type for that purpose...)
|
||||
* HACK: if constant is NULL, don't fold it here. This is needed by
|
||||
* make_subplan(), which calls this routine on placeholder Const
|
||||
* nodes that mustn't be collapsed. (It'd be a lot cleaner to
|
||||
* make a separate node type for that purpose...)
|
||||
*/
|
||||
if (IsA(node, Const) && ! ((Const *) node)->constisnull)
|
||||
if (IsA(node, Const) &&!((Const *) node)->constisnull)
|
||||
result = eval_const_expressions(result);
|
||||
}
|
||||
|
||||
@@ -181,8 +186,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
||||
/* run through argument list... */
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
Oid inputTypeId = input_typeids[i];
|
||||
Oid targetTypeId = func_typeids[i];
|
||||
Oid inputTypeId = input_typeids[i];
|
||||
Oid targetTypeId = func_typeids[i];
|
||||
|
||||
/* no problem if same type */
|
||||
if (inputTypeId == targetTypeId)
|
||||
@@ -203,8 +208,8 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* If input is an untyped string constant, assume we can
|
||||
* convert it to anything except a class type.
|
||||
* If input is an untyped string constant, assume we can convert
|
||||
* it to anything except a class type.
|
||||
*/
|
||||
if (inputTypeId == UNKNOWNOID)
|
||||
{
|
||||
@@ -220,15 +225,15 @@ can_coerce_type(int nargs, Oid *input_typeids, Oid *func_typeids)
|
||||
continue;
|
||||
|
||||
/*
|
||||
* Else, try for explicit conversion using functions:
|
||||
* look for a single-argument function named with the
|
||||
* target type name and accepting the source type.
|
||||
* Else, try for explicit conversion using functions: look for a
|
||||
* single-argument function named with the target type name and
|
||||
* accepting the source type.
|
||||
*/
|
||||
MemSet(oid_array, 0, FUNC_MAX_ARGS * sizeof(Oid));
|
||||
oid_array[0] = inputTypeId;
|
||||
|
||||
ftup = SearchSysCacheTuple(PROCNAME,
|
||||
PointerGetDatum(typeidTypeName(targetTypeId)),
|
||||
PointerGetDatum(typeidTypeName(targetTypeId)),
|
||||
Int32GetDatum(1),
|
||||
PointerGetDatum(oid_array),
|
||||
0);
|
||||
@@ -331,14 +336,14 @@ TypeCategory(Oid inType)
|
||||
result = STRING_TYPE;
|
||||
break;
|
||||
|
||||
/*
|
||||
* Kluge added 4/8/00 by tgl: treat the new BIT types as strings,
|
||||
* so that 'unknown' || 'unknown' continues to resolve as textcat
|
||||
* rather than generating an ambiguous-operator error. Probably
|
||||
* BIT types should have their own type category, or maybe they
|
||||
* should be numeric? Need a better way of handling unknown types
|
||||
* first.
|
||||
*/
|
||||
/*
|
||||
* Kluge added 4/8/00 by tgl: treat the new BIT types as
|
||||
* strings, so that 'unknown' || 'unknown' continues to
|
||||
* resolve as textcat rather than generating an
|
||||
* ambiguous-operator error. Probably BIT types should have
|
||||
* their own type category, or maybe they should be numeric?
|
||||
* Need a better way of handling unknown types first.
|
||||
*/
|
||||
case (ZPBITOID):
|
||||
case (VARBITOID):
|
||||
result = STRING_TYPE;
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.75 2000/03/19 07:13:58 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_expr.c,v 1.76 2000/04/12 17:15:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -33,17 +33,17 @@
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
int max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;
|
||||
int max_expr_depth = DEFAULT_MAX_EXPR_DEPTH;
|
||||
|
||||
static int expr_depth_counter = 0;
|
||||
|
||||
static Node *parser_typecast_constant(Value *expr, TypeName *typename);
|
||||
static Node *parser_typecast_expression(ParseState *pstate,
|
||||
Node *expr, TypeName *typename);
|
||||
Node *expr, TypeName *typename);
|
||||
static Node *transformAttr(ParseState *pstate, Attr *att, int precedence);
|
||||
static Node *transformIdent(ParseState *pstate, Ident *ident, int precedence);
|
||||
static Node *transformIndirection(ParseState *pstate, Node *basenode,
|
||||
List *indirection);
|
||||
List *indirection);
|
||||
|
||||
|
||||
/*
|
||||
@@ -92,8 +92,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
return NULL;
|
||||
|
||||
/*
|
||||
* Guard against an overly complex expression leading to coredump
|
||||
* due to stack overflow here, or in later recursive routines that
|
||||
* Guard against an overly complex expression leading to coredump due
|
||||
* to stack overflow here, or in later recursive routines that
|
||||
* traverse expression trees. Note that this is very unlikely to
|
||||
* happen except with pathological queries; but we don't want someone
|
||||
* to be able to crash the backend quite that easily...
|
||||
@@ -172,7 +172,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
"nullvalue",
|
||||
lcons(lexpr, NIL),
|
||||
false, false,
|
||||
&pstate->p_last_resno,
|
||||
&pstate->p_last_resno,
|
||||
precedence);
|
||||
}
|
||||
break;
|
||||
@@ -184,7 +184,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
"nonnullvalue",
|
||||
lcons(lexpr, NIL),
|
||||
false, false,
|
||||
&pstate->p_last_resno,
|
||||
&pstate->p_last_resno,
|
||||
precedence);
|
||||
}
|
||||
break;
|
||||
@@ -289,7 +289,9 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
|
||||
if (sublink->subLinkType == EXISTS_SUBLINK)
|
||||
{
|
||||
/* EXISTS needs no lefthand or combining operator.
|
||||
|
||||
/*
|
||||
* EXISTS needs no lefthand or combining operator.
|
||||
* These fields should be NIL already, but make sure.
|
||||
*/
|
||||
sublink->lefthand = NIL;
|
||||
@@ -299,7 +301,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
{
|
||||
List *tlist = qtree->targetList;
|
||||
|
||||
/* Make sure the subselect delivers a single column
|
||||
/*
|
||||
* Make sure the subselect delivers a single column
|
||||
* (ignoring resjunk targets).
|
||||
*/
|
||||
if (tlist == NIL ||
|
||||
@@ -307,11 +310,13 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
elog(ERROR, "Subselect must have a field");
|
||||
while ((tlist = lnext(tlist)) != NIL)
|
||||
{
|
||||
if (! ((TargetEntry *) lfirst(tlist))->resdom->resjunk)
|
||||
if (!((TargetEntry *) lfirst(tlist))->resdom->resjunk)
|
||||
elog(ERROR, "Subselect must have only one field");
|
||||
}
|
||||
/* EXPR needs no lefthand or combining operator.
|
||||
* These fields should be NIL already, but make sure.
|
||||
|
||||
/*
|
||||
* EXPR needs no lefthand or combining operator. These
|
||||
* fields should be NIL already, but make sure.
|
||||
*/
|
||||
sublink->lefthand = NIL;
|
||||
sublink->oper = NIL;
|
||||
@@ -336,10 +341,12 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
|
||||
sublink->oper = NIL;
|
||||
|
||||
/* Scan subquery's targetlist to find values that will be
|
||||
* matched against lefthand values. We need to ignore
|
||||
* resjunk targets, so doing the outer iteration over
|
||||
* right_list is easier than doing it over left_list.
|
||||
/*
|
||||
* Scan subquery's targetlist to find values that will
|
||||
* be matched against lefthand values. We need to
|
||||
* ignore resjunk targets, so doing the outer
|
||||
* iteration over right_list is easier than doing it
|
||||
* over left_list.
|
||||
*/
|
||||
while (right_list != NIL)
|
||||
{
|
||||
@@ -370,8 +377,8 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
op, typeidTypeName(opform->oprresult),
|
||||
typeidTypeName(BOOLOID));
|
||||
|
||||
newop = makeOper(oprid(optup),/* opno */
|
||||
InvalidOid, /* opid */
|
||||
newop = makeOper(oprid(optup), /* opno */
|
||||
InvalidOid, /* opid */
|
||||
opform->oprresult,
|
||||
0,
|
||||
NULL);
|
||||
@@ -453,9 +460,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
|| ((TypeCategory(wtype) == USER_TYPE)
|
||||
&& (TypeCategory(c->casetype) == USER_TYPE)))
|
||||
{
|
||||
|
||||
/*
|
||||
* both types in different categories?
|
||||
* then not much hope...
|
||||
* both types in different categories? then
|
||||
* not much hope...
|
||||
*/
|
||||
elog(ERROR, "CASE/WHEN types '%s' and '%s' not matched",
|
||||
typeidTypeName(c->casetype), typeidTypeName(wtype));
|
||||
@@ -463,9 +471,10 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
else if (IsPreferredType(pcategory, wtype)
|
||||
&& can_coerce_type(1, &ptype, &wtype))
|
||||
{
|
||||
|
||||
/*
|
||||
* new one is preferred and can convert?
|
||||
* then take it...
|
||||
* new one is preferred and can convert? then
|
||||
* take it...
|
||||
*/
|
||||
ptype = wtype;
|
||||
pcategory = TypeCategory(ptype);
|
||||
@@ -478,6 +487,7 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
{
|
||||
if (!c->casetype || c->casetype == UNKNOWNOID)
|
||||
{
|
||||
|
||||
/*
|
||||
* default clause is NULL, so assign preferred
|
||||
* type from WHEN clauses...
|
||||
@@ -553,14 +563,14 @@ transformExpr(ParseState *pstate, Node *expr, int precedence)
|
||||
break;
|
||||
}
|
||||
|
||||
/*
|
||||
* Quietly accept node types that may be presented when we are called
|
||||
* on an already-transformed tree.
|
||||
*
|
||||
* Do any other node types need to be accepted? For now we are taking
|
||||
* a conservative approach, and only accepting node types that are
|
||||
* demonstrably necessary to accept.
|
||||
*/
|
||||
/*
|
||||
* Quietly accept node types that may be presented when we are
|
||||
* called on an already-transformed tree.
|
||||
*
|
||||
* Do any other node types need to be accepted? For now we are
|
||||
* taking a conservative approach, and only accepting node
|
||||
* types that are demonstrably necessary to accept.
|
||||
*/
|
||||
case T_Expr:
|
||||
case T_Var:
|
||||
case T_Const:
|
||||
@@ -610,7 +620,10 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
|
||||
Node *result = NULL;
|
||||
RangeTblEntry *rte;
|
||||
|
||||
/* try to find the ident as a relation ... but not if subscripts appear */
|
||||
/*
|
||||
* try to find the ident as a relation ... but not if subscripts
|
||||
* appear
|
||||
*/
|
||||
if (ident->indirection == NIL &&
|
||||
refnameRangeTableEntry(pstate, ident->name) != NULL)
|
||||
{
|
||||
@@ -625,6 +638,7 @@ transformIdent(ParseState *pstate, Ident *ident, int precedence)
|
||||
{
|
||||
/* Convert it to a fully qualified Attr, and transform that */
|
||||
Attr *att = makeAttr(rte->eref->relname, ident->name);
|
||||
|
||||
att->indirection = ident->indirection;
|
||||
return transformAttr(pstate, att, precedence);
|
||||
}
|
||||
@@ -687,7 +701,7 @@ exprType(Node *expr)
|
||||
Query *qtree = (Query *) sublink->subselect;
|
||||
TargetEntry *tent;
|
||||
|
||||
if (! qtree || ! IsA(qtree, Query))
|
||||
if (!qtree || !IsA(qtree, Query))
|
||||
elog(ERROR, "Cannot get type for untransformed sublink");
|
||||
tent = (TargetEntry *) lfirst(qtree->targetList);
|
||||
type = tent->resdom->restype;
|
||||
@@ -735,11 +749,12 @@ exprTypmod(Node *expr)
|
||||
case T_Const:
|
||||
{
|
||||
/* Be smart about string constants... */
|
||||
Const *con = (Const *) expr;
|
||||
Const *con = (Const *) expr;
|
||||
|
||||
switch (con->consttype)
|
||||
{
|
||||
case BPCHAROID:
|
||||
if (! con->constisnull)
|
||||
if (!con->constisnull)
|
||||
return VARSIZE(DatumGetPointer(con->constvalue));
|
||||
break;
|
||||
default:
|
||||
@@ -749,7 +764,7 @@ exprTypmod(Node *expr)
|
||||
break;
|
||||
case T_Expr:
|
||||
{
|
||||
int32 coercedTypmod;
|
||||
int32 coercedTypmod;
|
||||
|
||||
/* Be smart about length-coercion functions... */
|
||||
if (exprIsLengthCoercion(expr, &coercedTypmod))
|
||||
@@ -794,7 +809,7 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
||||
|
||||
/* Is it a function-call at all? */
|
||||
if (expr == NULL ||
|
||||
! IsA(expr, Expr) ||
|
||||
!IsA(expr, Expr) ||
|
||||
((Expr *) expr)->opType != FUNC_EXPR)
|
||||
return false;
|
||||
func = (Func *) (((Expr *) expr)->oper);
|
||||
@@ -802,12 +817,13 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
||||
|
||||
/*
|
||||
* If it's not a two-argument function with the second argument being
|
||||
* an int4 constant, it can't have been created from a length coercion.
|
||||
* an int4 constant, it can't have been created from a length
|
||||
* coercion.
|
||||
*/
|
||||
if (length(((Expr *) expr)->args) != 2)
|
||||
return false;
|
||||
second_arg = (Const *) lsecond(((Expr *) expr)->args);
|
||||
if (! IsA(second_arg, Const) ||
|
||||
if (!IsA(second_arg, Const) ||
|
||||
second_arg->consttype != INT4OID ||
|
||||
second_arg->constisnull)
|
||||
return false;
|
||||
@@ -823,9 +839,9 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
||||
procStruct = (Form_pg_proc) GETSTRUCT(tup);
|
||||
|
||||
/*
|
||||
* It must be a function with two arguments where the first is of
|
||||
* the same type as the return value and the second is an int4.
|
||||
* Also, just to be sure, check return type agrees with expr node.
|
||||
* It must be a function with two arguments where the first is of the
|
||||
* same type as the return value and the second is an int4. Also, just
|
||||
* to be sure, check return type agrees with expr node.
|
||||
*/
|
||||
if (procStruct->pronargs != 2 ||
|
||||
procStruct->prorettype != procStruct->proargtypes[0] ||
|
||||
@@ -834,8 +850,8 @@ exprIsLengthCoercion(Node *expr, int32 *coercedTypmod)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Furthermore, the name of the function must be the same
|
||||
* as the argument/result type's name.
|
||||
* Furthermore, the name of the function must be the same as the
|
||||
* argument/result type's name.
|
||||
*/
|
||||
tup = SearchSysCacheTuple(TYPEOID,
|
||||
ObjectIdGetDatum(procStruct->prorettype),
|
||||
@@ -891,7 +907,7 @@ parser_typecast_constant(Value *expr, TypeName *typename)
|
||||
|
||||
if (typename->arrayBounds != NIL)
|
||||
{
|
||||
char type_string[NAMEDATALEN+2];
|
||||
char type_string[NAMEDATALEN + 2];
|
||||
|
||||
sprintf(type_string, "_%s", typename->name);
|
||||
tp = (Type) typenameType(type_string);
|
||||
@@ -936,7 +952,7 @@ parser_typecast_expression(ParseState *pstate,
|
||||
|
||||
if (typename->arrayBounds != NIL)
|
||||
{
|
||||
char type_string[NAMEDATALEN+2];
|
||||
char type_string[NAMEDATALEN + 2];
|
||||
|
||||
sprintf(type_string, "_%s", typename->name);
|
||||
tp = (Type) typenameType(type_string);
|
||||
@@ -957,9 +973,10 @@ parser_typecast_expression(ParseState *pstate,
|
||||
typeidTypeName(inputType),
|
||||
typeidTypeName(targetType));
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target is a fixed-length type, it may need a length
|
||||
* coercion as well as a type coercion.
|
||||
* If the target is a fixed-length type, it may need a length coercion
|
||||
* as well as a type coercion.
|
||||
*/
|
||||
expr = coerce_type_typmod(pstate, expr,
|
||||
targetType, typename->typmod);
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.77 2000/03/23 07:38:30 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_func.c,v 1.78 2000/04/12 17:15:26 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -45,13 +45,14 @@ static Oid **argtype_inherit(int nargs, Oid *oid_array);
|
||||
|
||||
static int find_inheritors(Oid relid, Oid **supervec);
|
||||
static CandidateList func_get_candidates(char *funcname, int nargs);
|
||||
static bool func_get_detail(char *funcname,
|
||||
int nargs,
|
||||
Oid *oid_array,
|
||||
Oid *funcid, /* return value */
|
||||
Oid *rettype, /* return value */
|
||||
bool *retset, /* return value */
|
||||
Oid **true_typeids);
|
||||
static bool
|
||||
func_get_detail(char *funcname,
|
||||
int nargs,
|
||||
Oid *oid_array,
|
||||
Oid *funcid, /* return value */
|
||||
Oid *rettype, /* return value */
|
||||
bool *retset, /* return value */
|
||||
Oid **true_typeids);
|
||||
static Oid **gen_cross_product(InhPaths *arginh, int nargs);
|
||||
static void make_arguments(ParseState *pstate,
|
||||
int nargs,
|
||||
@@ -127,7 +128,7 @@ agg_get_candidates(char *aggname,
|
||||
HeapTuple tup;
|
||||
Form_pg_aggregate agg;
|
||||
int ncandidates = 0;
|
||||
ScanKeyData aggKey[1];
|
||||
ScanKeyData aggKey[1];
|
||||
|
||||
*candidates = NULL;
|
||||
|
||||
@@ -179,8 +180,8 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
|
||||
current_category;
|
||||
|
||||
/*
|
||||
* First look for exact matches or binary compatible matches.
|
||||
* (Of course exact matches shouldn't even get here, but anyway.)
|
||||
* First look for exact matches or binary compatible matches. (Of
|
||||
* course exact matches shouldn't even get here, but anyway.)
|
||||
*/
|
||||
ncandidates = 0;
|
||||
last_candidate = NULL;
|
||||
@@ -191,18 +192,18 @@ agg_select_candidate(Oid typeid, CandidateList candidates)
|
||||
current_typeid = current_candidate->args[0];
|
||||
|
||||
if (current_typeid == typeid
|
||||
|| IS_BINARY_COMPATIBLE(current_typeid, typeid))
|
||||
|| IS_BINARY_COMPATIBLE(current_typeid, typeid))
|
||||
{
|
||||
last_candidate = current_candidate;
|
||||
ncandidates++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (ncandidates == 1)
|
||||
return last_candidate->args[0];
|
||||
|
||||
/*
|
||||
* If no luck that way, look for candidates which allow coercion
|
||||
* and have a preferred type. Keep all candidates if none match.
|
||||
* If no luck that way, look for candidates which allow coercion and
|
||||
* have a preferred type. Keep all candidates if none match.
|
||||
*/
|
||||
category = TypeCategory(typeid);
|
||||
ncandidates = 0;
|
||||
@@ -290,11 +291,11 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
if (nargs == 1 && !must_be_agg)
|
||||
{
|
||||
/* Is it a plain Relation name from the parser? */
|
||||
if (IsA(first_arg, Ident) && ((Ident *) first_arg)->isRel)
|
||||
if (IsA(first_arg, Ident) &&((Ident *) first_arg)->isRel)
|
||||
{
|
||||
Ident *ident = (Ident *) first_arg;
|
||||
RangeTblEntry *rte;
|
||||
AttrNumber attnum;
|
||||
AttrNumber attnum;
|
||||
|
||||
/*
|
||||
* first arg is a relation. This could be a projection.
|
||||
@@ -308,9 +309,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
makeAttr(refname, NULL),
|
||||
FALSE, FALSE, TRUE);
|
||||
#ifdef WARN_FROM
|
||||
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
|
||||
pstate->parentParseState != NULL ? " in subquery" : "",
|
||||
refname);
|
||||
elog(NOTICE, "Adding missing FROM-clause entry%s for table %s",
|
||||
pstate->parentParseState != NULL ? " in subquery" : "",
|
||||
refname);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -320,35 +321,39 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
|
||||
/*
|
||||
* If the attr isn't a set, just make a var for it. If it is
|
||||
* a set, treat it like a function and drop through.
|
||||
* Look through the explicit column list first, since we
|
||||
* now allow column aliases.
|
||||
* - thomas 2000-02-07
|
||||
* 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 (rte->eref->attrs != NULL)
|
||||
{
|
||||
List *c;
|
||||
/* start counting attributes/columns from one.
|
||||
* zero is reserved for InvalidAttrNumber.
|
||||
* - thomas 2000-01-27
|
||||
List *c;
|
||||
|
||||
/*
|
||||
* start counting attributes/columns from one. zero is
|
||||
* reserved for InvalidAttrNumber. - thomas 2000-01-27
|
||||
*/
|
||||
int i = 1;
|
||||
foreach (c, rte->eref->attrs)
|
||||
int i = 1;
|
||||
|
||||
foreach(c, rte->eref->attrs)
|
||||
{
|
||||
char *colname = strVal(lfirst(c));
|
||||
char *colname = strVal(lfirst(c));
|
||||
|
||||
/* found a match? */
|
||||
if (strcmp(colname, funcname) == 0)
|
||||
{
|
||||
char *basename = get_attname(relid, i);
|
||||
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
|
||||
|
||||
/*
|
||||
* attnum was initialized to InvalidAttrNumber
|
||||
* earlier, so no need to reset it if the above
|
||||
* test fails. - thomas 2000-02-07
|
||||
*/
|
||||
break;
|
||||
}
|
||||
@@ -358,9 +363,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
attnum = specialAttNum(funcname);
|
||||
}
|
||||
else
|
||||
{
|
||||
attnum = get_attnum(relid, funcname);
|
||||
}
|
||||
|
||||
if (attnum != InvalidAttrNumber)
|
||||
{
|
||||
@@ -373,6 +376,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
}
|
||||
else if (ISCOMPLEX(exprType(first_arg)))
|
||||
{
|
||||
|
||||
/*
|
||||
* Attempt to handle projection of a complex argument. If
|
||||
* ParseComplexProjection can't handle the projection, we have
|
||||
@@ -411,6 +415,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
|
||||
if (nargs == 1 || must_be_agg)
|
||||
{
|
||||
|
||||
/*
|
||||
* See if it's an aggregate.
|
||||
*/
|
||||
@@ -423,8 +428,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
elog(ERROR, "Aggregate functions may only have one parameter");
|
||||
|
||||
/*
|
||||
* the aggregate COUNT is a special case, ignore its base
|
||||
* type. Treat it as zero. XXX mighty ugly --- FIXME
|
||||
* the aggregate COUNT is a special case, ignore its base type.
|
||||
* Treat it as zero. XXX mighty ugly --- FIXME
|
||||
*/
|
||||
if (strcmp(funcname, "count") == 0)
|
||||
basetype = 0;
|
||||
@@ -469,6 +474,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
|
||||
if (must_be_agg)
|
||||
{
|
||||
|
||||
/*
|
||||
* No matching agg, but we had '*' or DISTINCT, so a plain
|
||||
* function could not have been meant.
|
||||
@@ -491,7 +497,7 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
{
|
||||
Node *arg = lfirst(i);
|
||||
|
||||
if (IsA(arg, Ident) && ((Ident *) arg)->isRel)
|
||||
if (IsA(arg, Ident) &&((Ident *) arg)->isRel)
|
||||
{
|
||||
RangeTblEntry *rte;
|
||||
int vnum;
|
||||
@@ -509,9 +515,9 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
makeAttr(refname, NULL),
|
||||
FALSE, FALSE, TRUE);
|
||||
#ifdef WARN_FROM
|
||||
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
|
||||
pstate->parentParseState != NULL ? " in subquery" : "",
|
||||
refname);
|
||||
elog(NOTICE, "Adding missing FROM-clause entry%s for table %s",
|
||||
pstate->parentParseState != NULL ? " in subquery" : "",
|
||||
refname);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -532,17 +538,16 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
lfirst(i) = makeVar(vnum, 0, toid, -1, sublevels_up);
|
||||
}
|
||||
else if (!attisset)
|
||||
{
|
||||
toid = exprType(arg);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* if attisset is true, we already set toid for the single arg */
|
||||
}
|
||||
|
||||
/* Most of the rest of the parser just assumes that functions do not
|
||||
* have more than FUNC_MAX_ARGS parameters. We have to test here
|
||||
* to protect against array overruns, etc.
|
||||
/*
|
||||
* Most of the rest of the parser just assumes that functions do
|
||||
* not have more than FUNC_MAX_ARGS parameters. We have to test
|
||||
* here to protect against array overruns, etc.
|
||||
*/
|
||||
if (nargs >= FUNC_MAX_ARGS)
|
||||
elog(ERROR, "Cannot pass more than %d arguments to a function",
|
||||
@@ -585,23 +590,26 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
&rettype, &retset, &true_oid_array);
|
||||
if (!exists)
|
||||
{
|
||||
|
||||
/*
|
||||
* If we can't find a function (or can't find a unique function),
|
||||
* see if this is really a type-coercion request: single-argument
|
||||
* function call where the function name is a type name. If so,
|
||||
* and if we can do the coercion trivially, just go ahead and do
|
||||
* it without requiring there to be a real function for it.
|
||||
* If we can't find a function (or can't find a unique
|
||||
* function), see if this is really a type-coercion request:
|
||||
* single-argument function call where the function name is a
|
||||
* type name. If so, and if we can do the coercion trivially,
|
||||
* just go ahead and do it without requiring there to be a
|
||||
* real function for it.
|
||||
*
|
||||
* "Trivial" coercions are ones that involve binary-compatible
|
||||
* types and ones that are coercing a previously-unknown-type
|
||||
* literal constant to a specific type.
|
||||
*
|
||||
* DO NOT try to generalize this code to nontrivial coercions,
|
||||
* because you'll just set up an infinite recursion between this
|
||||
* routine and coerce_type! We have already failed to find a
|
||||
* suitable "real" coercion function, so we have to fail unless
|
||||
* this is a coercion that coerce_type can handle by itself.
|
||||
* Make sure this code stays in sync with what coerce_type does!
|
||||
* because you'll just set up an infinite recursion between
|
||||
* this routine and coerce_type! We have already failed to
|
||||
* find a suitable "real" coercion function, so we have to
|
||||
* fail unless this is a coercion that coerce_type can handle
|
||||
* by itself. Make sure this code stays in sync with what
|
||||
* coerce_type does!
|
||||
*/
|
||||
if (nargs == 1)
|
||||
{
|
||||
@@ -612,15 +620,17 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
0, 0, 0);
|
||||
if (HeapTupleIsValid(tp))
|
||||
{
|
||||
Oid sourceType = oid_array[0];
|
||||
Oid targetType = typeTypeId(tp);
|
||||
Node *arg1 = lfirst(fargs);
|
||||
Oid sourceType = oid_array[0];
|
||||
Oid targetType = typeTypeId(tp);
|
||||
Node *arg1 = lfirst(fargs);
|
||||
|
||||
if ((sourceType == UNKNOWNOID && IsA(arg1, Const)) ||
|
||||
sourceType == targetType ||
|
||||
IS_BINARY_COMPATIBLE(sourceType, targetType))
|
||||
{
|
||||
/* Ah-hah, we can do it as a trivial coercion.
|
||||
|
||||
/*
|
||||
* Ah-hah, we can do it as a trivial coercion.
|
||||
* coerce_type can handle these cases, so why
|
||||
* duplicate code...
|
||||
*/
|
||||
@@ -640,7 +650,8 @@ ParseFuncOrColumn(ParseState *pstate, char *funcname, List *fargs,
|
||||
*/
|
||||
if (nargs == 1)
|
||||
{
|
||||
Type tp = typeidType(oid_array[0]);
|
||||
Type tp = typeidType(oid_array[0]);
|
||||
|
||||
if (typeTypeFlag(tp) == 'c')
|
||||
elog(ERROR, "No such attribute or function '%s'",
|
||||
funcname);
|
||||
@@ -911,8 +922,8 @@ func_select_candidate(int nargs,
|
||||
current_type;
|
||||
|
||||
/*
|
||||
* Run through all candidates and keep those with the most matches
|
||||
* on exact types. Keep all candidates if none match.
|
||||
* Run through all candidates and keep those with the most matches on
|
||||
* exact types. Keep all candidates if none match.
|
||||
*/
|
||||
ncandidates = 0;
|
||||
nbestMatch = 0;
|
||||
@@ -955,10 +966,9 @@ func_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Still too many candidates?
|
||||
* Run through all candidates and keep those with the most matches
|
||||
* on exact types + binary-compatible types.
|
||||
* Keep all candidates if none match.
|
||||
* Still too many candidates? Run through all candidates and keep
|
||||
* those with the most matches on exact types + binary-compatible
|
||||
* types. Keep all candidates if none match.
|
||||
*/
|
||||
ncandidates = 0;
|
||||
nbestMatch = 0;
|
||||
@@ -1005,10 +1015,9 @@ func_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Still too many candidates?
|
||||
* Now look for candidates which are preferred types at the args that
|
||||
* will require coercion.
|
||||
* Keep all candidates if none match.
|
||||
* Still too many candidates? Now look for candidates which are
|
||||
* preferred types at the args that will require coercion. Keep all
|
||||
* candidates if none match.
|
||||
*/
|
||||
ncandidates = 0;
|
||||
nbestMatch = 0;
|
||||
@@ -1052,19 +1061,19 @@ func_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Still too many candidates?
|
||||
* Try assigning types for the unknown columns.
|
||||
* Still too many candidates? Try assigning types for the unknown
|
||||
* columns.
|
||||
*
|
||||
* We do this by examining each unknown argument position to see if all the
|
||||
* candidates agree on the type category of that slot. If so, and if some
|
||||
* candidates accept the preferred type in that category, eliminate the
|
||||
* candidates with other input types. If we are down to one candidate
|
||||
* at the end, we win.
|
||||
* We do this by examining each unknown argument position to see if all
|
||||
* the candidates agree on the type category of that slot. If so, and
|
||||
* if some candidates accept the preferred type in that category,
|
||||
* eliminate the candidates with other input types. If we are down to
|
||||
* one candidate at the end, we win.
|
||||
*
|
||||
* XXX It's kinda bogus to do this left-to-right, isn't it? If we
|
||||
* eliminate some candidates because they are non-preferred at the first
|
||||
* slot, we won't notice that they didn't have the same type category for
|
||||
* a later slot.
|
||||
* eliminate some candidates because they are non-preferred at the
|
||||
* first slot, we won't notice that they didn't have the same type
|
||||
* category for a later slot.
|
||||
*/
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
@@ -1117,7 +1126,7 @@ func_select_candidate(int nargs,
|
||||
last_candidate = current_candidate;
|
||||
}
|
||||
}
|
||||
if (last_candidate) /* terminate rebuilt list */
|
||||
if (last_candidate) /* terminate rebuilt list */
|
||||
last_candidate->next = NULL;
|
||||
}
|
||||
}
|
||||
@@ -1174,7 +1183,11 @@ func_get_detail(char *funcname,
|
||||
}
|
||||
else
|
||||
{
|
||||
/* didn't find an exact match, so now try to match up candidates... */
|
||||
|
||||
/*
|
||||
* didn't find an exact match, so now try to match up
|
||||
* candidates...
|
||||
*/
|
||||
CandidateList function_typeids;
|
||||
|
||||
function_typeids = func_get_candidates(funcname, nargs);
|
||||
@@ -1234,7 +1247,9 @@ func_get_detail(char *funcname,
|
||||
0);
|
||||
Assert(HeapTupleIsValid(ftup));
|
||||
}
|
||||
/* otherwise, ambiguous function call, so fail by
|
||||
|
||||
/*
|
||||
* otherwise, ambiguous function call, so fail by
|
||||
* exiting loop with ftup still NULL.
|
||||
*/
|
||||
break;
|
||||
@@ -1242,7 +1257,8 @@ func_get_detail(char *funcname,
|
||||
|
||||
/*
|
||||
* No match here, so try the next inherited type vector.
|
||||
* First time through, we need to compute the list of vectors.
|
||||
* First time through, we need to compute the list of
|
||||
* vectors.
|
||||
*/
|
||||
if (input_typeid_vector == NULL)
|
||||
input_typeid_vector = argtype_inherit(nargs, oid_array);
|
||||
@@ -1341,10 +1357,10 @@ find_inheritors(Oid relid, Oid **supervec)
|
||||
|
||||
/*
|
||||
* Use queue to do a breadth-first traversal of the inheritance graph
|
||||
* from the relid supplied up to the root. At the top of the loop,
|
||||
* relid is the OID of the reltype to check next, queue is the list
|
||||
* of pending rels to check after this one, and visited is the list
|
||||
* of relids we need to output.
|
||||
* from the relid supplied up to the root. At the top of the loop,
|
||||
* relid is the OID of the reltype to check next, queue is the list of
|
||||
* pending rels to check after this one, and visited is the list of
|
||||
* relids we need to output.
|
||||
*/
|
||||
do
|
||||
{
|
||||
@@ -1372,7 +1388,7 @@ find_inheritors(Oid relid, Oid **supervec)
|
||||
{
|
||||
relid = lfirsti(queue);
|
||||
queue = lnext(queue);
|
||||
if (! intMember(relid, visited))
|
||||
if (!intMember(relid, visited))
|
||||
{
|
||||
newrelid = true;
|
||||
break;
|
||||
@@ -1401,7 +1417,7 @@ find_inheritors(Oid relid, Oid **supervec)
|
||||
|
||||
relid = lfirsti(elt);
|
||||
rd = heap_open(relid, NoLock);
|
||||
if (! RelationIsValid(rd))
|
||||
if (!RelationIsValid(rd))
|
||||
elog(ERROR, "Relid %u does not exist", relid);
|
||||
trelid = typeTypeId(typenameType(RelationGetRelationName(rd)));
|
||||
heap_close(rd, NoLock);
|
||||
@@ -1412,7 +1428,9 @@ find_inheritors(Oid relid, Oid **supervec)
|
||||
*supervec = (Oid *) NULL;
|
||||
|
||||
freeList(visited);
|
||||
/* there doesn't seem to be any equally easy way to release the queue
|
||||
|
||||
/*
|
||||
* there doesn't seem to be any equally easy way to release the queue
|
||||
* list cells, but since they're palloc'd space it's not critical.
|
||||
*/
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.38 2000/02/24 01:59:17 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_node.c,v 1.39 2000/04/12 17:15:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -225,7 +225,7 @@ make_var(ParseState *pstate, Oid relid, char *refname,
|
||||
*
|
||||
* In an array assignment, we are given a destination array value plus a
|
||||
* source value that is to be assigned to a single element or a slice of
|
||||
* that array. We produce an expression that represents the new array value
|
||||
* that array. We produce an expression that represents the new array value
|
||||
* with the source data inserted into the right part of the array.
|
||||
*
|
||||
* pstate Parse state
|
||||
@@ -234,7 +234,7 @@ make_var(ParseState *pstate, Oid relid, char *refname,
|
||||
* forceSlice If true, treat subscript as array slice in all cases
|
||||
* assignFrom NULL for array fetch, else transformed expression for source.
|
||||
*/
|
||||
ArrayRef *
|
||||
ArrayRef *
|
||||
transformArraySubscripts(ParseState *pstate,
|
||||
Node *arrayBase,
|
||||
List *indirection,
|
||||
@@ -281,19 +281,19 @@ transformArraySubscripts(ParseState *pstate,
|
||||
/*
|
||||
* A list containing only single subscripts refers to a single array
|
||||
* element. If any of the items are double subscripts (lower:upper),
|
||||
* then the subscript expression means an array slice operation.
|
||||
* In this case, we supply a default lower bound of 1 for any items
|
||||
* that contain only a single subscript.
|
||||
* The forceSlice parameter forces us to treat the operation as a
|
||||
* slice, even if no lower bounds are mentioned. Otherwise,
|
||||
* we have to prescan the indirection list to see if there are any
|
||||
* double subscripts.
|
||||
* then the subscript expression means an array slice operation. In
|
||||
* this case, we supply a default lower bound of 1 for any items that
|
||||
* contain only a single subscript. The forceSlice parameter forces us
|
||||
* to treat the operation as a slice, even if no lower bounds are
|
||||
* mentioned. Otherwise, we have to prescan the indirection list to
|
||||
* see if there are any double subscripts.
|
||||
*/
|
||||
if (! isSlice)
|
||||
if (!isSlice)
|
||||
{
|
||||
foreach (idx, indirection)
|
||||
foreach(idx, indirection)
|
||||
{
|
||||
A_Indices *ai = (A_Indices *) lfirst(idx);
|
||||
|
||||
if (ai->lidx != NULL)
|
||||
{
|
||||
isSlice = true;
|
||||
@@ -302,9 +302,10 @@ transformArraySubscripts(ParseState *pstate,
|
||||
}
|
||||
}
|
||||
|
||||
/* The type represented by the subscript expression is the element type
|
||||
* if we are fetching a single element, but it is the same as the array
|
||||
* type if we are fetching a slice or storing.
|
||||
/*
|
||||
* The type represented by the subscript expression is the element
|
||||
* type if we are fetching a single element, but it is the same as the
|
||||
* array type if we are fetching a slice or storing.
|
||||
*/
|
||||
if (isSlice || assignFrom != NULL)
|
||||
typeresult = typearray;
|
||||
@@ -314,7 +315,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
/*
|
||||
* Transform the subscript expressions.
|
||||
*/
|
||||
foreach (idx, indirection)
|
||||
foreach(idx, indirection)
|
||||
{
|
||||
A_Indices *ai = (A_Indices *) lfirst(idx);
|
||||
Node *subexpr;
|
||||
@@ -337,7 +338,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
sizeof(int32),
|
||||
Int32GetDatum(1),
|
||||
false,
|
||||
true, /* pass by value */
|
||||
true, /* pass by value */
|
||||
false,
|
||||
false);
|
||||
}
|
||||
@@ -371,7 +372,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
if (assignFrom == NULL)
|
||||
elog(ERROR, "Array assignment requires type '%s'"
|
||||
" but expression is of type '%s'"
|
||||
"\n\tYou will need to rewrite or cast the expression",
|
||||
"\n\tYou will need to rewrite or cast the expression",
|
||||
typeidTypeName(typeneeded),
|
||||
typeidTypeName(typesource));
|
||||
}
|
||||
@@ -384,7 +385,8 @@ transformArraySubscripts(ParseState *pstate,
|
||||
aref = makeNode(ArrayRef);
|
||||
aref->refattrlength = type_struct_array->typlen;
|
||||
aref->refelemlength = type_struct_element->typlen;
|
||||
aref->refelemtype = typeresult; /* XXX should save element type too */
|
||||
aref->refelemtype = typeresult; /* XXX should save element type
|
||||
* too */
|
||||
aref->refelembyval = type_struct_element->typbyval;
|
||||
aref->refupperindexpr = upperIndexpr;
|
||||
aref->reflowerindexpr = lowerIndexpr;
|
||||
@@ -407,7 +409,7 @@ transformArraySubscripts(ParseState *pstate,
|
||||
* resolution that we're not sure that it should be considered text.
|
||||
* Explicit "NULL" constants are also typed as UNKNOWN.
|
||||
*
|
||||
* For integers and floats we produce int4, float8, or numeric depending
|
||||
* For integers and floats we produce int4, float8, or numeric depending
|
||||
* on the value of the number. XXX In some cases it would be nice to take
|
||||
* context into account when determining the type to convert to, but in
|
||||
* other cases we can't delay the type choice. One possibility is to invent
|
||||
@@ -462,7 +464,7 @@ make_const(Value *value)
|
||||
case T_String:
|
||||
val = PointerGetDatum(textin(strVal(value)));
|
||||
|
||||
typeid = UNKNOWNOID; /* will be coerced later */
|
||||
typeid = UNKNOWNOID;/* will be coerced later */
|
||||
typelen = -1; /* variable len */
|
||||
typebyval = false;
|
||||
break;
|
||||
@@ -496,7 +498,7 @@ make_const(Value *value)
|
||||
|
||||
/*
|
||||
* Decide whether a T_Float value fits in float8, or must be treated as
|
||||
* type "numeric". We check the number of digits and check for overflow/
|
||||
* type "numeric". We check the number of digits and check for overflow/
|
||||
* underflow. (With standard compilation options, Postgres' NUMERIC type
|
||||
* can handle decimal exponents up to 1000, considerably more than most
|
||||
* implementations of float8, so this is a sensible test.)
|
||||
@@ -504,9 +506,9 @@ make_const(Value *value)
|
||||
static bool
|
||||
fitsInFloat(Value *value)
|
||||
{
|
||||
const char *ptr;
|
||||
int ndigits;
|
||||
char *endptr;
|
||||
const char *ptr;
|
||||
int ndigits;
|
||||
char *endptr;
|
||||
|
||||
/*
|
||||
* Count digits, ignoring leading zeroes (but not trailing zeroes).
|
||||
@@ -525,6 +527,7 @@ fitsInFloat(Value *value)
|
||||
}
|
||||
if (ndigits > DBL_DIG)
|
||||
return false;
|
||||
|
||||
/*
|
||||
* Use strtod() to check for overflow/underflow.
|
||||
*/
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.39 2000/03/19 00:19:39 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_oper.c,v 1.40 2000/04/12 17:15:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -29,10 +29,10 @@ static Oid *oper_select_candidate(int nargs, Oid *input_typeids,
|
||||
static Operator oper_exact(char *op, Oid arg1, Oid arg2);
|
||||
static Operator oper_inexact(char *op, Oid arg1, Oid arg2);
|
||||
static int binary_oper_get_candidates(char *opname,
|
||||
CandidateList *candidates);
|
||||
CandidateList *candidates);
|
||||
static int unary_oper_get_candidates(char *opname,
|
||||
CandidateList *candidates,
|
||||
char rightleft);
|
||||
CandidateList *candidates,
|
||||
char rightleft);
|
||||
static void op_error(char *op, Oid arg1, Oid arg2);
|
||||
static void unary_op_error(char *op, Oid arg, bool is_left_op);
|
||||
|
||||
@@ -229,8 +229,8 @@ oper_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Run through all candidates and keep those with the most matches
|
||||
* on exact types. Keep all candidates if none match.
|
||||
* Run through all candidates and keep those with the most matches on
|
||||
* exact types. Keep all candidates if none match.
|
||||
*/
|
||||
ncandidates = 0;
|
||||
nbestMatch = 0;
|
||||
@@ -273,10 +273,9 @@ oper_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Still too many candidates?
|
||||
* Run through all candidates and keep those with the most matches
|
||||
* on exact types + binary-compatible types.
|
||||
* Keep all candidates if none match.
|
||||
* Still too many candidates? Run through all candidates and keep
|
||||
* those with the most matches on exact types + binary-compatible
|
||||
* types. Keep all candidates if none match.
|
||||
*/
|
||||
ncandidates = 0;
|
||||
nbestMatch = 0;
|
||||
@@ -323,10 +322,9 @@ oper_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Still too many candidates?
|
||||
* Now look for candidates which are preferred types at the args that
|
||||
* will require coercion.
|
||||
* Keep all candidates if none match.
|
||||
* Still too many candidates? Now look for candidates which are
|
||||
* preferred types at the args that will require coercion. Keep all
|
||||
* candidates if none match.
|
||||
*/
|
||||
ncandidates = 0;
|
||||
nbestMatch = 0;
|
||||
@@ -370,15 +368,16 @@ oper_select_candidate(int nargs,
|
||||
return candidates->args;
|
||||
|
||||
/*
|
||||
* Still too many candidates?
|
||||
* Try assigning types for the unknown columns.
|
||||
* Still too many candidates? Try assigning types for the unknown
|
||||
* columns.
|
||||
*
|
||||
* First try: if we have an unknown and a non-unknown input, see whether
|
||||
* there is a candidate all of whose input types are the same as the known
|
||||
* input type (there can be at most one such candidate). If so, use that
|
||||
* candidate. NOTE that this is cool only because operators can't
|
||||
* have more than 2 args, so taking the last non-unknown as current_type
|
||||
* can yield only one possibility if there is also an unknown.
|
||||
* there is a candidate all of whose input types are the same as the
|
||||
* known input type (there can be at most one such candidate). If so,
|
||||
* use that candidate. NOTE that this is cool only because operators
|
||||
* can't have more than 2 args, so taking the last non-unknown as
|
||||
* current_type can yield only one possibility if there is also an
|
||||
* unknown.
|
||||
*/
|
||||
unknownOids = FALSE;
|
||||
current_type = UNKNOWNOID;
|
||||
@@ -410,16 +409,16 @@ oper_select_candidate(int nargs,
|
||||
}
|
||||
|
||||
/*
|
||||
* Second try: examine each unknown argument position to see if all the
|
||||
* candidates agree on the type category of that slot. If so, and if some
|
||||
* candidates accept the preferred type in that category, eliminate the
|
||||
* candidates with other input types. If we are down to one candidate
|
||||
* at the end, we win.
|
||||
* Second try: examine each unknown argument position to see if all
|
||||
* the candidates agree on the type category of that slot. If so, and
|
||||
* if some candidates accept the preferred type in that category,
|
||||
* eliminate the candidates with other input types. If we are down to
|
||||
* one candidate at the end, we win.
|
||||
*
|
||||
* XXX It's kinda bogus to do this left-to-right, isn't it? If we
|
||||
* eliminate some candidates because they are non-preferred at the first
|
||||
* slot, we won't notice that they didn't have the same type category for
|
||||
* a later slot.
|
||||
* eliminate some candidates because they are non-preferred at the
|
||||
* first slot, we won't notice that they didn't have the same type
|
||||
* category for a later slot.
|
||||
*/
|
||||
for (i = 0; i < nargs; i++)
|
||||
{
|
||||
@@ -472,7 +471,7 @@ oper_select_candidate(int nargs,
|
||||
last_candidate = current_candidate;
|
||||
}
|
||||
}
|
||||
if (last_candidate) /* terminate rebuilt list */
|
||||
if (last_candidate) /* terminate rebuilt list */
|
||||
last_candidate->next = NULL;
|
||||
}
|
||||
}
|
||||
@@ -588,9 +587,7 @@ oper(char *opname, Oid ltypeId, Oid rtypeId, bool noWarnings)
|
||||
{
|
||||
}
|
||||
else if (!noWarnings)
|
||||
{
|
||||
op_error(opname, ltypeId, rtypeId);
|
||||
}
|
||||
|
||||
return (Operator) tup;
|
||||
} /* oper() */
|
||||
@@ -679,14 +676,12 @@ right_oper(char *op, Oid arg)
|
||||
/* Try for inexact matches */
|
||||
ncandidates = unary_oper_get_candidates(op, &candidates, 'r');
|
||||
if (ncandidates == 0)
|
||||
{
|
||||
unary_op_error(op, arg, FALSE);
|
||||
}
|
||||
else if (ncandidates == 1)
|
||||
{
|
||||
tup = SearchSysCacheTuple(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(candidates->args[0]),
|
||||
ObjectIdGetDatum(candidates->args[0]),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
CharGetDatum('r'));
|
||||
}
|
||||
@@ -731,15 +726,13 @@ left_oper(char *op, Oid arg)
|
||||
/* Try for inexact matches */
|
||||
ncandidates = unary_oper_get_candidates(op, &candidates, 'l');
|
||||
if (ncandidates == 0)
|
||||
{
|
||||
unary_op_error(op, arg, TRUE);
|
||||
}
|
||||
else if (ncandidates == 1)
|
||||
{
|
||||
tup = SearchSysCacheTuple(OPERNAME,
|
||||
PointerGetDatum(op),
|
||||
ObjectIdGetDatum(InvalidOid),
|
||||
ObjectIdGetDatum(candidates->args[0]),
|
||||
ObjectIdGetDatum(candidates->args[0]),
|
||||
CharGetDatum('l'));
|
||||
}
|
||||
else
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.39 2000/03/23 07:38:30 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_relation.c,v 1.40 2000/04/12 17:15:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -76,7 +76,7 @@ static char *attnum_type[SPECIALS] = {
|
||||
* - thomas 2000-03-04
|
||||
*/
|
||||
List *
|
||||
refnameRangeTableEntries(ParseState *pstate, char *refname);
|
||||
refnameRangeTableEntries(ParseState *pstate, char *refname);
|
||||
|
||||
List *
|
||||
refnameRangeTableEntries(ParseState *pstate, char *refname)
|
||||
@@ -119,7 +119,7 @@ refnameRangeTableEntry(ParseState *pstate, char *refname)
|
||||
}
|
||||
|
||||
/* given refname, return RT index (starting with 1) of the relation,
|
||||
* and optionally get its nesting depth (0 = current). If sublevels_up
|
||||
* and optionally get its nesting depth (0 = current). If sublevels_up
|
||||
* is NULL, only consider rels at the current nesting level.
|
||||
*/
|
||||
int
|
||||
@@ -179,8 +179,9 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
|
||||
|
||||
if (rte->eref->attrs != NULL)
|
||||
{
|
||||
List *c;
|
||||
foreach (c, rte->ref->attrs)
|
||||
List *c;
|
||||
|
||||
foreach(c, rte->ref->attrs)
|
||||
{
|
||||
if (strcmp(strVal(lfirst(c)), colname) == 0)
|
||||
{
|
||||
@@ -192,16 +193,14 @@ colnameRangeTableEntry(ParseState *pstate, char *colname)
|
||||
}
|
||||
}
|
||||
|
||||
/* 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
|
||||
/*
|
||||
* 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;
|
||||
@@ -236,18 +235,18 @@ addRangeTableEntry(ParseState *pstate,
|
||||
bool inFromCl,
|
||||
bool inJoinSet)
|
||||
{
|
||||
Relation rel;
|
||||
RangeTblEntry *rte;
|
||||
Attr *eref;
|
||||
int maxattrs;
|
||||
int sublevels_up;
|
||||
int varattno;
|
||||
Relation rel;
|
||||
RangeTblEntry *rte;
|
||||
Attr *eref;
|
||||
int maxattrs;
|
||||
int sublevels_up;
|
||||
int varattno;
|
||||
|
||||
/* Look for an existing rte, if available... */
|
||||
if (pstate != NULL)
|
||||
{
|
||||
int rt_index = refnameRangeTablePosn(pstate, ref->relname,
|
||||
&sublevels_up);
|
||||
int rt_index = refnameRangeTablePosn(pstate, ref->relname,
|
||||
&sublevels_up);
|
||||
|
||||
if (rt_index != 0 && (!inFromCl || sublevels_up == 0))
|
||||
{
|
||||
@@ -262,12 +261,11 @@ addRangeTableEntry(ParseState *pstate,
|
||||
rte->relname = relname;
|
||||
rte->ref = ref;
|
||||
|
||||
/* Get the rel's OID. This access also ensures that we have an
|
||||
* up-to-date relcache entry for the rel. We don't need to keep
|
||||
* it open, however.
|
||||
* Since this is open anyway, let's check that the number of column
|
||||
* aliases is reasonable.
|
||||
* - Thomas 2000-02-04
|
||||
/*
|
||||
* Get the rel's OID. This access also ensures that we have an
|
||||
* up-to-date relcache entry for the rel. We don't need to keep it
|
||||
* open, however. Since this is open anyway, let's check that the
|
||||
* number of column aliases is reasonable. - Thomas 2000-02-04
|
||||
*/
|
||||
rel = heap_openr(relname, AccessShareLock);
|
||||
rte->relid = RelationGetRelid(rel);
|
||||
@@ -290,10 +288,9 @@ addRangeTableEntry(ParseState *pstate,
|
||||
rte->eref = eref;
|
||||
|
||||
/*
|
||||
* Flags:
|
||||
* - this RTE should be expanded to include descendant tables,
|
||||
* - this RTE is in the FROM clause,
|
||||
* - this RTE should be included in the planner's final join.
|
||||
* Flags: - this RTE should be expanded to include descendant tables,
|
||||
* - this RTE is in the FROM clause, - this RTE should be included in
|
||||
* the planner's final join.
|
||||
*/
|
||||
rte->inh = inh;
|
||||
rte->inFromCl = inFromCl;
|
||||
@@ -318,18 +315,16 @@ addRangeTableEntry(ParseState *pstate,
|
||||
Attr *
|
||||
expandTable(ParseState *pstate, char *refname, bool getaliases)
|
||||
{
|
||||
Attr *attr;
|
||||
RangeTblEntry *rte;
|
||||
Relation rel;
|
||||
Attr *attr;
|
||||
RangeTblEntry *rte;
|
||||
Relation rel;
|
||||
int varattno,
|
||||
maxattrs;
|
||||
|
||||
rte = refnameRangeTableEntry(pstate, refname);
|
||||
|
||||
if (getaliases && (rte != NULL))
|
||||
{
|
||||
return rte->eref;
|
||||
}
|
||||
|
||||
if (rte != NULL)
|
||||
rel = heap_open(rte->relid, AccessShareLock);
|
||||
@@ -350,7 +345,7 @@ expandTable(ParseState *pstate, char *refname, bool getaliases)
|
||||
#ifdef _DROP_COLUMN_HACK__
|
||||
if (COLUMN_IS_DROPPED(rel->rd_att->attrs[varattno]))
|
||||
continue;
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
|
||||
attr->attrs = lappend(attr->attrs, makeString(attrname));
|
||||
}
|
||||
@@ -367,11 +362,11 @@ expandTable(ParseState *pstate, char *refname, bool getaliases)
|
||||
List *
|
||||
expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno)
|
||||
{
|
||||
List *te_list = NIL;
|
||||
RangeTblEntry *rte;
|
||||
Relation rel;
|
||||
int varattno,
|
||||
maxattrs;
|
||||
List *te_list = NIL;
|
||||
RangeTblEntry *rte;
|
||||
Relation rel;
|
||||
int varattno,
|
||||
maxattrs;
|
||||
|
||||
rte = refnameRangeTableEntry(pstate, ref->relname);
|
||||
if (rte == NULL)
|
||||
@@ -379,9 +374,9 @@ expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno)
|
||||
rte = addRangeTableEntry(pstate, relname, ref,
|
||||
FALSE, FALSE, TRUE);
|
||||
#ifdef WARN_FROM
|
||||
elog(NOTICE,"Adding missing FROM-clause entry%s for table %s",
|
||||
pstate->parentParseState != NULL ? " in subquery" : "",
|
||||
refname);
|
||||
elog(NOTICE, "Adding missing FROM-clause entry%s for table %s",
|
||||
pstate->parentParseState != NULL ? " in subquery" : "",
|
||||
refname);
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -391,18 +386,21 @@ expandAll(ParseState *pstate, char *relname, Attr *ref, int *this_resno)
|
||||
|
||||
for (varattno = 0; varattno < maxattrs; varattno++)
|
||||
{
|
||||
char *attrname;
|
||||
char *label;
|
||||
Var *varnode;
|
||||
TargetEntry *te = makeNode(TargetEntry);
|
||||
char *attrname;
|
||||
char *label;
|
||||
Var *varnode;
|
||||
TargetEntry *te = makeNode(TargetEntry);
|
||||
|
||||
#ifdef _DROP_COLUMN_HACK__
|
||||
if (COLUMN_IS_DROPPED(rel->rd_att->attrs[varattno]))
|
||||
continue;
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
attrname = pstrdup(NameStr(rel->rd_att->attrs[varattno]->attname));
|
||||
|
||||
/* varattno is zero-based, so check that length() is always greater */
|
||||
/*
|
||||
* varattno is zero-based, so check that length() is always
|
||||
* greater
|
||||
*/
|
||||
if (length(rte->eref->attrs) > varattno)
|
||||
label = pstrdup(strVal(nth(varattno, rte->eref->attrs)));
|
||||
else
|
||||
@@ -452,7 +450,7 @@ attnameAttNum(Relation rd, char *a)
|
||||
/* on failure */
|
||||
elog(ERROR, "Relation '%s' does not have attribute '%s'",
|
||||
RelationGetRelationName(rd), a);
|
||||
return InvalidAttrNumber; /* lint */
|
||||
return InvalidAttrNumber; /* lint */
|
||||
}
|
||||
|
||||
/* specialAttNum()
|
||||
@@ -528,8 +526,3 @@ attnumTypeId(Relation rd, int attid)
|
||||
*/
|
||||
return rd->rd_att->attrs[attid - 1]->atttypid;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.57 2000/03/14 23:06:33 thomas Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parse_target.c,v 1.58 2000/04/12 17:15:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -61,7 +61,9 @@ transformTargetEntry(ParseState *pstate,
|
||||
|
||||
if (colname == NULL)
|
||||
{
|
||||
/* Generate a suitable column name for a column without any
|
||||
|
||||
/*
|
||||
* Generate a suitable column name for a column without any
|
||||
* explicit 'AS ColumnName' clause.
|
||||
*/
|
||||
colname = FigureColname(expr, node);
|
||||
@@ -101,14 +103,16 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
|
||||
if (att->relname != NULL && strcmp(att->relname, "*") == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Target item is a single '*', expand all tables
|
||||
* (eg. SELECT * FROM emp)
|
||||
* Target item is a single '*', expand all tables (eg.
|
||||
* SELECT * FROM emp)
|
||||
*/
|
||||
if (pstate->p_shape != NULL)
|
||||
{
|
||||
List *s, *a;
|
||||
int i;
|
||||
List *s,
|
||||
*a;
|
||||
int i;
|
||||
|
||||
Assert(length(pstate->p_shape) == length(pstate->p_alias));
|
||||
|
||||
@@ -116,12 +120,12 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
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);
|
||||
TargetEntry *te;
|
||||
char *colname;
|
||||
Attr *shape = lfirst(s);
|
||||
Attr *alias = lfirst(a);
|
||||
|
||||
Assert(IsA(shape, Attr) && IsA(alias, Attr));
|
||||
Assert(IsA(shape, Attr) &&IsA(alias, Attr));
|
||||
|
||||
colname = strVal(lfirst(alias->attrs));
|
||||
te = transformTargetEntry(pstate, (Node *) shape,
|
||||
@@ -138,9 +142,10 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
else if (att->attrs != NIL &&
|
||||
strcmp(strVal(lfirst(att->attrs)), "*") == 0)
|
||||
{
|
||||
|
||||
/*
|
||||
* Target item is relation.*, expand that table
|
||||
* (eg. SELECT emp.*, dname FROM emp, dept)
|
||||
* Target item is relation.*, expand that table (eg.
|
||||
* SELECT emp.*, dname FROM emp, dept)
|
||||
*/
|
||||
p_target = nconc(p_target,
|
||||
expandAll(pstate, att->relname,
|
||||
@@ -178,7 +183,7 @@ transformTargetList(ParseState *pstate, List *targetlist)
|
||||
|
||||
/*
|
||||
* updateTargetListEntry()
|
||||
* This is used in INSERT and UPDATE statements only. It prepares a
|
||||
* This is used in INSERT and UPDATE statements only. It prepares a
|
||||
* TargetEntry for assignment to a column of the target table.
|
||||
* This includes coercing the given value to the target column's type
|
||||
* (if necessary), and dealing with any subscripts attached to the target
|
||||
@@ -197,7 +202,7 @@ updateTargetListEntry(ParseState *pstate,
|
||||
int attrno,
|
||||
List *indirection)
|
||||
{
|
||||
Oid type_id = exprType(tle->expr); /* type of value provided */
|
||||
Oid type_id = exprType(tle->expr); /* type of value provided */
|
||||
Oid attrtype; /* type of target column */
|
||||
int32 attrtypmod;
|
||||
Resdom *resnode = tle->resdom;
|
||||
@@ -210,18 +215,20 @@ updateTargetListEntry(ParseState *pstate,
|
||||
attrtypmod = rd->rd_att->attrs[attrno - 1]->atttypmod;
|
||||
|
||||
/*
|
||||
* If there are subscripts on the target column, prepare an
|
||||
* array assignment expression. This will generate an array value
|
||||
* that the source value has been inserted into, which can then
|
||||
* be placed in the new tuple constructed by INSERT or UPDATE.
|
||||
* Note that transformArraySubscripts takes care of type coercion.
|
||||
* If there are subscripts on the target column, prepare an array
|
||||
* assignment expression. This will generate an array value that the
|
||||
* source value has been inserted into, which can then be placed in
|
||||
* the new tuple constructed by INSERT or UPDATE. Note that
|
||||
* transformArraySubscripts takes care of type coercion.
|
||||
*/
|
||||
if (indirection)
|
||||
{
|
||||
#ifndef DISABLE_JOIN_SYNTAX
|
||||
Attr *att = makeAttr(pstrdup(RelationGetRelationName(rd)), colname);
|
||||
|
||||
#else
|
||||
Attr *att = makeNode(Attr);
|
||||
|
||||
#endif
|
||||
Node *arrayBase;
|
||||
ArrayRef *aref;
|
||||
@@ -239,24 +246,26 @@ updateTargetListEntry(ParseState *pstate,
|
||||
tle->expr);
|
||||
if (pstate->p_is_insert)
|
||||
{
|
||||
|
||||
/*
|
||||
* The command is INSERT INTO table (arraycol[subscripts]) ...
|
||||
* so there is not really a source array value to work with.
|
||||
* Let the executor do something reasonable, if it can.
|
||||
* Notice that we forced transformArraySubscripts to treat
|
||||
* the subscripting op as an array-slice op above, so the
|
||||
* source data will have been coerced to array type.
|
||||
* Let the executor do something reasonable, if it can. Notice
|
||||
* that we forced transformArraySubscripts to treat the
|
||||
* subscripting op as an array-slice op above, so the source
|
||||
* data will have been coerced to array type.
|
||||
*/
|
||||
aref->refexpr = NULL; /* signal there is no source array */
|
||||
aref->refexpr = NULL; /* signal there is no source array */
|
||||
}
|
||||
tle->expr = (Node *) aref;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* For normal non-subscripted target column, do type checking
|
||||
* and coercion. But accept InvalidOid, which indicates the
|
||||
* source is a NULL constant.
|
||||
* For normal non-subscripted target column, do type checking and
|
||||
* coercion. But accept InvalidOid, which indicates the source is
|
||||
* a NULL constant.
|
||||
*/
|
||||
if (type_id != InvalidOid)
|
||||
{
|
||||
@@ -267,11 +276,12 @@ updateTargetListEntry(ParseState *pstate,
|
||||
if (tle->expr == NULL)
|
||||
elog(ERROR, "Attribute '%s' is of type '%s'"
|
||||
" but expression is of type '%s'"
|
||||
"\n\tYou will need to rewrite or cast the expression",
|
||||
"\n\tYou will need to rewrite or cast the expression",
|
||||
colname,
|
||||
typeidTypeName(attrtype),
|
||||
typeidTypeName(type_id));
|
||||
}
|
||||
|
||||
/*
|
||||
* If the target is a fixed-length type, it may need a length
|
||||
* coercion as well as a type coercion.
|
||||
@@ -282,9 +292,10 @@ updateTargetListEntry(ParseState *pstate,
|
||||
}
|
||||
|
||||
/*
|
||||
* The result of the target expression should now match the destination
|
||||
* column's type. Also, reset the resname and resno to identify
|
||||
* the destination column --- rewriter and planner depend on that!
|
||||
* The result of the target expression should now match the
|
||||
* destination column's type. Also, reset the resname and resno to
|
||||
* identify the destination column --- rewriter and planner depend on
|
||||
* that!
|
||||
*/
|
||||
resnode->restype = attrtype;
|
||||
resnode->restypmod = attrtypmod;
|
||||
@@ -344,6 +355,7 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
|
||||
|
||||
if (cols == NIL)
|
||||
{
|
||||
|
||||
/*
|
||||
* Generate default column list for INSERT.
|
||||
*/
|
||||
@@ -357,20 +369,19 @@ checkInsertTargets(ParseState *pstate, List *cols, List **attrnos)
|
||||
|
||||
#ifdef _DROP_COLUMN_HACK__
|
||||
if (COLUMN_IS_DROPPED(attr[i]))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
#endif /* _DROP_COLUMN_HACK__ */
|
||||
id->name = palloc(NAMEDATALEN);
|
||||
StrNCpy(id->name, NameStr(attr[i]->attname), NAMEDATALEN);
|
||||
id->indirection = NIL;
|
||||
id->isRel = false;
|
||||
cols = lappend(cols, id);
|
||||
*attrnos = lappendi(*attrnos, i+1);
|
||||
*attrnos = lappendi(*attrnos, i + 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/*
|
||||
* Do initial validation of user-supplied INSERT column list.
|
||||
*/
|
||||
@@ -407,6 +418,7 @@ ExpandAllTables(ParseState *pstate)
|
||||
rtable = pstate->p_rtable;
|
||||
if (pstate->p_is_rule)
|
||||
{
|
||||
|
||||
/*
|
||||
* skip first two entries, "*new*" and "*current*"
|
||||
*/
|
||||
@@ -422,9 +434,9 @@ ExpandAllTables(ParseState *pstate)
|
||||
RangeTblEntry *rte = lfirst(rt);
|
||||
|
||||
/*
|
||||
* we only expand those listed in the from clause. (This will
|
||||
* also prevent us from using the wrong table in inserts: eg.
|
||||
* tenk2 in "insert into tenk2 select * from tenk1;")
|
||||
* we only expand those listed in the from clause. (This will also
|
||||
* prevent us from using the wrong table in inserts: eg. tenk2 in
|
||||
* "insert into tenk2 select * from tenk1;")
|
||||
*/
|
||||
if (!rte->inFromCl)
|
||||
continue;
|
||||
@@ -449,11 +461,12 @@ FigureColname(Node *expr, Node *resval)
|
||||
/* Some of these are easiest to do with the untransformed node */
|
||||
switch (nodeTag(resval))
|
||||
{
|
||||
case T_Ident:
|
||||
case T_Ident:
|
||||
return ((Ident *) resval)->name;
|
||||
case T_Attr:
|
||||
{
|
||||
List *attrs = ((Attr *) resval)->attrs;
|
||||
|
||||
if (attrs)
|
||||
{
|
||||
while (lnext(attrs) != NIL)
|
||||
|
||||
@@ -7,7 +7,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.44 2000/03/17 05:29:05 tgl Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.45 2000/04/12 17:15:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#if defined(FLEX_SCANNER)
|
||||
extern void DeleteBuffer(void);
|
||||
|
||||
#endif /* FLEX_SCANNER */
|
||||
|
||||
char *parseString; /* the char* which holds the string to be
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.18 2000/01/26 05:56:43 momjian Exp $
|
||||
* $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.19 2000/04/12 17:15:27 momjian Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -44,7 +44,7 @@ scanstr(char *s)
|
||||
|
||||
len = strlen(s);
|
||||
|
||||
newStr = palloc(len+1); /* string cannot get longer */
|
||||
newStr = palloc(len + 1); /* string cannot get longer */
|
||||
|
||||
for (i = 0, j = 0; i < len; i++)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user