Patch - Reference Function Parameters by Name
Attached is a patch to perform parameter reference lookups by name in
the body of functions. I'm hesitant to put it in for the commitfest
as is, without a couple of questions posed to the group:
1. palloc needs no free? I suppose this is a general knowledge
question, but it seemed to be the case after trying to look for
deallocation
2. I inserted myself more than I had expected along the road from SQL
to columnref_hook, and I'm not sure all of those lookups of parameter
names and function name are required.
3. Since it was mentioned in an earlier email that the <function
name>.<parameter name> syntax was desired, I went ahead and added
that, but it required another passthrough as indicated in 2
4. I made a judgement call in terms of resolution: if the
columnref_hook for param-by-name resolution is called with a non-null
node (meaning a column was already found), we avoid being an ambiguous
reference, and prefer the column already found.
Passes all tests in make check, and I'll add some tests for this after
I get feedback for the above items.
Regards,
-George
Attachments:
param_names.patchapplication/octet-stream; name=param_names.patchDownload
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,
George Gensure <werkt0@gmail.com> writes:
Attached is a patch to perform parameter reference lookups by name in
the body of functions. I'm hesitant to put it in for the commitfest
as is, without a couple of questions posed to the group:
I looked through this very quickly. I'm not in favor of the approach
you have chosen of hacking all the upper layers in order to pass
parameter names through them; and putting the function name into those
APIs too is right out. What I did in plpgsql avoided that by
establishing a callback protocol and keeping all the knowledge of names
within the callback function. SQL functions have a different call path
to the parser, so we might need to adjust things in that path; but you
definitely should not be needing to mess with plancache.c any further.
1. palloc needs no free? I suppose this is a general knowledge
question, but it seemed to be the case after trying to look for
deallocation
Depends. If you're creating something that is meant to live about
as long as the current statement anyway, you can just leave it to be
garbage-collected when the current memory context is destroyed.
There are cases where you need to be more aggressive about pfree'ing
things to avoid large cumulative memory usage, but probably anything
that is invoking parsing doesn't really need to worry (the parse process
is going to create a whole lot more trash than you will anyway).
4. I made a judgement call in terms of resolution: if the
columnref_hook for param-by-name resolution is called with a non-null
node (meaning a column was already found), we avoid being an ambiguous
reference, and prefer the column already found.
The consensus seems to be that we should throw error for ambiguity.
regards, tom lane