Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit27dc7e2

Browse files
committed
Fix handling of collation in SQL-language functions.
Ensure that parameter symbols receive collation from the function'sresolved input collation, and fix inlining to behave properly.BTW, this commit lays about 90% of the infrastructure needed to supportuse of argument names in SQL functions. Parsing of parameters is nowdone via the parser-hook infrastructure ... we'd just need to supplya column-ref hook ...
1 parenta432e27 commit27dc7e2

File tree

7 files changed

+303
-76
lines changed

7 files changed

+303
-76
lines changed

‎src/backend/catalog/pg_proc.c

Lines changed: 9 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -845,16 +845,21 @@ fmgr_sql_validator(PG_FUNCTION_ARGS)
845845
* OK to do full precheck: analyze and rewrite the queries,
846846
* then verify the result type.
847847
*/
848+
SQLFunctionParseInfoPtrpinfo;
849+
850+
/* But first, set up parameter information */
851+
pinfo=prepare_sql_fn_parse_info(tuple,NULL,InvalidOid);
852+
848853
querytree_list=NIL;
849854
foreach(lc,raw_parsetree_list)
850855
{
851856
Node*parsetree= (Node*)lfirst(lc);
852857
List*querytree_sublist;
853858

854-
querytree_sublist=pg_analyze_and_rewrite(parsetree,
855-
prosrc,
856-
proc->proargtypes.values,
857-
proc->pronargs);
859+
querytree_sublist=pg_analyze_and_rewrite_params(parsetree,
860+
prosrc,
861+
(ParserSetupHook)sql_fn_parser_setup,
862+
pinfo);
858863
querytree_list=list_concat(querytree_list,
859864
querytree_sublist);
860865
}

‎src/backend/executor/functions.c

Lines changed: 135 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,8 @@ typedef struct
8181
char*fname;/* function name (for error msgs) */
8282
char*src;/* function body text (for error msgs) */
8383

84-
Oid*argtypes;/* resolved types of arguments */
84+
SQLFunctionParseInfoPtrpinfo;/* data for parser callback hooks */
85+
8586
Oidrettype;/* actual return type */
8687
int16typlen;/* length of the return type */
8788
booltypbyval;/* true if return type is pass by value */
@@ -108,8 +109,21 @@ typedef struct
108109

109110
typedefSQLFunctionCache*SQLFunctionCachePtr;
110111

112+
/*
113+
* Data structure needed by the parser callback hooks to resolve parameter
114+
* references during parsing of a SQL function's body. This is separate from
115+
* SQLFunctionCache since we sometimes do parsing separately from execution.
116+
*/
117+
typedefstructSQLFunctionParseInfo
118+
{
119+
Oid*argtypes;/* resolved types of input arguments */
120+
intnargs;/* number of input arguments */
121+
Oidcollation;/* function's input collation, if known */
122+
}SQLFunctionParseInfo;
123+
111124

112125
/* non-export function prototypes */
126+
staticNode*sql_fn_param_ref(ParseState*pstate,ParamRef*pref);
113127
staticList*init_execution_state(List*queryTree_list,
114128
SQLFunctionCachePtrfcache,
115129
boollazyEvalOK);
@@ -131,6 +145,112 @@ static void sqlfunction_shutdown(DestReceiver *self);
131145
staticvoidsqlfunction_destroy(DestReceiver*self);
132146

133147

