← 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%)
LineHitsSourceCommit
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%)
LineHitsSourceCommit
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%)
LineHitsSourceCommit
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 - } -