diff options
Diffstat (limited to 'src/backend/parser')
-rw-r--r-- | src/backend/parser/analyze.c | 4324 | ||||
-rw-r--r-- | src/backend/parser/catalog_utils.c | 2457 | ||||
-rw-r--r-- | src/backend/parser/dbcommands.c | 409 | ||||
-rw-r--r-- | src/backend/parser/keywords.c | 366 | ||||
-rw-r--r-- | src/backend/parser/parse_query.c | 1340 | ||||
-rw-r--r-- | src/backend/parser/parser.c | 844 | ||||
-rw-r--r-- | src/backend/parser/scansup.c | 173 | ||||
-rw-r--r-- | src/backend/parser/sysfunc.c | 51 |
8 files changed, 5282 insertions, 4682 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; } diff --git a/src/backend/parser/catalog_utils.c b/src/backend/parser/catalog_utils.c index 043c2865060..41e6fffac9b 100644 --- a/src/backend/parser/catalog_utils.c +++ b/src/backend/parser/catalog_utils.c @@ -6,7 +6,7 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.22 1997/08/22 00:02:05 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/Attic/catalog_utils.c,v 1.23 1997/09/07 04:44:42 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -48,83 +48,110 @@ #include "utils/lsyscache.h" #include "storage/lmgr.h" -#include "port-protos.h" /* strdup() */ - -struct { - char *field; - int code; -} special_attr[] = { - { "ctid", SelfItemPointerAttributeNumber }, - { "oid", ObjectIdAttributeNumber }, - { "xmin", MinTransactionIdAttributeNumber }, - { "cmin", MinCommandIdAttributeNumber }, - { "xmax", MaxTransactionIdAttributeNumber }, - { "cmax", MaxCommandIdAttributeNumber }, - { "chain", ChainItemPointerAttributeNumber }, - { "anchor", AnchorItemPointerAttributeNumber }, - { "tmin", MinAbsoluteTimeAttributeNumber }, - { "tmax", MaxAbsoluteTimeAttributeNumber }, - { "vtype", VersionTypeAttributeNumber } +#include "port-protos.h" /* strdup() */ + +struct +{ + char *field; + int code; +} special_attr[] = + +{ + { + "ctid", SelfItemPointerAttributeNumber + }, + { + "oid", ObjectIdAttributeNumber + }, + { + "xmin", MinTransactionIdAttributeNumber + }, + { + "cmin", MinCommandIdAttributeNumber + }, + { + "xmax", MaxTransactionIdAttributeNumber + }, + { + "cmax", MaxCommandIdAttributeNumber + }, + { + "chain", ChainItemPointerAttributeNumber + }, + { + "anchor", AnchorItemPointerAttributeNumber + }, + { + "tmin", MinAbsoluteTimeAttributeNumber + }, + { + "tmax", MaxAbsoluteTimeAttributeNumber + }, + { + "vtype", VersionTypeAttributeNumber + } }; #define SPECIALS (sizeof(special_attr)/sizeof(*special_attr)) - -static char *attnum_type[SPECIALS] = { - "tid", - "oid", - "xid", - "cid", - "xid", - "cid", - "tid", - "tid", - "abstime", - "abstime", - "char" - }; - -#define MAXFARGS 8 /* max # args to a c or postquel function */ + +static char *attnum_type[SPECIALS] = { + "tid", + "oid", + "xid", + "cid", + "xid", + "cid", + "tid", + "tid", + "abstime", + "abstime", + "char" +}; + +#define MAXFARGS 8 /* max # args to a c or postquel function */ /* - * This structure is used to explore the inheritance hierarchy above - * nodes in the type tree in order to disambiguate among polymorphic - * functions. + * This structure is used to explore the inheritance hierarchy above + * nodes in the type tree in order to disambiguate among polymorphic + * functions. */ -typedef struct _InhPaths { - int nsupers; /* number of superclasses */ - Oid self; /* this class */ - Oid *supervec; /* vector of superclasses */ -} InhPaths; +typedef struct _InhPaths +{ + int nsupers; /* number of superclasses */ + Oid self; /* this class */ + Oid *supervec; /* vector of superclasses */ +} InhPaths; /* - * This structure holds a list of possible functions or operators that - * agree with the known name and argument types of the function/operator. + * This structure holds a list of possible functions or operators that + * agree with the known name and argument types of the function/operator. */ -typedef struct _CandidateList { - Oid *args; - struct _CandidateList *next; -} *CandidateList; - -static Oid **argtype_inherit(int nargs, Oid *oid_array); -static Oid **genxprod(InhPaths *arginh, int nargs); -static int findsupers(Oid relid, Oid **supervec); -static bool check_typeid(Oid id); -static char *instr1(TypeTupleForm tp, char *string, int typlen); -static void op_error(char *op, Oid arg1, Oid arg2); +typedef struct _CandidateList +{ + Oid *args; + struct _CandidateList *next; +} *CandidateList; + +static Oid **argtype_inherit(int nargs, Oid * oid_array); +static Oid **genxprod(InhPaths * arginh, int nargs); +static int findsupers(Oid relid, Oid ** supervec); +static bool check_typeid(Oid id); +static char *instr1(TypeTupleForm tp, char *string, int typlen); +static void op_error(char *op, Oid arg1, Oid arg2); /* check to see if a type id is valid, - * returns true if it is. By using this call before calling + * returns true if it is. By using this call before calling * get_id_type or get_id_typname, more meaningful error messages * can be produced because the caller typically has more context of - * what's going on - jolly + * what's going on - jolly */ -static bool +static bool check_typeid(Oid id) { - return (SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(id), - 0,0,0) != NULL); + return (SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(id), + 0, 0, 0) != NULL); } @@ -132,46 +159,50 @@ check_typeid(Oid id) Type get_id_type(Oid id) { - HeapTuple tup; - - if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id), - 0,0,0))) { - elog ( WARN, "type id lookup of %ud failed", id); - return(NULL); - } - return((Type) tup); + HeapTuple tup; + + if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id), + 0, 0, 0))) + { + elog(WARN, "type id lookup of %ud failed", id); + return (NULL); + } + return ((Type) tup); } /* return a type name, given a typeid */ -char* +char * get_id_typname(Oid id) { - HeapTuple tup; - TypeTupleForm typetuple; - - if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id), - 0,0,0))) { - elog ( WARN, "type id lookup of %ud failed", id); - return(NULL); - } - typetuple = (TypeTupleForm)GETSTRUCT(tup); - return (typetuple->typname).data; + HeapTuple tup; + TypeTupleForm typetuple; + + if (!(tup = SearchSysCacheTuple(TYPOID, ObjectIdGetDatum(id), + 0, 0, 0))) + { + elog(WARN, "type id lookup of %ud failed", id); + return (NULL); + } + typetuple = (TypeTupleForm) GETSTRUCT(tup); + return (typetuple->typname).data; } /* return a Type structure, given type name */ Type type(char *s) { - HeapTuple tup; - - if (s == NULL) { - elog ( WARN , "type(): Null type" ); - } - - if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0,0,0))) { - elog (WARN , "type name lookup of %s failed", s); - } - return((Type) tup); + HeapTuple tup; + + if (s == NULL) + { + elog(WARN, "type(): Null type"); + } + + if (!(tup = SearchSysCacheTuple(TYPNAME, PointerGetDatum(s), 0, 0, 0))) + { + elog(WARN, "type name lookup of %s failed", s); + } + return ((Type) tup); } /* given attribute id, return type of that attribute */ @@ -179,297 +210,327 @@ type(char *s) Oid att_typeid(Relation rd, int attid) { - - if (attid < 0) { - return(typeid(type(attnum_type[-attid-1]))); - } - /* -1 because varattno (where attid comes from) returns one - more than index */ - return(rd->rd_att->attrs[attid-1]->atttypid); + + if (attid < 0) + { + return (typeid(type(attnum_type[-attid - 1]))); + } + + /* + * -1 because varattno (where attid comes from) returns one more than + * index + */ + return (rd->rd_att->attrs[attid - 1]->atttypid); } int att_attnelems(Relation rd, int attid) { - return(rd->rd_att->attrs[attid-1]->attnelems); + return (rd->rd_att->attrs[attid - 1]->attnelems); } /* given type, return the type OID */ Oid typeid(Type tp) { - if (tp == NULL) { - elog ( WARN , "typeid() called with NULL type struct"); - } - return(tp->t_oid); + if (tp == NULL) + { + elog(WARN, "typeid() called with NULL type struct"); + } + return (tp->t_oid); } /* given type (as type struct), return the length of type */ int16 tlen(Type t) { - TypeTupleForm typ; - - typ = (TypeTupleForm)GETSTRUCT(t); - return(typ->typlen); + TypeTupleForm typ; + + typ = (TypeTupleForm) GETSTRUCT(t); + return (typ->typlen); } /* given type (as type struct), return the value of its 'byval' attribute.*/ bool tbyval(Type t) { - TypeTupleForm typ; - - typ = (TypeTupleForm)GETSTRUCT(t); - return(typ->typbyval); + TypeTupleForm typ; + + typ = (TypeTupleForm) GETSTRUCT(t); + return (typ->typbyval); } /* given type (as type struct), return the name of type */ -char* +char * tname(Type t) { - TypeTupleForm typ; - - typ = (TypeTupleForm)GETSTRUCT(t); - return (typ->typname).data; + TypeTupleForm typ; + + typ = (TypeTupleForm) GETSTRUCT(t); + return (typ->typname).data; } /* given type (as type struct), return wether type is passed by value */ int tbyvalue(Type t) { - TypeTupleForm typ; - - typ = (TypeTupleForm) GETSTRUCT(t); - return(typ->typbyval); + TypeTupleForm typ; + + typ = (TypeTupleForm) GETSTRUCT(t); + return (typ->typbyval); } /* given a type, return its typetype ('c' for 'c'atalog types) */ static char typetypetype(Type t) { - TypeTupleForm typ; - - typ = (TypeTupleForm) GETSTRUCT(t); - return(typ->typtype); + TypeTupleForm typ; + + typ = (TypeTupleForm) GETSTRUCT(t); + return (typ->typtype); } /* given operator, return the operator OID */ Oid oprid(Operator op) { - return(op->t_oid); + return (op->t_oid); } /* - * given opname, leftTypeId and rightTypeId, - * find all possible (arg1, arg2) pairs for which an operator named - * opname exists, such that leftTypeId can be coerced to arg1 and - * rightTypeId can be coerced to arg2 + * given opname, leftTypeId and rightTypeId, + * find all possible (arg1, arg2) pairs for which an operator named + * opname exists, such that leftTypeId can be coerced to arg1 and + * rightTypeId can be coerced to arg2 */ static int binary_oper_get_candidates(char *opname, - Oid leftTypeId, - Oid rightTypeId, - CandidateList *candidates) + Oid leftTypeId, + Oid rightTypeId, + CandidateList * candidates) { - CandidateList current_candidate; - Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; - HeapTuple tup; - OperatorTupleForm oper; - Buffer buffer; - int nkeys; - int ncandidates = 0; - ScanKeyData opKey[3]; - - *candidates = NULL; - - ScanKeyEntryInitialize(&opKey[0], 0, - Anum_pg_operator_oprname, - NameEqualRegProcedure, - NameGetDatum(opname)); - - ScanKeyEntryInitialize(&opKey[1], 0, - Anum_pg_operator_oprkind, - CharacterEqualRegProcedure, - CharGetDatum('b')); - - - if (leftTypeId == UNKNOWNOID) { - if (rightTypeId == UNKNOWNOID) { - nkeys = 2; - } else { - nkeys = 3; - - ScanKeyEntryInitialize(&opKey[2], 0, - Anum_pg_operator_oprright, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(rightTypeId)); - } - } else if (rightTypeId == UNKNOWNOID) { - nkeys = 3; - - ScanKeyEntryInitialize(&opKey[2], 0, - Anum_pg_operator_oprleft, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(leftTypeId)); - } else { - /* currently only "unknown" can be coerced */ - return 0; - } - - pg_operator_desc = heap_openr(OperatorRelationName); - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SelfTimeQual, - nkeys, - opKey); - - do { - tup = heap_getnext(pg_operator_scan, 0, &buffer); - if (HeapTupleIsValid(tup)) { - current_candidate = (CandidateList)palloc(sizeof(struct _CandidateList)); - current_candidate->args = (Oid *)palloc(2 * sizeof(Oid)); - - oper = (OperatorTupleForm)GETSTRUCT(tup); - current_candidate->args[0] = oper->oprleft; - current_candidate->args[1] = oper->oprright; - current_candidate->next = *candidates; - *candidates = current_candidate; - ncandidates++; - ReleaseBuffer(buffer); + CandidateList current_candidate; + Relation pg_operator_desc; + HeapScanDesc pg_operator_scan; + HeapTuple tup; + OperatorTupleForm oper; + Buffer buffer; + int nkeys; + int ncandidates = 0; + ScanKeyData opKey[3]; + + *candidates = NULL; + + ScanKeyEntryInitialize(&opKey[0], 0, + Anum_pg_operator_oprname, + NameEqualRegProcedure, + NameGetDatum(opname)); + + ScanKeyEntryInitialize(&opKey[1], 0, + Anum_pg_operator_oprkind, + CharacterEqualRegProcedure, + CharGetDatum('b')); + + + if (leftTypeId == UNKNOWNOID) + { + if (rightTypeId == UNKNOWNOID) + { + nkeys = 2; + } + else + { + nkeys = 3; + + ScanKeyEntryInitialize(&opKey[2], 0, + Anum_pg_operator_oprright, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(rightTypeId)); + } + } + else if (rightTypeId == UNKNOWNOID) + { + nkeys = 3; + + ScanKeyEntryInitialize(&opKey[2], 0, + Anum_pg_operator_oprleft, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(leftTypeId)); } - } while(HeapTupleIsValid(tup)); - - heap_endscan(pg_operator_scan); - heap_close(pg_operator_desc); - - return ncandidates; + else + { + /* currently only "unknown" can be coerced */ + return 0; + } + + pg_operator_desc = heap_openr(OperatorRelationName); + pg_operator_scan = heap_beginscan(pg_operator_desc, + 0, + SelfTimeQual, + nkeys, + opKey); + + do + { + tup = heap_getnext(pg_operator_scan, 0, &buffer); + if (HeapTupleIsValid(tup)) + { + current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); + current_candidate->args = (Oid *) palloc(2 * sizeof(Oid)); + + oper = (OperatorTupleForm) GETSTRUCT(tup); + current_candidate->args[0] = oper->oprleft; + current_candidate->args[1] = oper->oprright; + current_candidate->next = *candidates; + *candidates = current_candidate; + ncandidates++; + ReleaseBuffer(buffer); + } + } while (HeapTupleIsValid(tup)); + + heap_endscan(pg_operator_scan); + heap_close(pg_operator_desc); + + return ncandidates; } /* * equivalentOpersAfterPromotion - - * checks if a list of candidate operators obtained from - * binary_oper_get_candidates() contain equivalent operators. If - * this routine is called, we have more than 1 candidate and need to - * decided whether to pick one of them. This routine returns true if - * the all the candidates operate on the same data types after - * promotion (int2, int4, float4 -> float8). + * checks if a list of candidate operators obtained from + * binary_oper_get_candidates() contain equivalent operators. If + * this routine is called, we have more than 1 candidate and need to + * decided whether to pick one of them. This routine returns true if + * the all the candidates operate on the same data types after + * promotion (int2, int4, float4 -> float8). */ -static bool +static bool equivalentOpersAfterPromotion(CandidateList candidates) { - CandidateList result; - CandidateList promotedCandidates = NULL; - Oid leftarg, rightarg; - - for (result = candidates; result != NULL; result = result->next) { - CandidateList c; - c = (CandidateList)palloc(sizeof(*c)); - c->args = (Oid *)palloc(2 * sizeof(Oid)); - switch (result->args[0]) { - case FLOAT4OID: - case INT4OID: - case INT2OID: - case CASHOID: - c->args[0] = FLOAT8OID; - break; - default: - c->args[0] = result->args[0]; - break; + CandidateList result; + CandidateList promotedCandidates = NULL; + Oid leftarg, + rightarg; + + for (result = candidates; result != NULL; result = result->next) + { + CandidateList c; + + c = (CandidateList) palloc(sizeof(*c)); + c->args = (Oid *) palloc(2 * sizeof(Oid)); + switch (result->args[0]) + { + case FLOAT4OID: + case INT4OID: + case INT2OID: + case CASHOID: + c->args[0] = FLOAT8OID; + break; + default: + c->args[0] = result->args[0]; + break; + } + switch (result->args[1]) + { + case FLOAT4OID: + case INT4OID: + case INT2OID: + case CASHOID: + c->args[1] = FLOAT8OID; + break; + default: + c->args[1] = result->args[1]; + break; + } + c->next = promotedCandidates; + promotedCandidates = c; } - switch (result->args[1]) { - case FLOAT4OID: - case INT4OID: - case INT2OID: - case CASHOID: - c->args[1] = FLOAT8OID; - break; - default: - c->args[1] = result->args[1]; - break; + + /* + * if we get called, we have more than 1 candidates so we can do the + * following safely + */ + leftarg = promotedCandidates->args[0]; + rightarg = promotedCandidates->args[1]; + + for (result = promotedCandidates->next; result != NULL; result = result->next) + { + if (result->args[0] != leftarg || result->args[1] != rightarg) + + /* + * this list contains operators that operate on different data + * types even after promotion. Hence we can't decide on which + * one to pick. The user must do explicit type casting. + */ + return FALSE; } - c->next = promotedCandidates; - promotedCandidates = c; - } - - /* if we get called, we have more than 1 candidates so we can do the - following safely */ - leftarg = promotedCandidates->args[0]; - rightarg = promotedCandidates->args[1]; - - for (result=promotedCandidates->next; result!=NULL; result=result->next) { - if (result->args[0]!=leftarg || result->args[1]!=rightarg) - /* - * this list contains operators that operate on different - * data types even after promotion. Hence we can't decide on - * which one to pick. The user must do explicit type casting. - */ - return FALSE; - } - - /* all the candidates are equivalent in the following sense: they operate - on equivalent data types and picking any one of them is as good. */ - return TRUE; + + /* + * all the candidates are equivalent in the following sense: they + * operate on equivalent data types and picking any one of them is as + * good. + */ + return TRUE; } - + /* - * given a choice of argument type pairs for a binary operator, - * try to choose a default pair + * given a choice of argument type pairs for a binary operator, + * try to choose a default pair */ -static CandidateList +static CandidateList binary_oper_select_candidate(Oid arg1, - Oid arg2, - CandidateList candidates) + Oid arg2, + CandidateList candidates) { - CandidateList result; - - /* - * if both are "unknown", there is no way to select a candidate - * - * current wisdom holds that the default operator should be one - * in which both operands have the same type (there will only - * be one such operator) - * - * 7.27.93 - I have decided not to do this; it's too hard to - * justify, and it's easy enough to typecast explicitly -avi - * [the rest of this routine were commented out since then -ay] - */ - - if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID) - return (NULL); + CandidateList result; + + /* + * if both are "unknown", there is no way to select a candidate + * + * current wisdom holds that the default operator should be one in which + * both operands have the same type (there will only be one such + * operator) + * + * 7.27.93 - I have decided not to do this; it's too hard to justify, and + * it's easy enough to typecast explicitly -avi [the rest of this + * routine were commented out since then -ay] + */ + + if (arg1 == UNKNOWNOID && arg2 == UNKNOWNOID) + return (NULL); + + /* + * 6/23/95 - I don't complete agree with avi. In particular, casting + * floats is a pain for users. Whatever the rationale behind not doing + * this is, I need the following special case to work. + * + * In the WHERE clause of a query, if a float is specified without + * quotes, we treat it as float8. I added the float48* operators so + * that we can operate on float4 and float8. But now we have more than + * one matching operator if the right arg is unknown (eg. float + * specified with quotes). This break some stuff in the regression + * test where there are floats in quotes not properly casted. Below is + * the solution. In addition to requiring the operator operates on the + * same type for both operands [as in the code Avi originally + * commented out], we also require that the operators be equivalent in + * some sense. (see equivalentOpersAfterPromotion for details.) - ay + * 6/95 + */ + if (!equivalentOpersAfterPromotion(candidates)) + return NULL; + + /* + * if we get here, any one will do but we're more picky and require + * both operands be the same. + */ + for (result = candidates; result != NULL; result = result->next) + { + if (result->args[0] == result->args[1]) + return result; + } - /* - * 6/23/95 - I don't complete agree with avi. In particular, casting - * floats is a pain for users. Whatever the rationale behind not doing - * this is, I need the following special case to work. - * - * In the WHERE clause of a query, if a float is specified without - * quotes, we treat it as float8. I added the float48* operators so - * that we can operate on float4 and float8. But now we have more - * than one matching operator if the right arg is unknown (eg. float - * specified with quotes). This break some stuff in the regression - * test where there are floats in quotes not properly casted. Below - * is the solution. In addition to requiring the operator operates - * on the same type for both operands [as in the code Avi originally - * commented out], we also require that the operators be equivalent - * in some sense. (see equivalentOpersAfterPromotion for details.) - * - ay 6/95 - */ - if (!equivalentOpersAfterPromotion(candidates)) - return NULL; - - /* if we get here, any one will do but we're more picky and require - both operands be the same. */ - for (result = candidates; result != NULL; result = result->next) { - if (result->args[0] == result->args[1]) - return result; - } - - return (NULL); + return (NULL); } /* Given operator, types of arg1, and arg2, return oper struct */ @@ -477,135 +538,158 @@ binary_oper_select_candidate(Oid arg1, Operator oper(char *op, Oid arg1, Oid arg2, bool noWarnings) { - HeapTuple tup; - CandidateList candidates; - int ncandidates; - - if (!arg2) arg2=arg1; - if (!arg1) arg1=arg2; - - if (!(tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(arg1), - ObjectIdGetDatum(arg2), - Int8GetDatum('b')))) { - ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates); - if (ncandidates == 0) { - /* - * no operators of the desired types found - */ - if (!noWarnings) - op_error(op, arg1, arg2); - return(NULL); - } else if (ncandidates == 1) { - /* - * exactly one operator of the desired types found - */ - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(candidates->args[0]), - ObjectIdGetDatum(candidates->args[1]), - Int8GetDatum('b')); - Assert(HeapTupleIsValid(tup)); - } else { - /* - * multiple operators of the desired types found - */ - candidates = binary_oper_select_candidate(arg1, arg2, candidates); - if (candidates != NULL) { - /* we chose one of them */ - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(candidates->args[0]), - ObjectIdGetDatum(candidates->args[1]), - Int8GetDatum('b')); - Assert(HeapTupleIsValid(tup)); - } else { - Type tp1, tp2; - - /* we chose none of them */ - tp1 = get_id_type(arg1); - tp2 = get_id_type(arg2); - if (!noWarnings) { - elog(NOTICE, "there is more than one operator %s for types", op); - elog(NOTICE, "%s and %s. You will have to retype this query", - tname(tp1), tname(tp2)); - elog(WARN, "using an explicit cast"); + HeapTuple tup; + CandidateList candidates; + int ncandidates; + + if (!arg2) + arg2 = arg1; + if (!arg1) + arg1 = arg2; + + if (!(tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(arg1), + ObjectIdGetDatum(arg2), + Int8GetDatum('b')))) + { + ncandidates = binary_oper_get_candidates(op, arg1, arg2, &candidates); + if (ncandidates == 0) + { + + /* + * no operators of the desired types found + */ + if (!noWarnings) + op_error(op, arg1, arg2); + return (NULL); + } + else if (ncandidates == 1) + { + + /* + * exactly one operator of the desired types found + */ + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(candidates->args[0]), + ObjectIdGetDatum(candidates->args[1]), + Int8GetDatum('b')); + Assert(HeapTupleIsValid(tup)); + } + else + { + + /* + * multiple operators of the desired types found + */ + candidates = binary_oper_select_candidate(arg1, arg2, candidates); + if (candidates != NULL) + { + /* we chose one of them */ + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(candidates->args[0]), + ObjectIdGetDatum(candidates->args[1]), + Int8GetDatum('b')); + Assert(HeapTupleIsValid(tup)); + } + else + { + Type tp1, + tp2; + + /* we chose none of them */ + tp1 = get_id_type(arg1); + tp2 = get_id_type(arg2); + if (!noWarnings) + { + elog(NOTICE, "there is more than one operator %s for types", op); + elog(NOTICE, "%s and %s. You will have to retype this query", + tname(tp1), tname(tp2)); + elog(WARN, "using an explicit cast"); + } + return (NULL); + } } - return(NULL); - } } - } - return((Operator) tup); + return ((Operator) tup); } /* - * given opname and typeId, find all possible types for which - * a right/left unary operator named opname exists, - * such that typeId can be coerced to it + * given opname and typeId, find all possible types for which + * a right/left unary operator named opname exists, + * such that typeId can be coerced to it */ static int unary_oper_get_candidates(char *op, - Oid typeId, - CandidateList *candidates, - char rightleft) + Oid typeId, + CandidateList * candidates, + char rightleft) { - CandidateList current_candidate; - Relation pg_operator_desc; - HeapScanDesc pg_operator_scan; - HeapTuple tup; - OperatorTupleForm oper; - Buffer buffer; - int ncandidates = 0; - - static ScanKeyData opKey[2] = { - { 0, Anum_pg_operator_oprname, NameEqualRegProcedure }, - { 0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure } }; - - *candidates = NULL; - - fmgr_info(NameEqualRegProcedure, (func_ptr *) &opKey[0].sk_func, - &opKey[0].sk_nargs); - opKey[0].sk_argument = NameGetDatum(op); - fmgr_info(CharacterEqualRegProcedure, (func_ptr *) &opKey[1].sk_func, - &opKey[1].sk_nargs); - opKey[1].sk_argument = CharGetDatum(rightleft); - - /* currently, only "unknown" can be coerced */ - /* but we should allow types that are internally the same to be "coerced" */ - if (typeId != UNKNOWNOID) { - return 0; - } - - pg_operator_desc = heap_openr(OperatorRelationName); - pg_operator_scan = heap_beginscan(pg_operator_desc, - 0, - SelfTimeQual, - 2, - opKey); - - do { - tup = heap_getnext(pg_operator_scan, 0, &buffer); - if (HeapTupleIsValid(tup)) { - current_candidate = (CandidateList)palloc(sizeof(struct _CandidateList)); - current_candidate->args = (Oid *)palloc(sizeof(Oid)); - - oper = (OperatorTupleForm)GETSTRUCT(tup); - if (rightleft == 'r') - current_candidate->args[0] = oper->oprleft; - else - current_candidate->args[0] = oper->oprright; - current_candidate->next = *candidates; - *candidates = current_candidate; - ncandidates++; - ReleaseBuffer(buffer); + CandidateList current_candidate; + Relation pg_operator_desc; + HeapScanDesc pg_operator_scan; + HeapTuple tup; + OperatorTupleForm oper; + Buffer buffer; + int ncandidates = 0; + + static ScanKeyData opKey[2] = { + {0, Anum_pg_operator_oprname, NameEqualRegProcedure}, + {0, Anum_pg_operator_oprkind, CharacterEqualRegProcedure}}; + + *candidates = NULL; + + fmgr_info(NameEqualRegProcedure, (func_ptr *) & opKey[0].sk_func, + &opKey[0].sk_nargs); + opKey[0].sk_argument = NameGetDatum(op); + fmgr_info(CharacterEqualRegProcedure, (func_ptr *) & opKey[1].sk_func, + &opKey[1].sk_nargs); + opKey[1].sk_argument = CharGetDatum(rightleft); + + /* currently, only "unknown" can be coerced */ + + /* + * but we should allow types that are internally the same to be + * "coerced" + */ + if (typeId != UNKNOWNOID) + { + return 0; } - } while(HeapTupleIsValid(tup)); - - heap_endscan(pg_operator_scan); - heap_close(pg_operator_desc); - - return ncandidates; + + pg_operator_desc = heap_openr(OperatorRelationName); + pg_operator_scan = heap_beginscan(pg_operator_desc, + 0, + SelfTimeQual, + 2, + opKey); + + do + { + tup = heap_getnext(pg_operator_scan, 0, &buffer); + if (HeapTupleIsValid(tup)) + { + current_candidate = (CandidateList) palloc(sizeof(struct _CandidateList)); + current_candidate->args = (Oid *) palloc(sizeof(Oid)); + + oper = (OperatorTupleForm) GETSTRUCT(tup); + if (rightleft == 'r') + current_candidate->args[0] = oper->oprleft; + else + current_candidate->args[0] = oper->oprright; + current_candidate->next = *candidates; + *candidates = current_candidate; + ncandidates++; + ReleaseBuffer(buffer); + } + } while (HeapTupleIsValid(tup)); + + heap_endscan(pg_operator_scan); + heap_close(pg_operator_desc); + + return ncandidates; } /* Given unary right-side operator (operator on right), return oper struct */ @@ -613,42 +697,44 @@ unary_oper_get_candidates(char *op, Operator right_oper(char *op, Oid arg) { - HeapTuple tup; - CandidateList candidates; - int ncandidates; - - /* - if (!OpCache) { - init_op_cache(); - } - */ - if (!(tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(arg), - ObjectIdGetDatum(InvalidOid), - Int8GetDatum('r')))) { - ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r'); - if (ncandidates == 0) { - elog ( WARN , - "Can't find right op: %s for type %d", op, arg ); - return(NULL); - } - else if (ncandidates == 1) { - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(candidates->args[0]), - ObjectIdGetDatum(InvalidOid), - Int8GetDatum('r')); - Assert(HeapTupleIsValid(tup)); - } - else { - elog(NOTICE, "there is more than one right operator %s", op); - elog(NOTICE, "you will have to retype this query"); - elog(WARN, "using an explicit cast"); - return(NULL); + HeapTuple tup; + CandidateList candidates; + int ncandidates; + + /* + * if (!OpCache) { init_op_cache(); } + */ + if (!(tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(arg), + ObjectIdGetDatum(InvalidOid), + Int8GetDatum('r')))) + { + ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'r'); + if (ncandidates == 0) + { + elog(WARN, + "Can't find right op: %s for type %d", op, arg); + return (NULL); + } + else if (ncandidates == 1) + { + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(candidates->args[0]), + ObjectIdGetDatum(InvalidOid), + Int8GetDatum('r')); + Assert(HeapTupleIsValid(tup)); + } + else + { + elog(NOTICE, "there is more than one right operator %s", op); + elog(NOTICE, "you will have to retype this query"); + elog(WARN, "using an explicit cast"); + return (NULL); + } } - } - return((Operator) tup); + return ((Operator) tup); } /* Given unary left-side operator (operator on left), return oper struct */ @@ -656,42 +742,44 @@ right_oper(char *op, Oid arg) Operator left_oper(char *op, Oid arg) { - HeapTuple tup; - CandidateList candidates; - int ncandidates; - - /* - if (!OpCache) { - init_op_cache(); - } - */ - if (!(tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(InvalidOid), - ObjectIdGetDatum(arg), - Int8GetDatum('l')))) { - ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l'); - if (ncandidates == 0) { - elog ( WARN , - "Can't find left op: %s for type %d", op, arg ); - return(NULL); - } - else if (ncandidates == 1) { - tup = SearchSysCacheTuple(OPRNAME, - PointerGetDatum(op), - ObjectIdGetDatum(InvalidOid), - ObjectIdGetDatum(candidates->args[0]), - Int8GetDatum('l')); - Assert(HeapTupleIsValid(tup)); - } - else { - elog(NOTICE, "there is more than one left operator %s", op); - elog(NOTICE, "you will have to retype this query"); - elog(WARN, "using an explicit cast"); - return(NULL); + HeapTuple tup; + CandidateList candidates; + int ncandidates; + + /* + * if (!OpCache) { init_op_cache(); } + */ + if (!(tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(InvalidOid), + ObjectIdGetDatum(arg), + Int8GetDatum('l')))) + { + ncandidates = unary_oper_get_candidates(op, arg, &candidates, 'l'); + if (ncandidates == 0) + { + elog(WARN, + "Can't find left op: %s for type %d", op, arg); + return (NULL); + } + else if (ncandidates == 1) + { + tup = SearchSysCacheTuple(OPRNAME, + PointerGetDatum(op), + ObjectIdGetDatum(InvalidOid), + ObjectIdGetDatum(candidates->args[0]), + Int8GetDatum('l')); + Assert(HeapTupleIsValid(tup)); + } + else + { + elog(NOTICE, "there is more than one left operator %s", op); + elog(NOTICE, "you will have to retype this query"); + elog(WARN, "using an explicit cast"); + return (NULL); + } } - } - return((Operator) tup); + return ((Operator) tup); } /* given range variable, return id of variable */ @@ -699,22 +787,26 @@ left_oper(char *op, Oid arg) int varattno(Relation rd, char *a) { - int i; - - for (i = 0; i < rd->rd_rel->relnatts; i++) { - if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) { - return(i+1); + int i; + + for (i = 0; i < rd->rd_rel->relnatts; i++) + { + if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) + { + return (i + 1); + } } - } - for (i = 0; i < SPECIALS; i++) { - if (!strcmp(special_attr[i].field, a)) { - return(special_attr[i].code); + for (i = 0; i < SPECIALS; i++) + { + if (!strcmp(special_attr[i].field, a)) + { + return (special_attr[i].code); + } } - } - - elog(WARN,"Relation %s does not have attribute %s\n", - RelationGetRelationName(rd), a ); - return(-1); + + elog(WARN, "Relation %s does not have attribute %s\n", + RelationGetRelationName(rd), a); + return (-1); } /* Given range variable, return whether attribute of this name @@ -725,104 +817,118 @@ varattno(Relation rd, char *a) bool varisset(Relation rd, char *name) { - int i; - - /* First check if this is a system attribute */ - for (i = 0; i < SPECIALS; i++) { - if (! strcmp(special_attr[i].field, name)) { - return(false); /* no sys attr is a set */ + int i; + + /* First check if this is a system attribute */ + for (i = 0; i < SPECIALS; i++) + { + if (!strcmp(special_attr[i].field, name)) + { + return (false); /* no sys attr is a set */ + } } - } - return (get_attisset(rd->rd_id, name)); + return (get_attisset(rd->rd_id, name)); } /* given range variable, return id of variable */ int nf_varattno(Relation rd, char *a) { - int i; - - for (i = 0; i < rd->rd_rel->relnatts; i++) { - if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) { - return(i+1); + int i; + + for (i = 0; i < rd->rd_rel->relnatts; i++) + { + if (!namestrcmp(&(rd->rd_att->attrs[i]->attname), a)) + { + return (i + 1); + } } - } - for (i = 0; i < SPECIALS; i++) { - if (!strcmp(special_attr[i].field, a)) { - return(special_attr[i].code); + for (i = 0; i < SPECIALS; i++) + { + if (!strcmp(special_attr[i].field, a)) + { + return (special_attr[i].code); + } } - } - return InvalidAttrNumber; + return InvalidAttrNumber; } /*------------- * given an attribute number and a relation, return its relation name */ -char* +char * getAttrName(Relation rd, int attrno) { - char *name; - int i; - - if (attrno<0) { - for (i = 0; i < SPECIALS; i++) { - if (special_attr[i].code == attrno) { - name = special_attr[i].field; - return(name); - } + char *name; + int i; + + if (attrno < 0) + { + for (i = 0; i < SPECIALS; i++) + { + if (special_attr[i].code == attrno) + { + name = special_attr[i].field; + return (name); + } + } + elog(WARN, "Illegal attr no %d for relation %s\n", + attrno, RelationGetRelationName(rd)); + } + else if (attrno >= 1 && attrno <= RelationGetNumberOfAttributes(rd)) + { + name = (rd->rd_att->attrs[attrno - 1]->attname).data; + return (name); + } + else + { + elog(WARN, "Illegal attr no %d for relation %s\n", + attrno, RelationGetRelationName(rd)); } - elog(WARN, "Illegal attr no %d for relation %s\n", - attrno, RelationGetRelationName(rd)); - } else if (attrno >=1 && attrno<= RelationGetNumberOfAttributes(rd)) { - name = (rd->rd_att->attrs[attrno-1]->attname).data; - return(name); - } else { - elog(WARN, "Illegal attr no %d for relation %s\n", - attrno, RelationGetRelationName(rd)); - } - - /* - * Shouldn't get here, but we want lint to be happy... - */ - - return(NULL); + + /* + * Shouldn't get here, but we want lint to be happy... + */ + + return (NULL); } /* Given a typename and value, returns the ascii form of the value */ #ifdef NOT_USED -char * -outstr(char *typename, /* Name of type of value */ - char *value) /* Could be of any type */ +char * +outstr(char *typename, /* Name of type of value */ + char *value) /* Could be of any type */ { - TypeTupleForm tp; - Oid op; - - tp = (TypeTupleForm ) GETSTRUCT(type(typename)); - op = tp->typoutput; - return((char *) fmgr(op, value)); + TypeTupleForm tp; + Oid op; + + tp = (TypeTupleForm) GETSTRUCT(type(typename)); + op = tp->typoutput; + return ((char *) fmgr(op, value)); } + #endif /* Given a Type and a string, return the internal form of that string */ -char * +char * instr2(Type tp, char *string, int typlen) { - return(instr1((TypeTupleForm ) GETSTRUCT(tp), string, typlen)); + return (instr1((TypeTupleForm) GETSTRUCT(tp), string, typlen)); } /* Given a type structure and a string, returns the internal form of that string */ -static char * +static char * instr1(TypeTupleForm tp, char *string, int typlen) { - Oid op; - Oid typelem; - - op = tp->typinput; - typelem = tp->typelem; /* XXX - used for array_in */ - /* typlen is for bpcharin() and varcharin() */ - return((char *) fmgr(op, string, typelem, typlen)); + Oid op; + Oid typelem; + + op = tp->typinput; + typelem = tp->typelem; /* XXX - used for array_in */ + /* typlen is for bpcharin() and varcharin() */ + return ((char *) fmgr(op, string, typelem, typlen)); } /* Given the attribute type of an array return the arrtribute type of @@ -831,151 +937,160 @@ instr1(TypeTupleForm tp, char *string, int typlen) Oid GetArrayElementType(Oid typearray) { - HeapTuple type_tuple; - TypeTupleForm type_struct_array; - - type_tuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(typearray), - 0,0,0); - - if (!HeapTupleIsValid(type_tuple)) - elog(WARN, "GetArrayElementType: Cache lookup failed for type %d\n", - typearray); - - /* get the array type struct from the type tuple */ - type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple); - - if (type_struct_array->typelem == InvalidOid) { - elog(WARN, "GetArrayElementType: type %s is not an array", - (Name)&(type_struct_array->typname.data[0])); - } - - return(type_struct_array->typelem); + HeapTuple type_tuple; + TypeTupleForm type_struct_array; + + type_tuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(typearray), + 0, 0, 0); + + if (!HeapTupleIsValid(type_tuple)) + elog(WARN, "GetArrayElementType: Cache lookup failed for type %d\n", + typearray); + + /* get the array type struct from the type tuple */ + type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple); + + if (type_struct_array->typelem == InvalidOid) + { + elog(WARN, "GetArrayElementType: type %s is not an array", + (Name) & (type_struct_array->typname.data[0])); + } + + return (type_struct_array->typelem); } Oid funcid_get_rettype(Oid funcid) { - HeapTuple func_tuple = NULL; - Oid funcrettype = (Oid)0; - - func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), - 0,0,0); - - if ( !HeapTupleIsValid ( func_tuple )) - elog (WARN, "function %d does not exist", funcid); - - funcrettype = (Oid) - ((Form_pg_proc)GETSTRUCT(func_tuple))->prorettype ; - - return (funcrettype); + HeapTuple func_tuple = NULL; + Oid funcrettype = (Oid) 0; + + func_tuple = SearchSysCacheTuple(PROOID, ObjectIdGetDatum(funcid), + 0, 0, 0); + + if (!HeapTupleIsValid(func_tuple)) + elog(WARN, "function %d does not exist", funcid); + + funcrettype = (Oid) + ((Form_pg_proc) GETSTRUCT(func_tuple))->prorettype; + + return (funcrettype); } /* * get a list of all argument type vectors for which a function named * funcname taking nargs arguments exists */ -static CandidateList +static CandidateList func_get_candidates(char *funcname, int nargs) { - Relation heapRelation; - Relation idesc; - ScanKeyData skey; - HeapTuple tuple; - IndexScanDesc sd; - RetrieveIndexResult indexRes; - Buffer buffer; - Form_pg_proc pgProcP; - bool bufferUsed = FALSE; - CandidateList candidates = NULL; - CandidateList current_candidate; - int i; - - heapRelation = heap_openr(ProcedureRelationName); - ScanKeyEntryInitialize(&skey, - (bits16)0x0, - (AttrNumber)1, - (RegProcedure)NameEqualRegProcedure, - (Datum)funcname); - - idesc = index_openr(ProcedureNameIndex); - - sd = index_beginscan(idesc, false, 1, &skey); - - do { - tuple = (HeapTuple)NULL; - if (bufferUsed) { - ReleaseBuffer(buffer); - bufferUsed = FALSE; - } - - indexRes = index_getnext(sd, ForwardScanDirection); - if (indexRes) { - ItemPointer iptr; - - iptr = &indexRes->heap_iptr; - tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer); - pfree(indexRes); - if (HeapTupleIsValid(tuple)) { - pgProcP = (Form_pg_proc)GETSTRUCT(tuple); - bufferUsed = TRUE; - if (pgProcP->pronargs == nargs) { - current_candidate = (CandidateList) - palloc(sizeof(struct _CandidateList)); - current_candidate->args = (Oid *) - palloc(8 * sizeof(Oid)); - memset(current_candidate->args, 0, 8 * sizeof(Oid)); - for (i=0; i<nargs; i++) { - current_candidate->args[i] = - pgProcP->proargtypes[i]; - } - - current_candidate->next = candidates; - candidates = current_candidate; + Relation heapRelation; + Relation idesc; + ScanKeyData skey; + HeapTuple tuple; + IndexScanDesc sd; + RetrieveIndexResult indexRes; + Buffer buffer; + Form_pg_proc pgProcP; + bool bufferUsed = FALSE; + CandidateList candidates = NULL; + CandidateList current_candidate; + int i; + + heapRelation = heap_openr(ProcedureRelationName); + ScanKeyEntryInitialize(&skey, + (bits16) 0x0, + (AttrNumber) 1, + (RegProcedure) NameEqualRegProcedure, + (Datum) funcname); + + idesc = index_openr(ProcedureNameIndex); + + sd = index_beginscan(idesc, false, 1, &skey); + + do + { + tuple = (HeapTuple) NULL; + if (bufferUsed) + { + ReleaseBuffer(buffer); + bufferUsed = FALSE; } - } - } - } while (indexRes); - - index_endscan(sd); - index_close(idesc); - heap_close(heapRelation); - - return candidates; + + indexRes = index_getnext(sd, ForwardScanDirection); + if (indexRes) + { + ItemPointer iptr; + + iptr = &indexRes->heap_iptr; + tuple = heap_fetch(heapRelation, NowTimeQual, iptr, &buffer); + pfree(indexRes); + if (HeapTupleIsValid(tuple)) + { + pgProcP = (Form_pg_proc) GETSTRUCT(tuple); + bufferUsed = TRUE; + if (pgProcP->pronargs == nargs) + { + current_candidate = (CandidateList) + palloc(sizeof(struct _CandidateList)); + current_candidate->args = (Oid *) + palloc(8 * sizeof(Oid)); + memset(current_candidate->args, 0, 8 * sizeof(Oid)); + for (i = 0; i < nargs; i++) + { + current_candidate->args[i] = + pgProcP->proargtypes[i]; + } + + current_candidate->next = candidates; + candidates = current_candidate; + } + } + } + } while (indexRes); + + index_endscan(sd); + index_close(idesc); + heap_close(heapRelation); + + return candidates; } /* * can input_typeids be coerced to func_typeids? */ -static bool -can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids) +static bool +can_coerce(int nargs, Oid * input_typeids, Oid * func_typeids) { - int i; - Type tp; - - /* - * right now, we only coerce "unknown", and we cannot coerce it to a - * relation type - */ - for (i=0; i<nargs; i++) { - if (input_typeids[i] != func_typeids[i]) { - if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) || - (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) || - (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) || - (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) || - (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) || - (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID)) - ; /* these are OK */ - else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0) - return false; - - tp = get_id_type(input_typeids[i]); - if (typetypetype(tp) == 'c' ) - return false; + int i; + Type tp; + + /* + * right now, we only coerce "unknown", and we cannot coerce it to a + * relation type + */ + for (i = 0; i < nargs; i++) + { + if (input_typeids[i] != func_typeids[i]) + { + if ((input_typeids[i] == BPCHAROID && func_typeids[i] == TEXTOID) || + (input_typeids[i] == BPCHAROID && func_typeids[i] == VARCHAROID) || + (input_typeids[i] == VARCHAROID && func_typeids[i] == TEXTOID) || + (input_typeids[i] == VARCHAROID && func_typeids[i] == BPCHAROID) || + (input_typeids[i] == CASHOID && func_typeids[i] == INT4OID) || + (input_typeids[i] == INT4OID && func_typeids[i] == CASHOID)) + ; /* these are OK */ + else if (input_typeids[i] != UNKNOWNOID || func_typeids[i] == 0) + return false; + + tp = get_id_type(input_typeids[i]); + if (typetypetype(tp) == 'c') + return false; + } } - } - - return true; + + return true; } /* @@ -986,32 +1101,34 @@ can_coerce(int nargs, Oid *input_typeids, Oid *func_typeids) */ static int match_argtypes(int nargs, - Oid *input_typeids, - CandidateList function_typeids, - CandidateList *candidates) /* return value */ + Oid * input_typeids, + CandidateList function_typeids, + CandidateList * candidates) /* return value */ { - CandidateList current_candidate; - CandidateList matching_candidate; - Oid *current_typeids; - int ncandidates = 0; - - *candidates = NULL; - - for (current_candidate = function_typeids; - current_candidate != NULL; - current_candidate = current_candidate->next) { - current_typeids = current_candidate->args; - if (can_coerce(nargs, input_typeids, current_typeids)) { - matching_candidate = (CandidateList) - palloc(sizeof(struct _CandidateList)); - matching_candidate->args = current_typeids; - matching_candidate->next = *candidates; - *candidates = matching_candidate; - ncandidates++; + CandidateList current_candidate; + CandidateList matching_candidate; + Oid *current_typeids; + int ncandidates = 0; + + *candidates = NULL; + + for (current_candidate = function_typeids; + current_candidate != NULL; + current_candidate = current_candidate->next) + { + current_typeids = current_candidate->args; + if (can_coerce(nargs, input_typeids, current_typeids)) + { + matching_candidate = (CandidateList) + palloc(sizeof(struct _CandidateList)); + matching_candidate->args = current_typeids; + matching_candidate->next = *candidates; + *candidates = matching_candidate; + ncandidates++; + } } - } - - return ncandidates; + + return ncandidates; } /* @@ -1020,442 +1137,483 @@ match_argtypes(int nargs, * returns the selected argtype array if the conflict can be resolved, * otherwise returns NULL */ -static Oid * +static Oid * func_select_candidate(int nargs, - Oid *input_typeids, - CandidateList candidates) + Oid * input_typeids, + CandidateList candidates) { - /* XXX no conflict resolution implemeneted yet */ - return (NULL); + /* XXX no conflict resolution implemeneted yet */ + return (NULL); } bool func_get_detail(char *funcname, - int nargs, - Oid *oid_array, - Oid *funcid, /* return value */ - Oid *rettype, /* return value */ - bool *retset, /* return value */ - Oid **true_typeids) /* return value */ + int nargs, + Oid * oid_array, + Oid * funcid, /* return value */ + Oid * rettype, /* return value */ + bool * retset, /* return value */ + Oid ** true_typeids) /* return value */ { - Oid **input_typeid_vector; - Oid *current_input_typeids; - CandidateList function_typeids; - CandidateList current_function_typeids; - HeapTuple ftup; - Form_pg_proc pform; - - /* - * attempt to find named function in the system catalogs - * with arguments exactly as specified - so that the normal - * case is just as quick as before - */ - ftup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(funcname), - Int32GetDatum(nargs), - PointerGetDatum(oid_array), - 0); - *true_typeids = oid_array; - - /* - * If an exact match isn't found : - * 1) get a vector of all possible input arg type arrays constructed - * from the superclasses of the original input arg types - * 2) get a list of all possible argument type arrays to the - * function with given name and number of arguments - * 3) for each input arg type array from vector #1 : - * a) find how many of the function arg type arrays from list #2 - * it can be coerced to - * b) - if the answer is one, we have our function - * - if the answer is more than one, attempt to resolve the - * conflict - * - if the answer is zero, try the next array from vector #1 - */ - if (!HeapTupleIsValid(ftup)) { - function_typeids = func_get_candidates(funcname, nargs); - - if (function_typeids != NULL) { - int ncandidates = 0; - - input_typeid_vector = argtype_inherit(nargs, oid_array); - current_input_typeids = oid_array; - - do { - ncandidates = match_argtypes(nargs, current_input_typeids, - function_typeids, - ¤t_function_typeids); - if (ncandidates == 1) { - *true_typeids = current_function_typeids->args; - ftup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(funcname), - Int32GetDatum(nargs), - PointerGetDatum(*true_typeids), - 0); - Assert(HeapTupleIsValid(ftup)); + Oid **input_typeid_vector; + Oid *current_input_typeids; + CandidateList function_typeids; + CandidateList current_function_typeids; + HeapTuple ftup; + Form_pg_proc pform; + + /* + * attempt to find named function in the system catalogs with + * arguments exactly as specified - so that the normal case is just as + * quick as before + */ + ftup = SearchSysCacheTuple(PRONAME, + PointerGetDatum(funcname), + Int32GetDatum(nargs), + PointerGetDatum(oid_array), + 0); + *true_typeids = oid_array; + + /* + * If an exact match isn't found : 1) get a vector of all possible + * input arg type arrays constructed from the superclasses of the + * original input arg types 2) get a list of all possible argument + * type arrays to the function with given name and number of arguments + * 3) for each input arg type array from vector #1 : a) find how many + * of the function arg type arrays from list #2 it can be coerced to + * b) - if the answer is one, we have our function - if the answer is + * more than one, attempt to resolve the conflict - if the answer is + * zero, try the next array from vector #1 + */ + if (!HeapTupleIsValid(ftup)) + { + function_typeids = func_get_candidates(funcname, nargs); + + if (function_typeids != NULL) + { + int ncandidates = 0; + + input_typeid_vector = argtype_inherit(nargs, oid_array); + current_input_typeids = oid_array; + + do + { + ncandidates = match_argtypes(nargs, current_input_typeids, + function_typeids, + ¤t_function_typeids); + if (ncandidates == 1) + { + *true_typeids = current_function_typeids->args; + ftup = SearchSysCacheTuple(PRONAME, + PointerGetDatum(funcname), + Int32GetDatum(nargs), + PointerGetDatum(*true_typeids), + 0); + Assert(HeapTupleIsValid(ftup)); + } + else if (ncandidates > 1) + { + *true_typeids = + func_select_candidate(nargs, + current_input_typeids, + current_function_typeids); + if (*true_typeids == NULL) + { + elog(NOTICE, "there is more than one function named \"%s\"", + funcname); + elog(NOTICE, "that satisfies the given argument types. you will have to"); + elog(NOTICE, "retype your query using explicit typecasts."); + func_error("func_get_detail", funcname, nargs, oid_array); + } + else + { + ftup = SearchSysCacheTuple(PRONAME, + PointerGetDatum(funcname), + Int32GetDatum(nargs), + PointerGetDatum(*true_typeids), + 0); + Assert(HeapTupleIsValid(ftup)); + } + } + current_input_typeids = *input_typeid_vector++; + } + while (current_input_typeids != + InvalidOid && ncandidates == 0); } - else if (ncandidates > 1) { - *true_typeids = - func_select_candidate(nargs, - current_input_typeids, - current_function_typeids); - if (*true_typeids == NULL) { - elog(NOTICE, "there is more than one function named \"%s\"", - funcname); - elog(NOTICE, "that satisfies the given argument types. you will have to"); - elog(NOTICE, "retype your query using explicit typecasts."); - func_error("func_get_detail", funcname, nargs, oid_array); - } - else { - ftup = SearchSysCacheTuple(PRONAME, - PointerGetDatum(funcname), - Int32GetDatum(nargs), - PointerGetDatum(*true_typeids), - 0); - Assert(HeapTupleIsValid(ftup)); - } + } + + if (!HeapTupleIsValid(ftup)) + { + Type tp; + + if (nargs == 1) + { + tp = get_id_type(oid_array[0]); + if (typetypetype(tp) == 'c') + elog(WARN, "no such attribute or function \"%s\"", + funcname); } - current_input_typeids = *input_typeid_vector++; - } - while (current_input_typeids != - InvalidOid && ncandidates == 0); + func_error("func_get_detail", funcname, nargs, oid_array); } - } - - if (!HeapTupleIsValid(ftup)) { - Type tp; - - if (nargs == 1) { - tp = get_id_type(oid_array[0]); - if (typetypetype(tp) == 'c') - elog(WARN, "no such attribute or function \"%s\"", - funcname); + else + { + pform = (Form_pg_proc) GETSTRUCT(ftup); + *funcid = ftup->t_oid; + *rettype = pform->prorettype; + *retset = pform->proretset; + + return (true); } - func_error("func_get_detail", funcname, nargs, oid_array); - } else { - pform = (Form_pg_proc) GETSTRUCT(ftup); - *funcid = ftup->t_oid; - *rettype = pform->prorettype; - *retset = pform->proretset; - - return (true); - } /* shouldn't reach here */ - return (false); + return (false); } /* - * argtype_inherit() -- Construct an argtype vector reflecting the - * inheritance properties of the supplied argv. + * argtype_inherit() -- Construct an argtype vector reflecting the + * inheritance properties of the supplied argv. * - * This function is used to disambiguate among functions with the - * same name but different signatures. It takes an array of eight - * type ids. For each type id in the array that's a complex type - * (a class), it walks up the inheritance tree, finding all - * superclasses of that type. A vector of new Oid type arrays - * is returned to the caller, reflecting the structure of the - * inheritance tree above the supplied arguments. + * This function is used to disambiguate among functions with the + * same name but different signatures. It takes an array of eight + * type ids. For each type id in the array that's a complex type + * (a class), it walks up the inheritance tree, finding all + * superclasses of that type. A vector of new Oid type arrays + * is returned to the caller, reflecting the structure of the + * inheritance tree above the supplied arguments. * - * The order of this vector is as follows: all superclasses of the - * rightmost complex class are explored first. The exploration - * continues from right to left. This policy means that we favor - * keeping the leftmost argument type as low in the inheritance tree - * as possible. This is intentional; it is exactly what we need to - * do for method dispatch. The last type array we return is all - * zeroes. This will match any functions for which return types are - * not defined. There are lots of these (mostly builtins) in the - * catalogs. + * The order of this vector is as follows: all superclasses of the + * rightmost complex class are explored first. The exploration + * continues from right to left. This policy means that we favor + * keeping the leftmost argument type as low in the inheritance tree + * as possible. This is intentional; it is exactly what we need to + * do for method dispatch. The last type array we return is all + * zeroes. This will match any functions for which return types are + * not defined. There are lots of these (mostly builtins) in the + * catalogs. */ -static Oid ** -argtype_inherit(int nargs, Oid *oid_array) +static Oid ** +argtype_inherit(int nargs, Oid * oid_array) { - Oid relid; - int i; - InhPaths arginh[MAXFARGS]; - - for (i = 0; i < MAXFARGS; i++) { - if (i < nargs) { - arginh[i].self = oid_array[i]; - if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid) { - arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec)); - } else { - arginh[i].nsupers = 0; - arginh[i].supervec = (Oid *) NULL; - } - } else { - arginh[i].self = InvalidOid; - arginh[i].nsupers = 0; - arginh[i].supervec = (Oid *) NULL; + Oid relid; + int i; + InhPaths arginh[MAXFARGS]; + + for (i = 0; i < MAXFARGS; i++) + { + if (i < nargs) + { + arginh[i].self = oid_array[i]; + if ((relid = typeid_get_relid(oid_array[i])) != InvalidOid) + { + arginh[i].nsupers = findsupers(relid, &(arginh[i].supervec)); + } + else + { + arginh[i].nsupers = 0; + arginh[i].supervec = (Oid *) NULL; + } + } + else + { + arginh[i].self = InvalidOid; + arginh[i].nsupers = 0; + arginh[i].supervec = (Oid *) NULL; + } } - } - - /* return an ordered cross-product of the classes involved */ - return (genxprod(arginh, nargs)); + + /* return an ordered cross-product of the classes involved */ + return (genxprod(arginh, nargs)); } -typedef struct _SuperQE { - Oid sqe_relid; -} SuperQE; +typedef struct _SuperQE +{ + Oid sqe_relid; +} SuperQE; static int -findsupers(Oid relid, Oid **supervec) +findsupers(Oid relid, Oid ** supervec) { - Oid *relidvec; - Relation inhrel; - HeapScanDesc inhscan; - ScanKeyData skey; - HeapTuple inhtup; - TupleDesc inhtupdesc; - int nvisited; - SuperQE *qentry, *vnode; - Dllist *visited, *queue; - Dlelem *qe, *elt; - - Relation rd; - Buffer buf; - Datum d; - bool newrelid; - char isNull; - - nvisited = 0; - queue = DLNewList(); - visited = DLNewList(); - - - inhrel = heap_openr(InheritsRelationName); - RelationSetLockForRead(inhrel); - inhtupdesc = RelationGetTupleDescriptor(inhrel); - - /* - * Use queue to do a breadth-first traversal of the inheritance - * graph from the relid supplied up to the root. - */ - do { - ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel, - ObjectIdEqualRegProcedure, - ObjectIdGetDatum(relid)); - - inhscan = heap_beginscan(inhrel, 0, NowTimeQual, 1, &skey); - - while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf))) { - qentry = (SuperQE *) palloc(sizeof(SuperQE)); - - d = (Datum) fastgetattr(inhtup, Anum_pg_inherits_inhparent, - inhtupdesc, &isNull); - qentry->sqe_relid = DatumGetObjectId(d); - - /* put this one on the queue */ - DLAddTail(queue, DLNewElem(qentry)); - - ReleaseBuffer(buf); + Oid *relidvec; + Relation inhrel; + HeapScanDesc inhscan; + ScanKeyData skey; + HeapTuple inhtup; + TupleDesc inhtupdesc; + int nvisited; + SuperQE *qentry, + *vnode; + Dllist *visited, + *queue; + Dlelem *qe, + *elt; + + Relation rd; + Buffer buf; + Datum d; + bool newrelid; + char isNull; + + nvisited = 0; + queue = DLNewList(); + visited = DLNewList(); + + + inhrel = heap_openr(InheritsRelationName); + RelationSetLockForRead(inhrel); + inhtupdesc = RelationGetTupleDescriptor(inhrel); + + /* + * Use queue to do a breadth-first traversal of the inheritance graph + * from the relid supplied up to the root. + */ + do + { + ScanKeyEntryInitialize(&skey, 0x0, Anum_pg_inherits_inhrel, + ObjectIdEqualRegProcedure, + ObjectIdGetDatum(relid)); + + inhscan = heap_beginscan(inhrel, 0, NowTimeQual, 1, &skey); + + while (HeapTupleIsValid(inhtup = heap_getnext(inhscan, 0, &buf))) + { + qentry = (SuperQE *) palloc(sizeof(SuperQE)); + + d = (Datum) fastgetattr(inhtup, Anum_pg_inherits_inhparent, + inhtupdesc, &isNull); + qentry->sqe_relid = DatumGetObjectId(d); + + /* put this one on the queue */ + DLAddTail(queue, DLNewElem(qentry)); + + ReleaseBuffer(buf); + } + + heap_endscan(inhscan); + + /* pull next unvisited relid off the queue */ + do + { + qe = DLRemHead(queue); + qentry = qe ? (SuperQE *) DLE_VAL(qe) : NULL; + + if (qentry == (SuperQE *) NULL) + break; + + relid = qentry->sqe_relid; + newrelid = true; + + for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) + { + vnode = (SuperQE *) DLE_VAL(elt); + if (vnode && (qentry->sqe_relid == vnode->sqe_relid)) + { + newrelid = false; + break; + } + } + } while (!newrelid); + + if (qentry != (SuperQE *) NULL) + { + + /* save the type id, rather than the relation id */ + if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL) + elog(WARN, "relid %d does not exist", qentry->sqe_relid); + qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data)); + heap_close(rd); + + DLAddTail(visited, qe); + + nvisited++; + } + } while (qentry != (SuperQE *) NULL); + + RelationUnsetLockForRead(inhrel); + heap_close(inhrel); + + if (nvisited > 0) + { + relidvec = (Oid *) palloc(nvisited * sizeof(Oid)); + *supervec = relidvec; + + for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) + { + vnode = (SuperQE *) DLE_VAL(elt); + *relidvec++ = vnode->sqe_relid; + } + } - - heap_endscan(inhscan); - - /* pull next unvisited relid off the queue */ - do { - qe = DLRemHead(queue); - qentry = qe ? (SuperQE*)DLE_VAL(qe) : NULL; - - if (qentry == (SuperQE *) NULL) - break; - - relid = qentry->sqe_relid; - newrelid = true; - - for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) { - vnode = (SuperQE*)DLE_VAL(elt); - if (vnode && (qentry->sqe_relid == vnode->sqe_relid)) { - newrelid = false; - break; - } - } - } while (!newrelid); - - if (qentry != (SuperQE *) NULL) { - - /* save the type id, rather than the relation id */ - if ((rd = heap_open(qentry->sqe_relid)) == (Relation) NULL) - elog(WARN, "relid %d does not exist", qentry->sqe_relid); - qentry->sqe_relid = typeid(type(RelationGetRelationName(rd)->data)); - heap_close(rd); - - DLAddTail(visited, qe); - - nvisited++; + else + { + *supervec = (Oid *) NULL; } - } while (qentry != (SuperQE *) NULL); - - RelationUnsetLockForRead(inhrel); - heap_close(inhrel); - - if (nvisited > 0) { - relidvec = (Oid *) palloc(nvisited * sizeof(Oid)); - *supervec = relidvec; - - for (elt = DLGetHead(visited); elt; elt = DLGetSucc(elt)) { - vnode = (SuperQE*)DLE_VAL(elt); - *relidvec++ = vnode->sqe_relid; - } - - } else { - *supervec = (Oid *) NULL; - } - - return (nvisited); + + return (nvisited); } -static Oid ** -genxprod(InhPaths *arginh, int nargs) +static Oid ** +genxprod(InhPaths * arginh, int nargs) { - int nanswers; - Oid **result, **iter; - Oid *oneres; - int i, j; - int cur[MAXFARGS]; - - nanswers = 1; - for (i = 0; i < nargs; i++) { - nanswers *= (arginh[i].nsupers + 2); - cur[i] = 0; - } - - iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers); - - /* compute the cross product from right to left */ - for (;;) { - oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid)); - memset(oneres, 0, MAXFARGS * sizeof(Oid)); - - for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--) - continue; - - /* if we're done, terminate with NULL pointer */ - if (i < 0) { - *iter = NULL; - return (result); + int nanswers; + Oid **result, + **iter; + Oid *oneres; + int i, + j; + int cur[MAXFARGS]; + + nanswers = 1; + for (i = 0; i < nargs; i++) + { + nanswers *= (arginh[i].nsupers + 2); + cur[i] = 0; } - - /* no, increment this column and zero the ones after it */ - cur[i] = cur[i] + 1; - for (j = nargs - 1; j > i; j--) - cur[j] = 0; - - for (i = 0; i < nargs; i++) { - if (cur[i] == 0) - oneres[i] = arginh[i].self; - else if (cur[i] > arginh[i].nsupers) - oneres[i] = 0; /* wild card */ - else - oneres[i] = arginh[i].supervec[cur[i] - 1]; + + iter = result = (Oid **) palloc(sizeof(Oid *) * nanswers); + + /* compute the cross product from right to left */ + for (;;) + { + oneres = (Oid *) palloc(MAXFARGS * sizeof(Oid)); + memset(oneres, 0, MAXFARGS * sizeof(Oid)); + + for (i = nargs - 1; i >= 0 && cur[i] > arginh[i].nsupers; i--) + continue; + + /* if we're done, terminate with NULL pointer */ + if (i < 0) + { + *iter = NULL; + return (result); + } + + /* no, increment this column and zero the ones after it */ + cur[i] = cur[i] + 1; + for (j = nargs - 1; j > i; j--) + cur[j] = 0; + + for (i = 0; i < nargs; i++) + { + if (cur[i] == 0) + oneres[i] = arginh[i].self; + else if (cur[i] > arginh[i].nsupers) + oneres[i] = 0; /* wild card */ + else + oneres[i] = arginh[i].supervec[cur[i] - 1]; + } + + *iter++ = oneres; } - - *iter++ = oneres; - } } /* Given a type id, returns the in-conversion function of the type */ Oid typeid_get_retinfunc(Oid type_id) { - HeapTuple typeTuple; - TypeTupleForm type; - Oid infunc; - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type_id), - 0,0,0); - if ( !HeapTupleIsValid ( typeTuple )) - elog(WARN, - "typeid_get_retinfunc: Invalid type - oid = %u", - type_id); - - type = (TypeTupleForm) GETSTRUCT(typeTuple); - infunc = type->typinput; - return(infunc); + HeapTuple typeTuple; + TypeTupleForm type; + Oid infunc; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type_id), + 0, 0, 0); + if (!HeapTupleIsValid(typeTuple)) + elog(WARN, + "typeid_get_retinfunc: Invalid type - oid = %u", + type_id); + + type = (TypeTupleForm) GETSTRUCT(typeTuple); + infunc = type->typinput; + return (infunc); } /* Given a type id, returns the out-conversion function of the type */ Oid typeid_get_retoutfunc(Oid type_id) { - HeapTuple typeTuple; - TypeTupleForm type; - Oid outfunc; - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type_id), - 0,0,0); - if ( !HeapTupleIsValid ( typeTuple )) - elog(WARN, - "typeid_get_retoutfunc: Invalid type - oid = %u", - type_id); - - type = (TypeTupleForm) GETSTRUCT(typeTuple); - outfunc = type->typoutput; - return(outfunc); + HeapTuple typeTuple; + TypeTupleForm type; + Oid outfunc; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type_id), + 0, 0, 0); + if (!HeapTupleIsValid(typeTuple)) + elog(WARN, + "typeid_get_retoutfunc: Invalid type - oid = %u", + type_id); + + type = (TypeTupleForm) GETSTRUCT(typeTuple); + outfunc = type->typoutput; + return (outfunc); } Oid typeid_get_relid(Oid type_id) { - HeapTuple typeTuple; - TypeTupleForm type; - Oid infunc; - typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type_id), - 0,0,0); - if ( !HeapTupleIsValid ( typeTuple )) - elog(WARN, "typeid_get_relid: Invalid type - oid = %u ", type_id); - - type = (TypeTupleForm) GETSTRUCT(typeTuple); - infunc = type->typrelid; - return(infunc); + HeapTuple typeTuple; + TypeTupleForm type; + Oid infunc; + + typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type_id), + 0, 0, 0); + if (!HeapTupleIsValid(typeTuple)) + elog(WARN, "typeid_get_relid: Invalid type - oid = %u ", type_id); + + type = (TypeTupleForm) GETSTRUCT(typeTuple); + infunc = type->typrelid; + return (infunc); } Oid get_typrelid(Type typ) { - TypeTupleForm typtup; - - typtup = (TypeTupleForm) GETSTRUCT(typ); - - return (typtup->typrelid); + TypeTupleForm typtup; + + typtup = (TypeTupleForm) GETSTRUCT(typ); + + return (typtup->typrelid); } Oid get_typelem(Oid type_id) { - HeapTuple typeTuple; - TypeTupleForm type; - - if (!(typeTuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type_id), - 0,0,0))) { - elog (WARN , "type id lookup of %u failed", type_id); - } - type = (TypeTupleForm) GETSTRUCT(typeTuple); - - return (type->typelem); + HeapTuple typeTuple; + TypeTupleForm type; + + if (!(typeTuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type_id), + 0, 0, 0))) + { + elog(WARN, "type id lookup of %u failed", type_id); + } + type = (TypeTupleForm) GETSTRUCT(typeTuple); + + return (type->typelem); } #ifdef NOT_USED char FindDelimiter(char *typename) { - char delim; - HeapTuple typeTuple; - TypeTupleForm type; - - - if (!(typeTuple = SearchSysCacheTuple(TYPNAME, - PointerGetDatum(typename), - 0,0,0))) { - elog (WARN , "type name lookup of %s failed", typename); - } - type = (TypeTupleForm) GETSTRUCT(typeTuple); - - delim = type->typdelim; - return (delim); + char delim; + HeapTuple typeTuple; + TypeTupleForm type; + + + if (!(typeTuple = SearchSysCacheTuple(TYPNAME, + PointerGetDatum(typename), + 0, 0, 0))) + { + elog(WARN, "type name lookup of %s failed", typename); + } + type = (TypeTupleForm) GETSTRUCT(typeTuple); + + delim = type->typdelim; + return (delim); } + #endif /* @@ -1465,26 +1623,33 @@ FindDelimiter(char *typename) static void op_error(char *op, Oid arg1, Oid arg2) { - Type tp1 = NULL, tp2 = NULL; - - if (check_typeid(arg1)) { - tp1 = get_id_type(arg1); - } else { - elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op); - } - - if (check_typeid(arg2)) { - tp2 = get_id_type(arg2); - } else { - elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op); - } - - elog(NOTICE, "there is no operator %s for types %s and %s", - op, tname(tp1),tname(tp2)); - elog(NOTICE, "You will either have to retype this query using an"); - elog(NOTICE, "explicit cast, or you will have to define the operator"); - elog(WARN, "%s for %s and %s using CREATE OPERATOR", - op, tname(tp1),tname(tp2)); + Type tp1 = NULL, + tp2 = NULL; + + if (check_typeid(arg1)) + { + tp1 = get_id_type(arg1); + } + else + { + elog(WARN, "left hand side of operator %s has an unknown type, probably a bad attribute name", op); + } + + if (check_typeid(arg2)) + { + tp2 = get_id_type(arg2); + } + else + { + elog(WARN, "right hand side of operator %s has an unknown type, probably a bad attribute name", op); + } + + elog(NOTICE, "there is no operator %s for types %s and %s", + op, tname(tp1), tname(tp2)); + elog(NOTICE, "You will either have to retype this query using an"); + elog(NOTICE, "explicit cast, or you will have to define the operator"); + elog(WARN, "%s for %s and %s using CREATE OPERATOR", + op, tname(tp1), tname(tp2)); } /* @@ -1492,27 +1657,32 @@ op_error(char *op, Oid arg1, Oid arg2) * argument types */ void -func_error(char *caller, char *funcname, int nargs, Oid *argtypes) +func_error(char *caller, char *funcname, int nargs, Oid * argtypes) { - char p[(NAMEDATALEN+2)*MAXFMGRARGS], *ptr; - int i; - - ptr = p; - *ptr = '\0'; - for (i=0; i<nargs; i++) { - if (i) { - *ptr++ = ','; - *ptr++ = ' '; + char p[(NAMEDATALEN + 2) * MAXFMGRARGS], + *ptr; + int i; + + ptr = p; + *ptr = '\0'; + for (i = 0; i < nargs; i++) + { + if (i) + { + *ptr++ = ','; + *ptr++ = ' '; + } + if (argtypes[i] != 0) + { + strcpy(ptr, tname(get_id_type(argtypes[i]))); + *(ptr + NAMEDATALEN) = '\0'; + } + else + strcpy(ptr, "opaque"); + ptr += strlen(ptr); } - if (argtypes[i] != 0) { - strcpy(ptr, tname(get_id_type(argtypes[i]))); - *(ptr + NAMEDATALEN) = '\0'; - } else - strcpy(ptr, "opaque"); - ptr += strlen(ptr); - } - - elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p); + + elog(WARN, "%s: function %s(%s) does not exist", caller, funcname, p); } /* @@ -1522,12 +1692,19 @@ func_error(char *caller, char *funcname, int nargs, Oid *argtypes) void agg_error(char *caller, char *aggname, Oid basetypeID) { - /* basetypeID that is Invalid (zero) means aggregate over all types. (count) */ - - if (basetypeID == InvalidOid) { - elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname); - } else { - elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname, - tname(get_id_type(basetypeID))); - } + + /* + * basetypeID that is Invalid (zero) means aggregate over all types. + * (count) + */ + + if (basetypeID == InvalidOid) + { + elog(WARN, "%s: aggregate '%s' for all types does not exist", caller, aggname); + } + else + { + elog(WARN, "%s: aggregate '%s' for '%s' does not exist", caller, aggname, + tname(get_id_type(basetypeID))); + } } diff --git a/src/backend/parser/dbcommands.c b/src/backend/parser/dbcommands.c index f975937b5ad..158e033b6e7 100644 --- a/src/backend/parser/dbcommands.c +++ b/src/backend/parser/dbcommands.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * dbcommands.c-- - * + * * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/Attic/dbcommands.c,v 1.6 1997/08/19 21:32:14 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/Attic/dbcommands.c,v 1.7 1997/09/07 04:44:45 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -16,7 +16,7 @@ #include <signal.h> #include "postgres.h" -#include "miscadmin.h" /* for DataDir */ +#include "miscadmin.h" /* for DataDir */ #include "access/heapam.h" #include "access/htup.h" #include "access/relscan.h" @@ -35,228 +35,253 @@ /* non-export function prototypes */ -static void check_permissions(char *command, char *dbname, - Oid *dbIdP, Oid *userIdP); +static void +check_permissions(char *command, char *dbname, + Oid * dbIdP, Oid * userIdP); static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel); -static void stop_vacuum(char *dbname); +static void stop_vacuum(char *dbname); void createdb(char *dbname) { - Oid db_id, user_id; - char buf[512]; - - /* - * If this call returns, the database does not exist and we're allowed - * to create databases. - */ - check_permissions("createdb", dbname, &db_id, &user_id); - - /* close virtual file descriptors so we can do system() calls */ - closeAllVfds(); - - sprintf(buf, "mkdir %s%cbase%c%s", DataDir, SEP_CHAR, SEP_CHAR, dbname); - system(buf); - sprintf(buf, "%s %s%cbase%ctemplate1%c* %s%cbase%c%s", - COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, DataDir, - SEP_CHAR, SEP_CHAR, dbname); - system(buf); - -/* sprintf(buf, "insert into pg_database (datname, datdba, datpath) \ + Oid db_id, + user_id; + char buf[512]; + + /* + * If this call returns, the database does not exist and we're allowed + * to create databases. + */ + check_permissions("createdb", dbname, &db_id, &user_id); + + /* close virtual file descriptors so we can do system() calls */ + closeAllVfds(); + + sprintf(buf, "mkdir %s%cbase%c%s", DataDir, SEP_CHAR, SEP_CHAR, dbname); + system(buf); + sprintf(buf, "%s %s%cbase%ctemplate1%c* %s%cbase%c%s", + COPY_CMD, DataDir, SEP_CHAR, SEP_CHAR, SEP_CHAR, DataDir, + SEP_CHAR, SEP_CHAR, dbname); + system(buf); + +/* sprintf(buf, "insert into pg_database (datname, datdba, datpath) \ values (\'%s\'::char16, \'%d\'::oid, \'%s\'::text);", - dbname, user_id, dbname); + dbname, user_id, dbname); */ - sprintf(buf, "insert into pg_database (datname, datdba, datpath) \ + sprintf(buf, "insert into pg_database (datname, datdba, datpath) \ values (\'%s\', \'%d\', \'%s\');", - dbname, user_id, dbname); + dbname, user_id, dbname); - pg_eval(buf, (char **) NULL, (Oid *) NULL, 0); + pg_eval(buf, (char **) NULL, (Oid *) NULL, 0); } void destroydb(char *dbname) { - Oid user_id, db_id; - char buf[512]; - - /* - * If this call returns, the database exists and we're allowed to - * remove it. - */ - check_permissions("destroydb", dbname, &db_id, &user_id); - - if (!OidIsValid(db_id)) { - elog(FATAL, "impossible: pg_database instance with invalid OID."); - } - - /* stop the vacuum daemon */ - stop_vacuum(dbname); - - /* remove the pg_database tuple FIRST, - this may fail due to permissions problems*/ - sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid", - db_id); - pg_eval(buf, (char **) NULL, (Oid *) NULL, 0); - - /* remove the data directory. If the DELETE above failed, this will - not be reached */ - sprintf(buf, "rm -r %s/base/%s", DataDir, dbname); - system(buf); - - /* drop pages for this database that are in the shared buffer cache */ - DropBuffers(db_id); + Oid user_id, + db_id; + char buf[512]; + + /* + * If this call returns, the database exists and we're allowed to + * remove it. + */ + check_permissions("destroydb", dbname, &db_id, &user_id); + + if (!OidIsValid(db_id)) + { + elog(FATAL, "impossible: pg_database instance with invalid OID."); + } + + /* stop the vacuum daemon */ + stop_vacuum(dbname); + + /* + * remove the pg_database tuple FIRST, this may fail due to + * permissions problems + */ + sprintf(buf, "delete from pg_database where pg_database.oid = \'%d\'::oid", + db_id); + pg_eval(buf, (char **) NULL, (Oid *) NULL, 0); + + /* + * remove the data directory. If the DELETE above failed, this will + * not be reached + */ + sprintf(buf, "rm -r %s/base/%s", DataDir, dbname); + system(buf); + + /* drop pages for this database that are in the shared buffer cache */ + DropBuffers(db_id); } -static HeapTuple +static HeapTuple get_pg_dbtup(char *command, char *dbname, Relation dbrel) { - HeapTuple dbtup; - HeapTuple tup; - Buffer buf; - HeapScanDesc scan; - ScanKeyData scanKey; - - ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname, - NameEqualRegProcedure, NameGetDatum(dbname)); - - scan = heap_beginscan(dbrel, 0, NowTimeQual, 1, &scanKey); - if (!HeapScanIsValid(scan)) - elog(WARN, "%s: cannot begin scan of pg_database.", command); - - /* - * since we want to return the tuple out of this proc, and we're - * going to close the relation, copy the tuple and return the copy. - */ - tup = heap_getnext(scan, 0, &buf); - - if (HeapTupleIsValid(tup)) { - dbtup = heap_copytuple(tup); - ReleaseBuffer(buf); - } else - dbtup = tup; - - heap_endscan(scan); - return (dbtup); + HeapTuple dbtup; + HeapTuple tup; + Buffer buf; + HeapScanDesc scan; + ScanKeyData scanKey; + + ScanKeyEntryInitialize(&scanKey, 0, Anum_pg_database_datname, + NameEqualRegProcedure, NameGetDatum(dbname)); + + scan = heap_beginscan(dbrel, 0, NowTimeQual, 1, &scanKey); + if (!HeapScanIsValid(scan)) + elog(WARN, "%s: cannot begin scan of pg_database.", command); + + /* + * since we want to return the tuple out of this proc, and we're going + * to close the relation, copy the tuple and return the copy. + */ + tup = heap_getnext(scan, 0, &buf); + + if (HeapTupleIsValid(tup)) + { + dbtup = heap_copytuple(tup); + ReleaseBuffer(buf); + } + else + dbtup = tup; + + heap_endscan(scan); + return (dbtup); } /* - * check_permissions() -- verify that the user is permitted to do this. + * check_permissions() -- verify that the user is permitted to do this. * - * If the user is not allowed to carry out this operation, this routine - * elog(WARN, ...)s, which will abort the xact. As a side effect, the - * user's pg_user tuple OID is returned in userIdP and the target database's - * OID is returned in dbIdP. + * If the user is not allowed to carry out this operation, this routine + * elog(WARN, ...)s, which will abort the xact. As a side effect, the + * user's pg_user tuple OID is returned in userIdP and the target database's + * OID is returned in dbIdP. */ static void check_permissions(char *command, - char *dbname, - Oid *dbIdP, - Oid *userIdP) + char *dbname, + Oid * dbIdP, + Oid * userIdP) { - Relation dbrel; - HeapTuple dbtup, utup; - Oid dbowner = (Oid)0; - char use_createdb; - bool dbfound; - bool use_super; - char *userName; - - userName = GetPgUserName(); - utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName), - 0,0,0); - *userIdP = ((Form_pg_user)GETSTRUCT(utup))->usesysid; - use_super = ((Form_pg_user)GETSTRUCT(utup))->usesuper; - use_createdb = ((Form_pg_user)GETSTRUCT(utup))->usecreatedb; - - /* Check to make sure user has permission to use createdb */ - if (!use_createdb) { - elog(WARN, "user \"%s\" is not allowed to create/destroy databases", - userName); - } - - /* Make sure we are not mucking with the template database */ - if (!strcmp(dbname, "template1")) { - elog(WARN, "%s cannot be executed on the template database.", command); - } - - /* Check to make sure database is not the currently open database */ - if (!strcmp(dbname, GetDatabaseName())) { - elog(WARN, "%s cannot be executed on an open database", command); - } - - /* Check to make sure database is owned by this user */ - - /* - * need the reldesc to get the database owner out of dbtup - * and to set a write lock on it. - */ - dbrel = heap_openr(DatabaseRelationName); - - if (!RelationIsValid(dbrel)) - elog(FATAL, "%s: cannot open relation \"%-.*s\"", - command, DatabaseRelationName); - - /* - * Acquire a write lock on pg_database from the beginning to avoid - * upgrading a read lock to a write lock. Upgrading causes long delays - * when multiple 'createdb's or 'destroydb's are run simult. -mer 7/3/91 - */ - RelationSetLockForWrite(dbrel); - dbtup = get_pg_dbtup(command, dbname, dbrel); - dbfound = HeapTupleIsValid(dbtup); - - if (dbfound) { - dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer, - Anum_pg_database_datdba, - RelationGetTupleDescriptor(dbrel), - (char *) NULL); - *dbIdP = dbtup->t_oid; - } else { - *dbIdP = InvalidOid; - } - - heap_close(dbrel); - - /* - * Now be sure that the user is allowed to do this. - */ - - if (dbfound && !strcmp(command, "createdb")) { - - elog(WARN, "createdb: database %s already exists.", dbname); - - } else if (!dbfound && !strcmp(command, "destroydb")) { - - elog(WARN, "destroydb: database %s does not exist.", dbname); - - } else if (dbfound && !strcmp(command, "destroydb") - && dbowner != *userIdP && use_super == false) { - - elog(WARN, "%s: database %s is not owned by you.", command, dbname); - - } + Relation dbrel; + HeapTuple dbtup, + utup; + Oid dbowner = (Oid) 0; + char use_createdb; + bool dbfound; + bool use_super; + char *userName; + + userName = GetPgUserName(); + utup = SearchSysCacheTuple(USENAME, PointerGetDatum(userName), + 0, 0, 0); + *userIdP = ((Form_pg_user) GETSTRUCT(utup))->usesysid; + use_super = ((Form_pg_user) GETSTRUCT(utup))->usesuper; + use_createdb = ((Form_pg_user) GETSTRUCT(utup))->usecreatedb; + + /* Check to make sure user has permission to use createdb */ + if (!use_createdb) + { + elog(WARN, "user \"%s\" is not allowed to create/destroy databases", + userName); + } + + /* Make sure we are not mucking with the template database */ + if (!strcmp(dbname, "template1")) + { + elog(WARN, "%s cannot be executed on the template database.", command); + } + + /* Check to make sure database is not the currently open database */ + if (!strcmp(dbname, GetDatabaseName())) + { + elog(WARN, "%s cannot be executed on an open database", command); + } + + /* Check to make sure database is owned by this user */ + + /* + * need the reldesc to get the database owner out of dbtup and to set + * a write lock on it. + */ + dbrel = heap_openr(DatabaseRelationName); + + if (!RelationIsValid(dbrel)) + elog(FATAL, "%s: cannot open relation \"%-.*s\"", + command, DatabaseRelationName); + + /* + * Acquire a write lock on pg_database from the beginning to avoid + * upgrading a read lock to a write lock. Upgrading causes long + * delays when multiple 'createdb's or 'destroydb's are run simult. + * -mer 7/3/91 + */ + RelationSetLockForWrite(dbrel); + dbtup = get_pg_dbtup(command, dbname, dbrel); + dbfound = HeapTupleIsValid(dbtup); + + if (dbfound) + { + dbowner = (Oid) heap_getattr(dbtup, InvalidBuffer, + Anum_pg_database_datdba, + RelationGetTupleDescriptor(dbrel), + (char *) NULL); + *dbIdP = dbtup->t_oid; + } + else + { + *dbIdP = InvalidOid; + } + + heap_close(dbrel); + + /* + * Now be sure that the user is allowed to do this. + */ + + if (dbfound && !strcmp(command, "createdb")) + { + + elog(WARN, "createdb: database %s already exists.", dbname); + + } + else if (!dbfound && !strcmp(command, "destroydb")) + { + + elog(WARN, "destroydb: database %s does not exist.", dbname); + + } + else if (dbfound && !strcmp(command, "destroydb") + && dbowner != *userIdP && use_super == false) + { + + elog(WARN, "%s: database %s is not owned by you.", command, dbname); + + } } /* - * stop_vacuum() -- stop the vacuum daemon on the database, if one is - * running. + * stop_vacuum() -- stop the vacuum daemon on the database, if one is + * running. */ static void stop_vacuum(char *dbname) { - char filename[256]; - FILE *fp; - int pid; - - sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR, - dbname, SEP_CHAR, dbname); - if ((fp = AllocateFile(filename, "r")) != NULL) { - fscanf(fp, "%d", &pid); - FreeFile(fp); - if (kill(pid, SIGKILLDAEMON1) < 0) { - elog(WARN, "can't kill vacuum daemon (pid %d) on %s", - pid, dbname); + char filename[256]; + FILE *fp; + int pid; + + sprintf(filename, "%s%cbase%c%s%c%s.vacuum", DataDir, SEP_CHAR, SEP_CHAR, + dbname, SEP_CHAR, dbname); + if ((fp = AllocateFile(filename, "r")) != NULL) + { + fscanf(fp, "%d", &pid); + FreeFile(fp); + if (kill(pid, SIGKILLDAEMON1) < 0) + { + elog(WARN, "can't kill vacuum daemon (pid %d) on %s", + pid, dbname); + } } - } } diff --git a/src/backend/parser/keywords.c b/src/backend/parser/keywords.c index 9aa6da82ca6..b9f1a273398 100644 --- a/src/backend/parser/keywords.c +++ b/src/backend/parser/keywords.c @@ -1,13 +1,13 @@ /*------------------------------------------------------------------------- * * keywords.c-- - * lexical token lookup for reserved words in postgres SQL + * lexical token lookup for reserved words in postgres SQL * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.14 1997/09/04 13:24:26 vadim Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/keywords.c,v 1.15 1997/09/07 04:44:47 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -20,202 +20,204 @@ #include "parse.h" #include "utils/elog.h" #include "parser/keywords.h" -#include "parser/dbcommands.h" /* createdb, destroydb stop_vacuum */ +#include "parser/dbcommands.h" /* createdb, destroydb stop_vacuum */ /* * List of (keyword-name, keyword-token-value) pairs. * * !!WARNING!!: This list must be sorted, because binary - * search is used to locate entries. + * search is used to locate entries. */ static ScanKeyword ScanKeywords[] = { - /* name value */ - { "abort", ABORT_TRANS }, - { "acl", ACL }, - { "add", ADD }, - { "after", AFTER }, - { "aggregate", AGGREGATE }, - { "all", ALL }, - { "alter", ALTER }, - { "analyze", ANALYZE }, - { "and", AND }, - { "append", APPEND }, - { "archIve", ARCHIVE }, /* XXX crooked: I < _ */ - { "arch_store", ARCH_STORE }, - { "archive", ARCHIVE }, /* XXX crooked: i > _ */ - { "as", AS }, - { "asc", ASC }, - { "backward", BACKWARD }, - { "before", BEFORE }, - { "begin", BEGIN_TRANS }, - { "between", BETWEEN }, - { "binary", BINARY }, - { "both", BOTH }, - { "by", BY }, - { "cast", CAST }, - { "change", CHANGE }, - { "check", CHECK }, - { "close", CLOSE }, - { "cluster", CLUSTER }, - { "column", COLUMN }, - { "commit", COMMIT }, - { "constraint", CONSTRAINT }, - { "copy", COPY }, - { "create", CREATE }, - { "cross", CROSS }, - { "current", CURRENT }, - { "cursor", CURSOR }, - { "database", DATABASE }, - { "day", DAYINTERVAL }, - { "declare", DECLARE }, - { "default", DEFAULT }, - { "delete", DELETE }, - { "delimiters", DELIMITERS }, - { "desc", DESC }, - { "distinct", DISTINCT }, - { "do", DO }, - { "drop", DROP }, - { "end", END_TRANS }, - { "execute", EXECUTE }, - { "exists", EXISTS }, - { "explain", EXPLAIN }, - { "extend", EXTEND }, - { "extract", EXTRACT }, - { "fetch", FETCH }, - { "for", FOR }, - { "forward", FORWARD }, - { "from", FROM }, - { "full", FULL }, - { "function", FUNCTION }, - { "grant", GRANT }, - { "group", GROUP }, - { "having", HAVING }, - { "heavy", HEAVY }, - { "hour", HOURINTERVAL }, - { "in", IN }, - { "index", INDEX }, - { "inherits", INHERITS }, - { "inner", INNERJOIN }, - { "insert", INSERT }, - { "instead", INSTEAD }, - { "interval", INTERVAL }, - { "into", INTO }, - { "is", IS }, - { "isnull", ISNULL }, - { "join", JOIN }, - { "language", LANGUAGE }, - { "leading", LEADING }, - { "left", LEFT }, - { "light", LIGHT }, - { "like", LIKE }, - { "listen", LISTEN }, - { "load", LOAD }, - { "local", LOCAL }, - { "merge", MERGE }, - { "minute", MINUTEINTERVAL }, - { "month", MONTHINTERVAL }, - { "move", MOVE }, - { "natural", NATURAL }, - { "new", NEW }, - { "none", NONE }, - { "not", NOT }, - { "nothing", NOTHING }, - { "notify", NOTIFY }, - { "notnull", NOTNULL }, - { "null", PNULL }, - { "oids", OIDS }, - { "on", ON }, - { "operator", OPERATOR }, - { "option", OPTION }, - { "or", OR }, - { "order", ORDER }, - { "outer", OUTERJOIN }, - { "position", POSITION }, - { "privileges", PRIVILEGES }, - { "procedure", PROCEDURE }, - { "public", PUBLIC }, - { "purge", PURGE }, - { "recipe", RECIPE }, - { "rename", RENAME }, - { "replace", REPLACE }, - { "reset", RESET }, - { "retrieve", RETRIEVE }, - { "returns", RETURNS }, - { "revoke", REVOKE }, - { "right", RIGHT }, - { "rollback", ROLLBACK }, - { "rule", RULE }, - { "second", SECONDINTERVAL }, - { "select", SELECT }, - { "sequence", SEQUENCE }, - { "set", SET }, - { "setof", SETOF }, - { "show", SHOW }, - { "stdin", STDIN }, - { "stdout", STDOUT }, - { "store", STORE }, - { "substring", SUBSTRING }, - { "table", TABLE }, - { "time", TIME }, - { "to", TO }, - { "transaction", TRANSACTION }, - { "trailing", TRAILING }, - { "trigger", TRIGGER }, - { "trim", TRIM }, - { "type", P_TYPE }, - { "union", UNION }, - { "unique", UNIQUE }, - { "update", UPDATE }, - { "using", USING }, - { "vacuum", VACUUM }, - { "values", VALUES }, - { "verbose", VERBOSE }, - { "version", VERSION }, - { "view", VIEW }, - { "where", WHERE }, - { "with", WITH }, - { "work", WORK }, - { "year", YEARINTERVAL }, - { "zone", ZONE }, + /* name value */ + {"abort", ABORT_TRANS}, + {"acl", ACL}, + {"add", ADD}, + {"after", AFTER}, + {"aggregate", AGGREGATE}, + {"all", ALL}, + {"alter", ALTER}, + {"analyze", ANALYZE}, + {"and", AND}, + {"append", APPEND}, + {"archIve", ARCHIVE}, /* XXX crooked: I < _ */ + {"arch_store", ARCH_STORE}, + {"archive", ARCHIVE}, /* XXX crooked: i > _ */ + {"as", AS}, + {"asc", ASC}, + {"backward", BACKWARD}, + {"before", BEFORE}, + {"begin", BEGIN_TRANS}, + {"between", BETWEEN}, + {"binary", BINARY}, + {"both", BOTH}, + {"by", BY}, + {"cast", CAST}, + {"change", CHANGE}, + {"check", CHECK}, + {"close", CLOSE}, + {"cluster", CLUSTER}, + {"column", COLUMN}, + {"commit", COMMIT}, + {"constraint", CONSTRAINT}, + {"copy", COPY}, + {"create", CREATE}, + {"cross", CROSS}, + {"current", CURRENT}, + {"cursor", CURSOR}, + {"database", DATABASE}, + {"day", DAYINTERVAL}, + {"declare", DECLARE}, + {"default", DEFAULT}, + {"delete", DELETE}, + {"delimiters", DELIMITERS}, + {"desc", DESC}, + {"distinct", DISTINCT}, + {"do", DO}, + {"drop", DROP}, + {"end", END_TRANS}, + {"execute", EXECUTE}, + {"exists", EXISTS}, + {"explain", EXPLAIN}, + {"extend", EXTEND}, + {"extract", EXTRACT}, + {"fetch", FETCH}, + {"for", FOR}, + {"forward", FORWARD}, + {"from", FROM}, + {"full", FULL}, + {"function", FUNCTION}, + {"grant", GRANT}, + {"group", GROUP}, + {"having", HAVING}, + {"heavy", HEAVY}, + {"hour", HOURINTERVAL}, + {"in", IN}, + {"index", INDEX}, + {"inherits", INHERITS}, + {"inner", INNERJOIN}, + {"insert", INSERT}, + {"instead", INSTEAD}, + {"interval", INTERVAL}, + {"into", INTO}, + {"is", IS}, + {"isnull", ISNULL}, + {"join", JOIN}, + {"language", LANGUAGE}, + {"leading", LEADING}, + {"left", LEFT}, + {"light", LIGHT}, + {"like", LIKE}, + {"listen", LISTEN}, + {"load", LOAD}, + {"local", LOCAL}, + {"merge", MERGE}, + {"minute", MINUTEINTERVAL}, + {"month", MONTHINTERVAL}, + {"move", MOVE}, + {"natural", NATURAL}, + {"new", NEW}, + {"none", NONE}, + {"not", NOT}, + {"nothing", NOTHING}, + {"notify", NOTIFY}, + {"notnull", NOTNULL}, + {"null", PNULL}, + {"oids", OIDS}, + {"on", ON}, + {"operator", OPERATOR}, + {"option", OPTION}, + {"or", OR}, + {"order", ORDER}, + {"outer", OUTERJOIN}, + {"position", POSITION}, + {"privileges", PRIVILEGES}, + {"procedure", PROCEDURE}, + {"public", PUBLIC}, + {"purge", PURGE}, + {"recipe", RECIPE}, + {"rename", RENAME}, + {"replace", REPLACE}, + {"reset", RESET}, + {"retrieve", RETRIEVE}, + {"returns", RETURNS}, + {"revoke", REVOKE}, + {"right", RIGHT}, + {"rollback", ROLLBACK}, + {"rule", RULE}, + {"second", SECONDINTERVAL}, + {"select", SELECT}, + {"sequence", SEQUENCE}, + {"set", SET}, + {"setof", SETOF}, + {"show", SHOW}, + {"stdin", STDIN}, + {"stdout", STDOUT}, + {"store", STORE}, + {"substring", SUBSTRING}, + {"table", TABLE}, + {"time", TIME}, + {"to", TO}, + {"transaction", TRANSACTION}, + {"trailing", TRAILING}, + {"trigger", TRIGGER}, + {"trim", TRIM}, + {"type", P_TYPE}, + {"union", UNION}, + {"unique", UNIQUE}, + {"update", UPDATE}, + {"using", USING}, + {"vacuum", VACUUM}, + {"values", VALUES}, + {"verbose", VERBOSE}, + {"version", VERSION}, + {"view", VIEW}, + {"where", WHERE}, + {"with", WITH}, + {"work", WORK}, + {"year", YEARINTERVAL}, + {"zone", ZONE}, }; -ScanKeyword * +ScanKeyword * ScanKeywordLookup(char *text) { - ScanKeyword *low = &ScanKeywords[0]; - ScanKeyword *high = endof(ScanKeywords) - 1; - ScanKeyword *middle; - int difference; - - while (low <= high) { - middle = low + (high - low) / 2; - difference = strcmp(middle->name, text); - if (difference == 0) - return (middle); - else if (difference < 0) - low = middle + 1; - else - high = middle - 1; - } - - return (NULL); + ScanKeyword *low = &ScanKeywords[0]; + ScanKeyword *high = endof(ScanKeywords) - 1; + ScanKeyword *middle; + int difference; + + while (low <= high) + { + middle = low + (high - low) / 2; + difference = strcmp(middle->name, text); + if (difference == 0) + return (middle); + else if (difference < 0) + low = middle + 1; + else + high = middle - 1; + } + + return (NULL); } #ifdef NOT_USED -char* +char * AtomValueGetString(int atomval) { - ScanKeyword *low = &ScanKeywords[0]; - ScanKeyword *high = endof(ScanKeywords) - 1; - int keyword_list_length = (high-low); - int i; - - for (i=0; i < keyword_list_length ; i++ ) - if (ScanKeywords[i].value == atomval ) - return(ScanKeywords[i].name); - - elog(WARN,"AtomGetString called with bogus atom # : %d", atomval ); - return(NULL); + ScanKeyword *low = &ScanKeywords[0]; + ScanKeyword *high = endof(ScanKeywords) - 1; + int keyword_list_length = (high - low); + int i; + + for (i = 0; i < keyword_list_length; i++) + if (ScanKeywords[i].value == atomval) + return (ScanKeywords[i].name); + + elog(WARN, "AtomGetString called with bogus atom # : %d", atomval); + return (NULL); } + #endif diff --git a/src/backend/parser/parse_query.c b/src/backend/parser/parse_query.c index b19b291769f..5d144660a48 100644 --- a/src/backend/parser/parse_query.c +++ b/src/backend/parser/parse_query.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * parse_query.c-- - * take an "optimizable" stmt and make the query tree that - * the planner requires. + * take an "optimizable" stmt and make the query tree that + * the planner requires. * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.18 1997/08/22 00:02:07 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/Attic/parse_query.c,v 1.19 1997/09/07 04:44:48 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -23,8 +23,8 @@ #include "utils/builtins.h" #include "utils/elog.h" #include "utils/palloc.h" -#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */ -#include "utils/rel.h" /* Relation stuff */ +#include "utils/acl.h" /* for ACL_NO_PRIV_WARNING */ +#include "utils/rel.h" /* Relation stuff */ #include "utils/syscache.h" #include "catalog/pg_type.h" @@ -38,680 +38,744 @@ #include "nodes/parsenodes.h" #include "nodes/makefuncs.h" -static void checkTargetTypes(ParseState *pstate, char *target_colname, - char *refname, char *colname); +static void +checkTargetTypes(ParseState * pstate, char *target_colname, + char *refname, char *colname); -Oid *param_type_info; -int pfunc_num_args; +Oid *param_type_info; +int pfunc_num_args; /* given refname, return a pointer to the range table entry */ -RangeTblEntry * -refnameRangeTableEntry(List *rtable, char *refname) +RangeTblEntry * +refnameRangeTableEntry(List * rtable, char *refname) { - List *temp; - - foreach(temp, rtable) { - RangeTblEntry *rte = lfirst(temp); - - if (!strcmp(rte->refname, refname)) - return rte; - } - return NULL; + List *temp; + + foreach(temp, rtable) + { + RangeTblEntry *rte = lfirst(temp); + + if (!strcmp(rte->refname, refname)) + return rte; + } + return NULL; } /* given refname, return id of variable; position starts with 1 */ int -refnameRangeTablePosn(List *rtable, char *refname) +refnameRangeTablePosn(List * rtable, char *refname) { - int index; - List *temp; - - index = 1; - foreach(temp, rtable) { - RangeTblEntry *rte = lfirst(temp); - - if (!strcmp(rte->refname, refname)) - return index; - index++; - } - return(0); + int index; + List *temp; + + index = 1; + foreach(temp, rtable) + { + RangeTblEntry *rte = lfirst(temp); + + if (!strcmp(rte->refname, refname)) + return index; + index++; + } + return (0); } /* * returns range entry if found, else NULL */ -RangeTblEntry * -colnameRangeTableEntry(ParseState *pstate, char *colname) +RangeTblEntry * +colnameRangeTableEntry(ParseState * pstate, char *colname) { - List *et; - List *rtable; - RangeTblEntry *rte_result; + List *et; + List *rtable; + RangeTblEntry *rte_result; - if (pstate->p_is_rule) - rtable = lnext(lnext(pstate->p_rtable)); - else - rtable = pstate->p_rtable; + if (pstate->p_is_rule) + rtable = lnext(lnext(pstate->p_rtable)); + else + rtable = pstate->p_rtable; - rte_result = NULL; - foreach(et, rtable) { - RangeTblEntry *rte = lfirst(et); + rte_result = NULL; + foreach(et, rtable) + { + RangeTblEntry *rte = lfirst(et); /* only entries on outer(non-function?) scope */ - if (!rte->inFromCl && rte != pstate->p_target_rangetblentry) - continue; - - if (get_attnum(rte->relid, colname) != InvalidAttrNumber) { - if (rte_result != NULL) { - if (!pstate->p_is_insert || - rte != pstate->p_target_rangetblentry) - elog(WARN, "Column %s is ambiguous", colname); - } - else rte_result = rte; + if (!rte->inFromCl && rte != pstate->p_target_rangetblentry) + continue; + + if (get_attnum(rte->relid, colname) != InvalidAttrNumber) + { + if (rte_result != NULL) + { + if (!pstate->p_is_insert || + rte != pstate->p_target_rangetblentry) + elog(WARN, "Column %s is ambiguous", colname); + } + else + rte_result = rte; + } } - } - return rte_result; + return rte_result; } /* * put new entry in pstate p_rtable structure, or return pointer * if pstate null */ -RangeTblEntry * -addRangeTableEntry(ParseState *pstate, - char *relname, - char *refname, - bool inh, bool inFromCl, - TimeRange *timeRange) +RangeTblEntry * +addRangeTableEntry(ParseState * pstate, + char *relname, + char *refname, + bool inh, bool inFromCl, + TimeRange * timeRange) { - Relation relation; - RangeTblEntry *rte = makeNode(RangeTblEntry); - - if (pstate != NULL && - refnameRangeTableEntry(pstate->p_rtable, refname) != NULL) - elog(WARN,"Table name %s specified more than once",refname); - - rte->relname = pstrdup(relname); - rte->refname = pstrdup(refname); - - relation = heap_openr(relname); - if (relation == NULL) { - elog(WARN,"%s: %s", - relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]); - } - - /* - * Flags - zero or more from archive,inheritance,union,version - * or recursive (transitive closure) - * [we don't support them all -- ay 9/94 ] - */ - rte->inh = inh; - - rte->timeRange = timeRange; - - /* RelOID */ - rte->relid = RelationGetRelationId(relation); - - rte->archive = false; - - rte->inFromCl = inFromCl; - - /* - * close the relation we're done with it for now. - */ - if (pstate != NULL) - pstate->p_rtable = lappend(pstate->p_rtable, rte); - - heap_close(relation); - - return rte; + Relation relation; + RangeTblEntry *rte = makeNode(RangeTblEntry); + + if (pstate != NULL && + refnameRangeTableEntry(pstate->p_rtable, refname) != NULL) + elog(WARN, "Table name %s specified more than once", refname); + + rte->relname = pstrdup(relname); + rte->refname = pstrdup(refname); + + relation = heap_openr(relname); + if (relation == NULL) + { + elog(WARN, "%s: %s", + relname, aclcheck_error_strings[ACLCHECK_NO_CLASS]); + } + + /* + * Flags - zero or more from archive,inheritance,union,version or + * recursive (transitive closure) [we don't support them all -- ay + * 9/94 ] + */ + rte->inh = inh; + + rte->timeRange = timeRange; + + /* RelOID */ + rte->relid = RelationGetRelationId(relation); + + rte->archive = false; + + rte->inFromCl = inFromCl; + + /* + * close the relation we're done with it for now. + */ + if (pstate != NULL) + pstate->p_rtable = lappend(pstate->p_rtable, rte); + + heap_close(relation); + + return rte; } /* * expandAll - - * makes a list of attributes - * assumes reldesc caching works + * makes a list of attributes + * assumes reldesc caching works */ -List * -expandAll(ParseState *pstate, char *relname, char *refname, int *this_resno) +List * +expandAll(ParseState * pstate, char *relname, char *refname, int *this_resno) { - Relation rdesc; - List *te_tail = NIL, *te_head = NIL; - Var *varnode; - int varattno, maxattrs; - Oid type_id; - int type_len; - RangeTblEntry *rte; - - rte = refnameRangeTableEntry(pstate->p_rtable, refname); - if (rte == NULL) - rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE, NULL); - - rdesc = heap_open(rte->relid); - - if (rdesc == NULL ) { - elog(WARN,"Unable to expand all -- heap_open failed on %s", - rte->refname); - return NIL; - } - maxattrs = RelationGetNumberOfAttributes(rdesc); - - for ( varattno = 0; varattno <= maxattrs-1 ; varattno++ ) { - char *attrname; - char *resname = NULL; - TargetEntry *te = makeNode(TargetEntry); - - attrname = pstrdup ((rdesc->rd_att->attrs[varattno]->attname).data); - varnode = (Var*)make_var(pstate, refname, attrname, &type_id); - type_len = (int)tlen(get_id_type(type_id)); - - handleTargetColname(pstate, &resname, refname, attrname); - if (resname != NULL) - attrname = resname; - - /* Even if the elements making up a set are complex, the - * set itself is not. */ - - te->resdom = makeResdom((AttrNumber) (*this_resno)++, - type_id, - (Size)type_len, - attrname, - (Index)0, - (Oid)0, - 0); - te->expr = (Node *)varnode; - if (te_head == NIL) - te_head = te_tail = lcons(te, NIL); - else te_tail = lappend(te_tail, te); - } - - heap_close(rdesc); - return(te_head); + Relation rdesc; + List *te_tail = NIL, + *te_head = NIL; + Var *varnode; + int varattno, + maxattrs; + Oid type_id; + int type_len; + RangeTblEntry *rte; + + rte = refnameRangeTableEntry(pstate->p_rtable, refname); + if (rte == NULL) + rte = addRangeTableEntry(pstate, relname, refname, FALSE, FALSE, NULL); + + rdesc = heap_open(rte->relid); + + if (rdesc == NULL) + { + elog(WARN, "Unable to expand all -- heap_open failed on %s", + rte->refname); + return NIL; + } + maxattrs = RelationGetNumberOfAttributes(rdesc); + + for (varattno = 0; varattno <= maxattrs - 1; varattno++) + { + char *attrname; + char *resname = NULL; + TargetEntry *te = makeNode(TargetEntry); + + attrname = pstrdup((rdesc->rd_att->attrs[varattno]->attname).data); + varnode = (Var *) make_var(pstate, refname, attrname, &type_id); + type_len = (int) tlen(get_id_type(type_id)); + + handleTargetColname(pstate, &resname, refname, attrname); + if (resname != NULL) + attrname = resname; + + /* + * Even if the elements making up a set are complex, the set + * itself is not. + */ + + te->resdom = makeResdom((AttrNumber) (*this_resno)++, + type_id, + (Size) type_len, + attrname, + (Index) 0, + (Oid) 0, + 0); + te->expr = (Node *) varnode; + if (te_head == NIL) + te_head = te_tail = lcons(te, NIL); + else + te_tail = lappend(te_tail, te); + } + + heap_close(rdesc); + return (te_head); } TimeQual makeTimeRange(char *datestring1, - char *datestring2, - int timecode) /* 0 = snapshot , 1 = timerange */ + char *datestring2, + int timecode) /* 0 = snapshot , 1 = timerange */ { - TimeQual qual = NULL; - AbsoluteTime t1,t2; - - switch (timecode) { - case 0: - if (datestring1 == NULL) { - elog(WARN, "MakeTimeRange: bad snapshot arg"); - } - t1 = nabstimein(datestring1); - if (!AbsoluteTimeIsValid(t1)) { - elog(WARN, "bad snapshot time: \"%s\"", - datestring1); - } - qual = TimeFormSnapshotTimeQual(t1); - break; - case 1: - if (datestring1 == NULL) { - t1 = NOSTART_ABSTIME; - } else { - t1 = nabstimein(datestring1); - if (!AbsoluteTimeIsValid(t1)) { - elog(WARN, - "bad range start time: \"%s\"", - datestring1); - } - } - if (datestring2 == NULL) { - t2 = NOEND_ABSTIME; - } else { - t2 = nabstimein(datestring2); - if (!AbsoluteTimeIsValid(t2)) { - elog(WARN, - "bad range end time: \"%s\"", - datestring2); - } + TimeQual qual = NULL; + AbsoluteTime t1, + t2; + + switch (timecode) + { + case 0: + if (datestring1 == NULL) + { + elog(WARN, "MakeTimeRange: bad snapshot arg"); + } + t1 = nabstimein(datestring1); + if (!AbsoluteTimeIsValid(t1)) + { + elog(WARN, "bad snapshot time: \"%s\"", + datestring1); + } + qual = TimeFormSnapshotTimeQual(t1); + break; + case 1: + if (datestring1 == NULL) + { + t1 = NOSTART_ABSTIME; + } + else + { + t1 = nabstimein(datestring1); + if (!AbsoluteTimeIsValid(t1)) + { + elog(WARN, + "bad range start time: \"%s\"", + datestring1); + } + } + if (datestring2 == NULL) + { + t2 = NOEND_ABSTIME; + } + else + { + t2 = nabstimein(datestring2); + if (!AbsoluteTimeIsValid(t2)) + { + elog(WARN, + "bad range end time: \"%s\"", + datestring2); + } + } + qual = TimeFormRangedTimeQual(t1, t2); + break; + default: + elog(WARN, "MakeTimeRange: internal parser error"); } - qual = TimeFormRangedTimeQual(t1,t2); - break; - default: - elog(WARN, "MakeTimeRange: internal parser error"); - } - return qual; + return qual; } static void -disallow_setop(char *op, Type optype, Node *operand) +disallow_setop(char *op, Type optype, Node * operand) { - if (operand==NULL) - return; - - if (nodeTag(operand) == T_Iter) { - elog(NOTICE, "An operand to the '%s' operator returns a set of %s,", - op, tname(optype)); - elog(WARN, "but '%s' takes single values, not sets.", - op); - } + if (operand == NULL) + return; + + if (nodeTag(operand) == T_Iter) + { + elog(NOTICE, "An operand to the '%s' operator returns a set of %s,", + op, tname(optype)); + elog(WARN, "but '%s' takes single values, not sets.", + op); + } } -static Node * +static Node * make_operand(char *opname, - Node *tree, - Oid orig_typeId, - Oid true_typeId) + Node * tree, + Oid orig_typeId, + Oid true_typeId) { - Node *result; - Type true_type; - Datum val; - Oid infunc; - - if (tree != NULL) { - result = tree; - true_type = get_id_type(true_typeId); - disallow_setop(opname, true_type, result); - if (true_typeId != orig_typeId) { /* must coerce */ - Const *con= (Const *)result; - - Assert(nodeTag(result)==T_Const); - val = (Datum)textout((struct varlena *) - con->constvalue); - infunc = typeid_get_retinfunc(true_typeId); - con = makeNode(Const); - con->consttype = true_typeId; - con->constlen = tlen(true_type); - con->constvalue = (Datum)fmgr(infunc, - val, - get_typelem(true_typeId), - -1 /* for varchar() type */); - con->constisnull = false; - con->constbyval = true; - con->constisset = false; - result = (Node *)con; + Node *result; + Type true_type; + Datum val; + Oid infunc; + + if (tree != NULL) + { + result = tree; + true_type = get_id_type(true_typeId); + disallow_setop(opname, true_type, result); + if (true_typeId != orig_typeId) + { /* must coerce */ + Const *con = (Const *) result; + + Assert(nodeTag(result) == T_Const); + val = (Datum) textout((struct varlena *) + con->constvalue); + infunc = typeid_get_retinfunc(true_typeId); + con = makeNode(Const); + con->consttype = true_typeId; + con->constlen = tlen(true_type); + con->constvalue = (Datum) fmgr(infunc, + val, + get_typelem(true_typeId), + -1 /* for varchar() type */ ); + con->constisnull = false; + con->constbyval = true; + con->constisset = false; + result = (Node *) con; + } + } + else + { + Const *con = makeNode(Const); + + con->consttype = true_typeId; + con->constlen = 0; + con->constvalue = (Datum) (struct varlena *) NULL; + con->constisnull = true; + con->constbyval = true; + con->constisset = false; + result = (Node *) con; } - }else { - Const *con= makeNode(Const); - - con->consttype = true_typeId; - con->constlen = 0; - con->constvalue = (Datum)(struct varlena *)NULL; - con->constisnull = true; - con->constbyval = true; - con->constisset = false; - result = (Node *)con; - } - - return result; + + return result; } -Expr * -make_op(char *opname, Node *ltree, Node *rtree) +Expr * +make_op(char *opname, Node * ltree, Node * rtree) { - Oid ltypeId, rtypeId; - Operator temp; - OperatorTupleForm opform; - Oper *newop; - Node *left, *right; - Expr *result; - - if (rtree == NULL) { - - /* right operator */ - ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree); - temp = right_oper(opname, ltypeId); - opform = (OperatorTupleForm) GETSTRUCT(temp); - left = make_operand(opname, ltree, ltypeId, opform->oprleft); - right = NULL; - - }else if (ltree == NULL) { - - /* left operator */ - rtypeId = (rtree==NULL) ? UNKNOWNOID : exprType(rtree); - temp = left_oper(opname, rtypeId); - opform = (OperatorTupleForm) GETSTRUCT(temp); - right = make_operand(opname, rtree, rtypeId, opform->oprright); - left = NULL; - - }else { - char *outstr; - Oid infunc, outfunc; - Type newtype; + Oid ltypeId, + rtypeId; + Operator temp; + OperatorTupleForm opform; + Oper *newop; + Node *left, + *right; + Expr *result; + + if (rtree == NULL) + { + + /* right operator */ + ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree); + temp = right_oper(opname, ltypeId); + opform = (OperatorTupleForm) GETSTRUCT(temp); + left = make_operand(opname, ltree, ltypeId, opform->oprleft); + right = NULL; + + } + else if (ltree == NULL) + { + + /* left operator */ + rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree); + temp = left_oper(opname, rtypeId); + opform = (OperatorTupleForm) GETSTRUCT(temp); + right = make_operand(opname, rtree, rtypeId, opform->oprright); + left = NULL; + + } + else + { + char *outstr; + Oid infunc, + outfunc; + Type newtype; #define CONVERTABLE_TYPE(t) ( (t) == INT2OID || \ - (t) == INT4OID || \ - (t) == OIDOID || \ - (t) == FLOAT4OID || \ - (t) == FLOAT8OID || \ - (t) == CASHOID) - - /* binary operator */ - ltypeId = (ltree==NULL) ? UNKNOWNOID : exprType(ltree); - rtypeId = (rtree==NULL) ? UNKNOWNOID : exprType(rtree); - - /* convert constant when using a const of a numeric type - and a non-const of another numeric type */ - if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const && - CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const && - !((Const *)rtree)->constiscast) { - outfunc = typeid_get_retoutfunc(rtypeId); - infunc = typeid_get_retinfunc(ltypeId); - outstr = (char *)fmgr(outfunc, ((Const *)rtree)->constvalue); - ((Const *)rtree)->constvalue = (Datum)fmgr(infunc, outstr); - pfree(outstr); - ((Const *)rtree)->consttype = rtypeId = ltypeId; - newtype = get_id_type(rtypeId); - ((Const *)rtree)->constlen = tlen(newtype); - ((Const *)rtree)->constbyval = tbyval(newtype); + (t) == INT4OID || \ + (t) == OIDOID || \ + (t) == FLOAT4OID || \ + (t) == FLOAT8OID || \ + (t) == CASHOID) + + /* binary operator */ + ltypeId = (ltree == NULL) ? UNKNOWNOID : exprType(ltree); + rtypeId = (rtree == NULL) ? UNKNOWNOID : exprType(rtree); + + /* + * convert constant when using a const of a numeric type and a + * non-const of another numeric type + */ + if (CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) != T_Const && + CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) == T_Const && + !((Const *) rtree)->constiscast) + { + outfunc = typeid_get_retoutfunc(rtypeId); + infunc = typeid_get_retinfunc(ltypeId); + outstr = (char *) fmgr(outfunc, ((Const *) rtree)->constvalue); + ((Const *) rtree)->constvalue = (Datum) fmgr(infunc, outstr); + pfree(outstr); + ((Const *) rtree)->consttype = rtypeId = ltypeId; + newtype = get_id_type(rtypeId); + ((Const *) rtree)->constlen = tlen(newtype); + ((Const *) rtree)->constbyval = tbyval(newtype); + } + + if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const && + CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const && + !((Const *) ltree)->constiscast) + { + outfunc = typeid_get_retoutfunc(ltypeId); + infunc = typeid_get_retinfunc(rtypeId); + outstr = (char *) fmgr(outfunc, ((Const *) ltree)->constvalue); + ((Const *) ltree)->constvalue = (Datum) fmgr(infunc, outstr); + pfree(outstr); + ((Const *) ltree)->consttype = ltypeId = rtypeId; + newtype = get_id_type(ltypeId); + ((Const *) ltree)->constlen = tlen(newtype); + ((Const *) ltree)->constbyval = tbyval(newtype); + } + + temp = oper(opname, ltypeId, rtypeId, false); + opform = (OperatorTupleForm) GETSTRUCT(temp); + left = make_operand(opname, ltree, ltypeId, opform->oprleft); + right = make_operand(opname, rtree, rtypeId, opform->oprright); } - if (CONVERTABLE_TYPE(rtypeId) && nodeTag(rtree) != T_Const && - CONVERTABLE_TYPE(ltypeId) && nodeTag(ltree) == T_Const && - !((Const *)ltree)->constiscast) { - outfunc = typeid_get_retoutfunc(ltypeId); - infunc = typeid_get_retinfunc(rtypeId); - outstr = (char *)fmgr(outfunc, ((Const *)ltree)->constvalue); - ((Const *)ltree)->constvalue = (Datum)fmgr(infunc, outstr); - pfree(outstr); - ((Const *)ltree)->consttype = ltypeId = rtypeId; - newtype = get_id_type(ltypeId); - ((Const *)ltree)->constlen = tlen(newtype); - ((Const *)ltree)->constbyval = tbyval(newtype); + newop = makeOper(oprid(temp), /* opno */ + InvalidOid,/* opid */ + opform->oprresult, /* operator result type */ + 0, + NULL); + + result = makeNode(Expr); + result->typeOid = opform->oprresult; + result->opType = OP_EXPR; + result->oper = (Node *) newop; + + if (!left) + { + result->args = lcons(right, NIL); + } + else if (!right) + { + result->args = lcons(left, NIL); + } + else + { + result->args = lcons(left, lcons(right, NIL)); } - temp = oper(opname, ltypeId, rtypeId, false); - opform = (OperatorTupleForm) GETSTRUCT(temp); - left = make_operand(opname, ltree, ltypeId, opform->oprleft); - right = make_operand(opname, rtree, rtypeId, opform->oprright); - } - - newop = makeOper(oprid(temp), /* opno */ - InvalidOid, /* opid */ - opform->oprresult, /* operator result type */ - 0, - NULL); - - result = makeNode(Expr); - result->typeOid = opform->oprresult; - result->opType = OP_EXPR; - result->oper = (Node *)newop; - - if (!left) { - result->args = lcons(right, NIL); - } else if (!right) { - result->args = lcons(left, NIL); - } else { - result->args = lcons(left, lcons(right, NIL)); - } - - return result; + return result; } Oid find_atttype(Oid relid, char *attrname) { - int attid; - Oid vartype; - Relation rd; - - rd = heap_open(relid); - if (!RelationIsValid(rd)) { - rd = heap_openr(tname(get_id_type(relid))); + int attid; + Oid vartype; + Relation rd; + + rd = heap_open(relid); if (!RelationIsValid(rd)) - elog(WARN, "cannot compute type of att %s for relid %d", - attrname, relid); - } - - attid = nf_varattno(rd, attrname); - - if (attid == InvalidAttrNumber) - elog(WARN, "Invalid attribute %s\n", attrname); - - vartype = att_typeid(rd , attid); - - /* - * close relation we're done with it now - */ - heap_close(rd); - - return (vartype); + { + rd = heap_openr(tname(get_id_type(relid))); + if (!RelationIsValid(rd)) + elog(WARN, "cannot compute type of att %s for relid %d", + attrname, relid); + } + + attid = nf_varattno(rd, attrname); + + if (attid == InvalidAttrNumber) + elog(WARN, "Invalid attribute %s\n", attrname); + + vartype = att_typeid(rd, attid); + + /* + * close relation we're done with it now + */ + heap_close(rd); + + return (vartype); } -Var * -make_var(ParseState *pstate, char *refname, char *attrname, Oid *type_id) +Var * +make_var(ParseState * pstate, char *refname, char *attrname, Oid * type_id) { - Var *varnode; - int vnum, attid; - Oid vartypeid; - Relation rd; - RangeTblEntry *rte; + Var *varnode; + int vnum, + attid; + Oid vartypeid; + Relation rd; + RangeTblEntry *rte; - rte = refnameRangeTableEntry(pstate->p_rtable, refname); - if (rte == NULL) - rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE, NULL); + rte = refnameRangeTableEntry(pstate->p_rtable, refname); + if (rte == NULL) + rte = addRangeTableEntry(pstate, refname, refname, FALSE, FALSE, NULL); - vnum = refnameRangeTablePosn(pstate->p_rtable, refname); + vnum = refnameRangeTablePosn(pstate->p_rtable, refname); - rd = heap_open(rte->relid); + rd = heap_open(rte->relid); - attid = nf_varattno(rd, attrname); - if (attid == InvalidAttrNumber) - elog(WARN, "Invalid attribute %s\n", attrname); - vartypeid = att_typeid(rd, attid); + attid = nf_varattno(rd, attrname); + if (attid == InvalidAttrNumber) + elog(WARN, "Invalid attribute %s\n", attrname); + vartypeid = att_typeid(rd, attid); - varnode = makeVar(vnum, attid, vartypeid, vnum, attid); + varnode = makeVar(vnum, attid, vartypeid, vnum, attid); - heap_close(rd); + heap_close(rd); - *type_id = vartypeid; - return varnode; + *type_id = vartypeid; + return varnode; } /* - * make_array_ref() -- Make an array reference node. + * make_array_ref() -- Make an array reference node. * - * Array references can hang off of arbitrary nested dot (or - * function invocation) expressions. This routine takes a - * tree generated by ParseFunc() and an array index and - * generates a new array reference tree. We do some simple - * typechecking to be sure the dereference is valid in the - * type system, but we don't do any bounds checking here. + * Array references can hang off of arbitrary nested dot (or + * function invocation) expressions. This routine takes a + * tree generated by ParseFunc() and an array index and + * generates a new array reference tree. We do some simple + * typechecking to be sure the dereference is valid in the + * type system, but we don't do any bounds checking here. * - * indirection is a list of A_Indices + * indirection is a list of A_Indices */ -ArrayRef * -make_array_ref(Node *expr, - List *indirection) +ArrayRef * +make_array_ref(Node * expr, + List * indirection) { - Oid typearray; - HeapTuple type_tuple; - TypeTupleForm type_struct_array, type_struct_element; - ArrayRef *aref; - Oid reftype; - List *upperIndexpr=NIL; - List *lowerIndexpr=NIL; - - typearray = exprType(expr); - - type_tuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(typearray), - 0,0,0); - - if (!HeapTupleIsValid(type_tuple)) - elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", - typearray); - - /* get the array type struct from the type tuple */ - type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple); - - if (type_struct_array->typelem == InvalidOid) { - elog(WARN, "make_array_ref: type %s is not an array", - (Name)&(type_struct_array->typname.data[0])); - } - - /* get the type tuple for the element type */ - type_tuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type_struct_array->typelem), - 0,0,0); - if (!HeapTupleIsValid(type_tuple)) - elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", - typearray); - - type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple); - - while(indirection!=NIL) { - A_Indices *ind = lfirst(indirection); - if (ind->lidx) { - /* XXX assumes all lower indices non null in this case - */ - lowerIndexpr = lappend(lowerIndexpr, ind->lidx); + Oid typearray; + HeapTuple type_tuple; + TypeTupleForm type_struct_array, + type_struct_element; + ArrayRef *aref; + Oid reftype; + List *upperIndexpr = NIL; + List *lowerIndexpr = NIL; + + typearray = exprType(expr); + + type_tuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(typearray), + 0, 0, 0); + + if (!HeapTupleIsValid(type_tuple)) + elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", + typearray); + + /* get the array type struct from the type tuple */ + type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple); + + if (type_struct_array->typelem == InvalidOid) + { + elog(WARN, "make_array_ref: type %s is not an array", + (Name) & (type_struct_array->typname.data[0])); + } + + /* get the type tuple for the element type */ + type_tuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type_struct_array->typelem), + 0, 0, 0); + if (!HeapTupleIsValid(type_tuple)) + elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", + typearray); + + type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple); + + while (indirection != NIL) + { + A_Indices *ind = lfirst(indirection); + + if (ind->lidx) + { + + /* + * XXX assumes all lower indices non null in this case + */ + lowerIndexpr = lappend(lowerIndexpr, ind->lidx); + } + upperIndexpr = lappend(upperIndexpr, ind->uidx); + indirection = lnext(indirection); } - upperIndexpr = lappend(upperIndexpr, ind->uidx); - indirection = lnext(indirection); - } - aref = makeNode(ArrayRef); - aref->refattrlength = type_struct_array->typlen; - aref->refelemlength = type_struct_element->typlen; - aref->refelemtype = type_struct_array->typelem; - aref->refelembyval = type_struct_element->typbyval; - aref->refupperindexpr = upperIndexpr; - aref->reflowerindexpr = lowerIndexpr; - aref->refexpr = expr; - aref->refassgnexpr = NULL; - - if (lowerIndexpr == NIL) /* accessing a single array element */ - reftype = aref->refelemtype; - else /* request to clip a part of the array, the result is another array */ - reftype = typearray; - - /* we change it to reflect the true type; since the original refelemtype - * doesn't seem to get used anywhere. - ay 10/94 - */ - aref->refelemtype = reftype; - - return aref; + aref = makeNode(ArrayRef); + aref->refattrlength = type_struct_array->typlen; + aref->refelemlength = type_struct_element->typlen; + aref->refelemtype = type_struct_array->typelem; + aref->refelembyval = type_struct_element->typbyval; + aref->refupperindexpr = upperIndexpr; + aref->reflowerindexpr = lowerIndexpr; + aref->refexpr = expr; + aref->refassgnexpr = NULL; + + if (lowerIndexpr == NIL) /* accessing a single array element */ + reftype = aref->refelemtype; + else +/* request to clip a part of the array, the result is another array */ + reftype = typearray; + + /* + * we change it to reflect the true type; since the original + * refelemtype doesn't seem to get used anywhere. - ay 10/94 + */ + aref->refelemtype = reftype; + + return aref; } -ArrayRef * -make_array_set(Expr *target_expr, - List *upperIndexpr, - List *lowerIndexpr, - Expr *expr) +ArrayRef * +make_array_set(Expr * target_expr, + List * upperIndexpr, + List * lowerIndexpr, + Expr * expr) { - Oid typearray; - HeapTuple type_tuple; - TypeTupleForm type_struct_array; - TypeTupleForm type_struct_element; - ArrayRef *aref; - Oid reftype; - - typearray = exprType((Node*)target_expr); - - type_tuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(typearray), - 0,0,0); - - if (!HeapTupleIsValid(type_tuple)) - elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", - typearray); - - /* get the array type struct from the type tuple */ - type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple); - - if (type_struct_array->typelem == InvalidOid) { - elog(WARN, "make_array_ref: type %s is not an array", - (Name)&(type_struct_array->typname.data[0])); - } - /* get the type tuple for the element type */ - type_tuple = SearchSysCacheTuple(TYPOID, - ObjectIdGetDatum(type_struct_array->typelem), - 0,0,0); - - if (!HeapTupleIsValid(type_tuple)) - elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", - typearray); - - type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple); - - aref = makeNode(ArrayRef); - aref->refattrlength = type_struct_array->typlen; - aref->refelemlength = type_struct_element->typlen; - aref->refelemtype = type_struct_array->typelem; - aref->refelembyval = type_struct_element->typbyval; - aref->refupperindexpr = upperIndexpr; - aref->reflowerindexpr = lowerIndexpr; - aref->refexpr = (Node*)target_expr; - aref->refassgnexpr = (Node*)expr; - - if (lowerIndexpr == NIL) /* accessing a single array element */ - reftype = aref->refelemtype; - else /* request to set a part of the array, by another array */ - reftype = typearray; - - aref->refelemtype = reftype; - - return aref; + Oid typearray; + HeapTuple type_tuple; + TypeTupleForm type_struct_array; + TypeTupleForm type_struct_element; + ArrayRef *aref; + Oid reftype; + + typearray = exprType((Node *) target_expr); + + type_tuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(typearray), + 0, 0, 0); + + if (!HeapTupleIsValid(type_tuple)) + elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", + typearray); + + /* get the array type struct from the type tuple */ + type_struct_array = (TypeTupleForm) GETSTRUCT(type_tuple); + + if (type_struct_array->typelem == InvalidOid) + { + elog(WARN, "make_array_ref: type %s is not an array", + (Name) & (type_struct_array->typname.data[0])); + } + /* get the type tuple for the element type */ + type_tuple = SearchSysCacheTuple(TYPOID, + ObjectIdGetDatum(type_struct_array->typelem), + 0, 0, 0); + + if (!HeapTupleIsValid(type_tuple)) + elog(WARN, "make_array_ref: Cache lookup failed for type %d\n", + typearray); + + type_struct_element = (TypeTupleForm) GETSTRUCT(type_tuple); + + aref = makeNode(ArrayRef); + aref->refattrlength = type_struct_array->typlen; + aref->refelemlength = type_struct_element->typlen; + aref->refelemtype = type_struct_array->typelem; + aref->refelembyval = type_struct_element->typbyval; + aref->refupperindexpr = upperIndexpr; + aref->reflowerindexpr = lowerIndexpr; + aref->refexpr = (Node *) target_expr; + aref->refassgnexpr = (Node *) expr; + + if (lowerIndexpr == NIL) /* accessing a single array element */ + reftype = aref->refelemtype; + else +/* request to set a part of the array, by another array */ + reftype = typearray; + + aref->refelemtype = reftype; + + return aref; } /* - * + * * make_const - - * + * * - takes a lispvalue, (as returned to the yacc routine by the lexer) - * extracts the type, and makes the appropriate type constant - * by invoking the (c-callable) lisp routine c-make-const - * via the lisp_call() mechanism + * extracts the type, and makes the appropriate type constant + * by invoking the (c-callable) lisp routine c-make-const + * via the lisp_call() mechanism * * eventually, produces a "const" lisp-struct as per nodedefs.cl - */ -Const * -make_const(Value *value) + */ +Const * +make_const(Value * value) { - Type tp; - Datum val; - Const *con; - - switch(nodeTag(value)) { - case T_Integer: - tp = type("int4"); - val = Int32GetDatum(intVal(value)); - break; - - case T_Float: - { - float64 dummy; - tp = type("float8"); - - dummy = (float64)palloc(sizeof(float64data)); - *dummy = floatVal(value); - - val = Float64GetDatum(dummy); - } - break; - - case T_String: - tp = type("unknown"); /* unknown for now, will be type coerced */ - val = PointerGetDatum(textin(strVal(value))); - break; - - case T_Null: - default: - { - if (nodeTag(value)!=T_Null) - elog(NOTICE,"unknown type : %d\n", nodeTag(value)); + Type tp; + Datum val; + Const *con; - /* null const */ - con = makeConst(0, 0, (Datum)NULL, true, false, false, false); - return con; + switch (nodeTag(value)) + { + case T_Integer: + tp = type("int4"); + val = Int32GetDatum(intVal(value)); + break; + + case T_Float: + { + float64 dummy; + + tp = type("float8"); + + dummy = (float64) palloc(sizeof(float64data)); + *dummy = floatVal(value); + + val = Float64GetDatum(dummy); + } + break; + + case T_String: + tp = type("unknown"); /* unknown for now, will be type coerced */ + val = PointerGetDatum(textin(strVal(value))); + break; + + case T_Null: + default: + { + if (nodeTag(value) != T_Null) + elog(NOTICE, "unknown type : %d\n", nodeTag(value)); + + /* null const */ + con = makeConst(0, 0, (Datum) NULL, true, false, false, false); + return con; + } } - } - con = makeConst(typeid(tp), - tlen(tp), - val, - false, - tbyval(tp), - false, /* not a set */ - false); + con = makeConst(typeid(tp), + tlen(tp), + val, + false, + tbyval(tp), + false, /* not a set */ + false); - return (con); + return (con); } /* @@ -721,87 +785,93 @@ make_const(Value *value) * used in postquel functions */ void -param_type_init(Oid* typev, int nargs) +param_type_init(Oid * typev, int nargs) { - pfunc_num_args = nargs; - param_type_info = typev; + pfunc_num_args = nargs; + param_type_info = typev; } Oid param_type(int t) { - if ((t >pfunc_num_args) ||(t ==0)) return InvalidOid; - return param_type_info[t-1]; + if ((t > pfunc_num_args) || (t == 0)) + return InvalidOid; + return param_type_info[t - 1]; } /* * handleTargetColname - - * use column names from insert + * use column names from insert */ void -handleTargetColname(ParseState *pstate, char **resname, +handleTargetColname(ParseState * pstate, char **resname, char *refname, char *colname) { - if (pstate->p_is_insert) { - if (pstate->p_insert_columns != NIL ) { - Ident *id = lfirst(pstate->p_insert_columns); - *resname = id->name; - pstate->p_insert_columns = lnext(pstate->p_insert_columns); - } - else - elog(WARN, "insert: more expressions than target columns"); - } - if (pstate->p_is_insert||pstate->p_is_update) - checkTargetTypes(pstate, *resname, refname, colname); + if (pstate->p_is_insert) + { + if (pstate->p_insert_columns != NIL) + { + Ident *id = lfirst(pstate->p_insert_columns); + + *resname = id->name; + pstate->p_insert_columns = lnext(pstate->p_insert_columns); + } + else + elog(WARN, "insert: more expressions than target columns"); + } + if (pstate->p_is_insert || pstate->p_is_update) + checkTargetTypes(pstate, *resname, refname, colname); } /* * checkTargetTypes - - * checks value and target column types + * checks value and target column types */ static void -checkTargetTypes(ParseState *pstate, char *target_colname, - char *refname, char *colname) +checkTargetTypes(ParseState * pstate, char *target_colname, + char *refname, char *colname) { - Oid attrtype_id, attrtype_target; - int resdomno_id, resdomno_target; - Relation rd; - RangeTblEntry *rte; - - if (target_colname == NULL || colname == NULL) - return; - - if (refname != NULL) - rte = refnameRangeTableEntry(pstate->p_rtable, refname); - else { - rte = colnameRangeTableEntry(pstate, colname); - if ( rte == (RangeTblEntry *) NULL ) - elog (WARN, "attribute %s not found", colname); - refname = rte->refname; - } + Oid attrtype_id, + attrtype_target; + int resdomno_id, + resdomno_target; + Relation rd; + RangeTblEntry *rte; + + if (target_colname == NULL || colname == NULL) + return; + + if (refname != NULL) + rte = refnameRangeTableEntry(pstate->p_rtable, refname); + else + { + rte = colnameRangeTableEntry(pstate, colname); + if (rte == (RangeTblEntry *) NULL) + elog(WARN, "attribute %s not found", colname); + refname = rte->refname; + } /* - if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry) - elog(WARN, "%s not available in this context", colname); + if (pstate->p_is_insert && rte == pstate->p_target_rangetblentry) + elog(WARN, "%s not available in this context", colname); */ - rd = heap_open(rte->relid); + rd = heap_open(rte->relid); - resdomno_id = varattno(rd,colname); - attrtype_id = att_typeid(rd,resdomno_id); + resdomno_id = varattno(rd, colname); + attrtype_id = att_typeid(rd, resdomno_id); - resdomno_target = varattno(pstate->p_target_relation,target_colname); - attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target); + resdomno_target = varattno(pstate->p_target_relation, target_colname); + attrtype_target = att_typeid(pstate->p_target_relation, resdomno_target); - if (attrtype_id != attrtype_target) - elog(WARN, "Type of %s does not match target column %s", - colname, target_colname); + if (attrtype_id != attrtype_target) + elog(WARN, "Type of %s does not match target column %s", + colname, target_colname); - if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) && - rd->rd_att->attrs[resdomno_id-1]->attlen != - pstate->p_target_relation->rd_att->attrs[resdomno_target-1]->attlen) - elog(WARN, "Length of %s does not match length of target column %s", - colname, target_colname); + if ((attrtype_id == BPCHAROID || attrtype_id == VARCHAROID) && + rd->rd_att->attrs[resdomno_id - 1]->attlen != + pstate->p_target_relation->rd_att->attrs[resdomno_target - 1]->attlen) + elog(WARN, "Length of %s does not match length of target column %s", + colname, target_colname); - heap_close(rd); + heap_close(rd); } - diff --git a/src/backend/parser/parser.c b/src/backend/parser/parser.c index ab4276055cd..99c6ce2bfdb 100644 --- a/src/backend/parser/parser.c +++ b/src/backend/parser/parser.c @@ -6,14 +6,14 @@ * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.22 1997/08/22 07:12:45 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/parser.c,v 1.23 1997/09/07 04:44:50 momjian Exp $ * *------------------------------------------------------------------------- */ #include <string.h> #include <stdio.h> #include <pwd.h> -#include <sys/param.h> /* for MAXPATHLEN */ +#include <sys/param.h> /* for MAXPATHLEN */ #include "postgres.h" #include "parser/catalog_utils.h" @@ -34,456 +34,510 @@ #include "catalog/pg_aggregate.h" #include "catalog/pg_type.h" #include "access/heapam.h" -#include "optimizer/clauses.h" +#include "optimizer/clauses.h" -void init_io(); /* from scan.l */ -void parser_init(Oid *typev, int nargs); /* from gram.y */ -int yyparse(); /* from gram.c */ +void init_io(); /* from scan.l */ +void parser_init(Oid * typev, int nargs); /* from gram.y */ +int yyparse(); /* from gram.c */ -char *parseString; /* the char* which holds the string to be parsed */ -char *parseCh; /* a pointer used during parsing to walk down ParseString*/ +char *parseString; /* the char* which holds the string to be + * parsed */ +char *parseCh; /* a pointer used during parsing to walk + * down ParseString */ -List *parsetree = NIL; +List *parsetree = NIL; #ifdef SETS_FIXED -static void fixupsets(); -static void define_sets(); +static void fixupsets(); +static void define_sets(); + #endif /* * parser-- returns a list of parse trees - * - * CALLER is responsible for free'ing the list returned + * + * CALLER is responsible for free'ing the list returned */ -QueryTreeList * -parser(char *str, Oid *typev, int nargs) +QueryTreeList * +parser(char *str, Oid * typev, int nargs) { - QueryTreeList* queryList; - int yyresult; + QueryTreeList *queryList; + int yyresult; #if defined(FLEX_SCANNER) - extern void DeleteBuffer(void); -#endif /* FLEX_SCANNER */ - - init_io(); - - /* Set things up to read from the string, if there is one */ - parseString = (char *) palloc(strlen(str) + 1); - memmove(parseString,str,strlen(str)+1); - - parser_init(typev, nargs); - yyresult = yyparse(); + extern void DeleteBuffer(void); + +#endif /* FLEX_SCANNER */ + + init_io(); + + /* Set things up to read from the string, if there is one */ + parseString = (char *) palloc(strlen(str) + 1); + memmove(parseString, str, strlen(str) + 1); + + parser_init(typev, nargs); + yyresult = yyparse(); #if defined(FLEX_SCANNER) - DeleteBuffer(); -#endif /* FLEX_SCANNER */ - - clearerr(stdin); - - if (yyresult) { /* error */ - return((QueryTreeList*)NULL); - } - - queryList = parse_analyze(parsetree); - + DeleteBuffer(); +#endif /* FLEX_SCANNER */ + + clearerr(stdin); + + if (yyresult) + { /* error */ + return ((QueryTreeList *) NULL); + } + + queryList = parse_analyze(parsetree); + #ifdef SETS_FIXED - /* Fixing up sets calls the parser, so it reassigns the global - * variable parsetree. So save the real parsetree. - */ - savetree = parsetree; - foreach (parse, savetree) { /* savetree is really a list of parses */ - /* find set definitions embedded in query */ - fixupsets((Query *)lfirst(parse)); + /* + * Fixing up sets calls the parser, so it reassigns the global + * variable parsetree. So save the real parsetree. + */ + savetree = parsetree; + foreach(parse, savetree) + { /* savetree is really a list of parses */ + + /* find set definitions embedded in query */ + fixupsets((Query *) lfirst(parse)); - } - return savetree; -#endif + } + return savetree; +#endif - return queryList; + return queryList; } #ifdef SETS_FIXED static void -fixupsets(Query *parse) +fixupsets(Query * parse) { - if (parse == NULL) - return; - if (parse->commandType==CMD_UTILITY) /* utility */ - return; - if (parse->commandType!=CMD_INSERT) - return; - define_sets(parse); + if (parse == NULL) + return; + if (parse->commandType == CMD_UTILITY) /* utility */ + return; + if (parse->commandType != CMD_INSERT) + return; + define_sets(parse); } /* Recursively find all of the Consts in the parsetree. Some of * these may represent a set. The value of the Const will be the - * query (a string) which defines the set. Call SetDefine to define + * query (a string) which defines the set. Call SetDefine to define * the set, and store the OID of the new set in the Const instead. */ static void -define_sets(Node *clause) +define_sets(Node * clause) { - Oid setoid; - Type t = type("oid"); - Oid typeoid = typeid(t); - Size oidsize = tlen(t); - bool oidbyval = tbyval(t); - - if (clause==NULL) { - return; - } else if (IsA(clause,LispList)) { - define_sets(lfirst(clause)); - define_sets(lnext(clause)); - } else if (IsA(clause,Const)) { - if (get_constisnull((Const)clause) || - !get_constisset((Const)clause)) { - return; + Oid setoid; + Type t = type("oid"); + Oid typeoid = typeid(t); + Size oidsize = tlen(t); + bool oidbyval = tbyval(t); + + if (clause == NULL) + { + return; + } + else if (IsA(clause, LispList)) + { + define_sets(lfirst(clause)); + define_sets(lnext(clause)); + } + else if (IsA(clause, Const)) + { + if (get_constisnull((Const) clause) || + !get_constisset((Const) clause)) + { + return; + } + setoid = SetDefine(((Const *) clause)->constvalue, + get_id_typname(((Const *) clause)->consttype)); + set_constvalue((Const) clause, setoid); + set_consttype((Const) clause, typeoid); + set_constlen((Const) clause, oidsize); + set_constbyval((Const) clause, oidbyval); + } + else if (IsA(clause, Iter)) + { + define_sets(((Iter *) clause)->iterexpr); + } + else if (single_node(clause)) + { + return; + } + else if (or_clause(clause)) + { + List *temp; + + /* mapcan */ + foreach(temp, ((Expr *) clause)->args) + { + define_sets(lfirst(temp)); + } } - setoid = SetDefine(((Const*)clause)->constvalue, - get_id_typname(((Const*)clause)->consttype)); - set_constvalue((Const)clause, setoid); - set_consttype((Const)clause,typeoid); - set_constlen((Const)clause,oidsize); - set_constbyval((Const)clause,oidbyval); - } else if ( IsA(clause,Iter) ) { - define_sets(((Iter*)clause)->iterexpr); - } else if (single_node (clause)) { - return; - } else if (or_clause(clause)) { - List *temp; - /* mapcan */ - foreach (temp, ((Expr*)clause)->args) { - define_sets(lfirst(temp)); + else if (is_funcclause(clause)) + { + List *temp; + + /* mapcan */ + foreach(temp, ((Expr *) clause)->args) + { + define_sets(lfirst(temp)); + } } - } else if (is_funcclause (clause)) { - List *temp; - /* mapcan */ - foreach(temp, ((Expr*)clause)->args) { - define_sets(lfirst(temp)); + else if (IsA(clause, ArrayRef)) + { + define_sets(((ArrayRef *) clause)->refassgnexpr); + } + else if (not_clause(clause)) + { + define_sets(get_notclausearg(clause)); + } + else if (is_opclause(clause)) + { + define_sets(get_leftop(clause)); + define_sets(get_rightop(clause)); } - } else if (IsA(clause,ArrayRef)) { - define_sets(((ArrayRef*)clause)->refassgnexpr); - } else if (not_clause (clause)) { - define_sets (get_notclausearg (clause)); - } else if (is_opclause (clause)) { - define_sets(get_leftop (clause)); - define_sets(get_rightop (clause)); - } } + #endif /* not used -#define PSIZE(PTR) (*((int32 *)(PTR) - 1)) +#define PSIZE(PTR) (*((int32 *)(PTR) - 1)) */ -Node * -parser_typecast(Value *expr, TypeName *typename, int typlen) +Node * +parser_typecast(Value * expr, TypeName * typename, int typlen) { - /* check for passing non-ints */ - Const *adt; - Datum lcp; - Type tp; - char type_string[16]; - int32 len; - char *cp = NULL; - char *const_string = NULL; - bool string_palloced = false; - - switch(nodeTag(expr)) { - case T_String: - const_string = DatumGetPointer(expr->val.str); - break; - case T_Integer: - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string, "%d", expr->val.ival); - break; - default: - elog(WARN, - "parser_typecast: cannot cast this expression to type \"%s\"", - typename->name); - } - - if (typename->arrayBounds != NIL) { - sprintf(type_string,"_%s", typename->name); - tp = (Type) type(type_string); - } else { - tp = (Type) type(typename->name); - } - - len = tlen(tp); - -#if 0 /* fix me */ - switch ( CInteger(lfirst(expr)) ) { - case INT4OID: /* int4 */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%d", ((Const*)lnext(expr))->constvalue); - break; - - case NAMEOID: /* char16 */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%s", ((Const*)lnext(expr))->constvalue); - break; - - case CHAROID: /* char */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%c", ((Const)lnext(expr))->constvalue); - break; - - case FLOAT8OID:/* float8 */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%f", ((Const)lnext(expr))->constvalue); - break; - - case CASHOID: /* money */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%d", - (int) ((Const*)expr)->constvalue); - break; - - case TEXTOID: /* text */ - const_string = DatumGetPointer(((Const)lnext(expr))->constvalue); - const_string = (char *) textout((struct varlena *)const_string); - break; - - case UNKNOWNOID: /* unknown */ - const_string = DatumGetPointer(((Const)lnext(expr))->constvalue); - const_string = (char *) textout((struct varlena *)const_string); - break; - - default: - elog(WARN,"unknown type %d", CInteger(lfirst(expr))); - } + /* check for passing non-ints */ + Const *adt; + Datum lcp; + Type tp; + char type_string[16]; + int32 len; + char *cp = NULL; + char *const_string = NULL; + bool string_palloced = false; + + switch (nodeTag(expr)) + { + case T_String: + const_string = DatumGetPointer(expr->val.str); + break; + case T_Integer: + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%d", expr->val.ival); + break; + default: + elog(WARN, + "parser_typecast: cannot cast this expression to type \"%s\"", + typename->name); + } + + if (typename->arrayBounds != NIL) + { + sprintf(type_string, "_%s", typename->name); + tp = (Type) type(type_string); + } + else + { + tp = (Type) type(typename->name); + } + + len = tlen(tp); + +#if 0 /* fix me */ + switch (CInteger(lfirst(expr))) + { + case INT4OID: /* int4 */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%d", ((Const *) lnext(expr))->constvalue); + break; + + case NAMEOID: /* char16 */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%s", ((Const *) lnext(expr))->constvalue); + break; + + case CHAROID: /* char */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%c", ((Const) lnext(expr))->constvalue); + break; + + case FLOAT8OID: /* float8 */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%f", ((Const) lnext(expr))->constvalue); + break; + + case CASHOID: /* money */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%d", + (int) ((Const *) expr)->constvalue); + break; + + case TEXTOID: /* text */ + const_string = DatumGetPointer(((Const) lnext(expr))->constvalue); + const_string = (char *) textout((struct varlena *) const_string); + break; + + case UNKNOWNOID: /* unknown */ + const_string = DatumGetPointer(((Const) lnext(expr))->constvalue); + const_string = (char *) textout((struct varlena *) const_string); + break; + + default: + elog(WARN, "unknown type %d", CInteger(lfirst(expr))); + } #endif - cp = instr2 (tp, const_string, typlen); - - if (!tbyvalue(tp)) { + cp = instr2(tp, const_string, typlen); + + if (!tbyvalue(tp)) + { /* - if (len >= 0 && len != PSIZE(cp)) { - char *pp; - pp = (char *) palloc(len); - memmove(pp, cp, len); - cp = pp; - } + if (len >= 0 && len != PSIZE(cp)) { + char *pp; + pp = (char *) palloc(len); + memmove(pp, cp, len); + cp = pp; + } */ - lcp = PointerGetDatum(cp); - } else { - switch(len) { - case 1: - lcp = Int8GetDatum(cp); - break; - case 2: - lcp = Int16GetDatum(cp); - break; - case 4: - lcp = Int32GetDatum(cp); - break; - default: - lcp = PointerGetDatum(cp); - break; + lcp = PointerGetDatum(cp); + } + else + { + switch (len) + { + case 1: + lcp = Int8GetDatum(cp); + break; + case 2: + lcp = Int16GetDatum(cp); + break; + case 4: + lcp = Int32GetDatum(cp); + break; + default: + lcp = PointerGetDatum(cp); + break; + } } - } - - adt = makeConst(typeid(tp), - len, - (Datum)lcp , - false, - tbyvalue(tp), - false, /* not a set */ - true /* is cast */); - - if (string_palloced) - pfree(const_string); - - return (Node*)adt; + + adt = makeConst(typeid(tp), + len, + (Datum) lcp, + false, + tbyvalue(tp), + false, /* not a set */ + true /* is cast */ ); + + if (string_palloced) + pfree(const_string); + + return (Node *) adt; } -Node * -parser_typecast2(Node *expr, Oid exprType, Type tp, int typlen) +Node * +parser_typecast2(Node * expr, Oid exprType, Type tp, int typlen) { - /* check for passing non-ints */ - Const *adt; - Datum lcp; - int32 len = tlen(tp); - char *cp = NULL; - - char *const_string = NULL; - bool string_palloced = false; - - Assert(IsA(expr,Const)); - - switch (exprType) { - case 0: /* NULL */ - break; - case INT4OID: /* int4 */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%d", - (int) ((Const*)expr)->constvalue); - break; - case NAMEOID: /* char16 */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%s", - (char*) ((Const*)expr)->constvalue); - break; - case CHAROID: /* char */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%c", - (char) ((Const*)expr)->constvalue); - break; - case FLOAT4OID: /* float4 */ + /* check for passing non-ints */ + Const *adt; + Datum lcp; + int32 len = tlen(tp); + char *cp = NULL; + + char *const_string = NULL; + bool string_palloced = false; + + Assert(IsA(expr, Const)); + + switch (exprType) { - float32 floatVal = - DatumGetFloat32(((Const*)expr)->constvalue); - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%f", *floatVal); - break; + case 0: /* NULL */ + break; + case INT4OID: /* int4 */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%d", + (int) ((Const *) expr)->constvalue); + break; + case NAMEOID: /* char16 */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%s", + (char *) ((Const *) expr)->constvalue); + break; + case CHAROID: /* char */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%c", + (char) ((Const *) expr)->constvalue); + break; + case FLOAT4OID: /* float4 */ + { + float32 floatVal = + DatumGetFloat32(((Const *) expr)->constvalue); + + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%f", *floatVal); + break; + } + case FLOAT8OID: /* float8 */ + { + float64 floatVal = + DatumGetFloat64(((Const *) expr)->constvalue); + + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%f", *floatVal); + break; + } + case CASHOID: /* money */ + const_string = (char *) palloc(256); + string_palloced = true; + sprintf(const_string, "%d", + (long) ((Const *) expr)->constvalue); + break; + case TEXTOID: /* text */ + const_string = + DatumGetPointer(((Const *) expr)->constvalue); + const_string = (char *) textout((struct varlena *) const_string); + break; + case UNKNOWNOID: /* unknown */ + const_string = + DatumGetPointer(((Const *) expr)->constvalue); + const_string = (char *) textout((struct varlena *) const_string); + break; + default: + elog(WARN, "unknown type %u ", exprType); } - case FLOAT8OID:/* float8 */ + + if (!exprType) { - float64 floatVal = - DatumGetFloat64(((Const*)expr)->constvalue); - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%f", *floatVal); - break; + adt = makeConst(typeid(tp), + (Size) 0, + (Datum) NULL, + true, /* isnull */ + false, /* was omitted */ + false, /* not a set */ + true /* is cast */ ); + return ((Node *) adt); } - case CASHOID: /* money */ - const_string = (char *) palloc(256); - string_palloced = true; - sprintf(const_string,"%d", - (long) ((Const*)expr)->constvalue); - break; - case TEXTOID: /* text */ - const_string = - DatumGetPointer(((Const*)expr)->constvalue ); - const_string = (char *) textout((struct varlena *)const_string); - break; - case UNKNOWNOID: /* unknown */ - const_string = - DatumGetPointer(((Const*)expr)->constvalue ); - const_string = (char *) textout((struct varlena *)const_string); - break; - default: - elog(WARN,"unknown type %u ",exprType); - } - - if (!exprType) { - adt = makeConst(typeid(tp), - (Size) 0, - (Datum) NULL, - true, /* isnull */ - false, /* was omitted */ - false, /* not a set */ - true /* is cast */); - return ((Node*) adt); - } - - cp = instr2 (tp, const_string, typlen); - - - if (!tbyvalue(tp)) { + + cp = instr2(tp, const_string, typlen); + + + if (!tbyvalue(tp)) + { /* - if (len >= 0 && len != PSIZE(cp)) { - char *pp; - pp = (char *) palloc(len); - memmove(pp, cp, len); - cp = pp; - } + if (len >= 0 && len != PSIZE(cp)) { + char *pp; + pp = (char *) palloc(len); + memmove(pp, cp, len); + cp = pp; + } */ - lcp = PointerGetDatum(cp); - } else { - switch(len) { - case 1: - lcp = Int8GetDatum(cp); - break; - case 2: - lcp = Int16GetDatum(cp); - break; - case 4: - lcp = Int32GetDatum(cp); - break; - default: - lcp = PointerGetDatum(cp); - break; + lcp = PointerGetDatum(cp); + } + else + { + switch (len) + { + case 1: + lcp = Int8GetDatum(cp); + break; + case 2: + lcp = Int16GetDatum(cp); + break; + case 4: + lcp = Int32GetDatum(cp); + break; + default: + lcp = PointerGetDatum(cp); + break; + } } - } - - adt = makeConst(typeid(tp), - (Size)len, - (Datum)lcp, - false, - false, /*was omitted*/ - false, /* not a set */ - true /* is cast */); - /* - printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) , - len,cp); - */ - if (string_palloced) pfree(const_string); - - return ((Node*) adt); + + adt = makeConst(typeid(tp), + (Size) len, + (Datum) lcp, + false, + false, /* was omitted */ + false, /* not a set */ + true /* is cast */ ); + + /* + * printf("adt %s : %u %d %d\n",CString(expr),typeid(tp) , len,cp); + */ + if (string_palloced) + pfree(const_string); + + return ((Node *) adt); } -Aggreg * -ParseAgg(char *aggname, Oid basetype, Node *target) +Aggreg * +ParseAgg(char *aggname, Oid basetype, Node * target) { - Oid fintype; - Oid vartype; - Oid xfn1; - Form_pg_aggregate aggform; - Aggreg *aggreg; - HeapTuple theAggTuple; - - theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname), - ObjectIdGetDatum(basetype), - 0, 0); - if (!HeapTupleIsValid(theAggTuple)) { - elog(WARN, "aggregate %s does not exist", aggname); - } - - aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple); - fintype = aggform->aggfinaltype; - xfn1 = aggform->aggtransfn1; - - if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr) - elog(WARN, "parser: aggregate can only be applied on an attribute or expression"); - - /* only aggregates with transfn1 need a base type */ - if (OidIsValid(xfn1)) { - basetype = aggform->aggbasetype; - if (nodeTag(target) == T_Var) - vartype = ((Var*)target)->vartype; - else - vartype = ((Expr*)target)->typeOid; - - if (basetype != vartype) { - Type tp1, tp2; - - tp1 = get_id_type(basetype); - tp2 = get_id_type(vartype); - elog(NOTICE, "Aggregate type mismatch:"); - elog(WARN, "%s works on %s, not %s", aggname, - tname(tp1), tname(tp2)); - } - } - - aggreg = makeNode(Aggreg); - aggreg->aggname = pstrdup(aggname); - aggreg->basetype = aggform->aggbasetype; - aggreg->aggtype = fintype; - - aggreg->target = target; - - return aggreg; -} + Oid fintype; + Oid vartype; + Oid xfn1; + Form_pg_aggregate aggform; + Aggreg *aggreg; + HeapTuple theAggTuple; + theAggTuple = SearchSysCacheTuple(AGGNAME, PointerGetDatum(aggname), + ObjectIdGetDatum(basetype), + 0, 0); + if (!HeapTupleIsValid(theAggTuple)) + { + elog(WARN, "aggregate %s does not exist", aggname); + } + + aggform = (Form_pg_aggregate) GETSTRUCT(theAggTuple); + fintype = aggform->aggfinaltype; + xfn1 = aggform->aggtransfn1; + + if (nodeTag(target) != T_Var && nodeTag(target) != T_Expr) + elog(WARN, "parser: aggregate can only be applied on an attribute or expression"); + + /* only aggregates with transfn1 need a base type */ + if (OidIsValid(xfn1)) + { + basetype = aggform->aggbasetype; + if (nodeTag(target) == T_Var) + vartype = ((Var *) target)->vartype; + else + vartype = ((Expr *) target)->typeOid; + + if (basetype != vartype) + { + Type tp1, + tp2; + + tp1 = get_id_type(basetype); + tp2 = get_id_type(vartype); + elog(NOTICE, "Aggregate type mismatch:"); + elog(WARN, "%s works on %s, not %s", aggname, + tname(tp1), tname(tp2)); + } + } + + aggreg = makeNode(Aggreg); + aggreg->aggname = pstrdup(aggname); + aggreg->basetype = aggform->aggbasetype; + aggreg->aggtype = fintype; + + aggreg->target = target; + + return aggreg; +} diff --git a/src/backend/parser/scansup.c b/src/backend/parser/scansup.c index 98bf6dba93b..0b944528980 100644 --- a/src/backend/parser/scansup.c +++ b/src/backend/parser/scansup.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- * * scansup.c-- - * support routines for the lex/flex scanner, used by both the normal + * support routines for the lex/flex scanner, used by both the normal * backend as well as the bootstrap backend * * Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.5 1996/11/15 18:38:55 momjian Exp $ + * $Header: /cvsroot/pgsql/src/backend/parser/scansup.c,v 1.6 1997/09/07 04:44:51 momjian Exp $ * *------------------------------------------------------------------------- */ @@ -24,12 +24,12 @@ #include "parser/scansup.h" /* ---------------- - * scanstr - * + * scanstr + * * if the string passed in has escaped codes, map the escape codes to actual * chars * - * also, remove leading and ending quotes '"' if any + * also, remove leading and ending quotes '"' if any * * the string passed in must be non-null * @@ -38,88 +38,95 @@ * ---------------- */ -char* +char * scanstr(char *s) { - static char newStr[MAX_PARSE_BUFFER]; - int len, i, j; - - if (s == NULL || s[0] == '\0') - return s; + static char newStr[MAX_PARSE_BUFFER]; + int len, + i, + j; - len = strlen(s); + if (s == NULL || s[0] == '\0') + return s; - for (i = 0, j = 0; i < len ; i++) { - if (s[i] == '\'') { - i = i + 1; - if (s[i] == '\'') - newStr[j] = '\''; - } - else { - if (s[i] == '\\') { - i = i + 1; - switch (s[i]) { - case '\\': - newStr[j] = '\\'; - break; - case 'b': - newStr[j] = '\b'; - break; - case 'f': - newStr[j] = '\f'; - break; - case 'n': - newStr[j] = '\n'; - break; - case 'r': - newStr[j] = '\r'; - break; - case 't': - newStr[j] = '\t'; - break; - case '"': - newStr[j] = '"'; - break; - case '\'': - newStr[j] = '\''; - break; - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - { - char octal[4]; - int k; - long octVal; + len = strlen(s); + + for (i = 0, j = 0; i < len; i++) + { + if (s[i] == '\'') + { + i = i + 1; + if (s[i] == '\'') + newStr[j] = '\''; + } + else + { + if (s[i] == '\\') + { + i = i + 1; + switch (s[i]) + { + case '\\': + newStr[j] = '\\'; + break; + case 'b': + newStr[j] = '\b'; + break; + case 'f': + newStr[j] = '\f'; + break; + case 'n': + newStr[j] = '\n'; + break; + case 'r': + newStr[j] = '\r'; + break; + case 't': + newStr[j] = '\t'; + break; + case '"': + newStr[j] = '"'; + break; + case '\'': + newStr[j] = '\''; + break; + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + { + char octal[4]; + int k; + long octVal; - for (k=0; - s[i+k] >= '0' && s[i+k] <= '7' && k < 3; - k++) - octal[k] = s[i+k]; - i += k-1; - octal[3] = '\0'; - - octVal = strtol(octal,0,8); -/* elog (NOTICE, "octal = %s octVal = %d, %od", octal, octVal, octVal);*/ - if (octVal <= 0377) { - newStr[j] = ((char)octVal); - break; - } - } - default: - newStr[j] = s[i]; - } /* switch */ - } /* s[i] == '\\' */ - else - newStr[j] = s[i]; + for (k = 0; + s[i + k] >= '0' && s[i + k] <= '7' && k < 3; + k++) + octal[k] = s[i + k]; + i += k - 1; + octal[3] = '\0'; + + octVal = strtol(octal, 0, 8); +/* elog (NOTICE, "octal = %s octVal = %d, %od", octal, octVal, octVal);*/ + if (octVal <= 0377) + { + newStr[j] = ((char) octVal); + break; + } + } + default: + newStr[j] = s[i]; + } /* switch */ + } /* s[i] == '\\' */ + else + newStr[j] = s[i]; + } + j++; } - j++; - } - newStr[j] = '\0'; - return newStr; + newStr[j] = '\0'; + return newStr; } - diff --git a/src/backend/parser/sysfunc.c b/src/backend/parser/sysfunc.c index fac1b60fd5a..02d6d6b21a7 100644 --- a/src/backend/parser/sysfunc.c +++ b/src/backend/parser/sysfunc.c @@ -1,14 +1,14 @@ /*------------------------------------------------------------------------- - * + * * sysfunc.c-- - * process system functions and return a string result - * + * process system functions and return a string result + * * Notes: * 1) I return a string result because most of the functions cannot return any - * normal type anyway (e.g. SYS_DATE, SYS_TIME, etc...), and the few that - * might (SYS_UID or whatever) can just return it as a string - no problem. - * This keeps the function flexible enough to be of good use. - * + * normal type anyway (e.g. SYS_DATE, SYS_TIME, etc...), and the few that + * might (SYS_UID or whatever) can just return it as a string - no problem. + * This keeps the function flexible enough to be of good use. + * * Written by Chad Robinson, chadr@brttech.com * Last modified: 04/27/1996 * ------------------------------------------------------------------------- @@ -27,39 +27,42 @@ * Can't get much more obvious than this. Might need to replace localtime() * on older systems... */ -static char *Sysfunc_system_date(void) +static char * +Sysfunc_system_date(void) { - time_t cur_time_secs; - struct tm *cur_time_expanded; - static char buf[12]; /* Just for safety, y'understand... */ - + time_t cur_time_secs; + struct tm *cur_time_expanded; + static char buf[12]; /* Just for safety, y'understand... */ + time(&cur_time_secs); cur_time_expanded = localtime(&cur_time_secs); if (EuroDates == 1) sprintf(buf, "%2.2d-%2.2d-%4.4d", cur_time_expanded->tm_mday, - cur_time_expanded->tm_mon+1, cur_time_expanded->tm_year+1900); + cur_time_expanded->tm_mon + 1, cur_time_expanded->tm_year + 1900); else - sprintf(buf, "%2.2d-%2.2d-%4.4d", cur_time_expanded->tm_mon+1, - cur_time_expanded->tm_mday, cur_time_expanded->tm_year+1900); + sprintf(buf, "%2.2d-%2.2d-%4.4d", cur_time_expanded->tm_mon + 1, + cur_time_expanded->tm_mday, cur_time_expanded->tm_year + 1900); return &buf[0]; } -static char *Sysfunc_system_time(void) +static char * +Sysfunc_system_time(void) { - time_t cur_time_secs; - struct tm *cur_time_expanded; - static char buf[10]; /* Just for safety, y'understand... */ - + time_t cur_time_secs; + struct tm *cur_time_expanded; + static char buf[10]; /* Just for safety, y'understand... */ + time(&cur_time_secs); cur_time_expanded = localtime(&cur_time_secs); sprintf(buf, "%2.2d:%2.2d:%2.2d", cur_time_expanded->tm_hour, - cur_time_expanded->tm_min, cur_time_expanded->tm_sec); + cur_time_expanded->tm_min, cur_time_expanded->tm_sec); return &buf[0]; } -char *SystemFunctionHandler(char *funct) +char * +SystemFunctionHandler(char *funct) { if (!strcmp(funct, "SYS_DATE")) return Sysfunc_system_date(); @@ -73,9 +76,11 @@ char *SystemFunctionHandler(char *funct) * Chad's rule of coding #4 - never delete a test function, even a stupid * one - you always need it 10 minutes after you delete it. */ -void main(void) +void +main(void) { printf("Current system date: %s\n", SystemFunctionHandler("SYS_DATE")); return; } + #endif |