src/backend/parser/parse_func.c - Coverage Report

← Back to Overview

# src/backend/parser/parse_func.c

Coverage: 55/57 lines (96.5%)
Total Lines
57
modified
Covered
55
96.5%
Uncovered
2
3.5%
Keyboard navigation
ParseFuncOrColumn() lines 95-973
Modified Lines Coverage: 18/18 lines (100.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
95 | - | ParseFuncOrColumn(ParseState *pstate, List *funcname, List *fargs, | -
96 | - | Node *last_srf, FuncCall *fn, bool proc_call, int location) | -
97 | - | { | -
98 | - | bool is_column = (fn == NULL); | -
99 | - | List *agg_order = (fn ? fn->agg_order : NIL); | -
100 | - | Expr *agg_filter = NULL; | -
101 | - | WindowDef *over = (fn ? fn->over : NULL); | -
102 | - | bool agg_within_group = (fn ? fn->agg_within_group : false); | -
103 | - | bool agg_star = (fn ? fn->agg_star : false); | -
104 | - | bool agg_distinct = (fn ? fn->agg_distinct : false); | -
105 | - | bool func_variadic = (fn ? fn->func_variadic : false); | -
106 | - | int ignore_nulls = (fn ? fn->ignore_nulls : NO_NULLTREATMENT); | -
107 | - | CoercionForm funcformat = (fn ? fn->funcformat : COERCE_EXPLICIT_CALL); | -
108 | - | bool could_be_projection; | -
109 | - | Oid rettype; | -
110 | - | Oid funcid; | -
111 | - | ListCell *l; | -
112 | - | Node *first_arg = NULL; | -
113 | - | int nargs; | -
114 | - | int nargsplusdefs; | -
115 | - | Oid actual_arg_types[FUNC_MAX_ARGS]; | -
116 | - | Oid *declared_arg_types; | -
117 | - | List *argnames; | -
118 | - | List *argdefaults; | -
119 | - | Node *retval; | -
120 | - | bool retset; | -
121 | - | int nvargs; | -
122 | - | Oid vatype; | -
123 | - | FuncDetailCode fdresult; | -
124 | - | int fgc_flags; | -
125 | - | char aggkind = 0; | -
126 | - | ParseCallbackState pcbstate; | -
127 | 514476 | bool could_be_rpr_nav = false; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
128 | - |  | -
129 | - | /* | -
130 | - | * If there's an aggregate filter, transform it using transformWhereClause | -
131 | - | */ | -
132 | - | if (fn && fn->agg_filter != NULL) | -
133 | - | agg_filter = (Expr *) transformWhereClause(pstate, fn->agg_filter, | -
134 | - | EXPR_KIND_FILTER, | -
135 | - | "FILTER"); | -
136 | - |  | -
137 | - | /* | -
138 | - | * Most of the rest of the parser just assumes that functions do not have | -
139 | - | * more than FUNC_MAX_ARGS parameters. We have to test here to protect | -
140 | - | * against array overruns, etc. Of course, this may not be a function, | -
141 | - | * but the test doesn't hurt. | -
142 | - | */ | -
143 | - | if (list_length(fargs) > FUNC_MAX_ARGS) | -
144 | - | ereport(ERROR, | -
145 | - | (errcode(ERRCODE_TOO_MANY_ARGUMENTS), | -
146 | - | errmsg_plural("cannot pass more than %d argument to a function", | -
147 | - | "cannot pass more than %d arguments to a function", | -
148 | - | FUNC_MAX_ARGS, | -
149 | - | FUNC_MAX_ARGS), | -
150 | - | parser_errposition(pstate, location))); | -
151 | - |  | -
152 | - | /* | -
153 | - | * Extract arg type info in preparation for function lookup. | -
154 | - | * | -
155 | - | * If any arguments are Param markers of type VOID, we discard them from | -
156 | - | * the parameter list. This is a hack to allow the JDBC driver to not have | -
157 | - | * to distinguish "input" and "output" parameter symbols while parsing | -
158 | - | * function-call constructs. Don't do this if dealing with column syntax, | -
159 | - | * nor if we had WITHIN GROUP (because in that case it's critical to keep | -
160 | - | * the argument count unchanged). | -
161 | - | */ | -
162 | - | nargs = 0; | -
163 | - | foreach(l, fargs) | -
164 | - | { | -
165 | - | Node *arg = lfirst(l); | -
166 | - | Oid argtype = exprType(arg); | -
167 | - |  | -
168 | - | if (argtype == VOIDOID && IsA(arg, Param) && | -
169 | - | !is_column && !agg_within_group) | -
170 | - | { | -
171 | - | fargs = foreach_delete_current(fargs, l); | -
172 | - | continue; | -
173 | - | } | -
174 | - |  | -
175 | - | actual_arg_types[nargs++] = argtype; | -
176 | - | } | -
177 | - |  | -
178 | - | /* | -
179 | - | * Check for named arguments; if there are any, build a list of names. | -
180 | - | * | -
181 | - | * We allow mixed notation (some named and some not), but only with all | -
182 | - | * the named parameters after all the unnamed ones. So the name list | -
183 | - | * corresponds to the last N actual parameters and we don't need any extra | -
184 | - | * bookkeeping to match things up. | -
185 | - | */ | -
186 | - | argnames = NIL; | -
187 | - | foreach(l, fargs) | -
188 | - | { | -
189 | - | Node *arg = lfirst(l); | -
190 | - |  | -
191 | - | if (IsA(arg, NamedArgExpr)) | -
192 | - | { | -
193 | - | NamedArgExpr *na = (NamedArgExpr *) arg; | -
194 | - | ListCell *lc; | -
195 | - |  | -
196 | - | /* Reject duplicate arg names */ | -
197 | - | foreach(lc, argnames) | -
198 | - | { | -
199 | - | if (strcmp(na->name, (char *) lfirst(lc)) == 0) | -
200 | - | ereport(ERROR, | -
201 | - | (errcode(ERRCODE_SYNTAX_ERROR), | -
202 | - | errmsg("argument name \"%s\" used more than once", | -
203 | - | na->name), | -
204 | - | parser_errposition(pstate, na->location))); | -
205 | - | } | -
206 | - | argnames = lappend(argnames, na->name); | -
207 | - | } | -
208 | - | else | -
209 | - | { | -
210 | - | if (argnames != NIL) | -
211 | - | ereport(ERROR, | -
212 | - | (errcode(ERRCODE_SYNTAX_ERROR), | -
213 | - | errmsg("positional argument cannot follow named argument"), | -
214 | - | parser_errposition(pstate, exprLocation(arg)))); | -
215 | - | } | -
216 | - | } | -
217 | - |  | -
218 | - | if (fargs) | -
219 | - | { | -
220 | - | first_arg = linitial(fargs); | -
221 | - | Assert(first_arg != NULL); | -
222 | - | } | -
223 | - |  | -
224 | - | /* | 7f135d9Recognize row pattern navigation operations by name in DEFINE
225 | - | * Inside an RPR DEFINE clause, an unqualified call to one of the row | 7f135d9Recognize row pattern navigation operations by name in DEFINE
226 | - | * pattern navigation names PREV/NEXT/FIRST/LAST denotes the navigation | 7f135d9Recognize row pattern navigation operations by name in DEFINE
227 | - | * operation, not an ordinary function. Just note that here; the catalog | 7f135d9Recognize row pattern navigation operations by name in DEFINE
228 | - | * lookup is skipped and the RPRNavExpr is built at the end, after the | 7f135d9Recognize row pattern navigation operations by name in DEFINE
229 | - | * common decoration checks have run (see the could_be_rpr_nav handling | 7f135d9Recognize row pattern navigation operations by name in DEFINE
230 | - | * below). A schema-qualified call is the explicit way to reach an | 7f135d9Recognize row pattern navigation operations by name in DEFINE
231 | - | * ordinary function of one of these names. | 7f135d9Recognize row pattern navigation operations by name in DEFINE
232 | - | */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
233 | 261484 | if (!is_column && !proc_call && | 7f135d9Recognize row pattern navigation operations by name in DEFINE
234 | 252657 | pstate->p_expr_kind == EXPR_KIND_RPR_DEFINE && | 7f135d9Recognize row pattern navigation operations by name in DEFINE
235 | 1660 | list_length(funcname) == 1) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
236 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
237 | 1648 | const char *name = strVal(linitial(funcname)); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
238 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
239 | 1648 | if (strcmp(name, "prev") == 0 || | 7f135d9Recognize row pattern navigation operations by name in DEFINE
240 | 588 | strcmp(name, "next") == 0 || | 7f135d9Recognize row pattern navigation operations by name in DEFINE
241 | 423 | strcmp(name, "first") == 0 || | 7f135d9Recognize row pattern navigation operations by name in DEFINE
242 | 192 | strcmp(name, "last") == 0) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
243 | 1596 | could_be_rpr_nav = true; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
244 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
245 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
246 | - | /* | -
247 | - | * Decide whether it's legitimate to consider the construct to be a column | -
248 | - | * projection. For that, there has to be a single argument of complex | -
249 | - | * type, the function name must not be qualified, and there cannot be any | -
250 | - | * syntactic decoration that'd require it to be a function (such as | -
251 | - | * aggregate or variadic decoration, or named arguments). | -
252 | - | */ | -
253 | - | could_be_projection = (nargs == 1 && !proc_call && | -
254 | - | agg_order == NIL && agg_filter == NULL && | -
255 | - | !agg_star && !agg_distinct && over == NULL && | -
256 | - | !func_variadic && argnames == NIL && | -
257 | - | list_length(funcname) == 1 && | -
258 | - | (actual_arg_types[0] == RECORDOID || | -
259 | - | ISCOMPLEX(actual_arg_types[0]))); | -
260 | - |  | -
261 | - | /* | -
262 | - | * If it's column syntax, check for column projection case first. | -
263 | - | */ | -
264 | - | if (could_be_projection && is_column) | -
265 | - | { | -
266 | - | retval = ParseComplexProjection(pstate, | -
267 | - | strVal(linitial(funcname)), | -
268 | - | first_arg, | -
269 | - | location); | -
270 | - | if (retval) | -
271 | - | return retval; | -
272 | - |  | -
273 | - | /* | -
274 | - | * If ParseComplexProjection doesn't recognize it as a projection, | -
275 | - | * just press on. | -
276 | - | */ | -
277 | - | } | -
278 | - |  | -
279 | - | /* | -
280 | - | * func_get_detail looks up the function in the catalogs, does | -
281 | - | * disambiguation for polymorphic functions, handles inheritance, and | -
282 | - | * returns the funcid and type and set or singleton status of the | -
283 | - | * function's return value. It also returns the true argument types to | -
284 | - | * the function. | -
285 | - | * | -
286 | - | * Note: for a named-notation or variadic function call, the reported | -
287 | - | * "true" types aren't really what is in pg_proc: the types are reordered | -
288 | - | * to match the given argument order of named arguments, and a variadic | -
289 | - | * argument is replaced by a suitable number of copies of its element | -
290 | - | * type. We'll fix up the variadic case below. We may also have to deal | -
291 | - | * with default arguments. | -
292 | - | */ | -
293 | - |  | -
294 | 253145 | if (!could_be_rpr_nav) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
295 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
296 | 251549 | setup_parser_errposition_callback(&pcbstate, pstate, location); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
297 | - |  | -
298 | 503098 | fdresult = func_get_detail(funcname, fargs, argnames, nargs, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
299 | - | actual_arg_types, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
300 | - | !func_variadic, true, proc_call, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
301 | - | &fgc_flags, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
302 | - | &funcid, &rettype, &retset, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
303 | - | &nvargs, &vatype, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
304 | 251549 | &declared_arg_types, &argdefaults); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
305 | - |  | -
306 | 251549 | cancel_parser_errposition_callback(&pcbstate); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
307 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
308 | - | else | 7f135d9Recognize row pattern navigation operations by name in DEFINE
309 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
310 | - | /* | 7f135d9Recognize row pattern navigation operations by name in DEFINE
311 | - | * A recognized navigation name skips catalog lookup entirely. Treat | 7f135d9Recognize row pattern navigation operations by name in DEFINE
312 | - | * it as an ordinary function so the common wrong-kind-of-routine and | 7f135d9Recognize row pattern navigation operations by name in DEFINE
313 | - | * decoration checks below run with the existing messages, then route | 7f135d9Recognize row pattern navigation operations by name in DEFINE
314 | - | * to ParseRPRNavCall to build the RPRNavExpr. | 7f135d9Recognize row pattern navigation operations by name in DEFINE
315 | - | */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
316 | 1596 | Assert(!proc_call); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
317 | - |  | b8d226bSetup cursor position for schema-qualified elements
318 | - | fdresult = FUNCDETAIL_NORMAL; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
319 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
320 | - |  | -
321 | - | /* | -
322 | - | * Check for various wrong-kind-of-routine cases. | -
323 | - | */ | -
324 | - |  | -
325 | - | /* If this is a CALL, reject things that aren't procedures */ | -
326 | - | if (proc_call && | -
327 | - | (fdresult == FUNCDETAIL_NORMAL || | -
328 | - | fdresult == FUNCDETAIL_AGGREGATE || | -
329 | - | fdresult == FUNCDETAIL_WINDOWFUNC || | -
330 | - | fdresult == FUNCDETAIL_COERCION)) | -
331 | - | ereport(ERROR, | -
332 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
333 | - | errmsg("%s is not a procedure", | -
334 | - | func_signature_string(funcname, nargs, | -
335 | - | argnames, | -
336 | - | actual_arg_types)), | -
337 | - | errhint("To call a function, use SELECT."), | -
338 | - | parser_errposition(pstate, location))); | -
339 | - | /* Conversely, if not a CALL, reject procedures */ | -
340 | - | if (fdresult == FUNCDETAIL_PROCEDURE && !proc_call) | -
341 | - | ereport(ERROR, | -
342 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
343 | - | errmsg("%s is a procedure", | -
344 | - | func_signature_string(funcname, nargs, | -
345 | - | argnames, | -
346 | - | actual_arg_types)), | -
347 | - | errhint("To call a procedure, use CALL."), | -
348 | - | parser_errposition(pstate, location))); | -
349 | - |  | -
350 | - | if (fdresult == FUNCDETAIL_NORMAL || | -
351 | - | fdresult == FUNCDETAIL_PROCEDURE || | -
352 | - | fdresult == FUNCDETAIL_COERCION) | -
353 | - | { | -
354 | - | /* | -
355 | - | * In these cases, complain if there was anything indicating it must | -
356 | - | * be an aggregate or window function. | -
357 | - | */ | -
358 | - | if (agg_star) | -
359 | - | ereport(ERROR, | -
360 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
361 | - | errmsg("%s(*) specified, but %s is not an aggregate function", | -
362 | - | NameListToString(funcname), | -
363 | - | NameListToString(funcname)), | -
364 | - | parser_errposition(pstate, location))); | -
365 | - | if (agg_distinct) | -
366 | - | ereport(ERROR, | -
367 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
368 | - | errmsg("DISTINCT specified, but %s is not an aggregate function", | -
369 | - | NameListToString(funcname)), | -
370 | - | parser_errposition(pstate, location))); | -
371 | - | if (agg_within_group) | -
372 | - | ereport(ERROR, | -
373 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
374 | - | errmsg("WITHIN GROUP specified, but %s is not an aggregate function", | -
375 | - | NameListToString(funcname)), | -
376 | - | parser_errposition(pstate, location))); | -
377 | - | if (agg_order != NIL) | -
378 | - | ereport(ERROR, | -
379 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
380 | - | errmsg("ORDER BY specified, but %s is not an aggregate function", | -
381 | - | NameListToString(funcname)), | -
382 | - | parser_errposition(pstate, location))); | -
383 | - | if (agg_filter) | -
384 | - | ereport(ERROR, | -
385 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
386 | - | errmsg("FILTER specified, but %s is not an aggregate function", | -
387 | - | NameListToString(funcname)), | -
388 | - | parser_errposition(pstate, location))); | -
389 | - | if (over) | -
390 | - | ereport(ERROR, | -
391 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
392 | - | errmsg("OVER specified, but %s is not a window function nor an aggregate function", | -
393 | - | NameListToString(funcname)), | -
394 | - | parser_errposition(pstate, location))); | -
395 | - | } | -
396 | - |  | -
397 | - | /* | -
398 | - | * NULL TREATEMENT is only allowed for window functions per spec. | -
399 | - | */ | -
400 | - | if (fdresult != FUNCDETAIL_WINDOWFUNC && ignore_nulls != NO_NULLTREATMENT) | -
401 | - | ereport(ERROR, | -
402 | - | errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
403 | - | errmsg("only window functions accept RESPECT/IGNORE NULLS"), | -
404 | - | parser_errposition(pstate, location)); | -
405 | - |  | -
406 | - | /* | -
407 | - | * So far so good, so do some fdresult-type-specific processing. | -
408 | - | */ | -
409 | - | if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE) | -
410 | - | { | -
411 | - | /* Nothing special to do for these cases. */ | -
412 | - | } | -
413 | - | else if (fdresult == FUNCDETAIL_AGGREGATE) | -
414 | - | { | -
415 | - | /* | -
416 | - | * It's an aggregate; fetch needed info from the pg_aggregate entry. | -
417 | - | */ | -
418 | - | HeapTuple tup; | -
419 | - | Form_pg_aggregate classForm; | -
420 | - | int catDirectArgs; | -
421 | - |  | -
422 | - | tup = SearchSysCache1(AGGFNOID, ObjectIdGetDatum(funcid)); | -
423 | - | if (!HeapTupleIsValid(tup)) /* should not happen */ | -
424 | - | elog(ERROR, "cache lookup failed for aggregate %u", funcid); | -
425 | - | classForm = (Form_pg_aggregate) GETSTRUCT(tup); | -
426 | - | aggkind = classForm->aggkind; | -
427 | - | catDirectArgs = classForm->aggnumdirectargs; | -
428 | - | ReleaseSysCache(tup); | -
429 | - |  | -
430 | - | /* Now check various disallowed cases. */ | -
431 | - | if (AGGKIND_IS_ORDERED_SET(aggkind)) | -
432 | - | { | -
433 | - | int numAggregatedArgs; | -
434 | - | int numDirectArgs; | -
435 | - |  | -
436 | - | if (!agg_within_group) | -
437 | - | ereport(ERROR, | -
438 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
439 | - | errmsg("WITHIN GROUP is required for ordered-set aggregate %s", | -
440 | - | NameListToString(funcname)), | -
441 | - | parser_errposition(pstate, location))); | -
442 | - | if (over) | -
443 | - | ereport(ERROR, | -
444 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
445 | - | errmsg("OVER is not supported for ordered-set aggregate %s", | -
446 | - | NameListToString(funcname)), | -
447 | - | parser_errposition(pstate, location))); | -
448 | - | /* gram.y rejects DISTINCT + WITHIN GROUP */ | -
449 | - | Assert(!agg_distinct); | -
450 | - | /* gram.y rejects VARIADIC + WITHIN GROUP */ | -
451 | - | Assert(!func_variadic); | -
452 | - |  | -
453 | - | /* | -
454 | - | * Since func_get_detail was working with an undifferentiated list | -
455 | - | * of arguments, it might have selected an aggregate that doesn't | -
456 | - | * really match because it requires a different division of direct | -
457 | - | * and aggregated arguments. Check that the number of direct | -
458 | - | * arguments is actually OK; if not, throw an "undefined function" | -
459 | - | * error, similarly to the case where a misplaced ORDER BY is used | -
460 | - | * in a regular aggregate call. | -
461 | - | */ | -
462 | - | numAggregatedArgs = list_length(agg_order); | -
463 | - | numDirectArgs = nargs - numAggregatedArgs; | -
464 | - | Assert(numDirectArgs >= 0); | -
465 | - |  | -
466 | - | if (!OidIsValid(vatype)) | -
467 | - | { | -
468 | - | /* Test is simple if aggregate isn't variadic */ | -
469 | - | if (numDirectArgs != catDirectArgs) | -
470 | - | ereport(ERROR, | -
471 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
472 | - | errmsg("function %s does not exist", | -
473 | - | func_signature_string(funcname, nargs, | -
474 | - | argnames, | -
475 | - | actual_arg_types)), | -
476 | - | errhint_plural("There is an ordered-set aggregate %s, but it requires %d direct argument, not %d.", | -
477 | - | "There is an ordered-set aggregate %s, but it requires %d direct arguments, not %d.", | -
478 | - | catDirectArgs, | -
479 | - | NameListToString(funcname), | -
480 | - | catDirectArgs, numDirectArgs), | -
481 | - | parser_errposition(pstate, location))); | -
482 | - | } | -
483 | - | else | -
484 | - | { | -
485 | - | /* | -
486 | - | * If it's variadic, we have two cases depending on whether | -
487 | - | * the agg was "... ORDER BY VARIADIC" or "..., VARIADIC ORDER | -
488 | - | * BY VARIADIC". It's the latter if catDirectArgs equals | -
489 | - | * pronargs; to save a catalog lookup, we reverse-engineer | -
490 | - | * pronargs from the info we got from func_get_detail. | -
491 | - | */ | -
492 | - | int pronargs; | -
493 | - |  | -
494 | - | pronargs = nargs; | -
495 | - | if (nvargs > 1) | -
496 | - | pronargs -= nvargs - 1; | -
497 | - | if (catDirectArgs < pronargs) | -
498 | - | { | -
499 | - | /* VARIADIC isn't part of direct args, so still easy */ | -
500 | - | if (numDirectArgs != catDirectArgs) | -
501 | - | ereport(ERROR, | -
502 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
503 | - | errmsg("function %s does not exist", | -
504 | - | func_signature_string(funcname, nargs, | -
505 | - | argnames, | -
506 | - | actual_arg_types)), | -
507 | - | errhint_plural("There is an ordered-set aggregate %s, but it requires %d direct argument, not %d.", | -
508 | - | "There is an ordered-set aggregate %s, but it requires %d direct arguments, not %d.", | -
509 | - | catDirectArgs, | -
510 | - | NameListToString(funcname), | -
511 | - | catDirectArgs, numDirectArgs), | -
512 | - | parser_errposition(pstate, location))); | -
513 | - | } | -
514 | - | else | -
515 | - | { | -
516 | - | /* | -
517 | - | * Both direct and aggregated args were declared variadic. | -
518 | - | * For a standard ordered-set aggregate, it's okay as long | -
519 | - | * as there aren't too few direct args. For a | -
520 | - | * hypothetical-set aggregate, we assume that the | -
521 | - | * hypothetical arguments are those that matched the | -
522 | - | * variadic parameter; there must be just as many of them | -
523 | - | * as there are aggregated arguments. | -
524 | - | */ | -
525 | - | if (aggkind == AGGKIND_HYPOTHETICAL) | -
526 | - | { | -
527 | - | if (nvargs != 2 * numAggregatedArgs) | -
528 | - | ereport(ERROR, | -
529 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
530 | - | errmsg("function %s does not exist", | -
531 | - | func_signature_string(funcname, nargs, | -
532 | - | argnames, | -
533 | - | actual_arg_types)), | -
534 | - | errhint("To use the hypothetical-set aggregate %s, the number of hypothetical direct arguments (here %d) must match the number of ordering columns (here %d).", | -
535 | - | NameListToString(funcname), | -
536 | - | nvargs - numAggregatedArgs, numAggregatedArgs), | -
537 | - | parser_errposition(pstate, location))); | -
538 | - | } | -
539 | - | else | -
540 | - | { | -
541 | - | if (nvargs <= numAggregatedArgs) | -
542 | - | ereport(ERROR, | -
543 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
544 | - | errmsg("function %s does not exist", | -
545 | - | func_signature_string(funcname, nargs, | -
546 | - | argnames, | -
547 | - | actual_arg_types)), | -
548 | - | errhint_plural("There is an ordered-set aggregate %s, but it requires at least %d direct argument.", | -
549 | - | "There is an ordered-set aggregate %s, but it requires at least %d direct arguments.", | -
550 | - | catDirectArgs, | -
551 | - | NameListToString(funcname), | -
552 | - | catDirectArgs), | -
553 | - | parser_errposition(pstate, location))); | -
554 | - | } | -
555 | - | } | -
556 | - | } | -
557 | - |  | -
558 | - | /* Check type matching of hypothetical arguments */ | -
559 | - | if (aggkind == AGGKIND_HYPOTHETICAL) | -
560 | - | unify_hypothetical_args(pstate, fargs, numAggregatedArgs, | -
561 | - | actual_arg_types, declared_arg_types); | -
562 | - | } | -
563 | - | else | -
564 | - | { | -
565 | - | /* Normal aggregate, so it can't have WITHIN GROUP */ | -
566 | - | if (agg_within_group) | -
567 | - | ereport(ERROR, | -
568 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
569 | - | errmsg("%s is not an ordered-set aggregate, so it cannot have WITHIN GROUP", | -
570 | - | NameListToString(funcname)), | -
571 | - | parser_errposition(pstate, location))); | -
572 | - | } | -
573 | - | } | -
574 | - | else if (fdresult == FUNCDETAIL_WINDOWFUNC) | -
575 | - | { | -
576 | - | /* | -
577 | - | * True window functions must be called with a window definition. | -
578 | - | */ | -
579 | - | if (!over) | -
580 | - | ereport(ERROR, | -
581 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
582 | - | errmsg("window function %s requires an OVER clause", | -
583 | - | NameListToString(funcname)), | -
584 | - | parser_errposition(pstate, location))); | -
585 | - | /* And, per spec, WITHIN GROUP isn't allowed */ | -
586 | - | if (agg_within_group) | -
587 | - | ereport(ERROR, | -
588 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
589 | - | errmsg("window function %s cannot have WITHIN GROUP", | -
590 | - | NameListToString(funcname)), | -
591 | - | parser_errposition(pstate, location))); | -
592 | - | } | -
593 | - | else if (fdresult == FUNCDETAIL_COERCION) | -
594 | - | { | -
595 | - | /* | -
596 | - | * We interpreted it as a type coercion. coerce_type can handle these | -
597 | - | * cases, so why duplicate code... | -
598 | - | */ | -
599 | - | return coerce_type(pstate, linitial(fargs), | -
600 | - | actual_arg_types[0], rettype, -1, | -
601 | - | COERCION_EXPLICIT, COERCE_EXPLICIT_CALL, location); | -
602 | - | } | -
603 | - | else if (fdresult == FUNCDETAIL_MULTIPLE) | -
604 | - | { | -
605 | - | /* | -
606 | - | * We found multiple possible functional matches. If we are dealing | -
607 | - | * with attribute notation, return failure, letting the caller report | -
608 | - | * "no such column" (we already determined there wasn't one). If | -
609 | - | * dealing with function notation, report "ambiguous function", | -
610 | - | * regardless of whether there's also a column by this name. | -
611 | - | */ | -
612 | - | if (is_column) | -
613 | - | return NULL; | -
614 | - |  | -
615 | - | if (proc_call) | -
616 | - | ereport(ERROR, | -
617 | - | (errcode(ERRCODE_AMBIGUOUS_FUNCTION), | -
618 | - | errmsg("procedure %s is not unique", | -
619 | - | func_signature_string(funcname, nargs, argnames, | -
620 | - | actual_arg_types)), | -
621 | - | errdetail("Could not choose a best candidate procedure."), | -
622 | - | errhint("You might need to add explicit type casts."), | -
623 | - | parser_errposition(pstate, location))); | -
624 | - | else | -
625 | - | ereport(ERROR, | -
626 | - | (errcode(ERRCODE_AMBIGUOUS_FUNCTION), | -
627 | - | errmsg("function %s is not unique", | -
628 | - | func_signature_string(funcname, nargs, argnames, | -
629 | - | actual_arg_types)), | -
630 | - | errdetail("Could not choose a best candidate function."), | -
631 | - | errhint("You might need to add explicit type casts."), | -
632 | - | parser_errposition(pstate, location))); | -
633 | - | } | -
634 | - | else | -
635 | - | { | -
636 | - | /* | -
637 | - | * Not found as a function. If we are dealing with attribute | -
638 | - | * notation, return failure, letting the caller report "no such | -
639 | - | * column" (we already determined there wasn't one). | -
640 | - | */ | -
641 | - | if (is_column) | -
642 | - | return NULL; | -
643 | - |  | -
644 | - | /* | -
645 | - | * Check for column projection interpretation, since we didn't before. | -
646 | - | */ | -
647 | - | if (could_be_projection) | -
648 | - | { | -
649 | - | retval = ParseComplexProjection(pstate, | -
650 | - | strVal(linitial(funcname)), | -
651 | - | first_arg, | -
652 | - | location); | -
653 | - | if (retval) | -
654 | - | return retval; | -
655 | - | } | -
656 | - |  | -
657 | - | /* | -
658 | - | * No function, and no column either. Since we're dealing with | -
659 | - | * function notation, report "function/procedure does not exist". | -
660 | - | * Depending on what was returned in fgc_flags, we can add some color | -
661 | - | * to that with detail or hint messages. | -
662 | - | */ | -
663 | - | if (list_length(agg_order) > 1 && !agg_within_group) | -
664 | - | { | -
665 | - | /* It's agg(x, ORDER BY y,z) ... perhaps misplaced ORDER BY */ | -
666 | - | ereport(ERROR, | -
667 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
668 | - | errmsg("function %s does not exist", | -
669 | - | func_signature_string(funcname, nargs, argnames, | -
670 | - | actual_arg_types)), | -
671 | - | errdetail("No aggregate function matches the given name and argument types."), | -
672 | - | errhint("Perhaps you misplaced ORDER BY; ORDER BY must appear " | -
673 | - | "after all regular arguments of the aggregate."), | -
674 | - | parser_errposition(pstate, location))); | -
675 | - | } | -
676 | - | else if (proc_call) | -
677 | - | ereport(ERROR, | -
678 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
679 | - | errmsg("procedure %s does not exist", | -
680 | - | func_signature_string(funcname, nargs, argnames, | -
681 | - | actual_arg_types)), | -
682 | - | func_lookup_failure_details(fgc_flags, argnames, | -
683 | - | proc_call), | -
684 | - | parser_errposition(pstate, location))); | -
685 | - | else | -
686 | - | ereport(ERROR, | -
687 | - | (errcode(ERRCODE_UNDEFINED_FUNCTION), | -
688 | - | errmsg("function %s does not exist", | -
689 | - | func_signature_string(funcname, nargs, argnames, | -
690 | - | actual_arg_types)), | -
691 | - | func_lookup_failure_details(fgc_flags, argnames, | -
692 | - | proc_call), | -
693 | - | parser_errposition(pstate, location))); | -
694 | - | } | -
695 | - |  | -
696 | - | /* | 7f135d9Recognize row pattern navigation operations by name in DEFINE
697 | - | * A recognized navigation name has now passed the common decoration and | 7f135d9Recognize row pattern navigation operations by name in DEFINE
698 | - | * wrong-kind checks above; build the RPRNavExpr. No fallback to function | 7f135d9Recognize row pattern navigation operations by name in DEFINE
699 | - | * resolution ever happens here. | 7f135d9Recognize row pattern navigation operations by name in DEFINE
700 | - | */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
701 | 252179 | if (could_be_rpr_nav) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
702 | 1568 | return ParseRPRNavCall(pstate, funcname, fargs, argnames, fn, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
703 | - | location); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
704 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
705 | - | /* | -
706 | - | * If there are default arguments, we have to include their types in | -
707 | - | * actual_arg_types for the purpose of checking generic type consistency. | -
708 | - | * However, we do NOT put them into the generated parse node, because | -
709 | - | * their actual values might change before the query gets run. The | -
710 | - | * planner has to insert the up-to-date values at plan time. | -
711 | - | */ | -
712 | - | nargsplusdefs = nargs; | -
713 | - | foreach(l, argdefaults) | -
714 | - | { | -
715 | - | Node *expr = (Node *) lfirst(l); | -
716 | - |  | -
717 | - | /* probably shouldn't happen ... */ | -
718 | - | if (nargsplusdefs >= FUNC_MAX_ARGS) | -
719 | - | ereport(ERROR, | -
720 | - | (errcode(ERRCODE_TOO_MANY_ARGUMENTS), | -
721 | - | errmsg_plural("cannot pass more than %d argument to a function", | -
722 | - | "cannot pass more than %d arguments to a function", | -
723 | - | FUNC_MAX_ARGS, | -
724 | - | FUNC_MAX_ARGS), | -
725 | - | parser_errposition(pstate, location))); | -
726 | - |  | -
727 | - | actual_arg_types[nargsplusdefs++] = exprType(expr); | -
728 | - | } | -
729 | - |  | -
730 | - | /* | -
731 | - | * enforce consistency with polymorphic argument and return types, | -
732 | - | * possibly adjusting return type or declared_arg_types (which will be | -
733 | - | * used as the cast destination by make_fn_arguments) | -
734 | - | */ | -
735 | - | rettype = enforce_generic_type_consistency(actual_arg_types, | -
736 | - | declared_arg_types, | -
737 | - | nargsplusdefs, | -
738 | - | rettype, | -
739 | - | false); | -
740 | - |  | -
741 | - | /* perform the necessary typecasting of arguments */ | -
742 | - | make_fn_arguments(pstate, fargs, actual_arg_types, declared_arg_types); | -
743 | - |  | -
744 | - | /* | -
745 | - | * If the function isn't actually variadic, forget any VARIADIC decoration | -
746 | - | * on the call. (Perhaps we should throw an error instead, but | -
747 | - | * historically we've allowed people to write that.) | -
748 | - | */ | -
749 | - | if (!OidIsValid(vatype)) | -
750 | - | { | -
751 | - | Assert(nvargs == 0); | -
752 | - | func_variadic = false; | -
753 | - | } | -
754 | - |  | -
755 | - | /* | -
756 | - | * If it's a variadic function call, transform the last nvargs arguments | -
757 | - | * into an array --- unless it's an "any" variadic. | -
758 | - | */ | -
759 | - | if (nvargs > 0 && vatype != ANYOID) | -
760 | - | { | -
761 | - | ArrayExpr *newa = makeNode(ArrayExpr); | -
762 | - | int non_var_args = nargs - nvargs; | -
763 | - | List *vargs; | -
764 | - |  | -
765 | - | Assert(non_var_args >= 0); | -
766 | - | vargs = list_copy_tail(fargs, non_var_args); | -
767 | - | fargs = list_truncate(fargs, non_var_args); | -
768 | - |  | -
769 | - | newa->elements = vargs; | -
770 | - | /* assume all the variadic arguments were coerced to the same type */ | -
771 | - | newa->element_typeid = exprType((Node *) linitial(vargs)); | -
772 | - | newa->array_typeid = get_array_type(newa->element_typeid); | -
773 | - | if (!OidIsValid(newa->array_typeid)) | -
774 | - | ereport(ERROR, | -
775 | - | (errcode(ERRCODE_UNDEFINED_OBJECT), | -
776 | - | errmsg("could not find array type for data type %s", | -
777 | - | format_type_be(newa->element_typeid)), | -
778 | - | parser_errposition(pstate, exprLocation((Node *) vargs)))); | -
779 | - | /* array_collid will be set by parse_collate.c */ | -
780 | - | newa->multidims = false; | -
781 | - | newa->location = exprLocation((Node *) vargs); | -
782 | - |  | -
783 | - | fargs = lappend(fargs, newa); | -
784 | - |  | -
785 | - | /* We could not have had VARIADIC marking before ... */ | -
786 | - | Assert(!func_variadic); | -
787 | - | /* ... but now, it's a VARIADIC call */ | -
788 | - | func_variadic = true; | -
789 | - | } | -
790 | - |  | -
791 | - | /* | -
792 | - | * If an "any" variadic is called with explicit VARIADIC marking, insist | -
793 | - | * that the variadic parameter be of some array type. | -
794 | - | */ | -
795 | - | if (nargs > 0 && vatype == ANYOID && func_variadic) | -
796 | - | { | -
797 | - | Oid va_arr_typid = actual_arg_types[nargs - 1]; | -
798 | - |  | -
799 | - | if (!OidIsValid(get_base_element_type(va_arr_typid))) | -
800 | - | ereport(ERROR, | -
801 | - | (errcode(ERRCODE_DATATYPE_MISMATCH), | -
802 | - | errmsg("VARIADIC argument must be an array"), | -
803 | - | parser_errposition(pstate, | -
804 | - | exprLocation((Node *) llast(fargs))))); | -
805 | - | } | -
806 | - |  | -
807 | - | /* if it returns a set, check that's OK */ | -
808 | - | if (retset) | -
809 | - | check_srf_call_placement(pstate, last_srf, location); | -
810 | - |  | -
811 | - | /* build the appropriate output structure */ | -
812 | - | if (fdresult == FUNCDETAIL_NORMAL || fdresult == FUNCDETAIL_PROCEDURE) | -
813 | - | { | -
814 | - | FuncExpr *funcexpr = makeNode(FuncExpr); | -
815 | - |  | -
816 | - | funcexpr->funcid = funcid; | -
817 | - | funcexpr->funcresulttype = rettype; | -
818 | - | funcexpr->funcretset = retset; | -
819 | - | funcexpr->funcvariadic = func_variadic; | -
820 | - | funcexpr->funcformat = funcformat; | -
821 | - | /* funccollid and inputcollid will be set by parse_collate.c */ | -
822 | - | funcexpr->args = fargs; | -
823 | - | funcexpr->location = location; | -
824 | - |  | -
825 | - | retval = (Node *) funcexpr; | -
826 | - | } | -
827 | - | else if (fdresult == FUNCDETAIL_AGGREGATE && !over) | -
828 | - | { | -
829 | - | /* aggregate function */ | -
830 | - | Aggref *aggref = makeNode(Aggref); | -
831 | - |  | -
832 | - | aggref->aggfnoid = funcid; | -
833 | - | aggref->aggtype = rettype; | -
834 | - | /* aggcollid and inputcollid will be set by parse_collate.c */ | -
835 | - | aggref->aggtranstype = InvalidOid; /* will be set by planner */ | -
836 | - | /* aggargtypes will be set by transformAggregateCall */ | -
837 | - | /* aggdirectargs and args will be set by transformAggregateCall */ | -
838 | - | /* aggorder and aggdistinct will be set by transformAggregateCall */ | -
839 | - | aggref->aggfilter = agg_filter; | -
840 | - | aggref->aggstar = agg_star; | -
841 | - | aggref->aggvariadic = func_variadic; | -
842 | - | aggref->aggkind = aggkind; | -
843 | - | aggref->aggpresorted = false; | -
844 | - | /* agglevelsup will be set by transformAggregateCall */ | -
845 | - | aggref->aggsplit = AGGSPLIT_SIMPLE; /* planner might change this */ | -
846 | - | aggref->aggno = -1; /* planner will set aggno and aggtransno */ | -
847 | - | aggref->aggtransno = -1; | -
848 | - | aggref->location = location; | -
849 | - |  | -
850 | - | /* | -
851 | - | * Reject attempt to call a parameterless aggregate without (*) | -
852 | - | * syntax. This is mere pedantry but some folks insisted ... | -
853 | - | */ | -
854 | - | if (fargs == NIL && !agg_star && !agg_within_group) | -
855 | - | ereport(ERROR, | -
856 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
857 | - | errmsg("%s(*) must be used to call a parameterless aggregate function", | -
858 | - | NameListToString(funcname)), | -
859 | - | parser_errposition(pstate, location))); | -
860 | - |  | -
861 | - | if (retset) | -
862 | - | ereport(ERROR, | -
863 | - | (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), | -
864 | - | errmsg("aggregates cannot return sets"), | -
865 | - | parser_errposition(pstate, location))); | -
866 | - |  | -
867 | - | /* | -
868 | - | * We might want to support named arguments later, but disallow it for | -
869 | - | * now. We'd need to figure out the parsed representation (should the | -
870 | - | * NamedArgExprs go above or below the TargetEntry nodes?) and then | -
871 | - | * teach the planner to reorder the list properly. Or maybe we could | -
872 | - | * make transformAggregateCall do that? However, if you'd also like | -
873 | - | * to allow default arguments for aggregates, we'd need to do it in | -
874 | - | * planning to avoid semantic problems. | -
875 | - | */ | -
876 | - | if (argnames != NIL) | -
877 | - | ereport(ERROR, | -
878 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
879 | - | errmsg("aggregates cannot use named arguments"), | -
880 | - | parser_errposition(pstate, location))); | -
881 | - |  | -
882 | - | /* parse_agg.c does additional aggregate-specific processing */ | -
883 | - | transformAggregateCall(pstate, aggref, fargs, agg_order, agg_distinct); | -
884 | - |  | -
885 | - | retval = (Node *) aggref; | -
886 | - | } | -
887 | - | else | -
888 | - | { | -
889 | - | /* window function */ | -
890 | - | WindowFunc *wfunc = makeNode(WindowFunc); | -
891 | - |  | -
892 | - | Assert(over); /* lack of this was checked above */ | -
893 | - | Assert(!agg_within_group); /* also checked above */ | -
894 | - |  | -
895 | - | wfunc->winfnoid = funcid; | -
896 | - | wfunc->wintype = rettype; | -
897 | - | /* wincollid and inputcollid will be set by parse_collate.c */ | -
898 | - | wfunc->args = fargs; | -
899 | - | /* winref will be set by transformWindowFuncCall */ | -
900 | - | wfunc->winstar = agg_star; | -
901 | - | wfunc->winagg = (fdresult == FUNCDETAIL_AGGREGATE); | -
902 | - | wfunc->aggfilter = agg_filter; | -
903 | - | wfunc->ignore_nulls = ignore_nulls; | -
904 | - | wfunc->runCondition = NIL; | -
905 | - | wfunc->location = location; | -
906 | - |  | -
907 | - | /* | -
908 | - | * agg_star is allowed for aggregate functions but distinct isn't | -
909 | - | */ | -
910 | - | if (agg_distinct) | -
911 | - | ereport(ERROR, | -
912 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
913 | - | errmsg("DISTINCT is not implemented for window functions"), | -
914 | - | parser_errposition(pstate, location))); | -
915 | - |  | -
916 | - | /* | -
917 | - | * Reject attempt to call a parameterless aggregate without (*) | -
918 | - | * syntax. This is mere pedantry but some folks insisted ... | -
919 | - | */ | -
920 | - | if (wfunc->winagg && fargs == NIL && !agg_star) | -
921 | - | ereport(ERROR, | -
922 | - | (errcode(ERRCODE_WRONG_OBJECT_TYPE), | -
923 | - | errmsg("%s(*) must be used to call a parameterless aggregate function", | -
924 | - | NameListToString(funcname)), | -
925 | - | parser_errposition(pstate, location))); | -
926 | - |  | -
927 | - | /* | -
928 | - | * ordered aggs not allowed in windows yet | -
929 | - | */ | -
930 | - | if (agg_order != NIL) | -
931 | - | ereport(ERROR, | -
932 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
933 | - | errmsg("aggregate ORDER BY is not implemented for window functions"), | -
934 | - | parser_errposition(pstate, location))); | -
935 | - |  | -
936 | - | /* | -
937 | - | * FILTER is not yet supported with true window functions | -
938 | - | */ | -
939 | - | if (!wfunc->winagg && agg_filter) | -
940 | - | ereport(ERROR, | -
941 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
942 | - | errmsg("FILTER is not implemented for non-aggregate window functions"), | -
943 | - | parser_errposition(pstate, location))); | -
944 | - |  | -
945 | - | /* | -
946 | - | * Window functions can't either take or return sets | -
947 | - | */ | -
948 | - | if (pstate->p_last_srf != last_srf) | -
949 | - | ereport(ERROR, | -
950 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
951 | - | errmsg("window function calls cannot contain set-returning function calls"), | -
952 | - | errhint("You might be able to move the set-returning function into a LATERAL FROM item."), | -
953 | - | parser_errposition(pstate, | -
954 | - | exprLocation(pstate->p_last_srf)))); | -
955 | - |  | -
956 | - | if (retset) | -
957 | - | ereport(ERROR, | -
958 | - | (errcode(ERRCODE_INVALID_FUNCTION_DEFINITION), | -
959 | - | errmsg("window functions cannot return sets"), | -
960 | - | parser_errposition(pstate, location))); | -
961 | - |  | -
962 | - | /* parse_agg.c does additional window-func-specific processing */ | -
963 | - | transformWindowFuncCall(pstate, wfunc, over); | -
964 | - |  | -
965 | - | retval = (Node *) wfunc; | -
966 | - | } | -
967 | - |  | -
968 | - | /* if it returns a set, remember it for error checks at higher levels */ | -
969 | - | if (retset) | -
970 | - | pstate->p_last_srf = retval; | -
971 | - |  | -
972 | - | return retval; | -
973 | - | } | -