148+
/*
149+
* Prepare the SQLFunctionParseInfo struct for parsing a SQL function body
150+
*
151+
* This includes resolving actual types of polymorphic arguments.
152+
*
153+
* call_expr can be passed as NULL, but then we will fail if there are any
154+
* polymorphic arguments.
155+
*/
156+
SQLFunctionParseInfoPtr
157+
prepare_sql_fn_parse_info(HeapTupleprocedureTuple,
158+
Node*call_expr,
159+
OidinputCollation)
160+
{
161+
SQLFunctionParseInfoPtrpinfo;
162+
Form_pg_procprocedureStruct= (Form_pg_proc)GETSTRUCT(procedureTuple);
163+
intnargs;
164+
165+
pinfo= (SQLFunctionParseInfoPtr)palloc0(sizeof(SQLFunctionParseInfo));
166+
167+
/* Save the function's input collation */
168+
pinfo->collation=inputCollation;
169+
170+
/*
171+
* Copy input argument types from the pg_proc entry, then resolve any
172+
* polymorphic types.
173+
*/
174+
pinfo->nargs=nargs=procedureStruct->pronargs;
175+
if (nargs>0)
176+
{
177+
Oid*argOidVect;
178+
intargnum;
179+
180+
argOidVect= (Oid*)palloc(nargs*sizeof(Oid));
181+
memcpy(argOidVect,
182+
procedureStruct->proargtypes.values,
183+
nargs*sizeof(Oid));
184+
185+
for (argnum=0;argnum<nargs;argnum++)
186+
{
187+
Oidargtype=argOidVect[argnum];
188+
189+
if (IsPolymorphicType(argtype))
190+
{
191+
argtype=get_call_expr_argtype(call_expr,argnum);
192+
if (argtype==InvalidOid)
193+
ereport(ERROR,
194+
(errcode(ERRCODE_DATATYPE_MISMATCH),
195+
errmsg("could not determine actual type of argument declared %s",
196+
format_type_be(argOidVect[argnum]))));
197+
argOidVect[argnum]=argtype;
198+
}
199+
}
200+
201+
pinfo->argtypes=argOidVect;
202+
}
203+
204+
returnpinfo;
205+
}
206+
207+
/*
208+
* Parser setup hook for parsing a SQL function body.
209+
*/
210+
void
211+
sql_fn_parser_setup(structParseState*pstate,SQLFunctionParseInfoPtrpinfo)
212+
{
213+
/* Later we might use these hooks to support parameter names */
214+
pstate->p_pre_columnref_hook=NULL;
215+
pstate->p_post_columnref_hook=NULL;
216+
pstate->p_paramref_hook=sql_fn_param_ref;
217+
/* no need to use p_coerce_param_hook */
218+
pstate->p_ref_hook_state= (void*)pinfo;
219+
}
220+
221+
/*
222+
* sql_fn_param_refparser callback for ParamRefs ($n symbols)
223+
*/
224+
staticNode*
225+
sql_fn_param_ref(ParseState*pstate,ParamRef*pref)
226+
{
227+
SQLFunctionParseInfoPtrpinfo= (SQLFunctionParseInfoPtr)pstate->p_ref_hook_state;
228+
intparamno=pref->number;
229+
Param*param;
230+
231+
/* Check parameter number is valid */
232+
if (paramno <=0||paramno>pinfo->nargs)
233+
returnNULL;/* unknown parameter number */
234+
235+
param=makeNode(Param);
236+
param->paramkind=PARAM_EXTERN;
237+
param->paramid=paramno;
238+
param->paramtype=pinfo->argtypes[paramno-1];
239+
param->paramtypmod=-1;
240+
param->paramcollid=get_typcollation(param->paramtype);
241+
param->location=pref->location;
242+
243+
/*
244+
* If we have a function input collation, allow it to override the
245+
* type-derived collation for parameter symbols. (XXX perhaps this should
246+
* not happen if the type collation is not default?)
247+
*/
248+
if (OidIsValid(pinfo->collation)&&OidIsValid(param->paramcollid))
249+
param->paramcollid=pinfo->collation;
250+
251+
return (Node*)param;
252+
}
253+
134254
/*
135255
* Set up the per-query execution_state records for a SQL function.
136256
*
@@ -239,7 +359,9 @@ init_execution_state(List *queryTree_list,
239359
returneslist;
240360
}
241361

242-
/* Initialize the SQLFunctionCache for a SQL function */
362+
/*
363+
* Initialize the SQLFunctionCache for a SQL function
364+
*/
243365
staticvoid
244366
init_sql_fcache(FmgrInfo*finfo,boollazyEvalOK)
245367
{
@@ -248,8 +370,6 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
248370
HeapTupleprocedureTuple;
249371
Form_pg_procprocedureStruct;
250372
SQLFunctionCachePtrfcache;
251-
Oid*argOidVect;
252-
intnargs;
253373
List*raw_parsetree_list;
254374
List*queryTree_list;
255375
List*flat_query_list;
@@ -302,37 +422,13 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
302422
(procedureStruct->provolatile!=PROVOLATILE_VOLATILE);
303423

304424
/*
305-
* We need the actual argument types to pass to the parser.
425+
* We need the actual argument types to pass to the parser. Also make
426+
* sure that parameter symbols are considered to have the function's
427+
* resolved input collation.
306428
*/
307-
nargs=procedureStruct->pronargs;
308-
if (nargs>0)
309-
{
310-
intargnum;
311-
312-
argOidVect= (Oid*)palloc(nargs*sizeof(Oid));
313-
memcpy(argOidVect,
314-
procedureStruct->proargtypes.values,
315-
nargs*sizeof(Oid));
316-
/* Resolve any polymorphic argument types */
317-
for (argnum=0;argnum<nargs;argnum++)
318-
{
319-
Oidargtype=argOidVect[argnum];
320-
321-
if (IsPolymorphicType(argtype))
322-
{
323-
argtype=get_fn_expr_argtype(finfo,argnum);
324-
if (argtype==InvalidOid)
325-
ereport(ERROR,
326-
(errcode(ERRCODE_DATATYPE_MISMATCH),
327-
errmsg("could not determine actual type of argument declared %s",
328-
format_type_be(argOidVect[argnum]))));
329-
argOidVect[argnum]=argtype;
330-
}
331-
}
332-
}
333-
else
334-
argOidVect=NULL;
335-
fcache->argtypes=argOidVect;
429+
fcache->pinfo=prepare_sql_fn_parse_info(procedureTuple,
430+
finfo->fn_expr,
431+
finfo->fn_collation);
336432

337433
/*
338434
* And of course we need the function body text.
@@ -364,10 +460,10 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
364460
Node*parsetree= (Node*)lfirst(lc);
365461
List*queryTree_sublist;
366462

367-
queryTree_sublist=pg_analyze_and_rewrite(parsetree,
368-
fcache->src,
369-
argOidVect,
370-
nargs);
463+
queryTree_sublist=pg_analyze_and_rewrite_params(parsetree,
464+
fcache->src,
465+
(ParserSetupHook)sql_fn_parser_setup,
466+
fcache->pinfo);
371467
queryTree_list=lappend(queryTree_list,queryTree_sublist);
372468
flat_query_list=list_concat(flat_query_list,
373469
list_copy(queryTree_sublist));
@@ -583,7 +679,7 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
583679
prm->value=fcinfo->arg[i];
584680
prm->isnull=fcinfo->argnull[i];
585681
prm->pflags=0;
586-
prm->ptype=fcache->argtypes[i];
682+
prm->ptype=fcache->pinfo->argtypes[i];
587683
}
588684
}
589685
else

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp