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.c4324
1 files changed, 2292 insertions, 2032 deletions
diff --git a/src/backend/parser/analyze.c b/src/backend/parser/analyze.c
index a78d2c5c70e..8f63522812e 100644
--- a/src/backend/parser/analyze.c
+++ b/src/backend/parser/analyze.c
@@ -1,13 +1,13 @@
/*-------------------------------------------------------------------------
*
* analyze.c--
- * transform the parse tree into a query tree
+ * transform the parse tree into a query tree
*
* Copyright (c) 1994, Regents of the University of California
*
*
* IDENTIFICATION
- * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.38 1997/09/05 19:32:31 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/backend/parser/analyze.c,v 1.39 1997/09/07 04:44:38 momjian Exp $
*
*-------------------------------------------------------------------------
*/
@@ -20,11 +20,11 @@
#include "nodes/primnodes.h"
#include "nodes/parsenodes.h"
#include "nodes/relation.h"
-#include "parse.h" /* for AND, OR, etc. */
+#include "parse.h" /* for AND, OR, etc. */
#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/builtins.h" /* namecmp(), textout() */
#include "utils/lsyscache.h"
#include "utils/palloc.h"
#include "utils/mcxt.h"
@@ -41,502 +41,519 @@
#include "miscadmin.h"
-#include "port-protos.h" /* strdup() */
+#include "port-protos.h" /* strdup() */
/* 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);
-static Query *transformExtendStmt(ParseState *pstate, ExtendStmt *stmt);
-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
+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);
+static Query *transformExtendStmt(ParseState * pstate, ExtendStmt * stmt);
+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 *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);
/*****************************************************************************
*
*****************************************************************************/
/*
- * makeParseState() --
- * allocate and initialize a new ParseState.
- * the CALLERS is responsible for freeing the ParseState* returned
+ * makeParseState() --
+ * allocate and initialize a new ParseState.
+ * the CALLERS is responsible for freeing the ParseState* returned
*
*/
-static ParseState*
+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);
+ 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 -
- * analyze a list of parse trees and transform them if necessary.
+ * analyze a list of parse trees and transform them if necessary.
*
* Returns a list of transformed parse trees. Optimizable statements are
* all transformed to Query while the rest stays the same.
*
* CALLER is responsible for freeing the QueryTreeList* returned
*/
-QueryTreeList *
-parse_analyze(List *pl)
+QueryTreeList *
+parse_analyze(List * pl)
{
- QueryTreeList *result;
- ParseState *pstate;
- int i = 0;
-
- result = malloc(sizeof(QueryTreeList));
- 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();
- result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
- pl = lnext(pl);
- if (pstate->p_target_relation != NULL)
- heap_close(pstate->p_target_relation);
- free(pstate);
- }
-
- return result;
+ QueryTreeList *result;
+ ParseState *pstate;
+ int i = 0;
+
+ result = malloc(sizeof(QueryTreeList));
+ 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();
+ result->qtrees[i++] = transformStmt(pstate, lfirst(pl));
+ pl = lnext(pl);
+ if (pstate->p_target_relation != NULL)
+ heap_close(pstate->p_target_relation);
+ free(pstate);
+ }
+
+ return result;
}
/*
* transformStmt -
- * transform a Parse tree. If it is an optimizable statement, turn it
- * into a Query tree.
+ * transform a Parse tree. If it is an optimizable statement, turn it
+ * into a Query tree.
*/
-static Query *
-transformStmt(ParseState* pstate, Node *parseTree)
+static Query *
+transformStmt(ParseState * pstate, Node * parseTree)
{
- Query* result = NULL;
-
- switch(nodeTag(parseTree)) {
- /*------------------------
- * Non-optimizable statements
- *------------------------
- */
- case T_IndexStmt:
- result = transformIndexStmt(pstate, (IndexStmt *)parseTree);
- break;
-
- case T_ExtendStmt:
- result = transformExtendStmt(pstate, (ExtendStmt *)parseTree);
- break;
-
- case T_RuleStmt:
- result = transformRuleStmt(pstate, (RuleStmt *)parseTree);
- break;
-
- case T_ViewStmt:
- {
- ViewStmt *n = (ViewStmt *)parseTree;
- n->query = (Query *)transformStmt(pstate, (Node*)n->query);
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- result->utilityStmt = (Node*)n;
- }
- break;
-
- case T_VacuumStmt:
- {
- MemoryContext oldcontext;
- /* make sure that this Query is allocated in TopMemory context
- because vacuum spans transactions and we don't want to lose
- the vacuum Query due to end-of-transaction free'ing*/
- oldcontext = MemoryContextSwitchTo(TopMemoryContext);
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- result->utilityStmt = (Node*)parseTree;
- MemoryContextSwitchTo(oldcontext);
- break;
-
- }
- case T_ExplainStmt:
- {
- ExplainStmt *n = (ExplainStmt *)parseTree;
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- n->query = transformStmt(pstate, (Node*)n->query);
- result->utilityStmt = (Node*)parseTree;
- }
- break;
-
- /*------------------------
- * Optimizable statements
- *------------------------
- */
- case T_AppendStmt:
- result = transformInsertStmt(pstate, (AppendStmt *)parseTree);
- break;
-
- case T_DeleteStmt:
- result = transformDeleteStmt(pstate, (DeleteStmt *)parseTree);
- break;
-
- case T_ReplaceStmt:
- result = transformUpdateStmt(pstate, (ReplaceStmt *)parseTree);
- break;
-
- case T_CursorStmt:
- result = transformCursorStmt(pstate, (CursorStmt *)parseTree);
- break;
-
- case T_RetrieveStmt:
- result = transformSelectStmt(pstate, (RetrieveStmt *)parseTree);
- break;
-
- default:
- /*
- * other statments don't require any transformation-- just
- * return the original parsetree
- */
- result = makeNode(Query);
- result->commandType = CMD_UTILITY;
- result->utilityStmt = (Node*)parseTree;
- break;
- }
- return result;
+ Query *result = NULL;
+
+ switch (nodeTag(parseTree))
+ {
+ /*------------------------
+ * Non-optimizable statements
+ *------------------------
+ */
+ case T_IndexStmt:
+ result = transformIndexStmt(pstate, (IndexStmt *) parseTree);
+ break;
+
+ case T_ExtendStmt:
+ result = transformExtendStmt(pstate, (ExtendStmt *) parseTree);
+ break;
+
+ case T_RuleStmt:
+ result = transformRuleStmt(pstate, (RuleStmt *) parseTree);
+ break;
+
+ case T_ViewStmt:
+ {
+ ViewStmt *n = (ViewStmt *) parseTree;
+
+ n->query = (Query *) transformStmt(pstate, (Node *) n->query);
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) n;
+ }
+ break;
+
+ case T_VacuumStmt:
+ {
+ MemoryContext oldcontext;
+
+ /*
+ * make sure that this Query is allocated in TopMemory context
+ * because vacuum spans transactions and we don't want to lose
+ * the vacuum Query due to end-of-transaction free'ing
+ */
+ oldcontext = MemoryContextSwitchTo(TopMemoryContext);
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) parseTree;
+ MemoryContextSwitchTo(oldcontext);
+ break;
+
+ }
+ case T_ExplainStmt:
+ {
+ ExplainStmt *n = (ExplainStmt *) parseTree;
+
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ n->query = transformStmt(pstate, (Node *) n->query);
+ result->utilityStmt = (Node *) parseTree;
+ }
+ break;
+
+ /*------------------------
+ * Optimizable statements
+ *------------------------
+ */
+ case T_AppendStmt:
+ result = transformInsertStmt(pstate, (AppendStmt *) parseTree);
+ break;
+
+ case T_DeleteStmt:
+ result = transformDeleteStmt(pstate, (DeleteStmt *) parseTree);
+ break;
+
+ case T_ReplaceStmt:
+ result = transformUpdateStmt(pstate, (ReplaceStmt *) parseTree);
+ break;
+
+ case T_CursorStmt:
+ result = transformCursorStmt(pstate, (CursorStmt *) parseTree);
+ break;
+
+ case T_RetrieveStmt:
+ result = transformSelectStmt(pstate, (RetrieveStmt *) parseTree);
+ break;
+
+ default:
+
+ /*
+ * other statments don't require any transformation-- just return
+ * the original parsetree
+ */
+ result = makeNode(Query);
+ result->commandType = CMD_UTILITY;
+ result->utilityStmt = (Node *) parseTree;
+ break;
+ }
+ return result;
}
/*
* transformDeleteStmt -
- * transforms a Delete Statement
+ * transforms a Delete Statement
*/
-static Query *
-transformDeleteStmt(ParseState *pstate, DeleteStmt *stmt)
+static Query *
+transformDeleteStmt(ParseState * pstate, DeleteStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
- qry->commandType = CMD_DELETE;
+ qry->commandType = CMD_DELETE;
- /* set up a range table */
- makeRangeTable(pstate, stmt->relname, NULL);
-
- qry->uniqueFlag = NULL;
+ /* set up a range table */
+ makeRangeTable(pstate, stmt->relname, NULL);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate, stmt->whereClause);
+ qry->uniqueFlag = NULL;
- qry->rtable = pstate->p_rtable;
- qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* make sure we don't have aggregates in the where clause */
- if (pstate->p_numAgg > 0)
- parseCheckAggregates(pstate, qry);
+ qry->rtable = pstate->p_rtable;
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+
+ /* make sure we don't have aggregates in the where clause */
+ if (pstate->p_numAgg > 0)
+ parseCheckAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformInsertStmt -
- * transform an Insert Statement
+ * transform an Insert Statement
*/
-static Query *
-transformInsertStmt(ParseState *pstate, AppendStmt *stmt)
+static Query *
+transformInsertStmt(ParseState * pstate, AppendStmt * stmt)
{
- Query *qry = makeNode(Query); /* make a new query tree */
+ Query *qry = makeNode(Query); /* make a new query tree */
- qry->commandType = CMD_INSERT;
- pstate->p_is_insert = true;
+ qry->commandType = CMD_INSERT;
+ pstate->p_is_insert = true;
- /* set up a range table */
- makeRangeTable(pstate, stmt->relname, stmt->fromClause);
+ /* set up a range table */
+ makeRangeTable(pstate, stmt->relname, stmt->fromClause);
- qry->uniqueFlag = NULL;
+ qry->uniqueFlag = NULL;
- /* fix the target list */
- pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
+ /* fix the target list */
+ pstate->p_insert_columns = makeTargetNames(pstate, stmt->cols);
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate, stmt->whereClause);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* now the range table will not change */
- qry->rtable = pstate->p_rtable;
- qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+ /* now the range table will not change */
+ qry->rtable = pstate->p_rtable;
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
- if (pstate->p_numAgg > 0)
- finalizeAggregates(pstate, qry);
+ if (pstate->p_numAgg > 0)
+ finalizeAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformIndexStmt -
- * transforms the qualification of the index statement
+ * transforms the qualification of the index statement
*/
-static Query *
-transformIndexStmt(ParseState *pstate, IndexStmt *stmt)
+static Query *
+transformIndexStmt(ParseState * pstate, IndexStmt * stmt)
{
- Query* q;
+ Query *q;
- q = makeNode(Query);
- q->commandType = CMD_UTILITY;
-
- /* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate,stmt->whereClause);
- stmt->rangetable = pstate->p_rtable;
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
- q->utilityStmt = (Node*)stmt;
+ /* take care of the where clause */
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+ stmt->rangetable = pstate->p_rtable;
- return q;
+ q->utilityStmt = (Node *) stmt;
+
+ return q;
}
/*
* transformExtendStmt -
- * transform the qualifications of the Extend Index Statement
+ * transform the qualifications of the Extend Index Statement
*
*/
-static Query *
-transformExtendStmt(ParseState *pstate, ExtendStmt *stmt)
+static Query *
+transformExtendStmt(ParseState * pstate, ExtendStmt * stmt)
{
- Query *q;
+ Query *q;
- q = makeNode(Query);
- q->commandType = CMD_UTILITY;
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
- /* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate,stmt->whereClause);
- stmt->rangetable = pstate->p_rtable;
+ /* take care of the where clause */
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
+ stmt->rangetable = pstate->p_rtable;
- q->utilityStmt = (Node*)stmt;
- return q;
+ q->utilityStmt = (Node *) stmt;
+ return q;
}
/*
* transformRuleStmt -
- * transform a Create Rule Statement. The actions is a list of parse
- * trees which is transformed into a list of query trees.
+ * transform a Create Rule Statement. The actions is a list of parse
+ * trees which is transformed into a list of query trees.
*/
-static Query *
-transformRuleStmt(ParseState *pstate, RuleStmt *stmt)
+static Query *
+transformRuleStmt(ParseState * pstate, RuleStmt * stmt)
{
- Query *q;
- List *actions;
-
- q = makeNode(Query);
- q->commandType = CMD_UTILITY;
-
- actions = stmt->actions;
- /*
- * transform each statment, like parse_analyze()
- */
- while (actions != NIL) {
+ Query *q;
+ List *actions;
+
+ q = makeNode(Query);
+ q->commandType = CMD_UTILITY;
+
+ actions = stmt->actions;
+
/*
- * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
- * equal to 2.
+ * transform each statment, like parse_analyze()
*/
- addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
- FALSE, FALSE, NULL);
- addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
- FALSE, FALSE, NULL);
+ while (actions != NIL)
+ {
- pstate->p_last_resno = 1;
- pstate->p_is_rule = true; /* for expand all */
- pstate->p_numAgg = 0;
- pstate->p_aggs = NULL;
-
- lfirst(actions) = transformStmt(pstate, lfirst(actions));
- actions = lnext(actions);
- }
+ /*
+ * NOTE: 'CURRENT' must always have a varno equal to 1 and 'NEW'
+ * equal to 2.
+ */
+ addRangeTableEntry(pstate, stmt->object->relname, "*CURRENT*",
+ FALSE, FALSE, NULL);
+ addRangeTableEntry(pstate, stmt->object->relname, "*NEW*",
+ FALSE, FALSE, NULL);
+
+ pstate->p_last_resno = 1;
+ pstate->p_is_rule = true; /* for expand all */
+ pstate->p_numAgg = 0;
+ pstate->p_aggs = NULL;
+
+ lfirst(actions) = transformStmt(pstate, lfirst(actions));
+ actions = lnext(actions);
+ }
- /* take care of the where clause */
- stmt->whereClause = transformWhereClause(pstate,stmt->whereClause);
+ /* take care of the where clause */
+ stmt->whereClause = transformWhereClause(pstate, stmt->whereClause);
- q->utilityStmt = (Node*)stmt;
- return q;
+ q->utilityStmt = (Node *) stmt;
+ return q;
}
/*
* transformSelectStmt -
- * transforms a Select Statement
+ * transforms a Select Statement
*
*/
-static Query *
-transformSelectStmt(ParseState *pstate, RetrieveStmt *stmt)
+static Query *
+transformSelectStmt(ParseState * pstate, RetrieveStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
+
+ qry->commandType = CMD_SELECT;
- qry->commandType = CMD_SELECT;
+ /* set up a range table */
+ makeRangeTable(pstate, NULL, stmt->fromClause);
- /* set up a range table */
- makeRangeTable(pstate, NULL, stmt->fromClause);
+ qry->uniqueFlag = stmt->unique;
- qry->uniqueFlag = stmt->unique;
+ qry->into = stmt->into;
+ qry->isPortal = FALSE;
- qry->into = stmt->into;
- qry->isPortal = FALSE;
+ /* fix the target list */
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix the target list */
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate,stmt->whereClause);
+ /* check subselect clause */
+ if (stmt->selectClause)
+ elog(NOTICE, "UNION not yet supported; using first SELECT only", NULL);
- /* check subselect clause */
- if (stmt->selectClause)
- elog(NOTICE,"UNION not yet supported; using first SELECT only",NULL);
+ /* check subselect clause */
+ if (stmt->havingClause)
+ elog(NOTICE, "HAVING not yet supported; ignore clause", NULL);
- /* check subselect clause */
- if (stmt->havingClause)
- elog(NOTICE,"HAVING not yet supported; ignore clause",NULL);
+ /* fix order clause */
+ qry->sortClause = transformSortClause(pstate,
+ stmt->sortClause,
+ qry->targetList,
+ qry->uniqueFlag);
- /* fix order clause */
- qry->sortClause = transformSortClause(pstate,
- stmt->sortClause,
- qry->targetList,
- qry->uniqueFlag);
+ /* fix group by clause */
+ qry->groupClause = transformGroupClause(pstate,
+ stmt->groupClause,
+ qry->targetList);
+ qry->rtable = pstate->p_rtable;
- /* fix group by clause */
- qry->groupClause = transformGroupClause(pstate,
- stmt->groupClause,
- qry->targetList);
- qry->rtable = pstate->p_rtable;
+ if (pstate->p_numAgg > 0)
+ finalizeAggregates(pstate, qry);
- if (pstate->p_numAgg > 0)
- finalizeAggregates(pstate, qry);
-
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformUpdateStmt -
- * transforms an update statement
+ * transforms an update statement
*
*/
-static Query *
-transformUpdateStmt(ParseState *pstate, ReplaceStmt *stmt)
+static Query *
+transformUpdateStmt(ParseState * pstate, ReplaceStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
+
+ qry->commandType = CMD_UPDATE;
+ pstate->p_is_update = true;
- qry->commandType = CMD_UPDATE;
- pstate->p_is_update = true;
- /*
- * the FROM clause is non-standard SQL syntax. We used to be able to
- * do this with REPLACE in POSTQUEL so we keep the feature.
- */
- makeRangeTable(pstate, stmt->relname, stmt->fromClause);
+ /*
+ * the FROM clause is non-standard SQL syntax. We used to be able to
+ * do this with REPLACE in POSTQUEL so we keep the feature.
+ */
+ makeRangeTable(pstate, stmt->relname, stmt->fromClause);
- /* fix the target list */
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ /* fix the target list */
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate,stmt->whereClause);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- qry->rtable = pstate->p_rtable;
- qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
+ qry->rtable = pstate->p_rtable;
+ qry->resultRelation = refnameRangeTablePosn(pstate->p_rtable, stmt->relname);
- /* make sure we don't have aggregates in the where clause */
- if (pstate->p_numAgg > 0)
- parseCheckAggregates(pstate, qry);
+ /* make sure we don't have aggregates in the where clause */
+ if (pstate->p_numAgg > 0)
+ parseCheckAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*
* transformCursorStmt -
- * transform a Create Cursor Statement
+ * transform a Create Cursor Statement
*
*/
-static Query *
-transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
+static Query *
+transformCursorStmt(ParseState * pstate, CursorStmt * stmt)
{
- Query *qry = makeNode(Query);
+ Query *qry = makeNode(Query);
- /*
- * in the old days, a cursor statement is a 'retrieve into portal';
- * If you change the following, make sure you also go through the code
- * in various places that tests the kind of operation.
- */
- qry->commandType = CMD_SELECT;
+ /*
+ * in the old days, a cursor statement is a 'retrieve into portal'; If
+ * you change the following, make sure you also go through the code in
+ * various places that tests the kind of operation.
+ */
+ qry->commandType = CMD_SELECT;
- /* set up a range table */
- makeRangeTable(pstate, NULL, stmt->fromClause);
+ /* set up a range table */
+ makeRangeTable(pstate, NULL, stmt->fromClause);
- qry->uniqueFlag = stmt->unique;
+ qry->uniqueFlag = stmt->unique;
- qry->into = stmt->portalname;
- qry->isPortal = TRUE;
- qry->isBinary = stmt->binary; /* internal portal */
+ qry->into = stmt->portalname;
+ qry->isPortal = TRUE;
+ qry->isBinary = stmt->binary; /* internal portal */
- /* fix the target list */
- qry->targetList = transformTargetList(pstate, stmt->targetList);
+ /* fix the target list */
+ qry->targetList = transformTargetList(pstate, stmt->targetList);
- /* fix where clause */
- qry->qual = transformWhereClause(pstate,stmt->whereClause);
+ /* fix where clause */
+ qry->qual = transformWhereClause(pstate, stmt->whereClause);
- /* fix order clause */
- qry->sortClause = transformSortClause(pstate,
- stmt->sortClause,
- qry->targetList,
- qry->uniqueFlag);
- /* fix group by clause */
- qry->groupClause = transformGroupClause(pstate,
- stmt->groupClause,
- qry->targetList);
+ /* fix order clause */
+ qry->sortClause = transformSortClause(pstate,
+ stmt->sortClause,
+ qry->targetList,
+ qry->uniqueFlag);
+ /* fix group by clause */
+ qry->groupClause = transformGroupClause(pstate,
+ stmt->groupClause,
+ qry->targetList);
- qry->rtable = pstate->p_rtable;
+ qry->rtable = pstate->p_rtable;
- if (pstate->p_numAgg > 0)
- finalizeAggregates(pstate, qry);
+ if (pstate->p_numAgg > 0)
+ finalizeAggregates(pstate, qry);
- return (Query *)qry;
+ return (Query *) qry;
}
/*****************************************************************************
@@ -547,236 +564,278 @@ transformCursorStmt(ParseState *pstate, CursorStmt *stmt)
/*
* 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.
+ * 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)
+static Node *
+transformExpr(ParseState * pstate, Node * expr, int precedence)
{
- Node *result = NULL;
+ 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 (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);
+ 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;
+ 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;
}
- 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;
+
+ return result;
}
-static Node *
-transformIdent(ParseState *pstate, Node *expr, int precedence)
+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;
+ 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
- result = column_result;
- }
+ {
+ if (relation_result)
+ result = relation_result;
+ else
+ result = column_result;
+ }
+
+ if (result == NULL)
+ elog(WARN, "attribute \"%s\" not found", ident->name);
- if(result == NULL)
- elog(WARN, "attribute \"%s\" not found", ident->name);
-
- return result;
+ return result;
}
/*****************************************************************************
@@ -787,201 +846,210 @@ transformIdent(ParseState *pstate, Node *expr, int precedence)
/*
* 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)
+ * 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)
+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;
+ List *fl;
- /*
- * 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,
- baserel->timeRange);
- }
+ 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,
+ baserel->timeRange);
+ }
}
/*
* makeRangeTable -
- * make a range table with the specified relation (optional) and the
- * from-clause.
+ * make a range table with the specified relation (optional) and the
+ * from-clause.
*/
static void
-makeRangeTable(ParseState *pstate, char *relname, List *frmList)
+makeRangeTable(ParseState * pstate, char *relname, List * frmList)
{
- RangeTblEntry *rte;
+ RangeTblEntry *rte;
- parseFromClause(pstate, frmList);
+ parseFromClause(pstate, frmList);
- if (relname == NULL)
- return;
-
- if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
- rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE, NULL);
- 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);
+ if (relname == NULL)
+ return;
+
+ if (refnameRangeTablePosn(pstate->p_rtable, relname) < 1)
+ rte = addRangeTableEntry(pstate, relname, relname, FALSE, FALSE, NULL);
+ 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.)
+ * exprType -
+ * returns the Oid of the type of the expression. (Used for typechecking.)
*/
Oid
-exprType(Node *expr)
+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;
+ 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)
+ * turns '*' (in the target list) into a list of attributes (of all
+ * relations in the range table)
*/
-static List *
-expandAllTables(ParseState *pstate)
+static List *
+expandAllTables(ParseState * pstate)
{
- List *target= NIL;
- List *legit_rtable=NIL;
- List *rt, *rtable;
+ 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);
+ 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");
/*
- * 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;")
+ * go through the range table and make a list of range table entries
+ * which we will expand.
*/
- 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);
+ 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;
+ return target;
}
/*
* figureColname -
- * if the name of the resulting column is not specified in the target
- * list, we have to guess.
+ * 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)
+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;
+ 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;
}
- break;
- default:
- break;
- }
-
- return "?column?";
+
+ return "?column?";
}
/*****************************************************************************
@@ -992,452 +1060,531 @@ figureColname(Node *expr, Node *resval)
/*
* 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)
+ * 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)
+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-1);
- id->indirection = NIL;
- id->isRel = false;
- if (tl == NIL)
- cols = tl = lcons(id, NIL);
- else {
- lnext(tl) = lcons(id,NIL);
- tl = lnext(tl);
- }
+ 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 - 1);
+ 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)
- /* elog on failure */
- varattno(pstate->p_target_relation,((Ident *)lfirst(tl))->name);
+ else
+ foreach(tl, cols)
+ /* elog on failure */
+ varattno(pstate->p_target_relation, ((Ident *) lfirst(tl))->name);
- return cols;
+ return cols;
}
/*
* transformTargetList -
- * turns a list of ResTarget's into a list of TargetEntry's
+ * turns a list of ResTarget's into a list of TargetEntry's
*/
-static List *
-transformTargetList(ParseState *pstate, List *targetlist)
+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))
+ 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,
- "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);
- }
+ "internal error: do not know how to transform targetlist");
+ break;
}
- 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);
+ if (p_target == NIL)
+ {
+ p_target = tail_p_target = lcons(tent, NIL);
+ }
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);
+ {
+ lnext(tail_p_target) = lcons(tent, NIL);
+ tail_p_target = lnext(tail_p_target);
}
- 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);
}
- targetlist = lnext(targetlist);
- }
- return p_target;
+ return p_target;
}
/*
* make_targetlist_expr -
- * make a TargetEntry from an expression
+ * 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)
+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));
- }
+ 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;
+ 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;
+ 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;
}
@@ -1449,26 +1596,27 @@ make_targetlist_expr(ParseState *pstate,
/*
* transformWhereClause -
- * transforms the qualification and make sure it is of type Boolean
+ * transforms the qualification and make sure it is of type Boolean
*
*/
-static Node *
-transformWhereClause(ParseState *pstate, Node *a_expr)
+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;
+ 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;
}
/*****************************************************************************
@@ -1478,203 +1626,237 @@ transformWhereClause(ParseState *pstate, Node *a_expr)
*****************************************************************************/
/*
- * find_targetlist_entry -
- * returns the Resdom in the target list matching the specified varname
- * and range
+ * 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)
+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;
+ 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);
+ 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;
- }
- }
+ 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;
+ return target_result;
}
-static Oid
+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;
+ 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
+ * transform a Group By clause
*
*/
-static List *
-transformGroupClause(ParseState *pstate, List *grouplist, List *targetlist)
+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 {
- lnext(gl) = lcons(grpcl, NIL);
- gl = lnext(gl);
+ 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
+ {
+ lnext(gl) = lcons(grpcl, NIL);
+ gl = lnext(gl);
+ }
+ grouplist = lnext(grouplist);
}
- grouplist = lnext(grouplist);
- }
- return glist;
+ return glist;
}
/*
* transformSortClause -
- * transform an Order By clause
+ * transform an Order By clause
*
*/
-static List *
-transformSortClause(ParseState *pstate,
- List *orderlist, List *targetlist,
- char* uniqueFlag)
+static List *
+transformSortClause(ParseState * pstate,
+ List * orderlist, List * targetlist,
+ char *uniqueFlag)
{
- List *sortlist = NIL;
- List *s = NIL, *i;
-
- 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 {
- lnext(s) = lcons(sortcl, NIL);
- s = lnext(s);
+ List *sortlist = NIL;
+ List *s = NIL,
+ *i;
+
+ 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
+ {
+ lnext(s) = lcons(sortcl, NIL);
+ s = lnext(s);
+ }
+ orderlist = lnext(orderlist);
}
- orderlist = lnext(orderlist);
- }
-
- if (uniqueFlag) {
- 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);
- }
+
+ if (uniqueFlag)
+ {
+ 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;
+ return sortlist;
}
/*
@@ -1682,578 +1864,645 @@ transformSortClause(ParseState *pstate,
** 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)
+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);
+ 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
+ ** 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)
+ 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);
+
+ /*
+ * 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.
+ ** 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 *
+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));
+ 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.
+ ** Build a tlist that extracts a base type from the tuple
+ ** returned by the executor.
*/
-static List *
+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));
+ 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).
+ * 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)
+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:
+ Oid argtype;
+ Oid argrelid;
+ Name relname;
+ Relation rd;
+ Oid relid;
+ int attnum;
+
+ switch (nodeTag(first_arg))
{
- 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);
+ 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;
}
- 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);
+ case T_Var:
+ {
+
+ /*
+ * The argument is a set, so this is either a projection or a
+ * function call on this set.
+ */
+ *attisset = true;
+ break;
}
- }else {
- /* drop through */
- ;
- }
- 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;
}
- case T_Var:
+
+ 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)
{
- /*
- * The argument is a set, so this is either a projection
- * or a function call on this set.
- */
- *attisset = true;
- break;
+ first_arg = lfirst(fargs);
+ if (first_arg == NULL)
+ elog(WARN, "function %s does not allow NULL input", funcname);
}
- case T_Expr:
+
+ /*
+ * * 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)
{
- Expr *expr = (Expr*)first_arg;
- Func *funcnode;
- if (expr->opType != FUNC_EXPR)
- break;
+ 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, NULL);
+
+ 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;
+ }
+ }
+ }
- 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 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, NULL);
+ 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);
}
- 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);
+ 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);
}
-
- }
- elog(WARN, "Function %s has bad returntype %d",
- funcname, argtype);
- break;
+ 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;
}
- case T_Param:
+ else
{
- 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;
+ exists = func_get_detail(funcname, nargs, oid_array, &funcid,
+ &rettype, &retset, &true_oid_array);
}
- 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,NULL);
-
- 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 (!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);
}
- }
-
- 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, NULL);
- 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);
+
+ /*
+ * Sequence handling.
+ */
+ if (funcid == SeqNextValueRegProcedure ||
+ funcid == SeqCurrValueRegProcedure)
+ {
+ Const *seq;
+ char *seqrel;
+ int32 aclcheck_result = -1;
+
+ Assert(length(fargs) == 1);
+ seq = (Const *) lfirst(fargs);
+ if (!IsA((Node *) seq, Const))
+ elog(WARN, "%s: only constant sequence names are acceptable", funcname);
+ seqrel = textout((struct varlena *) (seq->constvalue));
+
+ 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");
}
-
- 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.
+
+ 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.
*/
- 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);
+
+ if (retset)
+ {
+ Iter *iter = makeNode(Iter);
+
+ iter->itertype = rettype;
+ iter->iterexpr = retval;
+ retval = (Node *) iter;
}
- }
-
- /*
- * Sequence handling.
- */
- if ( funcid == SeqNextValueRegProcedure ||
- funcid == SeqCurrValueRegProcedure )
- {
- Const *seq;
- char *seqrel;
- int32 aclcheck_result = -1;
-
- Assert ( length(fargs) == 1 );
- seq = (Const*)lfirst(fargs);
- if ( ! IsA ((Node*)seq, Const) )
- elog (WARN, "%s: only constant sequence names are acceptable", funcname);
- seqrel = textout ((struct varlena *) (seq->constvalue));
-
- 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);
+
+ return (retval);
}
/*****************************************************************************
@@ -2262,232 +2511,243 @@ ParseFunc(ParseState *pstate, char *funcname, List *fargs, int *curr_resno)
/*
* AddAggToParseState -
- * add the aggregate to the list of unique aggregates in pstate.
+ * 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)
+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;
+ 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++;
}
- i++;
- }
-
- /* not found, new aggregate */
- aggreg->aggno = i;
- pstate->p_numAgg++;
- pstate->p_aggs = lappend(pstate->p_aggs, aggreg);
- return;
+
+ /* 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.
+ * 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);
+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.
+ * Recursively find aggreg nodes from a clause.
+ *
+ * Returns true if any aggregate found.
*/
-static bool
-contain_agg_clause(Node *clause)
+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)))
+ if (clause == NULL)
+ return FALSE;
+ else if (IsA(clause, Aggreg))
return TRUE;
- return FALSE;
- } else if (is_funcclause (clause)) {
- List *temp;
+ 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 (IsA(clause,ArrayRef)) {
- 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, ((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)));
+ 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;
+ return FALSE;
}
/*
* exprIsAggOrGroupCol -
- * returns true if the expression does not contain non-group columns.
+ * returns true if the expression does not contain non-group columns.
*/
-static bool
-exprIsAggOrGroupCol(Node *expr, List *groupClause)
+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) )
+ List *gl;
+
+ if (expr == NULL || IsA(expr, Const) ||
+ IsA(expr, Param) || IsA(expr, Aggreg))
return TRUE;
- }
- if ( IsA (expr, Expr) )
- {
- List *temp;
+ foreach(gl, groupClause)
+ {
+ GroupClause *grpcl = lfirst(gl);
- foreach (temp, ((Expr*)expr)->args)
- if (!exprIsAggOrGroupCol(lfirst(temp),groupClause))
- return FALSE;
- return TRUE;
- }
+ 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;
+ return FALSE;
}
/*
* tleIsAggOrGroupCol -
- * returns true if the TargetEntry is Agg or GroupCol.
+ * returns true if the TargetEntry is Agg or GroupCol.
*/
-static bool
-tleIsAggOrGroupCol(TargetEntry *tle, List *groupClause)
+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;
+ 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, Aggreg))
+ return TRUE;
- if ( IsA (expr, Expr) )
- {
- List *temp;
+ if (IsA(expr, Expr))
+ {
+ List *temp;
- foreach (temp, ((Expr*)expr)->args)
- if (!exprIsAggOrGroupCol(lfirst(temp),groupClause))
- return FALSE;
- return TRUE;
- }
+ foreach(temp, ((Expr *) expr)->args)
+ if (!exprIsAggOrGroupCol(lfirst(temp), groupClause))
+ return FALSE;
+ return TRUE;
+ }
- return FALSE;
+ 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.
+ * 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)
+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.
- */
+ 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;
+ * 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;
}