ParseRPRNavCall() lines 2102-2226
Modified Lines Coverage: 37/39 lines (94.9%)

Line | Hits | Source | Commit
--- | --- | --- | ---
2102 | 1568 | ParseRPRNavCall(ParseState *pstate, List *funcname, List *fargs, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2103 | - | List *argnames, FuncCall *fn, int location) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2104 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2105 | 1568 | const char *name = strVal(linitial(funcname)); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2106 | 1568 | RPRNavKind kind; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2107 | 1568 | const char *navname; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2108 | 1568 | int nargs = list_length(fargs); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2109 | 1568 | Node *arg; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2110 | 1568 | RPRNavExpr *navexpr; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2111 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2112 | - | /* match the parser-downcased identifier; otherwise not a navigation name */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2113 | 1568 | if (strcmp(name, "prev") == 0) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2114 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2115 | - | kind = RPR_NAV_PREV; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2116 | - | navname = "PREV"; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2117 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2118 | 536 | else if (strcmp(name, "next") == 0) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2119 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2120 | - | kind = RPR_NAV_NEXT; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2121 | - | navname = "NEXT"; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2122 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2123 | 371 | else if (strcmp(name, "first") == 0) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2124 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2125 | - | kind = RPR_NAV_FIRST; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2126 | - | navname = "FIRST"; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2127 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2128 | 140 | else if (strcmp(name, "last") == 0) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2129 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2130 | - | kind = RPR_NAV_LAST; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2131 | - | navname = "LAST"; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2132 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2133 | - | else | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2134 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2135 | - | /* the caller only routes here after matching one of the four names */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2136 | 0 | pg_unreachable(); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
| UnreachableDefensive (unreachable) · confidence high · `ParseRPRNavCall @2136` Reason
    Confirmed defensive-unreachable.
    ParseRPRNavCall is invoked only when could_be_rpr_nav is true (parse_func.c:701-702), which is set true only after name exactly matches one of "prev"/"next"/"first"/"last" (lines 239-243).
    Inside ParseRPRNavCall, name is re-derived from the same unmutated funcname list (line 2105). funcname is passed through unchanged (line 702) and not mutated in between.
    Thus when control reaches the if/else-if chain (2113-2132), exactly one strcmp must succeed;
    the else at 2133-2138 with pg_unreachable() at 2136 cannot execute via any SQL input.
    Attempts to refute: any other name yields could_be_rpr_nav=false -> normal func_get_detail path, never reaching this function;
    schema-qualified names fail list_length==1;
    case is normalized by the parser before both checks.
    No reachable input exists.
