*** pgsql/src/backend/catalog/pg_proc.c.orig 2007-11-15 22:14:33.000000000 +0100 --- pgsql/src/backend/catalog/pg_proc.c 2007-11-26 11:23:36.210317000 +0100 *************** *** 33,39 **** #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" ! Datum fmgr_internal_validator(PG_FUNCTION_ARGS); Datum fmgr_c_validator(PG_FUNCTION_ARGS); --- 33,39 ---- #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/syscache.h" ! #include "parser/parse_callback.h" Datum fmgr_internal_validator(PG_FUNCTION_ARGS); Datum fmgr_c_validator(PG_FUNCTION_ARGS); *************** *** 531,536 **** --- 531,537 ---- Datum tmp; char *prosrc; ErrorContextCallback sqlerrcontext; + ParserCallbackContext sqlcallbackcontext; bool haspolyarg; int i; *************** *** 586,591 **** --- 587,599 ---- sqlerrcontext.previous = error_context_stack; error_context_stack = &sqlerrcontext; + /* Attach parser callback handler */ + sqlcallbackcontext.context = T_ParsingFunctionBody; + sqlcallbackcontext.context_arg = (void *)funcoid; + sqlcallbackcontext.callback = sql_parser_callback_handler; + sqlcallbackcontext.previous = parser_callback_context_stack; + parser_callback_context_stack = &sqlcallbackcontext; + /* * We can't do full prechecking of the function definition if there * are any polymorphic input types, because actual datatypes of *************** *** 606,611 **** --- 614,622 ---- else querytree_list = pg_parse_query(prosrc); + /* detach this parser callback handler */ + parser_callback_context_stack = sqlcallbackcontext.previous; + error_context_stack = sqlerrcontext.previous; } *************** *** 614,619 **** --- 625,631 ---- PG_RETURN_VOID(); } + /* * Error context callback for handling errors in SQL function definitions */ *** pgsql/src/backend/executor/functions.c.orig 2007-11-15 22:14:34.000000000 +0100 --- pgsql/src/backend/executor/functions.c 2007-11-26 11:23:36.240359600 +0100 *************** *** 22,27 **** --- 22,28 ---- #include "funcapi.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" + #include "parser/parse_callback.h" #include "tcop/tcopprot.h" #include "tcop/utility.h" #include "utils/builtins.h" *************** *** 30,36 **** #include "utils/syscache.h" #include "utils/typcache.h" - /* * We have an execution_state record for each query in a function. Each * record contains a plantree for its query. If the query is currently in --- 31,36 ---- *************** *** 596,601 **** --- 596,602 ---- MemoryContext oldcontext; SQLFunctionCachePtr fcache; ErrorContextCallback sqlerrcontext; + ParserCallbackContext sqlcallbackcontext; execution_state *es; Datum result = 0; *************** *** 614,619 **** --- 615,627 ---- sqlerrcontext.previous = error_context_stack; error_context_stack = &sqlerrcontext; + /* Attach parser callback handler */ + sqlcallbackcontext.context = T_ParsingFunctionBody; + sqlcallbackcontext.context_arg = (void *)fcinfo->flinfo->fn_oid; + sqlcallbackcontext.callback = sql_parser_callback_handler; + sqlcallbackcontext.previous = parser_callback_context_stack; + parser_callback_context_stack = &sqlcallbackcontext; + /* * Initialize fcache (build plans) if first time through. */ *************** *** 691,696 **** --- 699,707 ---- } } + /* detach this parser callback handler */ + parser_callback_context_stack = sqlcallbackcontext.previous; + error_context_stack = sqlerrcontext.previous; MemoryContextSwitchTo(oldcontext); *************** *** 731,736 **** --- 742,750 ---- } } + /* detach this parser callback handler */ + parser_callback_context_stack = sqlcallbackcontext.previous; + error_context_stack = sqlerrcontext.previous; MemoryContextSwitchTo(oldcontext); *** pgsql/src/backend/optimizer/util/clauses.c.orig 2007-11-22 20:09:23.000000000 +0100 --- pgsql/src/backend/optimizer/util/clauses.c 2007-11-26 11:23:36.280416400 +0100 *************** *** 38,43 **** --- 38,44 ---- #include "parser/parse_clause.h" #include "parser/parse_coerce.h" #include "parser/parse_expr.h" + #include "parser/parse_callback.h" #include "tcop/tcopprot.h" #include "utils/acl.h" #include "utils/builtins.h" *************** *** 2924,2929 **** --- 2925,2931 ---- MemoryContext oldcxt; MemoryContext mycxt; ErrorContextCallback sqlerrcontext; + ParserCallbackContext sqlcallbackcontext; List *raw_parsetree_list; Query *querytree; Node *newexpr; *************** *** 2959,2964 **** --- 2961,2973 ---- sqlerrcontext.previous = error_context_stack; error_context_stack = &sqlerrcontext; + /* Attach parser callback handler */ + sqlcallbackcontext.context = T_ParsingFunctionBody; + sqlcallbackcontext.context_arg = (void *)funcid; + sqlcallbackcontext.callback = sql_parser_callback_handler; + sqlcallbackcontext.previous = parser_callback_context_stack; + parser_callback_context_stack = &sqlcallbackcontext; + /* * Make a temporary memory context, so that we don't leak all the stuff * that parsing might create. *************** *** 3144,3149 **** --- 3153,3161 ---- newexpr = eval_const_expressions_mutator(newexpr, context); context->active_fns = list_delete_first(context->active_fns); + /* detach this parser callback handler */ + parser_callback_context_stack = sqlcallbackcontext.previous; + error_context_stack = sqlerrcontext.previous; return (Expr *) newexpr; *************** *** 3152,3159 **** fail: MemoryContextSwitchTo(oldcxt); MemoryContextDelete(mycxt); - error_context_stack = sqlerrcontext.previous; return NULL; } --- 3164,3174 ---- fail: MemoryContextSwitchTo(oldcxt); MemoryContextDelete(mycxt); + /* detach this parser callback handler */ + parser_callback_context_stack = sqlcallbackcontext.previous; + + error_context_stack = sqlerrcontext.previous; return NULL; } *** pgsql/src/backend/parser/parse_callback.c.orig 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/backend/parser/parse_callback.c 2007-11-28 09:27:07.204611200 +0100 *************** *** 0 **** --- 1,158 ---- + /*------------------------------------------------------------------------- + * + * parse_callback.c + * Mechanisme to create callbacks from inside the parser + * + * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/parser/parse_callback.c $ + * + *------------------------------------------------------------------------- + */ + + #include "postgres.h" + #include "parser/parse_node.h" + #include "parser/parse_callback.h" + #include "utils/lsyscache.h" + #include "utils/syscache.h" + #include "funcapi.h" + #include "parser/parse_expr.h" + #include "nodes/parsenodes.h" + + /* global parser callback handler context stack */ + ParserCallbackContext *parser_callback_context_stack = NULL; + + /* This function can be called from various places within + * the parser to handle custom/language-specific actions. + * For example: The handling of referenced function parameters by name. + */ + void parser_do_callback(ParserCallbackActionTag action, void *args) + { + ParserCallbackContext *ctx; + + ctx = parser_callback_context_stack; + if(ctx != NULL) + { + ctx->action = action; + (*ctx->callback) (args); + } + } + + /* this is a helper function to avoid some redundatcy for + * function parameter refnames error messages + * 1 for parameter name not found. + */ + void invalid_function_paramref_error(int errortype,ParseState *pstate, int plocation,char* name1,char* name2) + { + char *proname; + + proname = get_func_name((Oid)parser_callback_context_stack->context_arg); + if(errortype == 1) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION_PARAMETER_NAME), + errmsg("there is no parameter %s defined for function %s", + name1,proname),parser_errposition(pstate, plocation))); + } + else if(errortype == 2) + { + ereport(ERROR, + (errcode(ERRCODE_UNDEFINED_FUNCTION_PARAMETER_NAME), + errmsg("there is no parameter %s.%s defined for function %s or this \n is an invalid reference to FROM-clause entry for table \"%s\"", + name1,name2,proname,name1),parser_errposition(pstate, plocation))); + } + } + + /* Handler for parser callback. this function processes: + * 1. SQL-language parameters referenced by name + */ + void + sql_parser_callback_handler(void *args) + { + Oid funcoid; + HeapTuple tuple; + int numargs; + int i; + int numNodeNames; + Oid *argtypes; + char **argnames; + char *argmodes; + char *name; + char *proname; + Node *node = NULL; + ParserCallbackColumnRefArgs *crefArgs; + ParserCallbackContext *currentctx = parser_callback_context_stack; + + if(currentctx->context == T_ParsingFunctionBody) + { + funcoid = (Oid)currentctx->context_arg; + tuple = SearchSysCache(PROCOID, + ObjectIdGetDatum(funcoid), + 0, 0, 0); + + switch(currentctx->action) + { + case A_ResolveAmbigColumnRef: + crefArgs = (ParserCallbackColumnRefArgs*)args; + crefArgs->result = NULL; + crefArgs->is_funcname_ambiguous = false; + crefArgs->is_invalid_parameter_name = false; + + proname = get_func_name(funcoid); + + numargs = get_func_arg_info(tuple, + &argtypes, &argnames, &argmodes); + + /* numNodeNames contains the ColumnRef information that the + * parser is trying to resolve. + * either a single value or identifier.identifier */ + numNodeNames = list_length(crefArgs->cref->fields); + + /* validating this function's name from identifier.identifier */ + if(numNodeNames == 2) + { + /* first field */ + name = strVal(linitial(crefArgs->cref->fields)); + + /* break if the first field is not equal to this function's name */ + if(strcmp(name,proname) != 0) + { + crefArgs->is_funcname_ambiguous = true; + break; + } + else + { + /* continue resolving with second item in cref*/ + name = strVal(lsecond(crefArgs->cref->fields)); + } + } + else + { + name = strVal(linitial(crefArgs->cref->fields)); + } + + for(i = 0; i < numargs; i++) + { + if(strcmp(argnames[i],name) == 0) + { + ParamRef pref; + pref.type = T_ParamRef; + pref.number = i+1; + node = transformExpr(crefArgs->pstate,(Node *)&pref); + crefArgs->result = node; + break; + } + } + + if(node == NULL) + crefArgs->is_invalid_parameter_name = true; + + break; /* A_ResolveAmbigColumnRef */ + } + + ReleaseSysCache(tuple); + } + } *** pgsql/src/backend/parser/parse_expr.c.orig 2007-11-15 23:25:15.000000000 +0100 --- pgsql/src/backend/parser/parse_expr.c 2007-11-28 09:29:27.516369600 +0100 *************** *** 31,36 **** --- 31,37 ---- #include "parser/parse_relation.h" #include "parser/parse_target.h" #include "parser/parse_type.h" + #include "parser/parse_callback.h" #include "utils/builtins.h" #include "utils/lsyscache.h" #include "utils/xml.h" *************** *** 62,68 **** static Node *transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, ! char *relname, int location); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); static Node *typecast_expression(ParseState *pstate, Node *expr, --- 63,70 ---- static Node *transformCurrentOfExpr(ParseState *pstate, CurrentOfExpr *cexpr); static Node *transformColumnRef(ParseState *pstate, ColumnRef *cref); static Node *transformWholeRowRef(ParseState *pstate, char *schemaname, ! char *relname, int location, ! bool skip_error); static Node *transformIndirection(ParseState *pstate, Node *basenode, List *indirection); static Node *typecast_expression(ParseState *pstate, Node *expr, *************** *** 354,362 **** * The allowed syntaxes are: * * A First try to resolve as unqualified column name; ! * if no luck, try to resolve as unqualified table name (A.*). * A.B A is an unqualified table name; B is either a * column or function name (trying column name first). * A.B.C schema A, table B, col or func name C. * A.B.C.D catalog A, schema B, table C, col or func D. * A.* A is an unqualified table name; means whole-row value. --- 356,368 ---- * The allowed syntaxes are: * * A First try to resolve as unqualified column name; ! * if no luck, try to resolve as unqualified table name (A.*); ! * if no lock and when parsing a function try resolve as a ! * refference to argument name. * A.B A is an unqualified table name; B is either a * column or function name (trying column name first). + * or when parsing function A can be function name + * and B is a refference to parameter * A.B.C schema A, table B, col or func name C. * A.B.C.D catalog A, schema B, table C, col or func D. * A.* A is an unqualified table name; means whole-row value. *************** *** 410,423 **** */ if (refnameRangeTblEntry(pstate, NULL, name, &levels_up) != NULL) node = transformWholeRowRef(pstate, NULL, name, ! cref->location); else ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", name), parser_errposition(pstate, cref->location))); } break; } --- 416,454 ---- */ if (refnameRangeTblEntry(pstate, NULL, name, &levels_up) != NULL) + { node = transformWholeRowRef(pstate, NULL, name, ! cref->location,false); ! } else + { + /* if we are in context of parsing or a function + * we make a final attempt to resolve this as column name ref */ + if(parser_callback_context_stack != NULL && + parser_callback_context_stack->context + == T_ParsingFunctionBody) + { + ParserCallbackColumnRefArgs crefArgs; + crefArgs.pstate = pstate; + crefArgs.cref = cref; + parser_do_callback(A_ResolveAmbigColumnRef,&crefArgs); + node = crefArgs.result; + + /* generate error if the parameter name is not found */ + if(crefArgs.is_invalid_parameter_name) + invalid_function_paramref_error(1,pstate,cref->location,name,NULL); + + } + } + + if(node == NULL) + { ereport(ERROR, (errcode(ERRCODE_UNDEFINED_COLUMN), errmsg("column \"%s\" does not exist", name), parser_errposition(pstate, cref->location))); + } } break; } *************** *** 425,442 **** { char *name1 = strVal(linitial(cref->fields)); char *name2 = strVal(lsecond(cref->fields)); /* Whole-row reference? */ if (strcmp(name2, "*") == 0) { node = transformWholeRowRef(pstate, NULL, name1, ! cref->location); break; } /* Try to identify as a once-qualified column */ ! node = qualifiedNameToVar(pstate, NULL, name1, name2, true, ! cref->location); if (node == NULL) { /* --- 456,526 ---- { char *name1 = strVal(linitial(cref->fields)); char *name2 = strVal(lsecond(cref->fields)); + ParserCallbackColumnRefArgs crefArgs; /* Whole-row reference? */ if (strcmp(name2, "*") == 0) { node = transformWholeRowRef(pstate, NULL, name1, ! cref->location,false); break; } + /* if we are in context of parsing a function */ + if(parser_callback_context_stack != NULL && + parser_callback_context_stack->context == T_ParsingFunctionBody) + { + node = qualifiedNameToVar(pstate, NULL, name1, name2, + true,cref->location,true); + + if(node == NULL) + { + /* we go for ParseFuncOrColumn */ + node = transformWholeRowRef(pstate, NULL, name1, + cref->location,true); + + /* normally the method above with skip_error false + * would return a valid node (or stop with an error), + * in this case when the node is null then there + * is not need to check it as FuncOrColumn */ + if(node != NULL) + { + node = ParseFuncOrColumn(pstate, + list_make1(makeString(name2)), + list_make1(node), + false, false, true, + cref->location); + break; + } + + /* reaching this point means refname (name1) does not exist + * as table alias or any kind of RTE. So we do a final match + * for function.parameter */ + crefArgs.pstate = pstate; + crefArgs.cref = cref; + parser_do_callback(A_ResolveAmbigColumnRef,&crefArgs); + node = crefArgs.result; + + /* generate error if the parameter name is not found */ + if(crefArgs.is_invalid_parameter_name) + invalid_function_paramref_error(1,pstate,cref->location,name2,NULL); + + /* at this point either relname is invalid of relname is not the + * name of this function */ + if(crefArgs.is_funcname_ambiguous) + invalid_function_paramref_error(2,pstate,cref->location,name1,name2); } + else + { + break; + } + } + else + node = NULL; + /* Try to identify as a once-qualified column */ ! if(node == NULL) ! node = qualifiedNameToVar(pstate, NULL, name1, name2, true, ! cref->location,false); if (node == NULL) { /* *************** *** 445,451 **** * implicit RTE for tables not already entered. */ node = transformWholeRowRef(pstate, NULL, name1, ! cref->location); node = ParseFuncOrColumn(pstate, list_make1(makeString(name2)), list_make1(node), --- 529,535 ---- * implicit RTE for tables not already entered. */ node = transformWholeRowRef(pstate, NULL, name1, ! cref->location,false); node = ParseFuncOrColumn(pstate, list_make1(makeString(name2)), list_make1(node), *************** *** 464,481 **** if (strcmp(name3, "*") == 0) { node = transformWholeRowRef(pstate, name1, name2, ! cref->location); break; } /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name1, name2, name3, true, ! cref->location); if (node == NULL) { /* Try it as a function call */ node = transformWholeRowRef(pstate, name1, name2, ! cref->location); node = ParseFuncOrColumn(pstate, list_make1(makeString(name3)), list_make1(node), --- 548,565 ---- if (strcmp(name3, "*") == 0) { node = transformWholeRowRef(pstate, name1, name2, ! cref->location,false); break; } /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name1, name2, name3, true, ! cref->location,false); if (node == NULL) { /* Try it as a function call */ node = transformWholeRowRef(pstate, name1, name2, ! cref->location,false); node = ParseFuncOrColumn(pstate, list_make1(makeString(name3)), list_make1(node), *************** *** 505,522 **** if (strcmp(name4, "*") == 0) { node = transformWholeRowRef(pstate, name2, name3, ! cref->location); break; } /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name2, name3, name4, true, ! cref->location); if (node == NULL) { /* Try it as a function call */ node = transformWholeRowRef(pstate, name2, name3, ! cref->location); node = ParseFuncOrColumn(pstate, list_make1(makeString(name4)), list_make1(node), --- 589,606 ---- if (strcmp(name4, "*") == 0) { node = transformWholeRowRef(pstate, name2, name3, ! cref->location,false); break; } /* Try to identify as a twice-qualified column */ node = qualifiedNameToVar(pstate, name2, name3, name4, true, ! cref->location,false); if (node == NULL) { /* Try it as a function call */ node = transformWholeRowRef(pstate, name2, name3, ! cref->location,false); node = ParseFuncOrColumn(pstate, list_make1(makeString(name4)), list_make1(node), *************** *** 1655,1667 **** */ static Node * transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, ! int location) { Node *result; RangeTblEntry *rte; int vnum; int sublevels_up; Oid toid; /* Look up the referenced RTE, creating it if needed */ --- 1739,1752 ---- */ static Node * transformWholeRowRef(ParseState *pstate, char *schemaname, char *relname, ! int location,bool skip_error) { Node *result; RangeTblEntry *rte; int vnum; int sublevels_up; Oid toid; + int skiped_sqlerrorcode; /* Look up the referenced RTE, creating it if needed */ *************** *** 1670,1676 **** if (rte == NULL) rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname), ! location); vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); --- 1755,1764 ---- if (rte == NULL) rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname), ! location,skip_error,&skiped_sqlerrorcode); ! ! if(!rte & skip_error && skiped_sqlerrorcode != 0) ! return NULL; vnum = RTERangeTablePosn(pstate, rte, &sublevels_up); *** pgsql/src/backend/parser/parse_relation.c.orig 2007-11-11 20:22:49.000000000 +0100 --- pgsql/src/backend/parser/parse_relation.c 2007-11-27 12:53:10.926588800 +0100 *************** *** 48,54 **** List **colnames, List **colvars); static int specialAttNum(const char *attname); static void warnAutoRange(ParseState *pstate, RangeVar *relation, ! int location); /* --- 48,54 ---- List **colnames, List **colvars); static int specialAttNum(const char *attname); static void warnAutoRange(ParseState *pstate, RangeVar *relation, ! int location,bool skip_error,int *skiped_sqlerrorcode); /* *************** *** 460,469 **** char *refname, char *colname, bool implicitRTEOK, ! int location) { RangeTblEntry *rte; int sublevels_up; rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up); --- 460,471 ---- char *refname, char *colname, bool implicitRTEOK, ! int location, ! bool skip_error) { RangeTblEntry *rte; int sublevels_up; + int skiped_sqlerrorcode; rte = refnameRangeTblEntry(pstate, schemaname, refname, &sublevels_up); *************** *** 472,480 **** if (!implicitRTEOK) return NULL; rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname), ! location); } return scanRTEForColumn(pstate, rte, colname, location); } --- 474,487 ---- if (!implicitRTEOK) return NULL; rte = addImplicitRTE(pstate, makeRangeVar(schemaname, refname), ! location, ! skip_error, ! &skiped_sqlerrorcode); } + if(!rte & skip_error && skiped_sqlerrorcode != 0) + return NULL; + return scanRTEForColumn(pstate, rte, colname, location); } *************** *** 1139,1150 **** * a conflicting name. */ RangeTblEntry * ! addImplicitRTE(ParseState *pstate, RangeVar *relation, int location) { RangeTblEntry *rte; /* issue warning or error as needed */ ! warnAutoRange(pstate, relation, location); /* * Note that we set inFromCl true, so that the RTE will be listed --- 1146,1160 ---- * a conflicting name. */ RangeTblEntry * ! addImplicitRTE(ParseState *pstate, RangeVar *relation, int location,bool skip_error,int *skiped_sqlerrorcode) { RangeTblEntry *rte; /* issue warning or error as needed */ ! warnAutoRange(pstate, relation, location,skip_error,skiped_sqlerrorcode); ! ! if(skip_error && *skiped_sqlerrorcode != 0) ! return NULL; /* * Note that we set inFromCl true, so that the RTE will be listed *************** *** 1955,1966 **** * a warning. */ static void ! warnAutoRange(ParseState *pstate, RangeVar *relation, int location) { RangeTblEntry *rte; int sublevels_up; const char *badAlias = NULL; /* * Check to see if there are any potential matches in the query's * rangetable. This affects the message we provide. --- 1965,1981 ---- * a warning. */ static void ! warnAutoRange(ParseState *pstate, RangeVar *relation, int location, ! bool skip_error,int *skiped_sqlerrorcode) { RangeTblEntry *rte; int sublevels_up; const char *badAlias = NULL; + /* initializing if possible*/ + if(skip_error) + *skiped_sqlerrorcode = 0; + /* * Check to see if there are any potential matches in the query's * rangetable. This affects the message we provide. *************** *** 1983,1988 **** --- 1998,2009 ---- &sublevels_up) == rte) badAlias = rte->eref->aliasname; + if(!rte && skip_error) + { + *skiped_sqlerrorcode = ERRCODE_UNDEFINED_TABLE; + return; + } + if (!add_missing_from) { if (rte) *** pgsql/src/backend/parser/parse_target.c.orig 2007-11-15 22:14:37.000000000 +0100 --- pgsql/src/backend/parser/parse_target.c 2007-11-26 11:23:36.400586800 +0100 *************** *** 890,896 **** &sublevels_up); if (rte == NULL) rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname), ! cref->location); /* Require read access --- see comments in setTargetTable() */ rte->requiredPerms |= ACL_SELECT; --- 890,896 ---- &sublevels_up); if (rte == NULL) rte = addImplicitRTE(pstate, makeRangeVar(schemaname, relname), ! cref->location,false,NULL); /* Require read access --- see comments in setTargetTable() */ rte->requiredPerms |= ACL_SELECT; *** pgsql/src/backend/parser/Makefile.orig 2007-06-24 00:12:51.000000000 +0200 --- pgsql/src/backend/parser/Makefile 2007-11-26 11:23:36.430629400 +0100 *************** *** 14,20 **** OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \ parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \ ! parse_type.o parse_coerce.o parse_target.o parse_utilcmd.o scansup.o FLEXFLAGS = -CF --- 14,21 ---- OBJS= analyze.o gram.o keywords.o parser.o parse_agg.o parse_clause.o \ parse_expr.o parse_func.o parse_node.o parse_oper.o parse_relation.o \ ! parse_type.o parse_coerce.o parse_target.o parse_utilcmd.o scansup.o \ ! parse_callback.o FLEXFLAGS = -CF *** pgsql/src/include/parser/parse_callback.h.orig 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/include/parser/parse_callback.h 2007-11-26 13:09:15.980024600 +0100 *************** *** 0 **** --- 1,68 ---- + /*------------------------------------------------------------------------- + * + * parse_callback.h + * Definitions for the parser callback mechanism + * + * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group + * Portions Copyright (c) 1994, Regents of the University of California + * + * + * IDENTIFICATION + * $PostgreSQL: pgsql/src/backend/parser/parse_callback.h $ + * + *------------------------------------------------------------------------- + */ + + /* provides information to callback handler function to determine + * in wat context whis callback is called. + */ + typedef enum ParserCallbackContextTag + { + T_ParsingFunctionBody = 1 + } ParserCallbackContextTag; + + /* Action types that is passed to the callback handler. */ + typedef enum ParserCallbackActionTag + { + A_ResolveAmbigColumnRef = 1 + } ParserCallbackActionTag; + + /* Support for handling callbacks from within the parser to + * external functions. + */ + typedef struct ParserCallbackContext + { + /* provides information about the this callback context */ + ParserCallbackContextTag context; + + /* What to do in callback handler function */ + ParserCallbackActionTag action; + + /* previous callback context */ + struct ParserCallbackContext *previous; + + /* handler to be called for in this context */ + void (*callback) (void *callback_arguments); + + /* global argument set when a handler is setup */ + void *context_arg; + } ParserCallbackContext; + + /* Support for passing ColumnRef data from within parser + * to callback handler function */ + typedef struct ParserCallbackColumnRefArgs + { + ParseState *pstate; /* parser state */ + ColumnRef *cref; /* current ColumnRef that is being processed in parser */ + Node *result; /* the result of callback handler function */ + bool is_funcname_ambiguous; + bool is_invalid_parameter_name; + } ParserCallbackColumnRefArgs; + + /* global callback handler */ + extern PGDLLIMPORT ParserCallbackContext *parser_callback_context_stack; + extern void parser_do_callback(ParserCallbackActionTag action, void *args); + extern void sql_parser_callback_handler(void *args); + extern void invalid_function_paramref_error(int error,ParseState *pstate, int plocation, + char* name1,char* name2); + *** pgsql/src/include/parser/parse_relation.h.orig 2007-01-05 23:19:57.000000000 +0100 --- pgsql/src/include/parser/parse_relation.h 2007-11-27 12:47:41.452828800 +0100 *************** *** 39,45 **** char *refname, char *colname, bool implicitRTEOK, ! int location); extern RangeTblEntry *addRangeTableEntry(ParseState *pstate, RangeVar *relation, Alias *alias, --- 39,46 ---- char *refname, char *colname, bool implicitRTEOK, ! int location, ! bool skip_error); extern RangeTblEntry *addRangeTableEntry(ParseState *pstate, RangeVar *relation, Alias *alias, *************** *** 73,79 **** bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace); extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation, ! int location); extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, bool include_dropped, List **colnames, List **colvars); --- 74,82 ---- bool addToJoinList, bool addToRelNameSpace, bool addToVarNameSpace); extern RangeTblEntry *addImplicitRTE(ParseState *pstate, RangeVar *relation, ! int location, ! bool skip_error, ! int *skiped_sqlerrorcode); extern void expandRTE(RangeTblEntry *rte, int rtindex, int sublevels_up, bool include_dropped, List **colnames, List **colvars); *** pgsql/src/include/utils/errcodes.h.orig 2007-02-03 15:06:56.000000000 +0100 --- pgsql/src/include/utils/errcodes.h 2007-11-26 11:23:36.490714600 +0100 *************** *** 293,298 **** --- 293,299 ---- #define ERRCODE_INVALID_SCHEMA_DEFINITION MAKE_SQLSTATE('4','2', 'P','1','5') #define ERRCODE_INVALID_TABLE_DEFINITION MAKE_SQLSTATE('4','2', 'P','1','6') #define ERRCODE_INVALID_OBJECT_DEFINITION MAKE_SQLSTATE('4','2', 'P','1','7') + #define ERRCODE_UNDEFINED_FUNCTION_PARAMETER_NAME MAKE_SQLSTATE('4','2', 'P','1','8') /* Class 44 - WITH CHECK OPTION Violation */ #define ERRCODE_WITH_CHECK_OPTION_VIOLATION MAKE_SQLSTATE('4','4', '0','0','0') *** pgsql/src/test/regress/serial_schedule.orig 2007-11-24 21:41:35.000000000 +0100 --- pgsql/src/test/regress/serial_schedule 2007-11-26 11:23:36.520757200 +0100 *************** *** 115,117 **** --- 115,118 ---- test: xml test: stats test: tablespace + test: func_paramname_ref *** pgsql/src/test/regress/parallel_schedule.orig 2007-11-24 20:49:23.000000000 +0100 --- pgsql/src/test/regress/parallel_schedule 2007-11-26 11:23:36.540785600 +0100 *************** *** 69,75 **** # ---------- # Another group of parallel tests # ---------- ! test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete test: privileges test: misc --- 69,75 ---- # ---------- # Another group of parallel tests # ---------- ! test: select_into select_distinct select_distinct_on select_implicit select_having subselect union case join aggregates transactions random portals arrays btree_index hash_index update namespace prepared_xacts delete func_paramname_ref test: privileges test: misc *** pgsql/src/test/regress/expected/func_paramname_ref.out.orig 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/test/regress/expected/func_paramname_ref.out 2007-11-27 11:07:55.325200000 +0100 *************** *** 0 **** --- 1,248 ---- + CREATE TABLE tbl1(id serial,field1 integer,field2 varchar); + NOTICE: CREATE TABLE will create implicit sequence "tbl1_id_seq" for serial column "tbl1.id" + INSERT INTO tbl1 (field1,field2) VALUES (1,'===='); + INSERT INTO tbl1 (field1,field2) VALUES (2,'++++'); + INSERT INTO tbl1 (field1,field2) VALUES (3,'))))'); + INSERT INTO tbl1 (field1,field2) VALUES (4,'(((('); + -- TEST GROUP 1 + -- test single parameter + CREATE FUNCTION ftest1(param1 integer) RETURNS integer AS + $$ + SELECT param1 * 2; + $$ + LANGUAGE SQL; + -- test func.param parameter with function name + CREATE FUNCTION ftest2(param1 integer) RETURNS integer AS + $$ + SELECT ftest2.param1 * 2; + $$ + LANGUAGE SQL; + -- test function in function parameter with function name + CREATE FUNCTION ftest3(param1 integer) RETURNS integer AS + $$ + SELECT ftest3.param1 + ftest2(2); + $$ + LANGUAGE SQL; + -- testing functions above + SELECT ftest1(2); + ftest1 + -------- + 4 + (1 row) + + SELECT ftest2(4); + ftest2 + -------- + 8 + (1 row) + + SELECT ftest3(2); + ftest3 + -------- + 6 + (1 row) + + -- TEST GROUP 2 + CREATE FUNCTION ftest4(param1 varchar) RETURNS SETOF record AS + $$ + SELECT *,param1 FROM tbl1; + $$ + LANGUAGE SQL; + CREATE FUNCTION ftest5(param1 varchar) RETURNS SETOF record AS + $$ + SELECT *,param1 FROM tbl1; + $$ + LANGUAGE SQL; + CREATE FUNCTION ftest6(param1 varchar) RETURNS SETOF record AS + $$ + SELECT *,ftest6.param1 FROM tbl1; + $$ + LANGUAGE SQL; + CREATE FUNCTION ftest7(param1 varchar) RETURNS SETOF record AS + $$ + SELECT tbl1.field1 || ' ' || ftest7.param1 FROM tbl1; + $$ + LANGUAGE SQL; + CREATE FUNCTION ftest8(param1 integer,param2 varchar) RETURNS SETOF record AS + $$ + SELECT + a.field1, + ftest8.param1, + ftest8.param2, + param1, + param2 + FROM + tbl1 a + WHERE + a.field1 = ftest8.param1 OR + a.field2 = param2; + $$ + LANGUAGE SQL; + CREATE FUNCTION ftest9(field1 varchar) RETURNS SETOF record AS + $$ + SELECT tbl1.field1 || ' ' || ftest9.field1 FROM tbl1; + $$ + LANGUAGE SQL; + -- should return tbl1 fields only + CREATE FUNCTION ftest10(field1 varchar) RETURNS SETOF record AS + $$ + SELECT tbl1.field1 || ' ' || field1 FROM tbl1; + $$ + LANGUAGE SQL; + CREATE FUNCTION ftest11(field1 integer,field2 varchar) RETURNS SETOF record AS + $$ + SELECT + a.field1, + a.field2, + b.field1, + b.field2, + ftest11.field1, + ftest11.field2, + c.* + + FROM + tbl1 a + INNER JOIN tbl1 b on a.field1 = b.field1 + INNER JOIN (select ftest11.field1,field2) c on a.field1 = c.field1; + $$ + LANGUAGE SQL; + -- testing functions above + SELECT ftest4('aaaa'); + ftest4 + ------------------- + (1,1,====,aaaa) + (2,2,++++,aaaa) + (3,3,"))))",aaaa) + (4,4,"((((",aaaa) + (4 rows) + + SELECT ftest5('bbbb'); + ftest5 + ------------------- + (1,1,====,bbbb) + (2,2,++++,bbbb) + (3,3,"))))",bbbb) + (4,4,"((((",bbbb) + (4 rows) + + SELECT ftest6('cccc'); + ftest6 + ------------------- + (1,1,====,cccc) + (2,2,++++,cccc) + (3,3,"))))",cccc) + (4,4,"((((",cccc) + (4 rows) + + SELECT ftest7('dddd'); + ftest7 + ------------ + ("1 dddd") + ("2 dddd") + ("3 dddd") + ("4 dddd") + (4 rows) + + SELECT ftest8(2,'(((('); + ftest8 + ----------------------- + (2,2,"((((",2,"((((") + (4,2,"((((",2,"((((") + (2 rows) + + SELECT ftest9('foo'); + ftest9 + ----------- + ("1 foo") + ("2 foo") + ("3 foo") + ("4 foo") + (4 rows) + + SELECT ftest10('foo'); + ftest10 + --------- + ("1 1") + ("2 2") + ("3 3") + ("4 4") + (4 rows) + + SELECT ftest11(2,'foo'); + ftest11 + ----------------------------- + (2,++++,2,++++,2,foo,2,foo) + (1 row) + + -- TEST GROUP 3 (COMPUTED COLUMN) + CREATE TABLE empl (name text,salary numeric,age integer); + INSERT INTO empl(name,salary,age) VALUES ('A. Manager',100,55); + INSERT INTO empl(name,salary,age) VALUES ('B. Developer',300,30); + CREATE FUNCTION double_salary(employee empl) RETURNS numeric AS $$ + SELECT (employee).salary * 2 AS salary; + $$ LANGUAGE SQL; + SELECT name, double_salary(empl.*) AS dream FROM empl; + name | dream + --------------+------- + A. Manager | 200 + B. Developer | 600 + (2 rows) + + -- ERRORS + CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS + $$ + SELECT param2 * 2; + $$ + LANGUAGE SQL; + ERROR: there is no parameter param2 defined for function ftest_error + LINE 3: SELECT param2 * 2; + ^ + CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS + $$ + SELECT ftest_error.param2 * 2; + $$ + LANGUAGE SQL; + ERROR: there is no parameter param2 defined for function ftest_error + LINE 3: SELECT ftest_error.param2 * 2; + ^ + CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS + $$ + SELECT ftest_error_zz.param1 * 2; + $$ + LANGUAGE SQL; + ERROR: there is no parameter ftest_error_zz.param1 defined for function ftest_error or this + is an invalid reference to FROM-clause entry for table "ftest_error_zz" + LINE 3: SELECT ftest_error_zz.param1 * 2; + ^ + CREATE FUNCTION ftest_error(param1 integer,param2 varchar) RETURNS SETOF record AS + $$ + SELECT + a.field1, + ftest_error.param1, + ftest_error.param2 + FROM + tbl1 a + WHERE + a.field1 = ftest_error_zz.param1 OR + a.field2 = param2; + $$ + LANGUAGE SQL; + ERROR: there is no parameter ftest_error_zz.param1 defined for function ftest_error or this + is an invalid reference to FROM-clause entry for table "ftest_error_zz" + LINE 10: a.field1 = ftest_error_zz.param1 OR + ^ + --- cleanup + DROP FUNCTION double_salary(empl); + DROP FUNCTION ftest11(integer,varchar); + DROP FUNCTION ftest10(varchar); + DROP FUNCTION ftest9(varchar); + DROP FUNCTION ftest8(integer,varchar); + DROP FUNCTION ftest7(varchar); + DROP FUNCTION ftest6(varchar); + DROP FUNCTION ftest5(varchar); + DROP FUNCTION ftest4(varchar); + DROP FUNCTION ftest3(integer); + DROP FUNCTION ftest2(integer); + DROP FUNCTION ftest1(integer); + DROP TABLE tbl1; + DROP TABLE empl; \ No newline at end of file *** pgsql/src/test/regress/sql/func_paramname_ref.sql.orig 1970-01-01 01:00:00.000000000 +0100 --- pgsql/src/test/regress/sql/func_paramname_ref.sql 2007-11-27 10:36:46.548030400 +0100 *************** *** 0 **** --- 1,189 ---- + CREATE TABLE tbl1(id serial,field1 integer,field2 varchar); + INSERT INTO tbl1 (field1,field2) VALUES (1,'===='); + INSERT INTO tbl1 (field1,field2) VALUES (2,'++++'); + INSERT INTO tbl1 (field1,field2) VALUES (3,'))))'); + INSERT INTO tbl1 (field1,field2) VALUES (4,'(((('); + + + + -- TEST GROUP 1 + -- test single parameter + CREATE FUNCTION ftest1(param1 integer) RETURNS integer AS + $$ + SELECT param1 * 2; + $$ + LANGUAGE SQL; + + -- test func.param parameter with function name + CREATE FUNCTION ftest2(param1 integer) RETURNS integer AS + $$ + SELECT ftest2.param1 * 2; + $$ + LANGUAGE SQL; + + + -- test function in function parameter with function name + CREATE FUNCTION ftest3(param1 integer) RETURNS integer AS + $$ + SELECT ftest3.param1 + ftest2(2); + $$ + LANGUAGE SQL; + + -- testing functions above + + SELECT ftest1(2); + SELECT ftest2(4); + SELECT ftest3(2); + + + -- TEST GROUP 2 + + CREATE FUNCTION ftest4(param1 varchar) RETURNS SETOF record AS + $$ + SELECT *,param1 FROM tbl1; + $$ + LANGUAGE SQL; + + CREATE FUNCTION ftest5(param1 varchar) RETURNS SETOF record AS + $$ + SELECT *,param1 FROM tbl1; + $$ + LANGUAGE SQL; + + + CREATE FUNCTION ftest6(param1 varchar) RETURNS SETOF record AS + $$ + SELECT *,ftest6.param1 FROM tbl1; + $$ + LANGUAGE SQL; + + CREATE FUNCTION ftest7(param1 varchar) RETURNS SETOF record AS + $$ + SELECT tbl1.field1 || ' ' || ftest7.param1 FROM tbl1; + $$ + LANGUAGE SQL; + + CREATE FUNCTION ftest8(param1 integer,param2 varchar) RETURNS SETOF record AS + $$ + SELECT + a.field1, + ftest8.param1, + ftest8.param2, + param1, + param2 + FROM + tbl1 a + WHERE + a.field1 = ftest8.param1 OR + a.field2 = param2; + $$ + LANGUAGE SQL; + + + CREATE FUNCTION ftest9(field1 varchar) RETURNS SETOF record AS + $$ + SELECT tbl1.field1 || ' ' || ftest9.field1 FROM tbl1; + $$ + LANGUAGE SQL; + + -- should return tbl1 fields only + CREATE FUNCTION ftest10(field1 varchar) RETURNS SETOF record AS + $$ + SELECT tbl1.field1 || ' ' || field1 FROM tbl1; + $$ + LANGUAGE SQL; + + + CREATE FUNCTION ftest11(field1 integer,field2 varchar) RETURNS SETOF record AS + $$ + SELECT + a.field1, + a.field2, + b.field1, + b.field2, + ftest11.field1, + ftest11.field2, + c.* + + FROM + tbl1 a + INNER JOIN tbl1 b on a.field1 = b.field1 + INNER JOIN (select ftest11.field1,field2) c on a.field1 = c.field1; + $$ + LANGUAGE SQL; + + -- testing functions above + + SELECT ftest4('aaaa'); + SELECT ftest5('bbbb'); + SELECT ftest6('cccc'); + SELECT ftest7('dddd'); + SELECT ftest8(2,'(((('); + SELECT ftest9('foo'); + SELECT ftest10('foo'); + SELECT ftest11(2,'foo'); + + + -- TEST GROUP 3 (COMPUTED COLUMN) + + CREATE TABLE empl (name text,salary numeric,age integer); + INSERT INTO empl(name,salary,age) VALUES ('A. Manager',100,55); + INSERT INTO empl(name,salary,age) VALUES ('B. Developer',300,30); + + CREATE FUNCTION double_salary(employee empl) RETURNS numeric AS $$ + SELECT (employee).salary * 2 AS salary; + $$ LANGUAGE SQL; + + SELECT name, double_salary(empl.*) AS dream FROM empl; + + -- ERRORS + + CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS + $$ + SELECT param2 * 2; + $$ + LANGUAGE SQL; + + CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS + $$ + SELECT ftest_error.param2 * 2; + $$ + LANGUAGE SQL; + + CREATE FUNCTION ftest_error(param1 integer) RETURNS integer AS + $$ + SELECT ftest_error_zz.param1 * 2; + $$ + LANGUAGE SQL; + + CREATE FUNCTION ftest_error(param1 integer,param2 varchar) RETURNS SETOF record AS + $$ + SELECT + a.field1, + ftest_error.param1, + ftest_error.param2 + FROM + tbl1 a + WHERE + a.field1 = ftest_error_zz.param1 OR + a.field2 = param2; + $$ + LANGUAGE SQL; + + --- cleanup + DROP FUNCTION double_salary(empl); + DROP FUNCTION ftest11(integer,varchar); + DROP FUNCTION ftest10(varchar); + DROP FUNCTION ftest9(varchar); + DROP FUNCTION ftest8(integer,varchar); + DROP FUNCTION ftest7(varchar); + DROP FUNCTION ftest6(varchar); + DROP FUNCTION ftest5(varchar); + DROP FUNCTION ftest4(varchar); + DROP FUNCTION ftest3(integer); + DROP FUNCTION ftest2(integer); + DROP FUNCTION ftest1(integer); + + + DROP TABLE tbl1; + DROP TABLE empl;