aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor/execUtils.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2017-04-18 13:20:59 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2017-04-18 13:21:08 -0400
commite240a65c7dfc5ad80ab757ecb1aa9b9032c7f8ae (patch)
tree6c5c740b6410925bc9228c68c6ac7d6bcfb2845d /src/backend/executor/execUtils.c
parent280c53ecfbcad442c4b5eaab4cc3e65408f486eb (diff)
downloadpostgresql-e240a65c7dfc5ad80ab757ecb1aa9b9032c7f8ae.tar.gz
postgresql-e240a65c7dfc5ad80ab757ecb1aa9b9032c7f8ae.zip
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 amount in terms of where you can and can't invoke set-returning functions, arrange for the executor's "set-valued function called in context that cannot 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 source text accessible in the executor; but it turns out that commit 4c728f382 already 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't properly reported if it occurred in a plpgsql FOR-over-query loop, which turned out to be because SPI_cursor_open_internal wasn't providing an error context callback during PortalStart. Fix that. There's a whole lot more that could be done with this infrastructure now that it's there, but this is not the right time in the development cycle for that sort of work. Hence, resist the temptation to plaster executor_errposition() calls everywhere ... for the moment. Discussion: https://postgr.es/m/5263.1492471571@sss.pgh.pa.us
Diffstat (limited to 'src/backend/executor/execUtils.c')
-rw-r--r--src/backend/executor/execUtils.c33
1 files changed, 33 insertions, 0 deletions
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index df3d6503d14..08229bd6a72 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -28,6 +28,8 @@
* ExecOpenScanRelation Common code for scan node init routines.
* ExecCloseScanRelation
*
+ * executor_errposition Report syntactic position of an error.
+ *
* RegisterExprContextCallback Register function shutdown callback
* UnregisterExprContextCallback Deregister function shutdown callback
*
@@ -44,6 +46,7 @@
#include "access/relscan.h"
#include "access/transam.h"
#include "executor/executor.h"
+#include "mb/pg_wchar.h"
#include "nodes/nodeFuncs.h"
#include "parser/parsetree.h"
#include "storage/lmgr.h"
@@ -686,6 +689,36 @@ UpdateChangedParamSet(PlanState *node, Bitmapset *newchg)
}
/*
+ * executor_errposition
+ * Report an execution-time cursor position, if possible.
+ *
+ * This is expected to be used within an ereport() call. The return value
+ * is a dummy (always 0, in fact).
+ *
+ * The locations stored in parsetrees are byte offsets into the source string.
+ * We have to convert them to 1-based character indexes for reporting to
+ * clients. (We do things this way to avoid unnecessary overhead in the
+ * normal non-error case: computing character indexes would be much more
+ * expensive than storing token offsets.)
+ */
+int
+executor_errposition(EState *estate, int location)
+{
+ int pos;
+
+ /* No-op if location was not provided */
+ if (location < 0)
+ return 0;
+ /* Can't do anything if source text is not available */
+ if (estate == NULL || estate->es_sourceText == NULL)
+ return 0;
+ /* Convert offset to character number */
+ pos = pg_mbstrlen_with_len(estate->es_sourceText, location) + 1;
+ /* And pass it to the ereport mechanism */
+ return errposition(pos);
+}
+
+/*
* Register a shutdown callback in an ExprContext.
*
* Shutdown callbacks will be called (in reverse order of registration)