Recommended fix
    Keep as-is.
    The pg_unreachable() plus return NULL is the correct defensive guard for an exhaustive dispatch.
    The trailing return NULL after pg_unreachable() is harmless and silences compilers that do not treat pg_unreachable() as no-return.
    No source change needed.
2137 | - | return NULL; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2138 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2139 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2140 | - | /* | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2141 | - | * Once the name matches we never fall back to function resolution, so any | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2142 | - | * decoration that does not make sense for a navigation operation is a | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2143 | - | * hard error. The aggregate/window decorations (agg_star, DISTINCT, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2144 | - | * WITHIN GROUP, ORDER BY, FILTER, OVER, RESPECT/IGNORE NULLS) are already | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2145 | - | * rejected by the common path in ParseFuncOrColumn, which treated the | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2146 | - | * recognized name as an ordinary function; what remains are the | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2147 | - | * decorations that path accepts for a plain function but a navigation | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2148 | - | * operation must still reject. | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2149 | - | */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2150 | 1568 | if (fn->func_variadic) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2151 | 4 | ereport(ERROR, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2152 | - | (errcode(ERRCODE_SYNTAX_ERROR), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2153 | - | errmsg("cannot use VARIADIC with row pattern navigation function %s", | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2154 | - | navname), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2155 | - | parser_errposition(pstate, location))); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2156 | 1564 | if (argnames != NIL) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2157 | 4 | ereport(ERROR, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2158 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2159 | - | errmsg("row pattern navigation operations cannot use named arguments"), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2160 | - | parser_errposition(pstate, location))); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2161 | - | /* takes a value expression and an optional offset */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2162 | 1560 | if (nargs == 0) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2163 | 4 | ereport(ERROR, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2164 | - | (errcode(ERRCODE_SYNTAX_ERROR), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2165 | - | errmsg("too few arguments for row pattern navigation function %s", | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2166 | - | navname), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2167 | - | errdetail("%s takes a value expression and an optional offset argument.", | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2168 | - | navname), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2169 | - | parser_errposition(pstate, location))); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2170 | 1556 | if (nargs > 2) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2171 | 8 | ereport(ERROR, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2172 | - | (errcode(ERRCODE_SYNTAX_ERROR), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2173 | - | errmsg("too many arguments for row pattern navigation function %s", | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2174 | - | navname), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2175 | - | errdetail("%s takes a value expression and an optional offset argument.", | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2176 | - | navname), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2177 | - | parser_errposition(pstate, location))); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2178 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2179 | - | /* | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2180 | - | * Resolve a still-unknown first argument to text, the same way the | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2181 | - | * anycompatible family does. A navigation operation is not a polymorphic | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2182 | - | * function, so the old "could not determine polymorphic type" error does | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2183 | - | * not apply; an unknown literal cannot contain a column reference, so the | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2184 | - | * walker still rejects it later. | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2185 | - | */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2186 | 1548 | arg = linitial(fargs); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2187 | 1548 | if (exprType(arg) == UNKNOWNOID) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2188 | 16 | arg = coerce_to_common_type(pstate, arg, TEXTOID, navname); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2189 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2190 | 1548 | navexpr = makeNode(RPRNavExpr); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2191 | 1548 | navexpr->kind = kind; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2192 | 1548 | navexpr->arg = (Expr *) arg; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2193 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2194 | - | /* an explicit offset is coerced to int8, which the executor reads */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2195 | 1548 | if (nargs == 2) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2196 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2197 | 487 | Node *offset = lsecond(fargs); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2198 | 487 | Oid offtype = exprType(offset); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2199 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2200 | 487 | if (offtype != INT8OID) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2201 | - | { | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2202 | 380 | Node *newoffset; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2203 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2204 | 380 | newoffset = coerce_to_target_type(pstate, offset, offtype, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2205 | - | INT8OID, -1, COERCION_IMPLICIT, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2206 | - | COERCE_IMPLICIT_CAST, -1); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2207 | 380 | if (newoffset == NULL) | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2208 | 0 | ereport(ERROR, | 7f135d9Recognize row pattern navigation operations by name in DEFINE
| ReachableTestable · confidence high · `ParseRPRNavCall @2208-2212` · 5 lines How to test
    Add to src/test/regress/sql/rpr.sql (and matching .out), against an existing RPR table such as stock/price-bearing table used elsewhere in the file.
    Use a numeric offset literal, which is the cleanest deterministic case:

    -- negative test: offset argument type with no implicit cast to bigint
    SELECT company, tdate, price, count(*) OVER w
    FROM stock
    WINDOW w AS (
    PARTITION BY company
    ORDER BY tdate
    ROWS BETWEEN CURRENT ROW AND UNBOUNDED FOLLOWING
    PATTERN (A B+)
    DEFINE B AS price > PREV(price, 1.5)
    );

    Expected .out (do not wrap in DO block):
    ERROR:  offset argument of PREV must be type bigint, not type numeric
    LINE n:
    DEFINE B AS price > PREV(price, 1.5)
                                              ^

    Notes / caveats verified:
    1. The decimal constant 1.5 is typed numeric (not float8);
    numeric->int8 is assignment-context only, so COERCION_IMPLICIT returns NULL -> exact lines hit.
    Good.
    2. An alternative offset PREV(price, 'x') also reaches the branch, BUT a bare 'x' is UNKNOWNOID: coercion of unknown to int8 also returns NULL, and the message would read "not type unknown" -- usable but less intuitive;
    if a text type is wanted use PREV(price, 'x'::text) which yields "not type text" (text has no cast to int8 at all).
    Prefer the numeric 1.5 form for clarity and determinism.
    3. Use the actual table/column names already present in rpr.sql (e.g. the 'stock'/'company'/'price'/'tdate' fixtures) so the parser reaches the
    DEFINE walk;
    the error is raised at parse-analysis of the nav call regardless of data, so no specific rows are required.
Verdict
    Confirmed reachable and testable.
    Lines 2207-2212 fire when a 2-arg nav call's explicit offset has a type lacking an IMPLICIT cast to int8. I verified the code (parse_func.c:2195-2216): nargs==2 with offtype != INT8OID calls coerce_to_target_type with COERCION_IMPLICIT/COERCE_IMPLICIT_CAST;
    a NULL result raises the ereport.
    I confirmed via pg_cast.dat that numeric->int8 has castcontext 'a' (assignment-only), so COERCION_IMPLICIT rejects it and returns NULL -> error fires.
    I grepped every 2-arg nav call in rpr.sql: all offsets are int4 literals, random()::int (int4), int4-returning subqueries, NULL::int8, untyped NULL, or params -- none are numeric/float/text, so this branch is genuinely uncovered.
    The decimal literal 1.5 is typed numeric in PostgreSQL, so PREV(price, 1.5) deterministically drives execution through these exact lines. format_type_be(numeric) yields "numeric" and the hardcoded "bigint" string makes the expected message exact.
2209 | - | (errcode(ERRCODE_DATATYPE_MISMATCH), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2210 | - | errmsg("offset argument of %s must be type %s, not type %s", | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2211 | - | navname, "bigint", format_type_be(offtype)), | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2212 | - | parser_errposition(pstate, exprLocation(offset)))); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2213 | - | offset = newoffset; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2214 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2215 | 487 | navexpr->offset_arg = (Expr *) offset; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2216 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2217 | - | else | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2218 | 1061 | navexpr->offset_arg = NULL; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2219 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2220 | - | /* compound_offset_arg stays NULL; define_walker flattening fills it in */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2221 | 1548 | navexpr->resulttype = exprType(arg); | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2222 | - | /* resultcollid will be set by parse_collate.c */ | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2223 | 1548 | navexpr->location = location; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2224 | - |  | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2225 | 1548 | return (Node *) navexpr; | 7f135d9Recognize row pattern navigation operations by name in DEFINE
2226 | - | } | 7f135d9Recognize row pattern navigation operations by name in DEFINE

