Index: src/backend/catalog/pg_proc.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/catalog/pg_proc.c,v retrieving revision 1.168 diff -u -r1.168 pg_proc.c --- src/backend/catalog/pg_proc.c 8 Oct 2009 02:39:18 -0000 1.168 +++ src/backend/catalog/pg_proc.c 18 Nov 2009 14:46:25 -0000 @@ -780,6 +780,31 @@ /* Postpone body checks if !check_function_bodies */ if (check_function_bodies) { + char **argnames = NULL; + Datum proargnames; + + /* Fetch and parse the param names */ + proargnames = SysCacheGetAttr(PROCOID, tuple, + Anum_pg_proc_proargnames, + &isnull); + if (!isnull) + { + int n_arg_names; + Datum proargmodes; + + proargmodes = SysCacheGetAttr(PROCOID, tuple, + Anum_pg_proc_proargmodes, + &isnull); + if (isnull) + proargmodes = PointerGetDatum(NULL); + + n_arg_names = get_func_input_arg_names(proargnames, + proargmodes, + &argnames); + + Assert(n_arg_names == func->pronargs); + } + tmp = SysCacheGetAttr(PROCOID, tuple, Anum_pg_proc_prosrc, &isnull); if (isnull) elog(ERROR, "null prosrc"); @@ -806,7 +831,9 @@ if (!haspolyarg) { querytree_list = pg_parse_and_rewrite(prosrc, + NameStr(proc->proname), proc->proargtypes.values, + argnames, proc->pronargs); (void) check_sql_fn_retval(funcoid, proc->prorettype, querytree_list, Index: src/backend/commands/copy.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/copy.c,v retrieving revision 1.317 diff -u -r1.317 copy.c --- src/backend/commands/copy.c 21 Sep 2009 20:10:21 -0000 1.317 +++ src/backend/commands/copy.c 18 Nov 2009 14:46:25 -0000 @@ -1061,7 +1061,7 @@ * DECLARE CURSOR and PREPARE.) XXX FIXME someday. */ rewritten = pg_analyze_and_rewrite((Node *) copyObject(stmt->query), - queryString, NULL, 0); + queryString, NULL, NULL, NULL, 0); /* We don't expect more or less than one result query */ if (list_length(rewritten) != 1) Index: src/backend/commands/prepare.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/prepare.c,v retrieving revision 1.100 diff -u -r1.100 prepare.c --- src/backend/commands/prepare.c 4 Nov 2009 22:26:05 -0000 1.100 +++ src/backend/commands/prepare.c 18 Nov 2009 14:46:26 -0000 @@ -467,7 +467,9 @@ plansource = CreateCachedPlan(raw_parse_tree, query_string, commandTag, + NULL, param_types, + NULL, num_params, cursor_options, stmt_list, Index: src/backend/commands/view.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/view.c,v retrieving revision 1.119 diff -u -r1.119 view.c --- src/backend/commands/view.c 5 Nov 2009 23:24:23 -0000 1.119 +++ src/backend/commands/view.c 18 Nov 2009 14:46:26 -0000 @@ -403,7 +403,7 @@ * this ensures we don't corrupt a prepared statement, for example. */ viewParse = parse_analyze((Node *) copyObject(stmt->query), - queryString, NULL, 0); + queryString, NULL, NULL, NULL, 0); /* * The grammar should ensure that the result is a single SELECT Query. Index: src/backend/executor/functions.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/executor/functions.c,v retrieving revision 1.136 diff -u -r1.136 functions.c --- src/backend/executor/functions.c 4 Nov 2009 22:26:05 -0000 1.136 +++ src/backend/executor/functions.c 18 Nov 2009 14:46:26 -0000 @@ -77,6 +77,7 @@ char *src; /* function body text (for error msgs) */ Oid *argtypes; /* resolved types of arguments */ + char **argnames; /* names of arguments */ Oid rettype; /* actual return type */ int16 typlen; /* length of the return type */ bool typbyval; /* true if return type is pass by value */ @@ -222,6 +223,7 @@ Form_pg_proc procedureStruct; SQLFunctionCachePtr fcache; Oid *argOidVect; + char **argNameVect; int nargs; List *queryTree_list; Datum tmp; @@ -274,6 +276,7 @@ if (nargs > 0) { int argnum; + Datum proargnames; argOidVect = (Oid *) palloc(nargs * sizeof(Oid)); memcpy(argOidVect, @@ -295,10 +298,37 @@ argOidVect[argnum] = argtype; } } + + proargnames = SysCacheGetAttr(PROCOID, procedureTuple, + Anum_pg_proc_proargnames, + &isNull); + if (!isNull) + { + int n_arg_names; + Datum proargmodes; + + proargmodes = SysCacheGetAttr(PROCOID, procedureTuple, + Anum_pg_proc_proargmodes, + &isNull); + if (isNull) + proargmodes = PointerGetDatum(NULL); + + n_arg_names = get_func_input_arg_names(proargnames, + proargmodes, + &argNameVect); + + Assert(n_arg_names == funcform->pronargs); + } else { + argNameVect = NULL; + } } else + { argOidVect = NULL; + argNameVect = NULL; + } fcache->argtypes = argOidVect; + fcache->argnames = argNameVect; /* * And of course we need the function body text. @@ -314,7 +344,10 @@ /* * Parse and rewrite the queries in the function text. */ - queryTree_list = pg_parse_and_rewrite(fcache->src, argOidVect, nargs); + queryTree_list = pg_parse_and_rewrite(fcache->src, + NameStr(procedureStruct->proname), + argOidVect, argNameVect, + nargs); /* * Check that the function returns the type it claims to. Although in Index: src/backend/executor/spi.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/executor/spi.c,v retrieving revision 1.211 diff -u -r1.211 spi.c --- src/backend/executor/spi.c 4 Nov 2009 22:26:06 -0000 1.211 +++ src/backend/executor/spi.c 18 Nov 2009 14:46:27 -0000 @@ -1714,7 +1714,9 @@ /* Need a copyObject here to keep parser from modifying raw tree */ stmt_list = pg_analyze_and_rewrite(copyObject(parsetree), src, + NULL, plan->argtypes, + NULL, plan->nargs); } stmt_list = pg_plan_queries(stmt_list, cursor_options, boundParams); @@ -2403,7 +2405,9 @@ newsource = CreateCachedPlan(plansource->raw_parse_tree, plansource->query_string, plansource->commandTag, + NULL, newplan->argtypes, + NULL, newplan->nargs, newplan->cursor_options, cplan->stmt_list, Index: src/backend/nodes/params.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/nodes/params.c,v retrieving revision 1.12 diff -u -r1.12 params.c --- src/backend/nodes/params.c 4 Nov 2009 22:26:06 -0000 1.12 +++ src/backend/nodes/params.c 18 Nov 2009 14:46:27 -0000 @@ -116,6 +116,6 @@ ptypes[i] = prm->ptype; } - parse_fixed_parameters(pstate, ptypes, params->numParams); + parse_fixed_parameters(pstate, NULL, ptypes, NULL, params->numParams); } } Index: src/backend/optimizer/util/clauses.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/optimizer/util/clauses.c,v retrieving revision 1.279 diff -u -r1.279 clauses.c --- src/backend/optimizer/util/clauses.c 8 Oct 2009 02:39:21 -0000 1.279 +++ src/backend/optimizer/util/clauses.c 18 Nov 2009 14:46:28 -0000 @@ -3670,8 +3670,10 @@ { Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple); Oid *argtypes; + char **argnames; char *src; Datum tmp; + Datum proargnames; bool isNull; MemoryContext oldcxt; MemoryContext mycxt; @@ -3734,6 +3736,32 @@ } } + /* Fetch and parse the param names */ + proargnames = SysCacheGetAttr(PROCOID, func_tuple, + Anum_pg_proc_proargnames, + &isNull); + if (!isNull) + { + int n_arg_names; + Datum proargmodes; + + proargmodes = SysCacheGetAttr(PROCOID, func_tuple, + Anum_pg_proc_proargmodes, + &isNull); + if (isNull) + proargmodes = PointerGetDatum(NULL); + + n_arg_names = get_func_input_arg_names(proargnames, + proargmodes, + &argnames); + + Assert(n_arg_names == funcform->pronargs); + } + else + { + argnames = NULL; + } + /* Fetch and parse the function body */ tmp = SysCacheGetAttr(PROCOID, func_tuple, @@ -3754,7 +3782,8 @@ goto fail; querytree = parse_analyze(linitial(raw_parsetree_list), src, - argtypes, funcform->pronargs); + NameStr(funcform->proname), argtypes, argnames, + funcform->pronargs); /* * The single command must be a simple "SELECT expression". @@ -4085,8 +4114,10 @@ HeapTuple func_tuple; Form_pg_proc funcform; Oid *argtypes; + char **argnames; char *src; Datum tmp; + Datum proargnames; bool isNull; MemoryContext oldcxt; MemoryContext mycxt; @@ -4216,6 +4247,32 @@ } } + /* Fetch and parse the param names */ + proargnames = SysCacheGetAttr(PROCOID, func_tuple, + Anum_pg_proc_proargnames, + &isNull); + if (!isNull) + { + int n_arg_names; + Datum proargmodes; + + proargmodes = SysCacheGetAttr(PROCOID, func_tuple, + Anum_pg_proc_proargmodes, + &isNull); + if (isNull) + proargmodes = PointerGetDatum(NULL); + + n_arg_names = get_func_input_arg_names(proargnames, + proargmodes, + &argnames); + + Assert(n_arg_names == funcform->pronargs); + } + else + { + argnames = NULL; + } + /* Fetch and parse the function body */ tmp = SysCacheGetAttr(PROCOID, func_tuple, @@ -4235,7 +4292,9 @@ goto fail; querytree_list = pg_analyze_and_rewrite(linitial(raw_parsetree_list), src, - argtypes, funcform->pronargs); + NameStr(funcform->proname), + argtypes, argnames, + funcform->pronargs); if (list_length(querytree_list) != 1) goto fail; querytree = linitial(querytree_list); Index: src/backend/parser/analyze.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/analyze.c,v retrieving revision 1.396 diff -u -r1.396 analyze.c --- src/backend/parser/analyze.c 31 Oct 2009 01:41:31 -0000 1.396 +++ src/backend/parser/analyze.c 18 Nov 2009 14:46:28 -0000 @@ -77,8 +77,8 @@ * a dummy CMD_UTILITY Query node. */ Query * -parse_analyze(Node *parseTree, const char *sourceText, - Oid *paramTypes, int numParams) +parse_analyze(Node *parseTree, const char *sourceText, char *funcName, + Oid *paramTypes, char **paramNames, int numParams) { ParseState *pstate = make_parsestate(NULL); Query *query; @@ -88,7 +88,8 @@ pstate->p_sourcetext = sourceText; if (numParams > 0) - parse_fixed_parameters(pstate, paramTypes, numParams); + parse_fixed_parameters(pstate, funcName, paramTypes, paramNames, + numParams); query = transformStmt(pstate, parseTree); Index: src/backend/parser/parse_param.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/parser/parse_param.c,v retrieving revision 2.1 diff -u -r2.1 parse_param.c --- src/backend/parser/parse_param.c 31 Oct 2009 01:41:31 -0000 2.1 +++ src/backend/parser/parse_param.c 18 Nov 2009 14:46:29 -0000 @@ -34,7 +34,9 @@ typedef struct FixedParamState { + char *funcName; /* name of the current function */ Oid *paramTypes; /* array of parameter type OIDs */ + char **paramNames; /* array of parameter name strings */ int numParams; /* number of array entries */ } FixedParamState; @@ -51,6 +53,7 @@ } VarParamState; static Node *fixed_paramref_hook(ParseState *pstate, ParamRef *pref); +static Node *fixed_pnameref_hook(ParseState *pstate, ColumnRef *pref, Node *var); static Node *variable_paramref_hook(ParseState *pstate, ParamRef *pref); static Node *variable_coerce_param_hook(ParseState *pstate, Param *param, Oid targetTypeId, int32 targetTypeMod, @@ -62,15 +65,19 @@ * Set up to process a query containing references to fixed parameters. */ void -parse_fixed_parameters(ParseState *pstate, - Oid *paramTypes, int numParams) +parse_fixed_parameters(ParseState *pstate, char *funcName, + Oid *paramTypes, char **paramNames, int numParams) { FixedParamState *parstate = palloc(sizeof(FixedParamState)); + parstate->funcName = funcName; parstate->paramTypes = paramTypes; + parstate->paramNames = paramNames; parstate->numParams = numParams; pstate->p_ref_hook_state = (void *) parstate; pstate->p_paramref_hook = fixed_paramref_hook; + Assert(!pstate->p_post_columnref_hook); + pstate->p_post_columnref_hook = fixed_pnameref_hook; /* no need to use p_coerce_param_hook */ } @@ -118,6 +125,76 @@ } /* + * Transform a PNameRef using fixed parameter types. + */ +static Node * +fixed_pnameref_hook(ParseState *pstate, ColumnRef *cref, Node *var) +{ + FixedParamState *parstate = (FixedParamState *) pstate->p_ref_hook_state; + char *pname; + Param *param; + int i; + + /* this was something of a judgement call: if another column reference + * is qualified before our argument, don't look up a param */ + /* can't do anything without a list of parameter names */ + if (var != NULL || parstate->paramNames == NULL) + return NULL; + + switch (list_length(cref->fields)) + { + case 1: + { + Node *field1 = (Node *) linitial(cref->fields); + + Assert(IsA(field1, String)); + pname = strVal(field1); + break; + } + case 2: + { + char *fname; + Node *field1 = (Node *) linitial(cref->fields); + Node *field2 = (Node *) lsecond(cref->fields); + + Assert(IsA(field1, String)); + fname = strVal(field1); + + if (parstate->funcName == NULL || + fname == NULL || + strcmp(fname, parstate->funcName)) + return NULL; + + Assert(IsA(field2, String)); + pname = strVal(field2); + break; + } + default: + /* too many names, ignore */ + return NULL; + } + + /* Find parameter in name list */ + for ( i = 0; i < parstate->numParams; i++ ) + { + if (parstate->paramNames[i] != NULL && + pname != NULL && + !strcmp(pname, parstate->paramNames[i])) + { + param = makeNode(Param); + param->paramkind = PARAM_EXTERN; + param->paramid = i + 1; + param->paramtype = parstate->paramTypes[i]; + param->paramtypmod = -1; + param->location = cref->location; + return (Node *) param; + } + } + + return NULL; +} + +/* * Transform a ParamRef using variable parameter types. * * The only difference here is we must enlarge the parameter type array Index: src/backend/tcop/postgres.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v retrieving revision 1.575 diff -u -r1.575 postgres.c --- src/backend/tcop/postgres.c 4 Nov 2009 22:26:06 -0000 1.575 +++ src/backend/tcop/postgres.c 18 Nov 2009 14:46:30 -0000 @@ -512,7 +512,9 @@ */ List * pg_parse_and_rewrite(const char *query_string, /* string to execute */ + char *funcName, /* function name */ Oid *paramTypes, /* parameter types */ + char **paramNames, /* parameter names */ int numParams) /* number of parameters */ { List *raw_parsetree_list; @@ -535,7 +537,9 @@ querytree_list = list_concat(querytree_list, pg_analyze_and_rewrite(parsetree, query_string, + funcName, paramTypes, + paramNames, numParams)); } @@ -599,7 +603,8 @@ */ List * pg_analyze_and_rewrite(Node *parsetree, const char *query_string, - Oid *paramTypes, int numParams) + char *funcName, Oid *paramTypes, char **paramNames, + int numParams) { Query *query; List *querytree_list; @@ -612,7 +617,8 @@ if (log_parser_stats) ResetUsage(); - query = parse_analyze(parsetree, query_string, paramTypes, numParams); + query = parse_analyze(parsetree, query_string, funcName, + paramTypes, paramNames, numParams); if (log_parser_stats) ShowUsage("PARSE ANALYSIS STATISTICS"); @@ -970,7 +976,7 @@ oldcontext = MemoryContextSwitchTo(MessageContext); querytree_list = pg_analyze_and_rewrite(parsetree, query_string, - NULL, 0); + NULL, NULL, NULL, 0); plantree_list = pg_plan_queries(querytree_list, 0, NULL); Index: src/backend/utils/cache/plancache.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/utils/cache/plancache.c,v retrieving revision 1.31 diff -u -r1.31 plancache.c --- src/backend/utils/cache/plancache.c 4 Nov 2009 22:26:06 -0000 1.31 +++ src/backend/utils/cache/plancache.c 18 Nov 2009 14:46:30 -0000 @@ -110,7 +110,9 @@ CreateCachedPlan(Node *raw_parse_tree, const char *query_string, const char *commandTag, + char *func_name, Oid *param_types, + char **param_names, int num_params, int cursor_options, List *stmt_list, @@ -148,13 +150,26 @@ plansource->raw_parse_tree = copyObject(raw_parse_tree); plansource->query_string = pstrdup(query_string); plansource->commandTag = commandTag; /* no copying needed */ + plansource->func_name = func_name; if (num_params > 0) { plansource->param_types = (Oid *) palloc(num_params * sizeof(Oid)); memcpy(plansource->param_types, param_types, num_params * sizeof(Oid)); + + if( param_names != NULL ) { + plansource->param_names = + (char **) palloc(num_params * sizeof(char **)); + memcpy(plansource->param_names, param_names, + num_params * sizeof(char *)); + } else { + plansource->param_names = NULL; + } } else + { plansource->param_types = NULL; + plansource->param_names = NULL; + } plansource->num_params = num_params; /* these can be set later with CachedPlanSetParserHook: */ plansource->parserSetup = NULL; @@ -530,7 +545,9 @@ else slist = pg_analyze_and_rewrite(rawtree, plansource->query_string, + plansource->func_name, plansource->param_types, + plansource->param_names, plansource->num_params); if (plansource->fully_planned) Index: src/include/nodes/params.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/nodes/params.h,v retrieving revision 1.39 diff -u -r1.39 params.h --- src/include/nodes/params.h 4 Nov 2009 22:26:06 -0000 1.39 +++ src/include/nodes/params.h 18 Nov 2009 14:46:30 -0000 @@ -56,6 +56,7 @@ bool isnull; /* is it NULL? */ uint16 pflags; /* flag bits, see above */ Oid ptype; /* parameter's datatype, or 0 */ + char *pname; /* parameter's name, or NULL */ } ParamExternData; typedef struct ParamListInfoData *ParamListInfo; Index: src/include/parser/analyze.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/parser/analyze.h,v retrieving revision 1.43 diff -u -r1.43 analyze.h --- src/include/parser/analyze.h 28 Oct 2009 14:55:47 -0000 1.43 +++ src/include/parser/analyze.h 18 Nov 2009 14:46:30 -0000 @@ -18,7 +18,8 @@ extern Query *parse_analyze(Node *parseTree, const char *sourceText, - Oid *paramTypes, int numParams); + char *funcName, Oid *paramTypes, char **paramNames, + int numParams); extern Query *parse_analyze_varparams(Node *parseTree, const char *sourceText, Oid **paramTypes, int *numParams); Index: src/include/parser/parse_param.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/parser/parse_param.h,v retrieving revision 1.1 diff -u -r1.1 parse_param.h --- src/include/parser/parse_param.h 31 Oct 2009 01:41:31 -0000 1.1 +++ src/include/parser/parse_param.h 18 Nov 2009 14:46:30 -0000 @@ -15,8 +15,8 @@ #include "parser/parse_node.h" -extern void parse_fixed_parameters(ParseState *pstate, - Oid *paramTypes, int numParams); +extern void parse_fixed_parameters(ParseState *pstate, char *funcName, + Oid *paramTypes, char **paramNames, int numParams); extern void parse_variable_parameters(ParseState *pstate, Oid **paramTypes, int *numParams); extern void check_variable_parameters(ParseState *pstate, Query *query); Index: src/include/tcop/tcopprot.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/tcop/tcopprot.h,v retrieving revision 1.101 diff -u -r1.101 tcopprot.h --- src/include/tcop/tcopprot.h 4 Nov 2009 22:26:07 -0000 1.101 +++ src/include/tcop/tcopprot.h 18 Nov 2009 14:46:30 -0000 @@ -44,11 +44,13 @@ extern int log_statement; -extern List *pg_parse_and_rewrite(const char *query_string, - Oid *paramTypes, int numParams); +extern List *pg_parse_and_rewrite(const char *query_string, char *funcName, + Oid *paramTypes, char **paramNames, + int numParams); extern List *pg_parse_query(const char *query_string); extern List *pg_analyze_and_rewrite(Node *parsetree, const char *query_string, - Oid *paramTypes, int numParams); + char *funcName, Oid *paramTypes, + char **paramNames, int numParams); extern List *pg_analyze_and_rewrite_params(Node *parsetree, const char *query_string, ParserSetupHook parserSetup, Index: src/include/utils/plancache.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/utils/plancache.h,v retrieving revision 1.16 diff -u -r1.16 plancache.h --- src/include/utils/plancache.h 4 Nov 2009 22:26:07 -0000 1.16 +++ src/include/utils/plancache.h 18 Nov 2009 14:46:30 -0000 @@ -49,7 +49,9 @@ Node *raw_parse_tree; /* output of raw_parser() */ char *query_string; /* text of query (as of 8.4, never NULL) */ const char *commandTag; /* command tag (a constant!), or NULL */ + char *func_name; /* function name or NULL */ Oid *param_types; /* array of parameter type OIDs, or NULL */ + char **param_names; /* array of parameter names, or NULL */ int num_params; /* length of param_types array */ ParserSetupHook parserSetup; /* alternative parameter spec method */ void *parserSetupArg; @@ -92,7 +94,9 @@ extern CachedPlanSource *CreateCachedPlan(Node *raw_parse_tree, const char *query_string, const char *commandTag, + char *func_name, Oid *param_types, + char **param_names, int num_params, int cursor_options, List *stmt_list,