diff options
Diffstat (limited to 'src/backend/executor/spi.c')
-rw-r--r-- | src/backend/executor/spi.c | 72 |
1 files changed, 72 insertions, 0 deletions
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 3da2d263023..de8d59a8cdc 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -1132,6 +1132,7 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, Snapshot snapshot; MemoryContext oldcontext; Portal portal; + ErrorContextCallback spierrcontext; /* * Check that the plan is something the Portal code will special-case as @@ -1182,6 +1183,15 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, plansource->query_string); /* + * Setup error traceback support for ereport(), in case GetCachedPlan + * throws an error. + */ + spierrcontext.callback = _SPI_error_callback; + spierrcontext.arg = (void *) plansource->query_string; + spierrcontext.previous = error_context_stack; + error_context_stack = &spierrcontext; + + /* * Note: for a saved plan, we mustn't have any failure occur between * GetCachedPlan and PortalDefineQuery; that would result in leaking our * plancache refcount. @@ -1191,6 +1201,9 @@ SPI_cursor_open_internal(const char *name, SPIPlanPtr plan, cplan = GetCachedPlan(plansource, paramLI, false); stmt_list = cplan->stmt_list; + /* Pop the error context stack */ + error_context_stack = spierrcontext.previous; + if (!plan->saved) { /* @@ -1552,6 +1565,65 @@ SPI_result_code_string(int code) return buf; } +/* + * SPI_plan_get_plan_sources --- get a SPI plan's underlying list of + * CachedPlanSources. + * + * This is exported so that pl/pgsql can use it (this beats letting pl/pgsql + * look directly into the SPIPlan for itself). It's not documented in + * spi.sgml because we'd just as soon not have too many places using this. + */ +List * +SPI_plan_get_plan_sources(SPIPlanPtr plan) +{ + Assert(plan->magic == _SPI_PLAN_MAGIC); + return plan->plancache_list; +} + +/* + * SPI_plan_get_cached_plan --- get a SPI plan's generic CachedPlan, + * if the SPI plan contains exactly one CachedPlanSource. If not, + * return NULL. Caller is responsible for doing ReleaseCachedPlan(). + * + * This is exported so that pl/pgsql can use it (this beats letting pl/pgsql + * look directly into the SPIPlan for itself). It's not documented in + * spi.sgml because we'd just as soon not have too many places using this. + */ +CachedPlan * +SPI_plan_get_cached_plan(SPIPlanPtr plan) +{ + CachedPlanSource *plansource; + CachedPlan *cplan; + ErrorContextCallback spierrcontext; + + Assert(plan->magic == _SPI_PLAN_MAGIC); + + /* Can't support one-shot plans here */ + if (plan->oneshot) + return NULL; + + /* Must have exactly one CachedPlanSource */ + if (list_length(plan->plancache_list) != 1) + return NULL; + plansource = (CachedPlanSource *) linitial(plan->plancache_list); + + /* Setup error traceback support for ereport() */ + spierrcontext.callback = _SPI_error_callback; + spierrcontext.arg = (void *) plansource->query_string; + spierrcontext.previous = error_context_stack; + error_context_stack = &spierrcontext; + + /* Get the generic plan for the query */ + cplan = GetCachedPlan(plansource, NULL, plan->saved); + Assert(cplan == plansource->gplan); + + /* Pop the error context stack */ + error_context_stack = spierrcontext.previous; + + return cplan; +} + + /* =================== private functions =================== */ /* |