aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/prepare.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/commands/prepare.c')
-rw-r--r--src/backend/commands/prepare.c96
1 files changed, 46 insertions, 50 deletions
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 4883abe470e..edd646e7c34 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -18,6 +18,7 @@
#include "access/xact.h"
#include "catalog/pg_type.h"
+#include "commands/createas.h"
#include "commands/prepare.h"
#include "miscadmin.h"
#include "nodes/nodeFuncs.h"
@@ -170,7 +171,12 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
}
/*
- * Implements the 'EXECUTE' utility statement.
+ * ExecuteQuery --- implement the 'EXECUTE' utility statement.
+ *
+ * This code also supports CREATE TABLE ... AS EXECUTE. That case is
+ * indicated by passing a non-null intoClause. The DestReceiver is already
+ * set up correctly for CREATE TABLE AS, but we still have to make a few
+ * other adjustments here.
*
* Note: this is one of very few places in the code that needs to deal with
* two query strings at once. The passed-in queryString is that of the
@@ -179,8 +185,8 @@ PrepareQuery(PrepareStmt *stmt, const char *queryString)
* source is that of the original PREPARE.
*/
void
-ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
- ParamListInfo params,
+ExecuteQuery(ExecuteStmt *stmt, IntoClause *intoClause,
+ const char *queryString, ParamListInfo params,
DestReceiver *dest, char *completionTag)
{
PreparedStatement *entry;
@@ -190,6 +196,8 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
EState *estate = NULL;
Portal portal;
char *query_string;
+ int eflags;
+ long count;
/* Look it up in the hash table */
entry = FetchPreparedStatement(stmt->name, true);
@@ -222,25 +230,27 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
query_string = MemoryContextStrdup(PortalGetHeapMemory(portal),
entry->plansource->query_string);
+ /* Replan if needed, and increment plan refcount for portal */
+ cplan = GetCachedPlan(entry->plansource, paramLI, false);
+ plan_list = cplan->stmt_list;
+
/*
- * For CREATE TABLE / AS EXECUTE, we must make a copy of the stored query
- * so that we can modify its destination (yech, but this has always been
- * ugly). For regular EXECUTE we can just use the cached query, since the
- * executor is read-only.
+ * For CREATE TABLE ... AS EXECUTE, we must verify that the prepared
+ * statement is one that produces tuples. Currently we insist that it be
+ * a plain old SELECT. In future we might consider supporting other
+ * things such as INSERT ... RETURNING, but there are a couple of issues
+ * to be settled first, notably how WITH NO DATA should be handled in such
+ * a case (do we really want to suppress execution?) and how to pass down
+ * the OID-determining eflags (PortalStart won't handle them in such a
+ * case, and for that matter it's not clear the executor will either).
+ *
+ * For CREATE TABLE ... AS EXECUTE, we also have to ensure that the
+ * proper eflags and fetch count are passed to PortalStart/PortalRun.
*/
- if (stmt->into)
+ if (intoClause)
{
- MemoryContext oldContext;
PlannedStmt *pstmt;
- /* Replan if needed, and increment plan refcount transiently */
- cplan = GetCachedPlan(entry->plansource, paramLI, true);
-
- /* Copy plan into portal's context, and modify */
- oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-
- plan_list = copyObject(cplan->stmt_list);
-
if (list_length(plan_list) != 1)
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
@@ -252,20 +262,21 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
ereport(ERROR,
(errcode(ERRCODE_WRONG_OBJECT_TYPE),
errmsg("prepared statement is not a SELECT")));
- pstmt->intoClause = copyObject(stmt->into);
- MemoryContextSwitchTo(oldContext);
+ /* Set appropriate eflags */
+ eflags = GetIntoRelEFlags(intoClause);
- /* We no longer need the cached plan refcount ... */
- ReleaseCachedPlan(cplan, true);
- /* ... and we don't want the portal to depend on it, either */
- cplan = NULL;
+ /* And tell PortalRun whether to run to completion or not */
+ if (intoClause->skipData)
+ count = 0;
+ else
+ count = FETCH_ALL;
}
else
{
- /* Replan if needed, and increment plan refcount for portal */
- cplan = GetCachedPlan(entry->plansource, paramLI, false);
- plan_list = cplan->stmt_list;
+ /* Plain old EXECUTE */
+ eflags = 0;
+ count = FETCH_ALL;
}
PortalDefineQuery(portal,
@@ -276,11 +287,11 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
cplan);
/*
- * Run the portal to completion.
+ * Run the portal as appropriate.
*/
- PortalStart(portal, paramLI, true);
+ PortalStart(portal, paramLI, eflags, true);
- (void) PortalRun(portal, FETCH_ALL, false, dest, dest, completionTag);
+ (void) PortalRun(portal, count, false, dest, dest, completionTag);
PortalDrop(portal, false);
@@ -615,11 +626,14 @@ DropAllPreparedStatements(void)
/*
* Implements the 'EXPLAIN EXECUTE' utility statement.
*
+ * "into" is NULL unless we are doing EXPLAIN CREATE TABLE AS EXECUTE,
+ * in which case executing the query should result in creating that table.
+ *
* Note: the passed-in queryString is that of the EXPLAIN EXECUTE,
* not the original PREPARE; we get the latter string from the plancache.
*/
void
-ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainState *es,
+ExplainExecuteQuery(ExecuteStmt *execstmt, IntoClause *into, ExplainState *es,
const char *queryString, ParamListInfo params)
{
PreparedStatement *entry;
@@ -665,27 +679,9 @@ ExplainExecuteQuery(ExecuteStmt *execstmt, ExplainState *es,
PlannedStmt *pstmt = (PlannedStmt *) lfirst(p);
if (IsA(pstmt, PlannedStmt))
- {
- if (execstmt->into)
- {
- if (pstmt->commandType != CMD_SELECT ||
- pstmt->utilityStmt != NULL)
- ereport(ERROR,
- (errcode(ERRCODE_WRONG_OBJECT_TYPE),
- errmsg("prepared statement is not a SELECT")));
-
- /* Copy the stmt so we can modify it */
- pstmt = copyObject(pstmt);
-
- pstmt->intoClause = execstmt->into;
- }
-
- ExplainOnePlan(pstmt, es, query_string, paramLI);
- }
+ ExplainOnePlan(pstmt, into, es, query_string, paramLI);
else
- {
- ExplainOneUtility((Node *) pstmt, es, query_string, paramLI);
- }
+ ExplainOneUtility((Node *) pstmt, into, es, query_string, paramLI);
/* No need for CommandCounterIncrement, as ExplainOnePlan did it */