check_srf_call_placement() lines 2834-3014
Modified Lines Coverage: 0/0 lines (0.0%)

Line | Hits | Source | Commit
--- | --- | --- | ---
2834 | - | check_srf_call_placement(ParseState *pstate, Node *last_srf, int location) | -
2835 | - | { | -
2836 | - | const char *err; | -
2837 | - | bool errkind; | -
2838 | - |  | -
2839 | - | /* | -
2840 | - | * Check to see if the set-returning function is in an invalid place | -
2841 | - | * within the query. Basically, we don't allow SRFs anywhere except in | -
2842 | - | * the targetlist (which includes GROUP BY/ORDER BY expressions), VALUES, | -
2843 | - | * and functions in FROM. | -
2844 | - | * | -
2845 | - | * For brevity we support two schemes for reporting an error here: set | -
2846 | - | * "err" to a custom message, or set "errkind" true if the error context | -
2847 | - | * is sufficiently identified by what ParseExprKindName will return, *and* | -
2848 | - | * what it will return is just a SQL keyword. (Otherwise, use a custom | -
2849 | - | * message to avoid creating translation problems.) | -
2850 | - | */ | -
2851 | - | err = NULL; | -
2852 | - | errkind = false; | -
2853 | - | switch (pstate->p_expr_kind) | -
2854 | - | { | -
2855 | - | case EXPR_KIND_NONE: | -
2856 | - | Assert(false); /* can't happen */ | -
2857 | - | break; | -
2858 | - | case EXPR_KIND_OTHER: | -
2859 | - | /* Accept SRF here; caller must throw error if wanted */ | -
2860 | - | break; | -
2861 | - | case EXPR_KIND_JOIN_ON: | -
2862 | - | case EXPR_KIND_JOIN_USING: | -
2863 | - | err = _("set-returning functions are not allowed in JOIN conditions"); | -
2864 | - | break; | -
2865 | - | case EXPR_KIND_FROM_SUBSELECT: | -
2866 | - | /* can't get here, but just in case, throw an error */ | -
2867 | - | errkind = true; | -
2868 | - | break; | -
2869 | - | case EXPR_KIND_FROM_FUNCTION: | -
2870 | - | /* okay, but we don't allow nested SRFs here */ | -
2871 | - | /* errmsg is chosen to match transformRangeFunction() */ | -
2872 | - | /* errposition should point to the inner SRF */ | -
2873 | - | if (pstate->p_last_srf != last_srf) | -
2874 | - | ereport(ERROR, | -
2875 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
2876 | - | errmsg("set-returning functions must appear at top level of FROM"), | -
2877 | - | parser_errposition(pstate, | -
2878 | - | exprLocation(pstate->p_last_srf)))); | -
2879 | - | break; | -
2880 | - | case EXPR_KIND_WHERE: | -
2881 | - | errkind = true; | -
2882 | - | break; | -
2883 | - | case EXPR_KIND_POLICY: | -
2884 | - | err = _("set-returning functions are not allowed in policy expressions"); | -
2885 | - | break; | -
2886 | - | case EXPR_KIND_HAVING: | -
2887 | - | errkind = true; | -
2888 | - | break; | -
2889 | - | case EXPR_KIND_FILTER: | -
2890 | - | errkind = true; | -
2891 | - | break; | -
2892 | - | case EXPR_KIND_WINDOW_PARTITION: | -
2893 | - | case EXPR_KIND_WINDOW_ORDER: | -
2894 | - | /* okay, these are effectively GROUP BY/ORDER BY */ | -
2895 | - | pstate->p_hasTargetSRFs = true; | -
2896 | - | break; | -
2897 | - | case EXPR_KIND_WINDOW_FRAME_RANGE: | -
2898 | - | case EXPR_KIND_WINDOW_FRAME_ROWS: | -
2899 | - | case EXPR_KIND_WINDOW_FRAME_GROUPS: | -
2900 | - | err = _("set-returning functions are not allowed in window definitions"); | -
2901 | - | break; | -
2902 | - | case EXPR_KIND_SELECT_TARGET: | -
2903 | - | case EXPR_KIND_INSERT_TARGET: | -
2904 | - | /* okay */ | -
2905 | - | pstate->p_hasTargetSRFs = true; | -
2906 | - | break; | -
2907 | - | case EXPR_KIND_UPDATE_SOURCE: | -
2908 | - | case EXPR_KIND_UPDATE_TARGET: | -
2909 | - | /* disallowed because it would be ambiguous what to do */ | -
2910 | - | errkind = true; | -
2911 | - | break; | -
2912 | - | case EXPR_KIND_GROUP_BY: | -
2913 | - | case EXPR_KIND_ORDER_BY: | -
2914 | - | /* okay */ | -
2915 | - | pstate->p_hasTargetSRFs = true; | -
2916 | - | break; | -
2917 | - | case EXPR_KIND_DISTINCT_ON: | -
2918 | - | /* okay */ | -
2919 | - | pstate->p_hasTargetSRFs = true; | -
2920 | - | break; | -
2921 | - | case EXPR_KIND_LIMIT: | -
2922 | - | case EXPR_KIND_OFFSET: | -
2923 | - | errkind = true; | -
2924 | - | break; | -
2925 | - | case EXPR_KIND_RETURNING: | -
2926 | - | case EXPR_KIND_MERGE_RETURNING: | -
2927 | - | errkind = true; | -
2928 | - | break; | -
2929 | - | case EXPR_KIND_VALUES: | -
2930 | - | /* SRFs are presently not supported by nodeValuesscan.c */ | -
2931 | - | errkind = true; | -
2932 | - | break; | -
2933 | - | case EXPR_KIND_VALUES_SINGLE: | -
2934 | - | /* okay, since we process this like a SELECT tlist */ | -
2935 | - | pstate->p_hasTargetSRFs = true; | -
2936 | - | break; | -
2937 | - | case EXPR_KIND_MERGE_WHEN: | -
2938 | - | err = _("set-returning functions are not allowed in MERGE WHEN conditions"); | -
2939 | - | break; | -
2940 | - | case EXPR_KIND_CHECK_CONSTRAINT: | -
2941 | - | case EXPR_KIND_DOMAIN_CHECK: | -
2942 | - | err = _("set-returning functions are not allowed in check constraints"); | -
2943 | - | break; | -
2944 | - | case EXPR_KIND_COLUMN_DEFAULT: | -
2945 | - | case EXPR_KIND_FUNCTION_DEFAULT: | -
2946 | - | err = _("set-returning functions are not allowed in DEFAULT expressions"); | -
2947 | - | break; | -
2948 | - | case EXPR_KIND_INDEX_EXPRESSION: | -
2949 | - | err = _("set-returning functions are not allowed in index expressions"); | -
2950 | - | break; | -
2951 | - | case EXPR_KIND_INDEX_PREDICATE: | -
2952 | - | err = _("set-returning functions are not allowed in index predicates"); | -
2953 | - | break; | -
2954 | - | case EXPR_KIND_STATS_EXPRESSION: | -
2955 | - | err = _("set-returning functions are not allowed in statistics expressions"); | -
2956 | - | break; | -
2957 | - | case EXPR_KIND_ALTER_COL_TRANSFORM: | -
2958 | - | err = _("set-returning functions are not allowed in transform expressions"); | -
2959 | - | break; | -
2960 | - | case EXPR_KIND_EXECUTE_PARAMETER: | -
2961 | - | err = _("set-returning functions are not allowed in EXECUTE parameters"); | -
2962 | - | break; | -
2963 | - | case EXPR_KIND_TRIGGER_WHEN: | -
2964 | - | err = _("set-returning functions are not allowed in trigger WHEN conditions"); | -
2965 | - | break; | -
2966 | - | case EXPR_KIND_PARTITION_BOUND: | -
2967 | - | err = _("set-returning functions are not allowed in partition bound"); | -
2968 | - | break; | -
2969 | - | case EXPR_KIND_PARTITION_EXPRESSION: | -
2970 | - | err = _("set-returning functions are not allowed in partition key expressions"); | -
2971 | - | break; | -
2972 | - | case EXPR_KIND_CALL_ARGUMENT: | -
2973 | - | err = _("set-returning functions are not allowed in CALL arguments"); | -
2974 | - | break; | -
2975 | - | case EXPR_KIND_COPY_WHERE: | -
2976 | - | err = _("set-returning functions are not allowed in COPY FROM WHERE conditions"); | -
2977 | - | break; | -
2978 | - | case EXPR_KIND_GENERATED_COLUMN: | -
2979 | - | err = _("set-returning functions are not allowed in column generation expressions"); | -
2980 | - | break; | -
2981 | - | case EXPR_KIND_CYCLE_MARK: | -
2982 | - | errkind = true; | -
2983 | - | break; | -
2984 | - | case EXPR_KIND_PROPGRAPH_PROPERTY: | -
2985 | - | err = _("set-returning functions are not allowed in property definition expressions"); | -
2986 | - | break; | -
2987 | - | case EXPR_KIND_FOR_PORTION: | -
2988 | - | err = _("set-returning functions are not allowed in FOR PORTION OF expressions"); | -
2989 | - | break; | -
2990 | - | case EXPR_KIND_RPR_DEFINE: | c54ba27Row pattern recognition patch (parse/analysis).
2991 | - | errkind = true; | c54ba27Row pattern recognition patch (parse/analysis).
2992 | - | break; | c54ba27Row pattern recognition patch (parse/analysis).
2993 | - |  | -
2994 | - | /* | -
2995 | - | * There is intentionally no default: case here, so that the | -
2996 | - | * compiler will warn if we add a new ParseExprKind without | -
2997 | - | * extending this switch. If we do see an unrecognized value at | -
2998 | - | * runtime, the behavior will be the same as for EXPR_KIND_OTHER, | -
2999 | - | * which is sane anyway. | -
3000 | - | */ | -
3001 | - | } | -
3002 | - | if (err) | -
3003 | - | ereport(ERROR, | -
3004 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
3005 | - | errmsg_internal("%s", err), | -
3006 | - | parser_errposition(pstate, location))); | -
3007 | - | if (errkind) | -
3008 | - | ereport(ERROR, | -
3009 | - | (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), | -
3010 | - | /* translator: %s is name of a SQL construct, eg GROUP BY */ | -
3011 | - | errmsg("set-returning functions are not allowed in %s", | -
3012 | - | ParseExprKindName(pstate->p_expr_kind)), | -
3013 | - | parser_errposition(pstate, location))); | -
3014 | - | } | -