Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

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

Provide feedback

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

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite240a65

Browse files
committed
Provide an error cursor for "can't call an SRF here" errors.
Since it appears that v10 is going to move the goalposts by some amountin terms of where you can and can't invoke set-returning functions,arrange for the executor's "set-valued function called in context thatcannot accept a set" errors to include a syntax position if possible,pointing to the specific SRF that can't be called where it's located.The main bit of infrastructure needed for this is to make the query sourcetext accessible in the executor; but it turns out that commit4c728f3already did that. We just need a new function executor_errposition()modeled on parser_errposition(), and we're ready to rock.While experimenting with this, I noted that the error position wasn'tproperly reported if it occurred in a plpgsql FOR-over-query loop,which turned out to be because SPI_cursor_open_internal wasn't providingan error context callback during PortalStart. Fix that.There's a whole lot more that could be done with this infrastructurenow that it's there, but this is not the right time in the developmentcycle for that sort of work. Hence, resist the temptation to plasterexecutor_errposition() calls everywhere ... for the moment.Discussion:https://postgr.es/m/5263.1492471571@sss.pgh.pa.us
1 parent280c53e commite240a65

File tree

6 files changed

+57
-10
lines changed

6 files changed

+57
-10
lines changed

‎src/backend/executor/execExpr.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2103,7 +2103,9 @@ ExecInitFunc(ExprEvalStep *scratch, Expr *node, List *args, Oid funcid,
21032103
if (flinfo->fn_retset)
21042104
ereport(ERROR,
21052105
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
2106-
errmsg("set-valued function called in context that cannot accept a set")));
2106+
errmsg("set-valued function called in context that cannot accept a set"),
2107+
parent ?executor_errposition(parent->state,
2108+
exprLocation((Node*)node)) :0));
21072109

21082110
/* Build code to evaluate arguments directly into the fcinfo struct */
21092111
argno=0;

‎src/backend/executor/execSRF.c

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@
3434

3535

