@@ -81,7 +81,8 @@ typedef struct
81
81
char * fname ; /* function name (for error msgs) */
82
82
char * src ; /* function body text (for error msgs) */
83
83
84
- Oid * argtypes ; /* resolved types of arguments */
84
+ SQLFunctionParseInfoPtr pinfo ; /* data for parser callback hooks */
85
+
85
86
Oid rettype ; /* actual return type */
86
87
int16 typlen ; /* length of the return type */
87
88
bool typbyval ; /* true if return type is pass by value */
@@ -108,8 +109,21 @@ typedef struct
108
109
109
110
typedef SQLFunctionCache * SQLFunctionCachePtr ;
110
111
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
+ typedef struct SQLFunctionParseInfo
118
+ {
119
+ Oid * argtypes ; /* resolved types of input arguments */
120
+ int nargs ; /* number of input arguments */
121
+ Oid collation ; /* function's input collation, if known */
122
+ } SQLFunctionParseInfo ;
123
+
111
124
112
125
/* non-export function prototypes */
126
+ static Node * sql_fn_param_ref (ParseState * pstate , ParamRef * pref );
113
127
static List * init_execution_state (List * queryTree_list ,
114
128
SQLFunctionCachePtr fcache ,
115
129
bool lazyEvalOK );
@@ -131,6 +145,112 @@ static void sqlfunction_shutdown(DestReceiver *self);
131
145
static void sqlfunction_destroy (DestReceiver * self );
132
146
133
147
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 (HeapTuple procedureTuple ,
158
+ Node * call_expr ,
159
+ Oid inputCollation )
160
+ {
161
+ SQLFunctionParseInfoPtr pinfo ;
162
+ Form_pg_proc procedureStruct = (Form_pg_proc ) GETSTRUCT (procedureTuple );
163
+ int nargs ;
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
+ int argnum ;
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
+ Oid argtype = 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
+ return pinfo ;
205
+ }
206
+
207
+ /*
208
+ * Parser setup hook for parsing a SQL function body.
209
+ */
210
+ void
211
+ sql_fn_parser_setup (struct ParseState * pstate , SQLFunctionParseInfoPtr pinfo )
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_ref parser callback for ParamRefs ($n symbols)
223
+ */
224
+ static Node *
225
+ sql_fn_param_ref (ParseState * pstate , ParamRef * pref )
226
+ {
227
+ SQLFunctionParseInfoPtr pinfo = (SQLFunctionParseInfoPtr ) pstate -> p_ref_hook_state ;
228
+ int paramno = pref -> number ;
229
+ Param * param ;
230
+
231
+ /* Check parameter number is valid */
232
+ if (paramno <= 0 || paramno > pinfo -> nargs )
233
+ return NULL ; /* 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
+
134
254
/*
135
255
* Set up the per-query execution_state records for a SQL function.
136
256
*
@@ -239,7 +359,9 @@ init_execution_state(List *queryTree_list,
239
359
return eslist ;
240
360
}
241
361
242
- /* Initialize the SQLFunctionCache for a SQL function */
362
+ /*
363
+ * Initialize the SQLFunctionCache for a SQL function
364
+ */
243
365
static void
244
366
init_sql_fcache (FmgrInfo * finfo , bool lazyEvalOK )
245
367
{
@@ -248,8 +370,6 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
248
370
HeapTuple procedureTuple ;
249
371
Form_pg_proc procedureStruct ;
250
372
SQLFunctionCachePtr fcache ;
251
- Oid * argOidVect ;
252
- int nargs ;
253
373
List * raw_parsetree_list ;
254
374
List * queryTree_list ;
255
375
List * flat_query_list ;
@@ -302,37 +422,13 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
302
422
(procedureStruct -> provolatile != PROVOLATILE_VOLATILE );
303
423
304
424
/*
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.
306
428
*/
307
- nargs = procedureStruct -> pronargs ;
308
- if (nargs > 0 )
309
- {
310
- int argnum ;
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
- Oid argtype = 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 );
336
432
337
433
/*
338
434
* And of course we need the function body text.
@@ -364,10 +460,10 @@ init_sql_fcache(FmgrInfo *finfo, bool lazyEvalOK)
364
460
Node * parsetree = (Node * ) lfirst (lc );
365
461
List * queryTree_sublist ;
366
462
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 );
371
467
queryTree_list = lappend (queryTree_list , queryTree_sublist );
372
468
flat_query_list = list_concat (flat_query_list ,
373
469
list_copy (queryTree_sublist ));
@@ -583,7 +679,7 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
583
679
prm -> value = fcinfo -> arg [i ];
584
680
prm -> isnull = fcinfo -> argnull [i ];
585
681
prm -> pflags = 0 ;
586
- prm -> ptype = fcache -> argtypes [i ];
682
+ prm -> ptype = fcache -> pinfo -> argtypes [i ];
587
683
}
588
684
}
589
685
else
0 commit comments