aboutsummaryrefslogtreecommitdiff
path: root/src/backend/parser/analyze.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/parser/analyze.c')
-rw-r--r--src/backend/parser/analyze.c2692
1 files changed, 15 insertions, 2677 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index bee5132a8b9..4a3800a8a4e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -7,46 +7,30 @@
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.49 1997/11/20 23:22:11 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.50 1997/11/25 22:00:27 momjian Exp $
*
*-------------------------------------------------------------------------
*/
+
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "postgres.h"
-#include "nodes/nodes.h"
-#include "nodes/params.h"
-#include "nodes/primnodes.h"
-#include "nodes/parsenodes.h"
-#include "nodes/relation.h"
-#include "parse.h" /* for AND, OR, etc. */
-#include "catalog/pg_aggregate.h"
-#include "catalog/pg_type.h" /* for INT4OID, etc. */
-#include "catalog/pg_proc.h"
-#include "utils/elog.h"
-#include "utils/builtins.h" /* namecmp(), textout() */
-#include "utils/lsyscache.h"
-#include "utils/palloc.h"
-#include "utils/mcxt.h"
-#include "utils/syscache.h"
-#include "utils/acl.h"
-#include "parser/parse_query.h"
-#include "parser/parse_state.h"
-#include "nodes/makefuncs.h" /* for makeResdom(), etc. */
-#include "nodes/nodeFuncs.h"
-#include "commands/sequence.h"
-
-#include "optimizer/clauses.h"
-#include "access/heapam.h"
-#include "miscadmin.h"
-
-#include "port-protos.h" /* strdup() */
+#include "access/heapam.h"
+#include "nodes/makefuncs.h"
+#include "nodes/memnodes.h"
+#include "nodes/pg_list.h"
+#include "parser/analyze.h"
+#include "parser/parse_agg.h"
+#include "parser/parse_node.h"
+#include "parser/parse_relation.h"
+#include "parser/parse_target.h"
+#include "parser/parse_clause.h"
+#include "utils/builtins.h"
+#include "utils/mcxt.h"
-/* convert the parse tree into a query tree */
static Query *transformStmt(ParseState *pstate, Node *stmt);
-
static Query *transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt);
static Query *transformInsertStmt(ParseState *pstate, AppendStmt *stmt);
static Query *transformIndexStmt(ParseState *pstate, IndexStmt *stmt);
@@ -55,74 +39,7 @@ static Query *transformRuleStmt(ParseState *query, RuleStmt *stmt);
static Query *transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt);
static Query *transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt);
static Query *transformCursorStmt(ParseState *pstate, CursorStmt *stmt);
-static Node *handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno);
-
-#define EXPR_COLUMN_FIRST 1
-#define EXPR_RELATION_FIRST 2
-static Node *transformExpr(ParseState *pstate, Node *expr, int precedence);
-static Node *transformIdent(ParseState *pstate, Node *expr, int precedence);
-
-static void makeRangeTable(ParseState *pstate, char *relname, List *frmList);
-static List *expandAllTables(ParseState *pstate);
-static char *figureColname(Node *expr, Node *resval);
-static List *makeTargetNames(ParseState *pstate, List *cols);
-static List *transformTargetList(ParseState *pstate, List *targetlist);
-static TargetEntry *make_targetlist_expr(ParseState *pstate,
- char *colname, Node *expr,
- List *arrayRef);
-static bool inWhereClause = false;
-static Node *transformWhereClause(ParseState *pstate, Node *a_expr);
-static List *transformGroupClause(ParseState *pstate, List *grouplist,
- List *targetlist);
-static List *transformSortClause(ParseState *pstate,
- List *orderlist, List *targetlist,
- char *uniqueFlag);
-
-static void parseFromClause(ParseState *pstate, List *frmList);
-static Node *ParseFunc(ParseState *pstate, char *funcname,
- List *fargs, int *curr_resno);
-static List *setup_tlist(char *attname, Oid relid);
-static List *setup_base_tlist(Oid typeid);
-static void make_arguments(int nargs, List *fargs, Oid *input_typeids,
- Oid *function_typeids);
-static void AddAggToParseState(ParseState *pstate, Aggreg *aggreg);
-static void finalizeAggregates(ParseState *pstate, Query *qry);
-static void parseCheckAggregates(ParseState *pstate, Query *qry);
-static ParseState *makeParseState(void);
-static Node *parser_typecast(Value *expr, TypeName *typename, int typlen);
-static Node *parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen);
-static Aggreg *ParseAgg(char *aggname, Oid basetype, Node *target);
-
-/*****************************************************************************
- *
- *****************************************************************************/
-
-/*
- * makeParseState() --
- * allocate and initialize a new ParseState.
- * the CALLERS is responsible for freeing the ParseState* returned
- *
- */
-static ParseState *
-makeParseState(void)
-{
- ParseState *pstate;
-
- pstate = malloc(sizeof(ParseState));
- pstate->p_last_resno = 1;
- pstate->p_rtable = NIL;
- pstate->p_numAgg = 0;
- pstate->p_aggs = NIL;
- pstate->p_is_insert = false;
- pstate->p_insert_columns = NIL;
- pstate->p_is_update = false;
- pstate->p_is_rule = false;
- pstate->p_target_relation = NULL;
- pstate->p_target_rangetblentry = NULL;
-
- return (pstate);
-}
/*
* parse_analyze -
@@ -144,11 +61,9 @@ parse_analyze(List *pl)
result->len = length(pl);
result->qtrees = (Query **) malloc(result->len * sizeof(Query *));
- inWhereClause = false; /* to avoid nextval(sequence) in WHERE */
-
while (pl != NIL)
{
- pstate = makeParseState();
+ pstate = make_parsestate();
result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
pl = lnext(pl);
if (pstate->p_target_relation != NULL)
@@ -620,2580 +535,3 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
return (Query *) qry;
}
-
-/*****************************************************************************
- *
- * Transform Exprs, Aggs, etc.
- *
- *****************************************************************************/
-
-/*
- * transformExpr -
- * analyze and transform expressions. Type checking and type casting is
- * done here. The optimizer and the executor cannot handle the original
- * (raw) expressions collected by the parse tree. Hence the transformation
- * here.
- */
-static Node *
-transformExpr(ParseState *pstate, Node *expr, int precedence)
-{
- Node *result = NULL;
-
- if (expr == NULL)
- return NULL;
-
- switch (nodeTag(expr))
- {
- case T_Attr:
- {
- Attr *att = (Attr *) expr;
- Node *temp;
-
- /* what if att.attrs == "*"?? */
- temp = handleNestedDots(pstate, att, &pstate->p_last_resno);
- if (att->indirection != NIL)
- {
- List *idx = att->indirection;
-
- while (idx != NIL)
- {
- A_Indices *ai = (A_Indices *) lfirst(idx);
- Node *lexpr = NULL,
- *uexpr;
-
- uexpr = transformExpr(pstate, ai->uidx, precedence); /* must exists */
- if (exprType(uexpr) != INT4OID)
- elog(WARN, "array index expressions must be int4's");
- if (ai->lidx != NULL)
- {
- lexpr = transformExpr(pstate, ai->lidx, precedence);
- if (exprType(lexpr) != INT4OID)
- elog(WARN, "array index expressions must be int4's");
- }
-#if 0
- pfree(ai->uidx);
- if (ai->lidx != NULL)
- pfree(ai->lidx);
-#endif
- ai->lidx = lexpr;
- ai->uidx = uexpr;
-
- /*
- * note we reuse the list of indices, make sure we
- * don't free them! Otherwise, make a new list
- * here
- */
- idx = lnext(idx);
- }
- result = (Node *) make_array_ref(temp, att->indirection);
- }
- else
- {
- result = temp;
- }
- break;
- }
- case T_A_Const:
- {
- A_Const *con = (A_Const *) expr;
- Value *val = &con->val;
-
- if (con->typename != NULL)
- {
- result = parser_typecast(val, con->typename, -1);
- }
- else
- {
- result = (Node *) make_const(val);
- }
- break;
- }
- case T_ParamNo:
- {
- ParamNo *pno = (ParamNo *) expr;
- Oid toid;
- int paramno;
- Param *param;
-
- paramno = pno->number;
- toid = param_type(paramno);
- if (!OidIsValid(toid))
- {
- elog(WARN, "Parameter '$%d' is out of range",
- paramno);
- }
- param = makeNode(Param);
- param->paramkind = PARAM_NUM;
- param->paramid = (AttrNumber) paramno;
- param->paramname = "<unnamed>";
- param->paramtype = (Oid) toid;
- param->param_tlist = (List *) NULL;
-
- result = (Node *) param;
- break;
- }
- case T_A_Expr:
- {
- A_Expr *a = (A_Expr *) expr;
-
- switch (a->oper)
- {
- case OP:
- {
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
- result = (Node *) make_op(a->opname, lexpr, rexpr);
- }
- break;
- case ISNULL:
- {
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
-
- result = ParseFunc(pstate,
- "nullvalue", lcons(lexpr, NIL),
- &pstate->p_last_resno);
- }
- break;
- case NOTNULL:
- {
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
-
- result = ParseFunc(pstate,
- "nonnullvalue", lcons(lexpr, NIL),
- &pstate->p_last_resno);
- }
- break;
- case AND:
- {
- Expr *expr = makeNode(Expr);
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
- if (exprType(lexpr) != BOOLOID)
- elog(WARN,
- "left-hand side of AND is type '%s', not bool",
- tname(get_id_type(exprType(lexpr))));
- if (exprType(rexpr) != BOOLOID)
- elog(WARN,
- "right-hand side of AND is type '%s', not bool",
- tname(get_id_type(exprType(rexpr))));
- expr->typeOid = BOOLOID;
- expr->opType = AND_EXPR;
- expr->args = makeList(lexpr, rexpr, -1);
- result = (Node *) expr;
- }
- break;
- case OR:
- {
- Expr *expr = makeNode(Expr);
- Node *lexpr = transformExpr(pstate, a->lexpr, precedence);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
- if (exprType(lexpr) != BOOLOID)
- elog(WARN,
- "left-hand side of OR is type '%s', not bool",
- tname(get_id_type(exprType(lexpr))));
- if (exprType(rexpr) != BOOLOID)
- elog(WARN,
- "right-hand side of OR is type '%s', not bool",
- tname(get_id_type(exprType(rexpr))));
- expr->typeOid = BOOLOID;
- expr->opType = OR_EXPR;
- expr->args = makeList(lexpr, rexpr, -1);
- result = (Node *) expr;
- }
- break;
- case NOT:
- {
- Expr *expr = makeNode(Expr);
- Node *rexpr = transformExpr(pstate, a->rexpr, precedence);
-
- if (exprType(rexpr) != BOOLOID)
- elog(WARN,
- "argument to NOT is type '%s', not bool",
- tname(get_id_type(exprType(rexpr))));
- expr->typeOid = BOOLOID;
- expr->opType = NOT_EXPR;
- expr->args = makeList(rexpr, -1);
- result = (Node *) expr;
- }
- break;
- }
- break;
- }
- case T_Ident:
- {
-
- /*
- * look for a column name or a relation name (the default
- * behavior)
- */
- result = transformIdent(pstate, expr, precedence);
- break;
- }
- case T_FuncCall:
- {
- FuncCall *fn = (FuncCall *) expr;
- List *args;
-
- /* transform the list of arguments */
- foreach(args, fn->args)
- lfirst(args) = transformExpr(pstate, (Node *) lfirst(args), precedence);
- result = ParseFunc(pstate,
- fn->funcname, fn->args, &pstate->p_last_resno);
- break;
- }
- default:
- /* should not reach here */
- elog(WARN, "transformExpr: does not know how to transform %d\n",
- nodeTag(expr));
- break;
- }
-
- return result;
-}
-
-static Node *
-transformIdent(ParseState *pstate, Node *expr, int precedence)
-{
- Ident *ident = (Ident *) expr;
- RangeTblEntry *rte;
- Node *column_result,
- *relation_result,
- *result;
-
- column_result = relation_result = result = 0;
- /* try to find the ident as a column */
- if ((rte = colnameRangeTableEntry(pstate, ident->name)) != NULL)
- {
- Attr *att = makeNode(Attr);
-
- att->relname = rte->refname;
- att->attrs = lcons(makeString(ident->name), NIL);
- column_result =
- (Node *) handleNestedDots(pstate, att, &pstate->p_last_resno);
- }
-
- /* try to find the ident as a relation */
- if (refnameRangeTableEntry(pstate->p_rtable, ident->name) != NULL)
- {
- ident->isRel = TRUE;
- relation_result = (Node *) ident;
- }
-
- /* choose the right result based on the precedence */
- if (precedence == EXPR_COLUMN_FIRST)
- {
- if (column_result)
- result = column_result;
- else
- result = relation_result;
- }
- else
- {
- if (relation_result)
- result = relation_result;
- else
- result = column_result;
- }
-
- if (result == NULL)
- elog(WARN, "attribute '%s' not found", ident->name);
-
- return result;
-}
-
-/*****************************************************************************
- *
- * From Clause
- *
- *****************************************************************************/
-
-/*
- * parseFromClause -
- * turns the table references specified in the from-clause into a
- * range table. The range table may grow as we transform the expressions
- * in the target list. (Note that this happens because in POSTQUEL, we
- * allow references to relations not specified in the from-clause. We
- * also allow that in our POST-SQL)
- *
- */
-static void
-parseFromClause(ParseState *pstate, List *frmList)
-{
- List *fl;
-
- foreach(fl, frmList)
- {
- RangeVar *r = lfirst(fl);
- RelExpr *baserel = r->relExpr;
- char *relname = baserel->relname;
- char *refname = r->name;
- RangeTblEntry *rte;
-
- if (refname == NULL)
- refname = relname;
-
- /*
- * marks this entry to indicate it comes from the FROM clause. In
- * SQL, the target list can only refer to range variables
- * specified in the from clause but we follow the more powerful
- * POSTQUEL semantics and automatically generate the range
- * variable if not specified. However there are times we need to
- * know whether the entries are legitimate.
- *
- * eg. select * from foo f where f.x = 1; will generate wrong answer
- * if we expand * to foo.x.
- */
- rte = addRangeTableEntry(pstate, relname, refname, baserel->inh, TRUE);
- }
-}
-
-/*
- * makeRangeTable -
- * make a range table with the specified relation (optional) and the
- * from-clause.
- */
-static void
-makeRangeTable(ParseState *pstate, char *relname, List *frmList)
-{
- RangeTblEntry *rte;
-
- parseFromClause(pstate, frmList);
-
- if (relname == NULL)
- return;
-
- if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
- rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE);
- else
- rte = refnameRangeTableEntry(pstate->p_rtable, relname);
-
- pstate->p_target_rangetblentry = rte;
- Assert(pstate->p_target_relation == NULL);
- pstate->p_target_relation = heap_open(rte->relid);
- Assert(pstate->p_target_relation != NULL);
- /* will close relation later */
-}
-
-/*
- * exprType -
- * returns the Oid of the type of the expression. (Used for typechecking.)
- */
-Oid
-exprType(Node *expr)
-{
- Oid type = (Oid) 0;
-
- switch (nodeTag(expr))
- {
- case T_Func:
- type = ((Func *) expr)->functype;
- break;
- case T_Iter:
- type = ((Iter *) expr)->itertype;
- break;
- case T_Var:
- type = ((Var *) expr)->vartype;
- break;
- case T_Expr:
- type = ((Expr *) expr)->typeOid;
- break;
- case T_Const:
- type = ((Const *) expr)->consttype;
- break;
- case T_ArrayRef:
- type = ((ArrayRef *) expr)->refelemtype;
- break;
- case T_Aggreg:
- type = ((Aggreg *) expr)->aggtype;
- break;
- case T_Param:
- type = ((Param *) expr)->paramtype;
- break;
- case T_Ident:
- /* is this right? */
- type = UNKNOWNOID;
- break;
- default:
- elog(WARN, "exprType: don't know how to get type for %d node",
- nodeTag(expr));
- break;
- }
- return type;
-}
-
-/*
- * expandAllTables -
- * turns '*' (in the target list) into a list of attributes
- * (of all relations in the range table)
- */
-static List *
-expandAllTables(ParseState *pstate)
-{
- List *target = NIL;
- List *legit_rtable = NIL;
- List *rt,
- *rtable;
-
- rtable = pstate->p_rtable;
- if (pstate->p_is_rule)
- {
-
- /*
- * skip first two entries, "*new*" and "*current*"
- */
- rtable = lnext(lnext(pstate->p_rtable));
- }
-
- /* this should not happen */
- if (rtable == NULL)
- elog(WARN, "cannot expand: null p_rtable");
-
- /*
- * go through the range table and make a list of range table entries
- * which we will expand.
- */
- foreach(rt, rtable)
- {
- RangeTblEntry *rte = lfirst(rt);
-
- /*
- * we only expand those specify 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;
- legit_rtable = lappend(legit_rtable, rte);
- }
-
- foreach(rt, legit_rtable)
- {
- RangeTblEntry *rte = lfirst(rt);
- List *temp = target;
-
- if (temp == NIL)
- target = expandAll(pstate, rte->relname, rte->refname,
- &pstate->p_last_resno);
- else
- {
- while (temp != NIL && lnext(temp) != NIL)
- temp = lnext(temp);
- lnext(temp) = expandAll(pstate, rte->relname, rte->refname,
- &pstate->p_last_resno);
- }
- }
- return target;
-}
-
-
-/*
- * figureColname -
- * if the name of the resulting column is not specified in the target
- * list, we have to guess.
- *
- */
-static char *
-figureColname(Node *expr, Node *resval)
-{
- switch (nodeTag(expr))
- {
- case T_Aggreg:
- return (char *) /* XXX */
- ((Aggreg *) expr)->aggname;
- case T_Expr:
- if (((Expr *) expr)->opType == FUNC_EXPR)
- {
- if (nodeTag(resval) == T_FuncCall)
- return ((FuncCall *) resval)->funcname;
- }
- break;
- default:
- break;
- }
-
- return "?column?";
-}
-
-/*****************************************************************************
- *
- * Target list
- *
- *****************************************************************************/
-
-/*
- * makeTargetNames -
- * generate a list of column names if not supplied or
- * test supplied column names to make sure they are in target table
- * (used exclusively for inserts)
- */
-static List *
-makeTargetNames(ParseState *pstate, List *cols)
-{
- List *tl = NULL;
-
- /* Generate ResTarget if not supplied */
-
- if (cols == NIL)
- {
- int numcol;
- int i;
- AttributeTupleForm *attr = pstate->p_target_relation->rd_att->attrs;
-
- numcol = pstate->p_target_relation->rd_rel->relnatts;
- for (i = 0; i < numcol; i++)
- {
- Ident *id = makeNode(Ident);
-
- id->name = palloc(NAMEDATALEN);
- StrNCpy(id->name, attr[i]->attname.data, NAMEDATALEN);
- id->indirection = NIL;
- id->isRel = false;
- if (tl == NIL)
- cols = tl = lcons(id, NIL);
- else
- {
- lnext(tl) = lcons(id, NIL);
- tl = lnext(tl);
- }
- }
- }
- else
- {
- foreach(tl, cols)
- {
- List *nxt;
- char *name = ((Ident *) lfirst(tl))->name;
-
- /* elog on failure */
- varattno(pstate->p_target_relation, name);
- foreach(nxt, lnext(tl))
- if (!strcmp(name, ((Ident *) lfirst(nxt))->name))
- elog (WARN, "Attribute '%s' should be specified only once", name);
- }
- }
-
- return cols;
-}
-
-/*
- * transformTargetList -
- * turns a list of ResTarget's into a list of TargetEntry's
- */
-static List *
-transformTargetList(ParseState *pstate, List *targetlist)
-{
- List *p_target = NIL;
- List *tail_p_target = NIL;
-
- while (targetlist != NIL)
- {
- ResTarget *res = (ResTarget *) lfirst(targetlist);
- TargetEntry *tent = makeNode(TargetEntry);
-
- switch (nodeTag(res->val))
- {
- case T_Ident:
- {
- Node *expr;
- Oid type_id;
- int type_len;
- char *identname;
- char *resname;
-
- identname = ((Ident *) res->val)->name;
- handleTargetColname(pstate, &res->name, NULL, identname);
-
- /*
- * here we want to look for column names only, not relation
- * names (even though they can be stored in Ident nodes, too)
- */
- expr = transformIdent(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
- type_id = exprType(expr);
- type_len = tlen(get_id_type(type_id));
- resname = (res->name) ? res->name : identname;
- tent->resdom = makeResdom((AttrNumber) pstate->p_last_resno++,
- (Oid) type_id,
- (Size) type_len,
- resname,
- (Index) 0,
- (Oid) 0,
- 0);
-
- tent->expr = expr;
- break;
- }
- case T_ParamNo:
- case T_FuncCall:
- case T_A_Const:
- case T_A_Expr:
- {
- Node *expr = transformExpr(pstate, (Node *) res->val, EXPR_COLUMN_FIRST);
-
- handleTargetColname(pstate, &res->name, NULL, NULL);
- /* note indirection has not been transformed */
- if (pstate->p_is_insert && res->indirection != NIL)
- {
- /* this is an array assignment */
- char *val;
- char *str,
- *save_str;
- List *elt;
- int i = 0,
- ndims;
- int lindx[MAXDIM],
- uindx[MAXDIM];
- int resdomno;
- Relation rd;
- Value *constval;
-
- if (exprType(expr) != UNKNOWNOID ||
- !IsA(expr, Const))
- elog(WARN, "yyparse: string constant expected");
-
- val = (char *) textout((struct varlena *)
- ((Const *) expr)->constvalue);
- str = save_str = (char *) palloc(strlen(val) + MAXDIM * 25 + 2);
- foreach(elt, res->indirection)
- {
- A_Indices *aind = (A_Indices *) lfirst(elt);
-
- aind->uidx = transformExpr(pstate, aind->uidx, EXPR_COLUMN_FIRST);
- if (!IsA(aind->uidx, Const))
- elog(WARN,
- "Array Index for Append should be a constant");
- uindx[i] = ((Const *) aind->uidx)->constvalue;
- if (aind->lidx != NULL)
- {
- aind->lidx = transformExpr(pstate, aind->lidx, EXPR_COLUMN_FIRST);
- if (!IsA(aind->lidx, Const))
- elog(WARN,
- "Array Index for Append should be a constant");
- lindx[i] = ((Const *) aind->lidx)->constvalue;
- }
- else
- {
- lindx[i] = 1;
- }
- if (lindx[i] > uindx[i])
- elog(WARN, "yyparse: lower index cannot be greater than upper index");
- sprintf(str, "[%d:%d]", lindx[i], uindx[i]);
- str += strlen(str);
- i++;
- }
- sprintf(str, "=%s", val);
- rd = pstate->p_target_relation;
- Assert(rd != NULL);
- resdomno = varattno(rd, res->name);
- ndims = att_attnelems(rd, resdomno);
- if (i != ndims)
- elog(WARN, "yyparse: array dimensions do not match");
- constval = makeNode(Value);
- constval->type = T_String;
- constval->val.str = save_str;
- tent = make_targetlist_expr(pstate, res->name,
- (Node *) make_const(constval),
- NULL);
- pfree(save_str);
- }
- else
- {
- char *colname = res->name;
-
- /* this is not an array assignment */
- if (colname == NULL)
- {
-
- /*
- * if you're wondering why this is here, look
- * at the yacc grammar for why a name can be
- * missing. -ay
- */
- colname = figureColname(expr, res->val);
- }
- if (res->indirection)
- {
- List *ilist = res->indirection;
-
- while (ilist != NIL)
- {
- A_Indices *ind = lfirst(ilist);
-
- ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
- ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
- ilist = lnext(ilist);
- }
- }
- res->name = colname;
- tent = make_targetlist_expr(pstate, res->name, expr,
- res->indirection);
- }
- break;
- }
- case T_Attr:
- {
- Oid type_id;
- int type_len;
- Attr *att = (Attr *) res->val;
- Node *result;
- char *attrname;
- char *resname;
- Resdom *resnode;
- List *attrs = att->attrs;
-
- /*
- * Target item is a single '*', expand all tables (eg.
- * SELECT * FROM emp)
- */
- if (att->relname != NULL && !strcmp(att->relname, "*"))
- {
- if (tail_p_target == NIL)
- p_target = tail_p_target = expandAllTables(pstate);
- else
- lnext(tail_p_target) = expandAllTables(pstate);
-
- while (lnext(tail_p_target) != NIL)
- /* make sure we point to the last target entry */
- tail_p_target = lnext(tail_p_target);
-
- /*
- * skip rest of while loop
- */
- targetlist = lnext(targetlist);
- continue;
- }
-
- /*
- * Target item is relation.*, expand the table (eg.
- * SELECT emp.*, dname FROM emp, dept)
- */
- attrname = strVal(lfirst(att->attrs));
- if (att->attrs != NIL && !strcmp(attrname, "*"))
- {
-
- /*
- * tail_p_target is the target list we're building
- * in the while loop. Make sure we fix it after
- * appending more nodes.
- */
- if (tail_p_target == NIL)
- p_target = tail_p_target = expandAll(pstate, att->relname,
- att->relname, &pstate->p_last_resno);
- else
- lnext(tail_p_target) =
- expandAll(pstate, att->relname, att->relname,
- &pstate->p_last_resno);
- while (lnext(tail_p_target) != NIL)
- /* make sure we point to the last target entry */
- tail_p_target = lnext(tail_p_target);
-
- /*
- * skip the rest of the while loop
- */
- targetlist = lnext(targetlist);
- continue;
- }
-
-
- /*
- * Target item is fully specified: ie.
- * relation.attribute
- */
- result = handleNestedDots(pstate, att, &pstate->p_last_resno);
- handleTargetColname(pstate, &res->name, att->relname, attrname);
- if (att->indirection != NIL)
- {
- List *ilist = att->indirection;
-
- while (ilist != NIL)
- {
- A_Indices *ind = lfirst(ilist);
-
- ind->lidx = transformExpr(pstate, ind->lidx, EXPR_COLUMN_FIRST);
- ind->uidx = transformExpr(pstate, ind->uidx, EXPR_COLUMN_FIRST);
- ilist = lnext(ilist);
- }
- result = (Node *) make_array_ref(result, att->indirection);
- }
- type_id = exprType(result);
- type_len = tlen(get_id_type(type_id));
- /* move to last entry */
- while (lnext(attrs) != NIL)
- attrs = lnext(attrs);
- resname = (res->name) ? res->name : strVal(lfirst(attrs));
- resnode = makeResdom((AttrNumber) pstate->p_last_resno++,
- (Oid) type_id,
- (Size) type_len,
- resname,
- (Index) 0,
- (Oid) 0,
- 0);
- tent->resdom = resnode;
- tent->expr = result;
- break;
- }
- default:
- /* internal error */
- elog(WARN,
- "internal error: do not know how to transform targetlist");
- break;
- }
-
- if (p_target == NIL)
- {
- p_target = tail_p_target = lcons(tent, NIL);
- }
- else
- {
- lnext(tail_p_target) = lcons(tent, NIL);
- tail_p_target = lnext(tail_p_target);
- }
- targetlist = lnext(targetlist);
- }
-
- return p_target;
-}
-
-
-/*
- * make_targetlist_expr -
- * make a TargetEntry from an expression
- *
- * arrayRef is a list of transformed A_Indices
- */
-static TargetEntry *
-make_targetlist_expr(ParseState *pstate,
- char *colname,
- Node *expr,
- List *arrayRef)
-{
- Oid type_id,
- attrtype;
- int type_len,
- attrlen;
- int resdomno;
- Relation rd;
- bool attrisset;
- TargetEntry *tent;
- Resdom *resnode;
-
- if (expr == NULL)
- elog(WARN, "make_targetlist_expr: invalid use of NULL expression");
-
- type_id = exprType(expr);
- if (type_id == InvalidOid)
- {
- type_len = 0;
- }
- else
- type_len = tlen(get_id_type(type_id));
-
- /* I have no idea what the following does! */
- /* It appears to process target columns that will be receiving results */
- if (pstate->p_is_insert || pstate->p_is_update)
- {
-
- /*
- * append or replace query -- append, replace work only on one
- * relation, so multiple occurence of same resdomno is bogus
- */
- rd = pstate->p_target_relation;
- Assert(rd != NULL);
- resdomno = varattno(rd, colname);
- attrisset = varisset(rd, colname);
- attrtype = att_typeid(rd, resdomno);
- if ((arrayRef != NIL) && (lfirst(arrayRef) == NIL))
- attrtype = GetArrayElementType(attrtype);
- if (attrtype == BPCHAROID || attrtype == VARCHAROID)
- {
- attrlen = rd->rd_att->attrs[resdomno - 1]->attlen;
- }
- else
- {
- attrlen = tlen(get_id_type(attrtype));
- }
-#if 0
- if (Input_is_string && Typecast_ok)
- {
- Datum val;
-
- if (type_id == typeid(type("unknown")))
- {
- val = (Datum) textout((struct varlena *)
- ((Const) lnext(expr))->constvalue);
- }
- else
- {
- val = ((Const) lnext(expr))->constvalue;
- }
- if (attrisset)
- {
- lnext(expr) = makeConst(attrtype,
- attrlen,
- val,
- false,
- true,
- true, /* is set */
- false);
- }
- else
- {
- lnext(expr) =
- makeConst(attrtype,
- attrlen,
- (Datum) fmgr(typeid_get_retinfunc(attrtype),
- val, get_typelem(attrtype), -1),
- false,
- true /* Maybe correct-- 80% chance */ ,
- false, /* is not a set */
- false);
- }
- }
- else if ((Typecast_ok) && (attrtype != type_id))
- {
- lnext(expr) =
- parser_typecast2(expr, get_id_type(attrtype));
- }
- else if (attrtype != type_id)
- {
- if ((attrtype == INT2OID) && (type_id == INT4OID))
- lfirst(expr) = lispInteger(INT2OID); /* handle CASHOID too */
- else if ((attrtype == FLOAT4OID) && (type_id == FLOAT8OID))
- lfirst(expr) = lispInteger(FLOAT4OID);
- else
- elog(WARN, "unequal type in tlist : %s \n", colname);
- }
-
- Input_is_string = false;
- Input_is_integer = false;
- Typecast_ok = true;
-#endif
-
- if (attrtype != type_id)
- {
- if (IsA(expr, Const))
- {
- /* try to cast the constant */
- if (arrayRef && !(((A_Indices *) lfirst(arrayRef))->lidx))
- {
- /* updating a single item */
- Oid typelem = get_typelem(attrtype);
-
- expr = (Node *) parser_typecast2(expr,
- type_id,
- get_id_type(typelem),
- attrlen);
- }
- else
- expr = (Node *) parser_typecast2(expr,
- type_id,
- get_id_type(attrtype),
- attrlen);
- }
- else
- {
- /* currently, we can't handle casting of expressions */
- elog(WARN, "parser: attribute '%s' is of type '%s' but expression is of type '%s'",
- colname,
- get_id_typname(attrtype),
- get_id_typname(type_id));
- }
- }
-
- if (arrayRef != NIL)
- {
- Expr *target_expr;
- Attr *att = makeNode(Attr);
- List *ar = arrayRef;
- List *upperIndexpr = NIL;
- List *lowerIndexpr = NIL;
-
- att->relname = pstrdup(RelationGetRelationName(rd)->data);
- att->attrs = lcons(makeString(colname), NIL);
- target_expr = (Expr *) handleNestedDots(pstate, att,
- &pstate->p_last_resno);
- while (ar != NIL)
- {
- A_Indices *ind = lfirst(ar);
-
- if (lowerIndexpr || (!upperIndexpr && ind->lidx))
- {
-
- /*
- * XXX assume all lowerIndexpr is non-null in this
- * case
- */
- lowerIndexpr = lappend(lowerIndexpr, ind->lidx);
- }
- upperIndexpr = lappend(upperIndexpr, ind->uidx);
- ar = lnext(ar);
- }
-
- expr = (Node *) make_array_set(target_expr,
- upperIndexpr,
- lowerIndexpr,
- (Expr *) expr);
- attrtype = att_typeid(rd, resdomno);
- attrlen = tlen(get_id_type(attrtype));
- }
- }
- else
- {
- resdomno = pstate->p_last_resno++;
- attrtype = type_id;
- attrlen = type_len;
- }
- tent = makeNode(TargetEntry);
-
- resnode = makeResdom((AttrNumber) resdomno,
- (Oid) attrtype,
- (Size) attrlen,
- colname,
- (Index) 0,
- (Oid) 0,
- 0);
-
- tent->resdom = resnode;
- tent->expr = expr;
-
- return tent;
-}
-
-
-/*****************************************************************************
- *
- * Where Clause
- *
- *****************************************************************************/
-
-/*
- * transformWhereClause -
- * transforms the qualification and make sure it is of type Boolean
- *
- */
-static Node *
-transformWhereClause(ParseState *pstate, Node *a_expr)
-{
- Node *qual;
-
- if (a_expr == NULL)
- return (Node *) NULL; /* no qualifiers */
-
- inWhereClause = true;
- qual = transformExpr(pstate, a_expr, EXPR_COLUMN_FIRST);
- inWhereClause = false;
- if (exprType(qual) != BOOLOID)
- {
- elog(WARN,
- "where clause must return type bool, not %s",
- tname(get_id_type(exprType(qual))));
- }
- return qual;
-}
-
-/*****************************************************************************
- *
- * Sort Clause
- *
- *****************************************************************************/
-
-/*
- * find_targetlist_entry -
- * returns the Resdom in the target list matching the specified varname
- * and range
- *
- */
-static TargetEntry *
-find_targetlist_entry(ParseState *pstate, SortGroupBy *sortgroupby, List *tlist)
-{
- List *i;
- int real_rtable_pos = 0,
- target_pos = 0;
- TargetEntry *target_result = NULL;
-
- if (sortgroupby->range)
- real_rtable_pos = refnameRangeTablePosn(pstate->p_rtable,
- sortgroupby->range);
-
- foreach(i, tlist)
- {
- TargetEntry *target = (TargetEntry *) lfirst(i);
- Resdom *resnode = target->resdom;
- Var *var = (Var *) target->expr;
- char *resname = resnode->resname;
- int test_rtable_pos = var->varno;
-
-#ifdef PARSEDEBUG
- printf("find_targetlist_entry- target name is %s, position %d, resno %d\n",
- (sortgroupby->name ? sortgroupby->name : "(null)"), target_pos + 1, sortgroupby->resno);
-#endif
-
- if (!sortgroupby->name)
- {
- if (sortgroupby->resno == ++target_pos)
- {
- target_result = target;
- break;
- }
- }
- else
- {
- if (!strcmp(resname, sortgroupby->name))
- {
- if (sortgroupby->range)
- {
- if (real_rtable_pos == test_rtable_pos)
- {
- if (target_result != NULL)
- elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
- else
- target_result = target;
- }
- }
- else
- {
- if (target_result != NULL)
- elog(WARN, "Order/Group By '%s' is ambiguous", sortgroupby->name);
- else
- target_result = target;
- }
- }
- }
- }
- return target_result;
-}
-
-static Oid
-any_ordering_op(int restype)
-{
- Operator order_op;
- Oid order_opid;
-
- order_op = oper("<", restype, restype, false);
- order_opid = oprid(order_op);
-
- return order_opid;
-}
-
-/*
- * transformGroupClause -
- * transform a Group By clause
- *
- */
-static List *
-transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
-{
- List *glist = NIL,
- *gl = NIL;
-
- while (grouplist != NIL)
- {
- GroupClause *grpcl = makeNode(GroupClause);
- TargetEntry *restarget;
- Resdom *resdom;
-
- restarget = find_targetlist_entry(pstate, lfirst(grouplist), targetlist);
-
- if (restarget == NULL)
- elog(WARN, "The field being grouped by must appear in the target list");
-
- grpcl->entry = restarget;
- resdom = restarget->resdom;
- grpcl->grpOpoid = oprid(oper("<",
- resdom->restype,
- resdom->restype, false));
- if (glist == NIL)
- gl = glist = lcons(grpcl, NIL);
- else
- {
- List *i;
-
- foreach (i, glist)
- {
- GroupClause *gcl = (GroupClause *) lfirst (i);
-
- if ( gcl->entry == grpcl->entry )
- break;
- }
- if ( i == NIL ) /* not in grouplist already */
- {
- lnext(gl) = lcons(grpcl, NIL);
- gl = lnext(gl);
- }
- else
- pfree (grpcl); /* get rid of this */
- }
- grouplist = lnext(grouplist);
- }
-
- return glist;
-}
-
-/*
- * transformSortClause -
- * transform an Order By clause
- *
- */
-static List *
-transformSortClause(ParseState *pstate,
- List *orderlist, List *targetlist,
- char *uniqueFlag)
-{
- List *sortlist = NIL;
- List *s = NIL;
-
- while (orderlist != NIL)
- {
- SortGroupBy *sortby = lfirst(orderlist);
- SortClause *sortcl = makeNode(SortClause);
- TargetEntry *restarget;
- Resdom *resdom;
-
- restarget = find_targetlist_entry(pstate, sortby, targetlist);
- if (restarget == NULL)
- elog(WARN, "The field being ordered by must appear in the target list");
-
- sortcl->resdom = resdom = restarget->resdom;
- sortcl->opoid = oprid(oper(sortby->useOp,
- resdom->restype,
- resdom->restype, false));
- if (sortlist == NIL)
- {
- s = sortlist = lcons(sortcl, NIL);
- }
- else
- {
- List *i;
-
- foreach (i, sortlist)
- {
- SortClause *scl = (SortClause *) lfirst (i);
-
- if ( scl->resdom == sortcl->resdom )
- break;
- }
- if ( i == NIL ) /* not in sortlist already */
- {
- lnext(s) = lcons(sortcl, NIL);
- s = lnext(s);
- }
- else
- pfree (sortcl); /* get rid of this */
- }
- orderlist = lnext(orderlist);
- }
-
- if (uniqueFlag)
- {
- List *i;
-
- if (uniqueFlag[0] == '*')
- {
-
- /*
- * concatenate all elements from target list that are not
- * already in the sortby list
- */
- foreach(i, targetlist)
- {
- TargetEntry *tlelt = (TargetEntry *) lfirst(i);
-
- s = sortlist;
- while (s != NIL)
- {
- SortClause *sortcl = lfirst(s);
-
- if (sortcl->resdom == tlelt->resdom)
- break;
- s = lnext(s);
- }
- if (s == NIL)
- {
- /* not a member of the sortclauses yet */
- SortClause *sortcl = makeNode(SortClause);
-
- sortcl->resdom = tlelt->resdom;
- sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
-
- sortlist = lappend(sortlist, sortcl);
- }
- }
- }
- else
- {
- TargetEntry *tlelt = NULL;
- char *uniqueAttrName = uniqueFlag;
-
- /* only create sort clause with the specified unique attribute */
- foreach(i, targetlist)
- {
- tlelt = (TargetEntry *) lfirst(i);
- if (strcmp(tlelt->resdom->resname, uniqueAttrName) == 0)
- break;
- }
- if (i == NIL)
- {
- elog(WARN, "The field specified in the UNIQUE ON clause is not in the targetlist");
- }
- s = sortlist;
- foreach(s, sortlist)
- {
- SortClause *sortcl = lfirst(s);
-
- if (sortcl->resdom == tlelt->resdom)
- break;
- }
- if (s == NIL)
- {
- /* not a member of the sortclauses yet */
- SortClause *sortcl = makeNode(SortClause);
-
- sortcl->resdom = tlelt->resdom;
- sortcl->opoid = any_ordering_op(tlelt->resdom->restype);
-
- sortlist = lappend(sortlist, sortcl);
- }
- }
-
- }
-
- return sortlist;
-}
-
-/*
- ** HandleNestedDots --
- ** Given a nested dot expression (i.e. (relation func ... attr), build up
- ** a tree with of Iter and Func nodes.
- */
-static Node *
-handleNestedDots(ParseState *pstate, Attr *attr, int *curr_resno)
-{
- List *mutator_iter;
- Node *retval = NULL;
-
- if (attr->paramNo != NULL)
- {
- Param *param = (Param *) transformExpr(pstate, (Node *) attr->paramNo, EXPR_RELATION_FIRST);
-
- retval =
- ParseFunc(pstate, strVal(lfirst(attr->attrs)),
- lcons(param, NIL),
- curr_resno);
- }
- else
- {
- Ident *ident = makeNode(Ident);
-
- ident->name = attr->relname;
- ident->isRel = TRUE;
- retval =
- ParseFunc(pstate, strVal(lfirst(attr->attrs)),
- lcons(ident, NIL),
- curr_resno);
- }
-
- foreach(mutator_iter, lnext(attr->attrs))
- {
- retval = ParseFunc(pstate, strVal(lfirst(mutator_iter)),
- lcons(retval, NIL),
- curr_resno);
- }
-
- return (retval);
-}
-
-/*
- ** make_arguments --
- ** Given the number and types of arguments to a function, and the
- ** actual arguments and argument types, do the necessary typecasting.
- */
-static void
-make_arguments(int nargs,
- List *fargs,
- Oid *input_typeids,
- Oid *function_typeids)
-{
-
- /*
- * there are two ways an input typeid can differ from a function
- * typeid : either the input type inherits the function type, so no
- * typecasting is necessary, or the input type can be typecast into
- * the function type. right now, we only typecast unknowns, and that
- * is all we check for.
- */
-
- List *current_fargs;
- int i;
-
- for (i = 0, current_fargs = fargs;
- i < nargs;
- i++, current_fargs = lnext(current_fargs))
- {
-
- if (input_typeids[i] == UNKNOWNOID && function_typeids[i] != InvalidOid)
- {
- lfirst(current_fargs) =
- parser_typecast2(lfirst(current_fargs),
- input_typeids[i],
- get_id_type(function_typeids[i]),
- -1);
- }
- }
-}
-
-/*
- ** setup_tlist --
- ** Build a tlist that says which attribute to project to.
- ** This routine is called by ParseFunc() to set up a target list
- ** on a tuple parameter or return value. Due to a bug in 4.0,
- ** it's not possible to refer to system attributes in this case.
- */
-static List *
-setup_tlist(char *attname, Oid relid)
-{
- TargetEntry *tle;
- Resdom *resnode;
- Var *varnode;
- Oid typeid;
- int attno;
-
- attno = get_attnum(relid, attname);
- if (attno < 0)
- elog(WARN, "cannot reference attribute '%s' of tuple params/return values for functions", attname);
-
- typeid = find_atttype(relid, attname);
- resnode = makeResdom(1,
- typeid,
- tlen(get_id_type(typeid)),
- get_attname(relid, attno),
- 0,
- (Oid) 0,
- 0);
- varnode = makeVar(-1, attno, typeid, -1, attno);
-
- tle = makeNode(TargetEntry);
- tle->resdom = resnode;
- tle->expr = (Node *) varnode;
- return (lcons(tle, NIL));
-}
-
-/*
- ** setup_base_tlist --
- ** Build a tlist that extracts a base type from the tuple
- ** returned by the executor.
- */
-static List *
-setup_base_tlist(Oid typeid)
-{
- TargetEntry *tle;
- Resdom *resnode;
- Var *varnode;
-
- resnode = makeResdom(1,
- typeid,
- tlen(get_id_type(typeid)),
- "<noname>",
- 0,
- (Oid) 0,
- 0);
- varnode = makeVar(-1, 1, typeid, -1, 1);
- tle = makeNode(TargetEntry);
- tle->resdom = resnode;
- tle->expr = (Node *) varnode;
-
- return (lcons(tle, NIL));
-}
-
-/*
- * ParseComplexProjection -
- * handles function calls with a single argument that is of complex type.
- * This routine returns NULL if it can't handle the projection (eg. sets).
- */
-static Node *
-ParseComplexProjection(ParseState *pstate,
- char *funcname,
- Node *first_arg,
- bool *attisset)
-{
- Oid argtype;
- Oid argrelid;
- Name relname;
- Relation rd;
- Oid relid;
- int attnum;
-
- switch (nodeTag(first_arg))
- {
- case T_Iter:
- {
- Func *func;
- Iter *iter;
-
- iter = (Iter *) first_arg;
- func = (Func *) ((Expr *) iter->iterexpr)->oper;
- argtype = funcid_get_rettype(func->funcid);
- argrelid = typeid_get_relid(argtype);
- if (argrelid &&
- ((attnum = get_attnum(argrelid, funcname))
- != InvalidAttrNumber))
- {
-
- /*
- * the argument is a function returning a tuple, so
- * funcname may be a projection
- */
-
- /* add a tlist to the func node and return the Iter */
- rd = heap_openr(tname(get_id_type(argtype)));
- if (RelationIsValid(rd))
- {
- relid = RelationGetRelationId(rd);
- relname = RelationGetRelationName(rd);
- heap_close(rd);
- }
- if (RelationIsValid(rd))
- {
- func->func_tlist =
- setup_tlist(funcname, argrelid);
- iter->itertype = att_typeid(rd, attnum);
- return ((Node *) iter);
- }
- else
- {
- elog(WARN,
- "Function '%s' has bad returntype %d",
- funcname, argtype);
- }
- }
- else
- {
- /* drop through */
- ;
- }
- break;
- }
- case T_Var:
- {
-
- /*
- * The argument is a set, so this is either a projection
- * or a function call on this set.
- */
- *attisset = true;
- break;
- }
- case T_Expr:
- {
- Expr *expr = (Expr *) first_arg;
- Func *funcnode;
-
- if (expr->opType != FUNC_EXPR)
- break;
-
- funcnode = (Func *) expr->oper;
- argtype = funcid_get_rettype(funcnode->funcid);
- argrelid = typeid_get_relid(argtype);
-
- /*
- * the argument is a function returning a tuple, so
- * funcname may be a projection
- */
- if (argrelid &&
- (attnum = get_attnum(argrelid, funcname))
- != InvalidAttrNumber)
- {
-
- /* add a tlist to the func node */
- rd = heap_openr(tname(get_id_type(argtype)));
- if (RelationIsValid(rd))
- {
- relid = RelationGetRelationId(rd);
- relname = RelationGetRelationName(rd);
- heap_close(rd);
- }
- if (RelationIsValid(rd))
- {
- Expr *newexpr;
-
- funcnode->func_tlist =
- setup_tlist(funcname, argrelid);
- funcnode->functype = att_typeid(rd, attnum);
-
- newexpr = makeNode(Expr);
- newexpr->typeOid = funcnode->functype;
- newexpr->opType = FUNC_EXPR;
- newexpr->oper = (Node *) funcnode;
- newexpr->args = lcons(first_arg, NIL);
-
- return ((Node *) newexpr);
- }
-
- }
-
- elog(WARN, "Function '%s' has bad returntype %d",
- funcname, argtype);
- break;
- }
- case T_Param:
- {
- Param *param = (Param *) first_arg;
-
- /*
- * If the Param is a complex type, this could be a
- * projection
- */
- rd = heap_openr(tname(get_id_type(param->paramtype)));
- if (RelationIsValid(rd))
- {
- relid = RelationGetRelationId(rd);
- relname = RelationGetRelationName(rd);
- heap_close(rd);
- }
- if (RelationIsValid(rd) &&
- (attnum = get_attnum(relid, funcname))
- != InvalidAttrNumber)
- {
-
- param->paramtype = att_typeid(rd, attnum);
- param->param_tlist = setup_tlist(funcname, relid);
- return ((Node *) param);
- }
- break;
- }
- default:
- break;
- }
-
- return NULL;
-}
-
-static Node *
-ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
-{
- Oid rettype = (Oid) 0;
- Oid argrelid = (Oid) 0;
- Oid funcid = (Oid) 0;
- List *i = NIL;
- Node *first_arg = NULL;
- char *relname = NULL;
- char *refname = NULL;
- Relation rd;
- Oid relid;
- int nargs;
- Func *funcnode;
- Oid oid_array[8];
- Oid *true_oid_array;
- Node *retval;
- bool retset;
- bool exists;
- bool attisset = false;
- Oid toid = (Oid) 0;
- Expr *expr;
-
- if (fargs)
- {
- first_arg = lfirst(fargs);
- if (first_arg == NULL)
- elog(WARN, "function '%s' does not allow NULL input", funcname);
- }
-
- /*
- * * check for projection methods: if function takes one argument, and *
- * that argument is a relation, param, or PQ function returning a
- * complex * type, then the function could be a projection.
- */
- if (length(fargs) == 1)
- {
-
- if (nodeTag(first_arg) == T_Ident && ((Ident *) first_arg)->isRel)
- {
- RangeTblEntry *rte;
- Ident *ident = (Ident *) first_arg;
-
- /*
- * first arg is a relation. This could be a projection.
- */
- refname = ident->name;
-
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- if (rte == NULL)
- rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE);
-
- relname = rte->relname;
- relid = rte->relid;
-
- /*
- * 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.
- */
- if (get_attnum(relid, funcname) != InvalidAttrNumber)
- {
- Oid dummyTypeId;
-
- return
- ((Node *) make_var(pstate,
- refname,
- funcname,
- &dummyTypeId));
- }
- else
- {
- /* drop through - attr is a set */
- ;
- }
- }
- else if (ISCOMPLEX(exprType(first_arg)))
- {
-
- /*
- * Attempt to handle projection of a complex argument. If
- * ParseComplexProjection can't handle the projection, we have
- * to keep going.
- */
- retval = ParseComplexProjection(pstate,
- funcname,
- first_arg,
- &attisset);
- if (attisset)
- {
- toid = exprType(first_arg);
- rd = heap_openr(tname(get_id_type(toid)));
- if (RelationIsValid(rd))
- {
- relname = RelationGetRelationName(rd)->data;
- heap_close(rd);
- }
- else
- elog(WARN,
- "Type '%s' is not a relation type",
- tname(get_id_type(toid)));
- argrelid = typeid_get_relid(toid);
-
- /*
- * A projection contains either an attribute name or the
- * "*".
- */
- if ((get_attnum(argrelid, funcname) == InvalidAttrNumber)
- && strcmp(funcname, "*"))
- {
- elog(WARN, "Functions on sets are not yet supported");
- }
- }
-
- if (retval)
- return retval;
- }
- else
- {
-
- /*
- * Parsing aggregates.
- */
- Oid basetype;
-
- /*
- * the aggregate count is a special case, ignore its base
- * type. Treat it as zero
- */
- if (strcmp(funcname, "count") == 0)
- basetype = 0;
- else
- basetype = exprType(lfirst(fargs));
- if (SearchSysCacheTuple(AGGNAME,
- PointerGetDatum(funcname),
- ObjectIdGetDatum(basetype),
- 0, 0))
- {
- Aggreg *aggreg = ParseAgg(funcname, basetype, lfirst(fargs));
-
- AddAggToParseState(pstate, aggreg);
- return (Node *) aggreg;
- }
- }
- }
-
-
- /*
- * * If we dropped through to here it's really a function (or a set,
- * which * is implemented as a function.) * extract arg type info and
- * transform relation name arguments into * varnodes of the
- * appropriate form.
- */
- MemSet(&oid_array[0], 0, 8 * sizeof(Oid));
-
- nargs = 0;
- foreach(i, fargs)
- {
- int vnum;
- RangeTblEntry *rte;
- Node *pair = lfirst(i);
-
- if (nodeTag(pair) == T_Ident && ((Ident *) pair)->isRel)
- {
-
- /*
- * a relation
- */
- refname = ((Ident *) pair)->name;
-
- rte = refnameRangeTableEntry(pstate->p_rtable, refname);
- if (rte == NULL)
- rte = addRangeTableEntry(pstate, refname, refname,
- FALSE, FALSE);
- relname = rte->relname;
-
- vnum = refnameRangeTablePosn(pstate->p_rtable, rte->refname);
-
- /*
- * for func(relname), the param to the function is the tuple
- * under consideration. we build a special VarNode to reflect
- * this -- it has varno set to the correct range table entry,
- * but has varattno == 0 to signal that the whole tuple is the
- * argument.
- */
- toid = typeid(type(relname));
- /* replace it in the arg list */
- lfirst(fargs) =
- makeVar(vnum, 0, toid, vnum, 0);
- }
- else if (!attisset)
- { /* set functions don't have parameters */
-
- /*
- * any functiona args which are typed "unknown", but aren't
- * constants, we don't know what to do with, because we can't
- * cast them - jolly
- */
- if (exprType(pair) == UNKNOWNOID &&
- !IsA(pair, Const))
- {
- elog(WARN, "ParseFunc: no function named '%s' that takes in an unknown type as argument #%d", funcname, nargs);
- }
- else
- toid = exprType(pair);
- }
-
- oid_array[nargs++] = toid;
- }
-
- /*
- * func_get_detail looks up the function in the catalogs, does
- * disambiguation for polymorphic functions, handles inheritance, and
- * returns the funcid and type and set or singleton status of the
- * function's return value. it also returns the true argument types
- * to the function. if func_get_detail returns true, the function
- * exists. otherwise, there was an error.
- */
- if (attisset)
- { /* we know all of these fields already */
-
- /*
- * We create a funcnode with a placeholder function SetEval.
- * SetEval() never actually gets executed. When the function
- * evaluation routines see it, they use the funcid projected out
- * from the relation as the actual function to call. Example:
- * retrieve (emp.mgr.name) The plan for this will scan the emp
- * relation, projecting out the mgr attribute, which is a funcid.
- * This function is then called (instead of SetEval) and "name" is
- * projected from its result.
- */
- funcid = SetEvalRegProcedure;
- rettype = toid;
- retset = true;
- true_oid_array = oid_array;
- exists = true;
- }
- else
- {
- exists = func_get_detail(funcname, nargs, oid_array, &funcid,
- &rettype, &retset, &true_oid_array);
- }
-
- if (!exists)
- elog(WARN, "no such attribute or function '%s'", funcname);
-
- /* got it */
- funcnode = makeNode(Func);
- funcnode->funcid = funcid;
- funcnode->functype = rettype;
- funcnode->funcisindex = false;
- funcnode->funcsize = 0;
- funcnode->func_fcache = NULL;
- funcnode->func_tlist = NIL;
- funcnode->func_planlist = NIL;
-
- /* perform the necessary typecasting */
- make_arguments(nargs, fargs, oid_array, true_oid_array);
-
- /*
- * for functions returning base types, we want to project out the
- * return value. set up a target list to do that. the executor will
- * ignore these for c functions, and do the right thing for postquel
- * functions.
- */
-
- if (typeid_get_relid(rettype) == InvalidOid)
- funcnode->func_tlist = setup_base_tlist(rettype);
-
- /*
- * For sets, we want to make a targetlist to project out this
- * attribute of the set tuples.
- */
- if (attisset)
- {
- if (!strcmp(funcname, "*"))
- {
- funcnode->func_tlist =
- expandAll(pstate, relname, refname, curr_resno);
- }
- else
- {
- funcnode->func_tlist = setup_tlist(funcname, argrelid);
- rettype = find_atttype(argrelid, funcname);
- }
- }
-
- /*
- * Sequence handling.
- */
- if (funcid == SeqNextValueRegProcedure ||
- funcid == SeqCurrValueRegProcedure)
- {
- Const *seq;
- char *seqrel;
- text *seqname;
- int32 aclcheck_result = -1;
- extern text *lower (text *string);
-
- Assert(length(fargs) == 1);
- seq = (Const *) lfirst(fargs);
- if (!IsA((Node *) seq, Const))
- elog(WARN, "%s: only constant sequence names are acceptable", funcname);
- seqname = lower ((text*)DatumGetPointer(seq->constvalue));
- pfree (DatumGetPointer(seq->constvalue));
- seq->constvalue = PointerGetDatum (seqname);
- seqrel = textout(seqname);
-
- if ((aclcheck_result = pg_aclcheck(seqrel, GetPgUserName(),
- ((funcid == SeqNextValueRegProcedure) ? ACL_WR : ACL_RD)))
- != ACLCHECK_OK)
- elog(WARN, "%s.%s: %s",
- seqrel, funcname, aclcheck_error_strings[aclcheck_result]);
-
- pfree(seqrel);
-
- if (funcid == SeqNextValueRegProcedure && inWhereClause)
- elog(WARN, "nextval of a sequence in WHERE disallowed");
- }
-
- expr = makeNode(Expr);
- expr->typeOid = rettype;
- expr->opType = FUNC_EXPR;
- expr->oper = (Node *) funcnode;
- expr->args = fargs;
- retval = (Node *) expr;
-
- /*
- * if the function returns a set of values, then we need to iterate
- * over all the returned values in the executor, so we stick an iter
- * node here. if it returns a singleton, then we don't need the iter
- * node.
- */
-
- if (retset)
- {
- Iter *iter = makeNode(Iter);
-
- iter->itertype = rettype;
- iter->iterexpr = retval;
- retval = (Node *) iter;
- }
-
- return (retval);
-}
-
-/*****************************************************************************
- *
- *****************************************************************************/
-
-/*
- * AddAggToParseState -
- * add the aggregate to the list of unique aggregates in pstate.
- *
- * SIDE EFFECT: aggno in target list entry will be modified
- */
-static void
-AddAggToParseState(ParseState *pstate, Aggreg *aggreg)
-{
- List *ag;
- int i;
-
- /*
- * see if we have the aggregate already (we only need to record the
- * aggregate once)
- */
- i = 0;
- foreach(ag, pstate->p_aggs)
- {
- Aggreg *a = lfirst(ag);
-
- if (!strcmp(a->aggname, aggreg->aggname) &&
- equal(a->target, aggreg->target))
- {
-
- /* fill in the aggno and we're done */
- aggreg->aggno = i;
- return;
- }
- i++;
- }
-
- /* not found, new aggregate */
- aggreg->aggno = i;
- pstate->p_numAgg++;
- pstate->p_aggs = lappend(pstate->p_aggs, aggreg);
- return;
-}
-
-/*
- * finalizeAggregates -
- * fill in qry_aggs from pstate. Also checks to make sure that aggregates
- * are used in the proper place.
- */
-static void
-finalizeAggregates(ParseState *pstate, Query *qry)
-{
- List *l;
- int i;
-
- parseCheckAggregates(pstate, qry);
-
- qry->qry_numAgg = pstate->p_numAgg;
- qry->qry_aggs =
- (Aggreg **) palloc(sizeof(Aggreg *) * qry->qry_numAgg);
- i = 0;
- foreach(l, pstate->p_aggs)
- qry->qry_aggs[i++] = (Aggreg *) lfirst(l);
-}
-
-/*
- * contain_agg_clause--
- * Recursively find aggreg nodes from a clause.
- *
- * Returns true if any aggregate found.
- */
-static bool
-contain_agg_clause(Node *clause)
-{
- if (clause == NULL)
- return FALSE;
- else if (IsA(clause, Aggreg))
- return TRUE;
- else if (IsA(clause, Iter))
- return contain_agg_clause(((Iter *) clause)->iterexpr);
- else if (single_node(clause))
- return FALSE;
- else if (or_clause(clause))
- {
- List *temp;
-
- foreach(temp, ((Expr *) clause)->args)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- return FALSE;
- }
- else if (is_funcclause(clause))
- {
- List *temp;
-
- foreach(temp, ((Expr *) clause)->args)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- return FALSE;
- }
- else if (IsA(clause, ArrayRef))
- {
- List *temp;
-
- foreach(temp, ((ArrayRef *) clause)->refupperindexpr)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- foreach(temp, ((ArrayRef *) clause)->reflowerindexpr)
- if (contain_agg_clause(lfirst(temp)))
- return TRUE;
- if (contain_agg_clause(((ArrayRef *) clause)->refexpr))
- return TRUE;
- if (contain_agg_clause(((ArrayRef *) clause)->refassgnexpr))
- return TRUE;
- return FALSE;
- }
- else if (not_clause(clause))
- return contain_agg_clause((Node *) get_notclausearg((Expr *) clause));
- else if (is_opclause(clause))
- return (contain_agg_clause((Node *) get_leftop((Expr *) clause)) ||
- contain_agg_clause((Node *) get_rightop((Expr *) clause)));
-
- return FALSE;
-}
-
-/*
- * exprIsAggOrGroupCol -
- * returns true if the expression does not contain non-group columns.
- */
-static bool
-exprIsAggOrGroupCol(Node *expr, List *groupClause)
-{
- List *gl;
-
- if (expr == NULL || IsA(expr, Const) ||
- IsA(expr, Param) ||IsA(expr, Aggreg))
- return TRUE;
-
- foreach(gl, groupClause)
- {
- GroupClause *grpcl = lfirst(gl);
-
- if (equal(expr, grpcl->entry->expr))
- return TRUE;
- }
-
- if (IsA(expr, Expr))
- {
- List *temp;
-
- foreach(temp, ((Expr *) expr)->args)
- if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
- return FALSE;
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
- * tleIsAggOrGroupCol -
- * returns true if the TargetEntry is Agg or GroupCol.
- */
-static bool
-tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
-{
- Node *expr = tle->expr;
- List *gl;
-
- if (expr == NULL || IsA(expr, Const) ||IsA(expr, Param))
- return TRUE;
-
- foreach(gl, groupClause)
- {
- GroupClause *grpcl = lfirst(gl);
-
- if (tle->resdom->resno == grpcl->entry->resdom->resno)
- {
- if (contain_agg_clause((Node *) expr))
- elog(WARN, "parser: aggregates not allowed in GROUP BY clause");
- return TRUE;
- }
- }
-
- if (IsA(expr, Aggreg))
- return TRUE;
-
- if (IsA(expr, Expr))
- {
- List *temp;
-
- foreach(temp, ((Expr *) expr)->args)
- if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
- return FALSE;
- return TRUE;
- }
-
- return FALSE;
-}
-
-/*
- * parseCheckAggregates -
- * this should really be done earlier but the current grammar
- * cannot differentiate functions from aggregates. So we have do check
- * here when the target list and the qualifications are finalized.
- */
-static void
-parseCheckAggregates(ParseState *pstate, Query *qry)
-{
- List *tl;
-
- Assert(pstate->p_numAgg > 0);
-
- /*
- * aggregates never appear in WHERE clauses. (we have to check where
- * clause first because if there is an aggregate, the check for
- * non-group column in target list may fail.)
- */
- if (contain_agg_clause(qry->qual))
- elog(WARN, "parser: aggregates not allowed in WHERE clause");
-
- /*
- * the target list can only contain aggregates, group columns and
- * functions thereof.
- */
- foreach(tl, qry->targetList)
- {
- TargetEntry *tle = lfirst(tl);
-
- if (!tleIsAggOrGroupCol(tle, qry->groupClause))
- elog(WARN,
- "parser: illegal use of aggregates or non-group column in target list");
- }
-
- /*
- * the expression specified in the HAVING clause has the same
- * restriction as those in the target list.
- */
-/*
- * Need to change here when we get HAVING works. Currently
- * qry->havingQual is NULL. - vadim 04/05/97
- if (!exprIsAggOrGroupCol(qry->havingQual, qry->groupClause))
- elog(WARN,
- "parser: illegal use of aggregates or non-group column in HAVING clause");
- */
- return;
-}
-
-/* not used
-#define PSIZE(PTR) (*((int32 *)(PTR) - 1))
-*/
-
-static Node *
-parser_typecast(Value *expr, TypeName *typename, int typlen)
-{
- /* check for passing non-ints */
- Const *adt;
- Datum lcp;
- Type tp;
- char type_string[NAMEDATALEN];
- int32 len;
- char *cp = NULL;
- char *const_string = NULL;
- bool string_palloced = false;
-
- switch (nodeTag(expr))
- {
- case T_String:
- const_string = DatumGetPointer(expr->val.str);
- break;
- case T_Integer:
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%ld", expr->val.ival);
- break;
- default:
- elog(WARN,
- "parser_typecast: cannot cast this expression to type \"%s\"",
- typename->name);
- }
-
- if (typename->arrayBounds != NIL)
- {
- sprintf(type_string, "_%s", typename->name);
- tp = (Type) type(type_string);
- }
- else
- {
- tp = (Type) type(typename->name);
- }
-
- len = tlen(tp);
-
-#if 0 /* fix me */
- switch (CInteger(lfirst(expr)))
- {
- case INT4OID: /* int4 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue);
- break;
-
- case NAMEOID: /* char16 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue);
- break;
-
- case CHAROID: /* char */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue);
- break;
-
- case FLOAT8OID: /* float8 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue);
- break;
-
- case CASHOID: /* money */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%d",
- (int) ((Const *) expr)->constvalue);
- break;
-
- case TEXTOID: /* text */
- const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
- const_string = (char *) textout((struct varlena *) const_string);
- break;
-
- case UNKNOWNOID: /* unknown */
- const_string = DatumGetPointer(((Const) lnext(expr))->constvalue);
- const_string = (char *) textout((struct varlena *) const_string);
- break;
-
- default:
- elog(WARN, "unknown type %d", CInteger(lfirst(expr)));
- }
-#endif
-
- cp = instr2(tp, const_string, typlen);
-
- if (!tbyvalue(tp))
- {
-/*
- if (len >= 0 && len != PSIZE(cp)) {
- char *pp;
- pp = (char *) palloc(len);
- memmove(pp, cp, len);
- cp = pp;
- }
-*/
- lcp = PointerGetDatum(cp);
- }
- else
- {
- switch (len)
- {
- case 1:
- lcp = Int8GetDatum(cp);
- break;
- case 2:
- lcp = Int16GetDatum(cp);
- break;
- case 4:
- lcp = Int32GetDatum(cp);
- break;
- default:
- lcp = PointerGetDatum(cp);
- break;
- }
- }
-
- adt = makeConst(typeid(tp),
- len,
- (Datum) lcp,
- false,
- tbyvalue(tp),
- false, /* not a set */
- true /* is cast */ );
-
- if (string_palloced)
- pfree(const_string);
-
- return (Node *) adt;
-}
-
-static Node *
-parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen)
-{
- /* check for passing non-ints */
- Const *adt;
- Datum lcp;
- int32 len = tlen(tp);
- char *cp = NULL;
-
- char *const_string = NULL;
- bool string_palloced = false;
-
- Assert(IsA(expr, Const));
-
- switch (exprType)
- {
- case 0: /* NULL */
- break;
- case INT4OID: /* int4 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%d",
- (int) ((Const *) expr)->constvalue);
- break;
- case NAMEOID: /* char16 */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%s",
- (char *) ((Const *) expr)->constvalue);
- break;
- case CHAROID: /* char */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%c",
- (char) ((Const *) expr)->constvalue);
- break;
- case FLOAT4OID: /* float4 */
- {
- float32 floatVal =
- DatumGetFloat32(((Const *) expr)->constvalue);
-
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%f", *floatVal);
- break;
- }
- case FLOAT8OID: /* float8 */
- {
- float64 floatVal =
- DatumGetFloat64(((Const *) expr)->constvalue);
-
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%f", *floatVal);
- break;
- }
- case CASHOID: /* money */
- const_string = (char *) palloc(256);
- string_palloced = true;
- sprintf(const_string, "%ld",
- (long) ((Const *) expr)->constvalue);
- break;
- case TEXTOID: /* text */
- const_string =
- DatumGetPointer(((Const *) expr)->constvalue);
- const_string = (char *) textout((struct varlena *) const_string);
- break;
- case UNKNOWNOID: /* unknown */
- const_string =
- DatumGetPointer(((Const *) expr)->constvalue);
- const_string = (char *) textout((struct varlena *) const_string);
- break;
- default:
- elog(WARN, "unknown type %u ", exprType);
- }
-
- if (!exprType)
- {
- adt = makeConst(typeid(tp),
- (Size) 0,
- (Datum) NULL,
- true, /* isnull */
- false, /* was omitted */
- false, /* not a set */
- true /* is cast */ );
- return ((Node *) adt);
- }
-
- cp = instr2(tp, const_string, typlen);
-
-
- if (!tbyvalue(tp))
- {
-/*
- if (len >= 0 && len != PSIZE(cp)) {
- char *pp;
- pp = (char *) palloc(len);
- memmove(pp, cp, len);
- cp = pp;
- }
-*/
- lcp = PointerGetDatum(cp);
- }
- else
- {
- switch (len)
- {
- case 1:
- lcp = Int8GetDatum(cp);
- break;
- case 2:
- lcp = Int16GetDatum(cp);
- break;
- case 4:
- lcp = Int32GetDatum(cp);
- break;
- default:
- lcp = PointerGetDatum(cp);
- break;
- }
- }
-
- adt = makeConst(typeid(tp),
- (Size) len,
- (Datum) lcp,
- false,
- false, /* was omitted */
- false, /* not a set */
- true /* is cast */ );
-
- /*
- * printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) , len,cp);
- */
- if (string_palloced)
- pfree(const_string);
-
- return ((Node *) adt);
-}
-
-static Aggreg *
-ParseAgg(char *aggname, Oid basetype, Node *target)
-{
- Oid fintype;
- Oid vartype;
- Oid xfn1;
- Form_pg_aggregate aggform;
- Aggreg *aggreg;
- HeapTuple theAggTuple;
-
- theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname),
- ObjectIdGetDatum(basetype),
- 0, 0);
- if (!HeapTupleIsValid(theAggTuple))
- {
- elog(WARN, "aggregate %s does not exist", aggname);
- }
-
- aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple);
- fintype = aggform->aggfinaltype;
- xfn1 = aggform->aggtransfn1;
-
- if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr)
- elog(WARN, "parser: aggregate can only be applied on an attribute or expression");
-
- /* only aggregates with transfn1 need a base type */
- if (OidIsValid(xfn1))
- {
- basetype = aggform->aggbasetype;
- if (nodeTag(target) == T_Var)
- vartype = ((Var *) target)->vartype;
- else
- vartype = ((Expr *) target)->typeOid;
-
- if (basetype != vartype)
- {
- Type tp1,
- tp2;
-
- tp1 = get_id_type(basetype);
- tp2 = get_id_type(vartype);
- elog(NOTICE, "Aggregate type mismatch:");
- elog(WARN, "%s works on %s, not %s", aggname,
- tname(tp1), tname(tp2));
- }
- }
-
- aggreg = makeNode(Aggreg);
- aggreg->aggname = pstrdup(aggname);
- aggreg->basetype = aggform->aggbasetype;
- aggreg->aggtype = fintype;
-
- aggreg->target = target;
-
- return aggreg;
-}