3636
/* static function decls */
37-
staticvoidinit_sexpr(Oidfoid,Oidinput_collation,SetExprState*sexpr,
37+
staticvoidinit_sexpr(Oidfoid,Oidinput_collation,Expr*node,
38+
SetExprState*sexpr,PlanState*parent,
3839
MemoryContextsexprCxt,boolallowSRF,boolneedDescForSRF);
3940
staticvoidShutdownSetExpr(Datumarg);
4041
staticvoidExecEvalFuncArgs(FunctionCallInfofcinfo,
@@ -77,7 +78,7 @@ ExecInitTableFunctionResult(Expr *expr,
7778
state->funcReturnsSet=func->funcretset;
7879
state->args=ExecInitExprList(func->args,parent);
7980

80-
init_sexpr(func->funcid,func->inputcollid,state,
81+
init_sexpr(func->funcid,func->inputcollid,expr,state,parent,
8182
econtext->ecxt_per_query_memory,func->funcretset, false);
8283
}
8384
else
@@ -438,15 +439,15 @@ ExecInitFunctionResultSet(Expr *expr,
438439
FuncExpr*func= (FuncExpr*)expr;
439440

440441
state->args=ExecInitExprList(func->args,parent);
441-
init_sexpr(func->funcid,func->inputcollid,state,
442+
init_sexpr(func->funcid,func->inputcollid,expr,state,parent,
442443
econtext->ecxt_per_query_memory, true, true);
443444
}
444445
elseif (IsA(expr,OpExpr))
445446
{
446447
OpExpr*op= (OpExpr*)expr;
447448

448449
state->args=ExecInitExprList(op->args,parent);
449-
init_sexpr(op->opfuncid,op->inputcollid,state,
450+
init_sexpr(op->opfuncid,op->inputcollid,expr,state,parent,
450451
econtext->ecxt_per_query_memory, true, true);
451452
}
452453
else
@@ -645,7 +646,8 @@ ExecMakeFunctionResultSet(SetExprState *fcache,
645646
* init_sexpr - initialize a SetExprState node during first use
646647
*/
647648
staticvoid
648-
init_sexpr(Oidfoid,Oidinput_collation,SetExprState*sexpr,
649+
init_sexpr(Oidfoid,Oidinput_collation,Expr*node,
650+
SetExprState*sexpr,PlanState*parent,
649651
MemoryContextsexprCxt,boolallowSRF,boolneedDescForSRF)
650652
{
651653
AclResultaclresult;
@@ -683,7 +685,9 @@ init_sexpr(Oid foid, Oid input_collation, SetExprState *sexpr,
683685
if (sexpr->func.fn_retset&& !allowSRF)
684686
ereport(ERROR,
685687
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
686-
errmsg("set-valued function called in context that cannot accept a set")));
688+
errmsg("set-valued function called in context that cannot accept a set"),
689+
parent ?executor_errposition(parent->state,
690+
exprLocation((Node*)node)) :0));
687691

688692
/* Otherwise, caller should have marked the sexpr correctly */
689693
Assert(sexpr->func.fn_retset==sexpr->funcReturnsSet);

‎src/backend/executor/execUtils.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@
2828
*ExecOpenScanRelationCommon code for scan node init routines.
2929
*ExecCloseScanRelation
3030
*
31+
*executor_errpositionReport syntactic position of an error.
32+
*
3133
*RegisterExprContextCallback Register function shutdown callback
3234
*UnregisterExprContextCallback Deregister function shutdown callback
3335
*
@@ -44,6 +46,7 @@
4446
#include"access/relscan.h"
4547
#include"access/transam.h"
4648
#include"executor/executor.h"
49+
#include"mb/pg_wchar.h"
4750
#include"nodes/nodeFuncs.h"
4851
#include"parser/parsetree.h"
4952
#include"storage/lmgr.h"
@@ -685,6 +688,36 @@ UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
685688
bms_free(parmset);
686689
}
687690

691+
/*
692+
* executor_errposition
693+
*Report an execution-time cursor position, if possible.
694+
*
695+
* This is expected to be used within an ereport() call. The return value
696+
* is a dummy (always 0, in fact).
697+
*
698+
* The locations stored in parsetrees are byte offsets into the source string.
699+
* We have to convert them to 1-based character indexes for reporting to
700+
* clients. (We do things this way to avoid unnecessary overhead in the
701+
* normal non-error case: computing character indexes would be much more
702+
* expensive than storing token offsets.)
703+
*/
704+
int
705+
executor_errposition(EState*estate,intlocation)
706+
{
707+
intpos;
708+
709+
/* No-op if location was not provided */
710+
if (location<0)
711+
return0;
712+
/* Can't do anything if source text is not available */
713+
if (estate==NULL||estate->es_sourceText==NULL)
714+
return0;
715+
/* Convert offset to character number */
716+
pos=pg_mbstrlen_with_len(estate->es_sourceText,location)+1;
717+
/* And pass it to the ereport mechanism */
718+
returnerrposition(pos);
719+
}
720+
688721
/*
689722
* Register a shutdown callback in an ExprContext.
690723
*

‎src/backend/executor/spi.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1197,9 +1197,6 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
11971197
cplan=GetCachedPlan(plansource,paramLI, false,_SPI_current->queryEnv);
11981198
stmt_list=cplan->stmt_list;
11991199

1200-
/* Pop the error context stack */
1201-
error_context_stack=spierrcontext.previous;
1202-
12031200
if (!plan->saved)
12041201
{
12051202
/*
@@ -1318,6 +1315,9 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan,
13181315

13191316
Assert(portal->strategy!=PORTAL_MULTI_QUERY);
13201317

1318+
/* Pop the error context stack */
1319+
error_context_stack=spierrcontext.previous;
1320+
13211321
/* Pop the SPI stack */
13221322
_SPI_end_call(true);
13231323

‎src/include/executor/executor.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -482,6 +482,8 @@ extern bool ExecRelationIsTargetRelation(EState *estate, Index scanrelid);
482482
externRelationExecOpenScanRelation(EState*estate,Indexscanrelid,inteflags);
483483
externvoidExecCloseScanRelation(Relationscanrel);
484484

485+
externintexecutor_errposition(EState*estate,intlocation);
486+
485487
externvoidRegisterExprContextCallback(ExprContext*econtext,
486488
ExprContextCallbackFunctionfunction,
487489
Datumarg);

‎src/test/regress/expected/tsrf.out

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -193,9 +193,13 @@ SELECT few.dataa, count(*) FROM few WHERE dataa = 'a' GROUP BY few.dataa, unnest
193193
-- SRFs are not allowed in aggregate arguments
194194
SELECT min(generate_series(1, 3)) FROM few;
195195
ERROR: set-valued function called in context that cannot accept a set
196+
LINE 1: SELECT min(generate_series(1, 3)) FROM few;
197+
^
196198
-- SRFs are not allowed in window function arguments, either
197199
SELECT min(generate_series(1, 3)) OVER() FROM few;
198200
ERROR: set-valued function called in context that cannot accept a set
201+
LINE 1: SELECT min(generate_series(1, 3)) OVER() FROM few;
202+
^
199203
-- SRFs are normally computed after window functions
200204
SELECT id,lag(id) OVER(), count(*) OVER(), generate_series(1,3) FROM few;
201205
id | lag | count | generate_series
@@ -424,6 +428,8 @@ SELECT int4mul(generate_series(1,2), 10);
424428
-- but SRFs in function RTEs must be at top level (annoying restriction)
425429
SELECT * FROM int4mul(generate_series(1,2), 10);
426430
ERROR: set-valued function called in context that cannot accept a set
431+
LINE 1: SELECT * FROM int4mul(generate_series(1,2), 10);
432+
^
427433
-- DISTINCT ON is evaluated before tSRF evaluation if SRF is not
428434
-- referenced either in ORDER BY or in the DISTINCT ON list. The ORDER
429435
-- BY reference can be implicitly generated, if there's no other ORDER BY.

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp