]> granicus.if.org Git - postgresql/commitdiff
Remove the Query structure from the executor's API. This allows us to stop
authorTom Lane <tgl@sss.pgh.pa.us>
Tue, 20 Feb 2007 17:32:18 +0000 (17:32 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Tue, 20 Feb 2007 17:32:18 +0000 (17:32 +0000)
storing mostly-redundant Query trees in prepared statements, portals, etc.
To replace Query, a new node type called PlannedStmt is inserted by the
planner at the top of a completed plan tree; this carries just the fields of
Query that are still needed at runtime.  The statement lists kept in portals
etc. now consist of intermixed PlannedStmt and bare utility-statement nodes
--- no Query.  This incidentally allows us to remove some fields from Query
and Plan nodes that shouldn't have been there in the first place.

Still to do: simplify the execution-time range table; at the moment the
range table passed to the executor still contains Query trees for subqueries.

initdb forced due to change of stored rules.

39 files changed:
src/backend/commands/copy.c
src/backend/commands/explain.c
src/backend/commands/portalcmds.c
src/backend/commands/prepare.c
src/backend/executor/execMain.c
src/backend/executor/execUtils.c
src/backend/executor/functions.c
src/backend/executor/spi.c
src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/outfuncs.c
src/backend/nodes/readfuncs.c
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/planner.c
src/backend/parser/analyze.c
src/backend/parser/gram.y
src/backend/tcop/postgres.c
src/backend/tcop/pquery.c
src/backend/tcop/utility.c
src/backend/utils/mmgr/portalmem.c
src/include/catalog/catversion.h
src/include/commands/portalcmds.h
src/include/commands/prepare.h
src/include/executor/execdesc.h
src/include/executor/executor.h
src/include/executor/spi_priv.h
src/include/nodes/execnodes.h
src/include/nodes/nodes.h
src/include/nodes/parsenodes.h
src/include/nodes/plannodes.h
src/include/nodes/primnodes.h
src/include/nodes/relation.h
src/include/optimizer/planner.h
src/include/tcop/pquery.h
src/include/tcop/tcopprot.h
src/include/tcop/utility.h
src/include/utils/portal.h
src/pl/plpgsql/src/pl_exec.c

index e61384beec85ba96c2138ffdd112c78e54e13d02..30118d5237b587733b64541cf58b11b440351b92 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.275 2007/01/25 02:17:26 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/copy.c,v 1.276 2007/02/20 17:32:13 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -986,10 +986,11 @@ DoCopy(const CopyStmt *stmt)
        {
                Query      *query = stmt->query;
                List       *rewritten;
-               Plan       *plan;
+               PlannedStmt *plan;
                DestReceiver *dest;
 
                Assert(query);
+               Assert(query->commandType == CMD_SELECT);
                Assert(!is_from);
                cstate->rel = NULL;
 
@@ -999,6 +1000,7 @@ DoCopy(const CopyStmt *stmt)
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                         errmsg("COPY (SELECT) WITH OIDS is not supported")));
 
+               /* Query mustn't use INTO, either */
                if (query->into)
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -1016,7 +1018,6 @@ DoCopy(const CopyStmt *stmt)
                 * shouldn't modify its input ... FIXME someday.
                 */
                query = copyObject(query);
-               Assert(query->commandType == CMD_SELECT);
 
                /*
                 * Must acquire locks in case we didn't come fresh from the parser.
@@ -1051,7 +1052,7 @@ DoCopy(const CopyStmt *stmt)
                ((DR_copy *) dest)->cstate = cstate;
 
                /* Create a QueryDesc requesting no output */
-               cstate->queryDesc = CreateQueryDesc(query, plan,
+               cstate->queryDesc = CreateQueryDesc(plan,
                                                                                        ActiveSnapshot, InvalidSnapshot,
                                                                                        dest, NULL, false);
 
index 7b2c521a3535dd833cee3fccb4868b62f1468ab5..58b7e6ded9a48b1a74b344a45022fba02159e298 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1994-5, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.155 2007/02/19 02:23:11 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.156 2007/02/20 17:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -149,7 +149,7 @@ static void
 ExplainOneQuery(Query *query, ExplainStmt *stmt, ParamListInfo params,
                                TupOutputState *tstate)
 {
-       Plan       *plan;
+       PlannedStmt *plan;
        QueryDesc  *queryDesc;
        bool            isCursor = false;
        int                     cursorOptions = 0;
@@ -203,7 +203,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, ParamListInfo params,
        ActiveSnapshot->curcid = GetCurrentCommandId();
 
        /* Create a QueryDesc requesting no output */
-       queryDesc = CreateQueryDesc(query, plan,
+       queryDesc = CreateQueryDesc(plan,
                                                                ActiveSnapshot, InvalidSnapshot,
                                                                None_Receiver, params,
                                                                stmt->analyze);
@@ -260,14 +260,14 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
 
        es->printNodes = stmt->verbose;
        es->printAnalyze = stmt->analyze;
-       es->rtable = queryDesc->parsetree->rtable;
+       es->rtable = queryDesc->plannedstmt->rtable;
 
        if (es->printNodes)
        {
                char       *s;
                char       *f;
 
-               s = nodeToString(queryDesc->plantree);
+               s = nodeToString(queryDesc->plannedstmt->planTree);
                if (s)
                {
                        if (Explain_pretty_print)
@@ -282,7 +282,8 @@ ExplainOnePlan(QueryDesc *queryDesc, ExplainStmt *stmt,
        }
 
        initStringInfo(&buf);
-       explain_outNode(&buf, queryDesc->plantree, queryDesc->planstate,
+       explain_outNode(&buf,
+                                       queryDesc->plannedstmt->planTree, queryDesc->planstate,
                                        NULL, 0, es);
 
        /*
index d1c119ca08f753cdf601cbaa68d87cb23c42e9a5..0219650c069fc30210397499c2ab8dccdb0e7db1 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.60 2007/02/06 22:49:24 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.61 2007/02/20 17:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
 {
        List       *rewritten;
        Query      *query;
-       Plan       *plan;
+       PlannedStmt *plan;
        Portal          portal;
        MemoryContext oldContext;
 
@@ -98,13 +98,12 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
        plan = planner(query, true, stmt->options, params);
 
        /*
-        * Create a portal and copy the query and plan into its memory context.
+        * Create a portal and copy the plan into its memory context.
         */
        portal = CreatePortal(stmt->portalname, false, false);
 
        oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
 
-       query = copyObject(query);
        plan = copyObject(plan);
 
        /*
@@ -115,7 +114,6 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
                                          NULL,
                                          debug_query_string ? pstrdup(debug_query_string) : NULL,
                                          "SELECT", /* cursor's query is always a SELECT */
-                                         list_make1(query),
                                          list_make1(plan),
                                          PortalGetHeapMemory(portal));
 
@@ -140,7 +138,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
        portal->cursorOptions = stmt->options;
        if (!(portal->cursorOptions & (CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL)))
        {
-               if (ExecSupportsBackwardScan(plan))
+               if (ExecSupportsBackwardScan(plan->planTree))
                        portal->cursorOptions |= CURSOR_OPT_SCROLL;
                else
                        portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
index ecd5074211e917b93a4f08a93730032398833e2c..8a5382c737815f975818d43b3c564cb9bd8a0759 100644 (file)
@@ -10,7 +10,7 @@
  * Copyright (c) 2002-2007, PostgreSQL Global Development Group
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.68 2007/01/28 19:05:35 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.69 2007/02/20 17:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -114,9 +114,9 @@ PrepareQuery(PrepareStmt *stmt)
        StorePreparedStatement(stmt->name,
                                                   debug_query_string,
                                                   commandTag,
-                                                  query_list,
                                                   plan_list,
                                                   stmt->argtype_oids,
+                                                  true,
                                                   true);
 }
 
@@ -129,8 +129,7 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
 {
        PreparedStatement *entry;
        char       *query_string;
-       List       *query_list,
-                          *plan_list;
+       List       *plan_list;
        MemoryContext qcontext;
        ParamListInfo paramLI = NULL;
        EState     *estate = NULL;
@@ -139,13 +138,18 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
        /* Look it up in the hash table */
        entry = FetchPreparedStatement(stmt->name, true);
 
+       /*
+        * Punt if not fully planned.  (Currently, that only happens for the
+        * protocol-level unnamed statement, which can't be accessed from SQL;
+        * so there's no point in doing more than a quick check here.)
+        */
+       if (!entry->fully_planned)
+               elog(ERROR, "EXECUTE does not support unplanned prepared statements");
+
        query_string = entry->query_string;
-       query_list = entry->query_list;
-       plan_list = entry->plan_list;
+       plan_list = entry->stmt_list;
        qcontext = entry->context;
 
-       Assert(list_length(query_list) == list_length(plan_list));
-
        /* Evaluate parameters, if any */
        if (entry->argtype_list != NIL)
        {
@@ -172,30 +176,26 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
        if (stmt->into)
        {
                MemoryContext oldContext;
-               Query      *query;
+               PlannedStmt *pstmt;
 
-               oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+               qcontext = PortalGetHeapMemory(portal);
+               oldContext = MemoryContextSwitchTo(qcontext);
 
                if (query_string)
                        query_string = pstrdup(query_string);
-               query_list = copyObject(query_list);
                plan_list = copyObject(plan_list);
-               qcontext = PortalGetHeapMemory(portal);
 
-               if (list_length(query_list) != 1)
+               if (list_length(plan_list) != 1)
                        ereport(ERROR,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                         errmsg("prepared statement is not a SELECT")));
-               query = (Query *) linitial(query_list);
-               if (query->commandType != CMD_SELECT)
+               pstmt = (PlannedStmt *) linitial(plan_list);
+               if (!IsA(pstmt, PlannedStmt) ||
+                       pstmt->commandType != CMD_SELECT)
                        ereport(ERROR,
                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                         errmsg("prepared statement is not a SELECT")));
-               query->into = copyObject(stmt->into);
-               query->intoOptions = copyObject(stmt->intoOptions);
-               query->intoOnCommit = stmt->into_on_commit;
-               if (stmt->into_tbl_space)
-                       query->intoTableSpaceName = pstrdup(stmt->into_tbl_space);
+               pstmt->into = copyObject(stmt->into);
 
                MemoryContextSwitchTo(oldContext);
        }
@@ -204,7 +204,6 @@ ExecuteQuery(ExecuteStmt *stmt, ParamListInfo params,
                                          NULL,
                                          query_string,
                                          entry->commandTag,
-                                         query_list,
                                          plan_list,
                                          qcontext);
 
@@ -305,9 +304,9 @@ void
 StorePreparedStatement(const char *stmt_name,
                                           const char *query_string,
                                           const char *commandTag,
-                                          List *query_list,
-                                          List *plan_list,
+                                          List *stmt_list,
                                           List *argtype_list,
+                                          bool fully_planned,
                                           bool from_sql)
 {
        PreparedStatement *entry;
@@ -345,8 +344,7 @@ StorePreparedStatement(const char *stmt_name,
         * incomplete (ie corrupt) hashtable entry.
         */
        qstring = query_string ? pstrdup(query_string) : NULL;
-       query_list = (List *) copyObject(query_list);
-       plan_list = (List *) copyObject(plan_list);
+       stmt_list = (List *) copyObject(stmt_list);
        argtype_list = list_copy(argtype_list);
 
        /* Now we can add entry to hash table */
@@ -363,12 +361,12 @@ StorePreparedStatement(const char *stmt_name,
        /* Fill in the hash table entry with copied data */
        entry->query_string = qstring;
        entry->commandTag = commandTag;
-       entry->query_list = query_list;
-       entry->plan_list = plan_list;
+       entry->stmt_list = stmt_list;
        entry->argtype_list = argtype_list;
+       entry->fully_planned = fully_planned;
+       entry->from_sql = from_sql;
        entry->context = entrycxt;
        entry->prepare_time = GetCurrentStatementStartTimestamp();
-       entry->from_sql = from_sql;
 
        MemoryContextSwitchTo(oldcxt);
 }
@@ -426,21 +424,54 @@ FetchPreparedStatementParams(const char *stmt_name)
 TupleDesc
 FetchPreparedStatementResultDesc(PreparedStatement *stmt)
 {
+       Node       *node;
        Query      *query;
+       PlannedStmt *pstmt;
 
-       switch (ChoosePortalStrategy(stmt->query_list))
+       switch (ChoosePortalStrategy(stmt->stmt_list))
        {
                case PORTAL_ONE_SELECT:
-                       query = (Query *) linitial(stmt->query_list);
-                       return ExecCleanTypeFromTL(query->targetList, false);
+                       node = (Node *) linitial(stmt->stmt_list);
+                       if (IsA(node, Query))
+                       {
+                               query = (Query *) node;
+                               return ExecCleanTypeFromTL(query->targetList, false);
+                       }
+                       if (IsA(node, PlannedStmt))
+                       {
+                               pstmt = (PlannedStmt *) node;
+                               return ExecCleanTypeFromTL(pstmt->planTree->targetlist, false);
+                       }
+                       /* other cases shouldn't happen, but return NULL */
+                       break;
 
                case PORTAL_ONE_RETURNING:
-                       query = PortalListGetPrimaryQuery(stmt->query_list);
-                       return ExecCleanTypeFromTL(query->returningList, false);
+                       node = PortalListGetPrimaryStmt(stmt->stmt_list);
+                       if (IsA(node, Query))
+                       {
+                               query = (Query *) node;
+                               Assert(query->returningList);
+                               return ExecCleanTypeFromTL(query->returningList, false);
+                       }
+                       if (IsA(node, PlannedStmt))
+                       {
+                               pstmt = (PlannedStmt *) node;
+                               Assert(pstmt->returningLists);
+                               return ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists), false);
+                       }
+                       /* other cases shouldn't happen, but return NULL */
+                       break;
 
                case PORTAL_UTIL_SELECT:
-                       query = (Query *) linitial(stmt->query_list);
-                       return UtilityTupleDescriptor(query->utilityStmt);
+                       node = (Node *) linitial(stmt->stmt_list);
+                       if (IsA(node, Query))
+                       {
+                               query = (Query *) node;
+                               Assert(query->utilityStmt);
+                               return UtilityTupleDescriptor(query->utilityStmt);
+                       }
+                       /* else it's a bare utility statement */
+                       return UtilityTupleDescriptor(node);
 
                case PORTAL_MULTI_QUERY:
                        /* will not return tuples */
@@ -460,7 +491,7 @@ FetchPreparedStatementResultDesc(PreparedStatement *stmt)
 bool
 PreparedStatementReturnsTuples(PreparedStatement *stmt)
 {
-       switch (ChoosePortalStrategy(stmt->query_list))
+       switch (ChoosePortalStrategy(stmt->stmt_list))
        {
                case PORTAL_ONE_SELECT:
                case PORTAL_ONE_RETURNING:
@@ -480,52 +511,15 @@ PreparedStatementReturnsTuples(PreparedStatement *stmt)
  * targetlist.
  *
  * Note: do not modify the result.
- *
- * XXX be careful to keep this in sync with FetchPortalTargetList,
- * and with UtilityReturnsTuples.
  */
 List *
 FetchPreparedStatementTargetList(PreparedStatement *stmt)
 {
-       PortalStrategy strategy = ChoosePortalStrategy(stmt->query_list);
-
-       if (strategy == PORTAL_ONE_SELECT)
-               return ((Query *) linitial(stmt->query_list))->targetList;
-       if (strategy == PORTAL_ONE_RETURNING)
-               return (PortalListGetPrimaryQuery(stmt->query_list))->returningList;
-       if (strategy == PORTAL_UTIL_SELECT)
-       {
-               Node       *utilityStmt;
-
-               utilityStmt = ((Query *) linitial(stmt->query_list))->utilityStmt;
-               switch (nodeTag(utilityStmt))
-               {
-                       case T_FetchStmt:
-                               {
-                                       FetchStmt  *substmt = (FetchStmt *) utilityStmt;
-                                       Portal          subportal;
-
-                                       Assert(!substmt->ismove);
-                                       subportal = GetPortalByName(substmt->portalname);
-                                       Assert(PortalIsValid(subportal));
-                                       return FetchPortalTargetList(subportal);
-                               }
-
-                       case T_ExecuteStmt:
-                               {
-                                       ExecuteStmt *substmt = (ExecuteStmt *) utilityStmt;
-                                       PreparedStatement *entry;
-
-                                       Assert(!substmt->into);
-                                       entry = FetchPreparedStatement(substmt->name, true);
-                                       return FetchPreparedStatementTargetList(entry);
-                               }
-
-                       default:
-                               break;
-               }
-       }
-       return NIL;
+       /* no point in looking if it doesn't return tuples */
+       if (ChoosePortalStrategy(stmt->stmt_list) == PORTAL_MULTI_QUERY)
+               return NIL;
+       /* get the primary statement and find out what it returns */
+       return FetchStatementTargetList(PortalListGetPrimaryStmt(stmt->stmt_list));
 }
 
 /*
@@ -574,10 +568,8 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
 {
        ExecuteStmt *execstmt = (ExecuteStmt *) stmt->query->utilityStmt;
        PreparedStatement *entry;
-       ListCell   *q,
-                          *p;
-       List       *query_list,
-                          *plan_list;
+       List       *plan_list;
+       ListCell   *p;
        ParamListInfo paramLI = NULL;
        EState     *estate = NULL;
 
@@ -587,10 +579,15 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
        /* Look it up in the hash table */
        entry = FetchPreparedStatement(execstmt->name, true);
 
-       query_list = entry->query_list;
-       plan_list = entry->plan_list;
+       /*
+        * Punt if not fully planned.  (Currently, that only happens for the
+        * protocol-level unnamed statement, which can't be accessed from SQL;
+        * so there's no point in doing more than a quick check here.)
+        */
+       if (!entry->fully_planned)
+               elog(ERROR, "EXPLAIN EXECUTE does not support unplanned prepared statements");
 
-       Assert(list_length(query_list) == list_length(plan_list));
+       plan_list = entry->stmt_list;
 
        /* Evaluate parameters, if any */
        if (entry->argtype_list != NIL)
@@ -606,17 +603,16 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
        }
 
        /* Explain each query */
-       forboth(q, query_list, p, plan_list)
+       foreach(p, plan_list)
        {
-               Query      *query = (Query *) lfirst(q);
-               Plan       *plan = (Plan *) lfirst(p);
+               PlannedStmt *pstmt = (PlannedStmt *) lfirst(p);
                bool            is_last_query;
 
                is_last_query = (lnext(p) == NULL);
 
-               if (query->commandType == CMD_UTILITY)
+               if (!IsA(pstmt, PlannedStmt))
                {
-                       if (query->utilityStmt && IsA(query->utilityStmt, NotifyStmt))
+                       if (IsA(pstmt, NotifyStmt))
                                do_text_output_oneline(tstate, "NOTIFY");
                        else
                                do_text_output_oneline(tstate, "UTILITY");
@@ -627,15 +623,15 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
 
                        if (execstmt->into)
                        {
-                               if (query->commandType != CMD_SELECT)
+                               if (pstmt->commandType != CMD_SELECT)
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_WRONG_OBJECT_TYPE),
                                                         errmsg("prepared statement is not a SELECT")));
 
-                               /* Copy the query so we can modify it */
-                               query = copyObject(query);
+                               /* Copy the stmt so we can modify it */
+                               pstmt = copyObject(pstmt);
 
-                               query->into = execstmt->into;
+                               pstmt->into = execstmt->into;
                        }
 
                        /*
@@ -648,7 +644,7 @@ ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
                        ActiveSnapshot->curcid = GetCurrentCommandId();
 
                        /* Create a QueryDesc requesting no output */
-                       qdesc = CreateQueryDesc(query, plan,
+                       qdesc = CreateQueryDesc(pstmt,
                                                                        ActiveSnapshot, InvalidSnapshot,
                                                                        None_Receiver,
                                                                        paramLI, stmt->analyze);
index 91a76bb0779b15c8c8e084e4693254f8290ed1a7..405b58f9fd6b087ec18ecda7541f7b1a98e63c9c 100644 (file)
@@ -26,7 +26,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.286 2007/02/02 00:07:02 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execMain.c,v 1.287 2007/02/20 17:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -93,7 +93,8 @@ static void ExecProcessReturning(ProjectionInfo *projectReturning,
 static TupleTableSlot *EvalPlanQualNext(EState *estate);
 static void EndEvalPlanQual(EState *estate);
 static void ExecCheckRTEPerms(RangeTblEntry *rte);
-static void ExecCheckXactReadOnly(Query *parsetree);
+static void ExecCheckXactReadOnly(PlannedStmt *plannedstmt);
+static void ExecCheckRangeTblReadOnly(List *rtable);
 static void EvalPlanQualStart(evalPlanQual *epq, EState *estate,
                                  evalPlanQual *priorepq);
 static void EvalPlanQualStop(evalPlanQual *epq);
@@ -139,7 +140,7 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
         * planned to non-temporary tables.  EXPLAIN is considered read-only.
         */
        if (XactReadOnly && !(eflags & EXEC_FLAG_EXPLAIN_ONLY))
-               ExecCheckXactReadOnly(queryDesc->parsetree);
+               ExecCheckXactReadOnly(queryDesc->plannedstmt);
 
        /*
         * Build EState, switch into per-query memory context for startup.
@@ -154,9 +155,9 @@ ExecutorStart(QueryDesc *queryDesc, int eflags)
         */
        estate->es_param_list_info = queryDesc->params;
 
-       if (queryDesc->plantree->nParamExec > 0)
+       if (queryDesc->plannedstmt->nParamExec > 0)
                estate->es_param_exec_vals = (ParamExecData *)
-                       palloc0(queryDesc->plantree->nParamExec * sizeof(ParamExecData));
+                       palloc0(queryDesc->plannedstmt->nParamExec * sizeof(ParamExecData));
 
        /*
         * Copy other important information into the EState
@@ -227,7 +228,7 @@ ExecutorRun(QueryDesc *queryDesc,
        estate->es_lastoid = InvalidOid;
 
        sendTuples = (operation == CMD_SELECT ||
-                                 queryDesc->parsetree->returningList);
+                                 queryDesc->plannedstmt->returningLists);
 
        if (sendTuples)
                (*dest->rStartup) (dest, operation, queryDesc->tupDesc);
@@ -414,26 +415,41 @@ ExecCheckRTEPerms(RangeTblEntry *rte)
  * Check that the query does not imply any writes to non-temp tables.
  */
 static void
-ExecCheckXactReadOnly(Query *parsetree)
+ExecCheckXactReadOnly(PlannedStmt *plannedstmt)
 {
-       ListCell   *l;
-
        /*
         * CREATE TABLE AS or SELECT INTO?
         *
         * XXX should we allow this if the destination is temp?
         */
-       if (parsetree->into != NULL)
+       if (plannedstmt->into != NULL)
                goto fail;
 
        /* Fail if write permissions are requested on any non-temp table */
-       foreach(l, parsetree->rtable)
+       ExecCheckRangeTblReadOnly(plannedstmt->rtable);
+
+       return;
+
+fail:
+       ereport(ERROR,
+                       (errcode(ERRCODE_READ_ONLY_SQL_TRANSACTION),
+                        errmsg("transaction is read-only")));
+}
+
+static void
+ExecCheckRangeTblReadOnly(List *rtable)
+{
+       ListCell   *l;
+
+       /* Fail if write permissions are requested on any non-temp table */
+       foreach(l, rtable)
        {
                RangeTblEntry *rte = lfirst(l);
 
                if (rte->rtekind == RTE_SUBQUERY)
                {
-                       ExecCheckXactReadOnly(rte->subquery);
+                       Assert(!rte->subquery->into);
+                       ExecCheckRangeTblReadOnly(rte->subquery->rtable);
                        continue;
                }
 
@@ -469,11 +485,11 @@ static void
 InitPlan(QueryDesc *queryDesc, int eflags)
 {
        CmdType         operation = queryDesc->operation;
-       Query      *parseTree = queryDesc->parsetree;
-       Plan       *plan = queryDesc->plantree;
+       PlannedStmt *plannedstmt = queryDesc->plannedstmt;
+       Plan       *plan = plannedstmt->planTree;
+       List       *rangeTable = plannedstmt->rtable;
        EState     *estate = queryDesc->estate;
        PlanState  *planstate;
-       List       *rangeTable;
        TupleDesc       tupType;
        ListCell   *l;
 
@@ -482,12 +498,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         * rangetable here --- subplan RTEs will be checked during
         * ExecInitSubPlan().
         */
-       ExecCheckRTPerms(parseTree->rtable);
-
-       /*
-        * get information from query descriptor
-        */
-       rangeTable = parseTree->rtable;
+       ExecCheckRTPerms(rangeTable);
 
        /*
         * initialize the node's execution state
@@ -495,50 +506,27 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        estate->es_range_table = rangeTable;
 
        /*
-        * if there is a result relation, initialize result relation stuff
+        * initialize result relation stuff
         */
-       if (parseTree->resultRelation)
+       if (plannedstmt->resultRelations)
        {
-               List       *resultRelations = parseTree->resultRelations;
-               int                     numResultRelations;
+               List       *resultRelations = plannedstmt->resultRelations;
+               int                     numResultRelations = list_length(resultRelations);
                ResultRelInfo *resultRelInfos;
+               ResultRelInfo *resultRelInfo;
 
-               if (resultRelations != NIL)
-               {
-                       /*
-                        * Multiple result relations (due to inheritance)
-                        * parseTree->resultRelations identifies them all
-                        */
-                       ResultRelInfo *resultRelInfo;
-
-                       numResultRelations = list_length(resultRelations);
-                       resultRelInfos = (ResultRelInfo *)
-                               palloc(numResultRelations * sizeof(ResultRelInfo));
-                       resultRelInfo = resultRelInfos;
-                       foreach(l, resultRelations)
-                       {
-                               initResultRelInfo(resultRelInfo,
-                                                                 lfirst_int(l),
-                                                                 rangeTable,
-                                                                 operation,
-                                                                 estate->es_instrument);
-                               resultRelInfo++;
-                       }
-               }
-               else
+               resultRelInfos = (ResultRelInfo *)
+                       palloc(numResultRelations * sizeof(ResultRelInfo));
+               resultRelInfo = resultRelInfos;
+               foreach(l, resultRelations)
                {
-                       /*
-                        * Single result relation identified by parseTree->resultRelation
-                        */
-                       numResultRelations = 1;
-                       resultRelInfos = (ResultRelInfo *) palloc(sizeof(ResultRelInfo));
-                       initResultRelInfo(resultRelInfos,
-                                                         parseTree->resultRelation,
+                       initResultRelInfo(resultRelInfo,
+                                                         lfirst_int(l),
                                                          rangeTable,
                                                          operation,
                                                          estate->es_instrument);
+                       resultRelInfo++;
                }
-
                estate->es_result_relations = resultRelInfos;
                estate->es_num_result_relations = numResultRelations;
                /* Initialize to first or only result rel */
@@ -560,10 +548,10 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         * correct tuple descriptors.  (Other SELECT INTO stuff comes later.)
         */
        estate->es_select_into = false;
-       if (operation == CMD_SELECT && parseTree->into != NULL)
+       if (operation == CMD_SELECT && plannedstmt->into != NULL)
        {
                estate->es_select_into = true;
-               estate->es_into_oids = interpretOidsOption(parseTree->intoOptions);
+               estate->es_into_oids = interpretOidsOption(plannedstmt->into->options);
        }
 
        /*
@@ -572,7 +560,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
         * While we are at it, build the ExecRowMark list.
         */
        estate->es_rowMarks = NIL;
-       foreach(l, parseTree->rowMarks)
+       foreach(l, plannedstmt->rowMarks)
        {
                RowMarkClause *rc = (RowMarkClause *) lfirst(l);
                Oid                     relid = getrelid(rc->rti, rangeTable);
@@ -600,13 +588,13 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        {
                int                     nSlots = ExecCountSlotsNode(plan);
 
-               if (parseTree->resultRelations != NIL)
-                       nSlots += list_length(parseTree->resultRelations);
+               if (plannedstmt->resultRelations != NIL)
+                       nSlots += list_length(plannedstmt->resultRelations);
                else
                        nSlots += 1;
                if (operation != CMD_SELECT)
                        nSlots++;                       /* for es_trig_tuple_slot */
-               if (parseTree->returningLists)
+               if (plannedstmt->returningLists)
                        nSlots++;                       /* for RETURNING projection */
 
                estate->es_tupleTable = ExecCreateTupleTable(nSlots);
@@ -617,7 +605,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        }
 
        /* mark EvalPlanQual not active */
-       estate->es_topPlan = plan;
+       estate->es_plannedstmt = plannedstmt;
        estate->es_evalPlanQual = NULL;
        estate->es_evTupleNull = NULL;
        estate->es_evTuple = NULL;
@@ -683,7 +671,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                         * junk filter.  Note this is only possible for UPDATE/DELETE, so
                         * we can't be fooled by some needing a filter and some not.
                         */
-                       if (parseTree->resultRelations != NIL)
+                       if (list_length(plannedstmt->resultRelations) > 1)
                        {
                                PlanState **appendplans;
                                int                     as_nplans;
@@ -772,7 +760,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
        /*
         * Initialize RETURNING projections if needed.
         */
-       if (parseTree->returningLists)
+       if (plannedstmt->returningLists)
        {
                TupleTableSlot *slot;
                ExprContext *econtext;
@@ -782,7 +770,7 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                 * We set QueryDesc.tupDesc to be the RETURNING rowtype in this case.
                 * We assume all the sublists will generate the same output tupdesc.
                 */
-               tupType = ExecTypeFromTL((List *) linitial(parseTree->returningLists),
+               tupType = ExecTypeFromTL((List *) linitial(plannedstmt->returningLists),
                                                                 false);
 
                /* Set up a slot for the output of the RETURNING projection(s) */
@@ -795,9 +783,9 @@ InitPlan(QueryDesc *queryDesc, int eflags)
                 * Build a projection for each result rel.      Note that any SubPlans in
                 * the RETURNING lists get attached to the topmost plan node.
                 */
-               Assert(list_length(parseTree->returningLists) == estate->es_num_result_relations);
+               Assert(list_length(plannedstmt->returningLists) == estate->es_num_result_relations);
                resultRelInfo = estate->es_result_relations;
-               foreach(l, parseTree->returningLists)
+               foreach(l, plannedstmt->returningLists)
                {
                        List       *rlist = (List *) lfirst(l);
                        List       *rliststate;
@@ -2273,14 +2261,14 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
        epqstate->es_into_relation_descriptor = estate->es_into_relation_descriptor;
        epqstate->es_into_relation_use_wal = estate->es_into_relation_use_wal;
        epqstate->es_param_list_info = estate->es_param_list_info;
-       if (estate->es_topPlan->nParamExec > 0)
+       if (estate->es_plannedstmt->nParamExec > 0)
                epqstate->es_param_exec_vals = (ParamExecData *)
-                       palloc0(estate->es_topPlan->nParamExec * sizeof(ParamExecData));
+                       palloc0(estate->es_plannedstmt->nParamExec * sizeof(ParamExecData));
        epqstate->es_rowMarks = estate->es_rowMarks;
        epqstate->es_instrument = estate->es_instrument;
        epqstate->es_select_into = estate->es_select_into;
        epqstate->es_into_oids = estate->es_into_oids;
-       epqstate->es_topPlan = estate->es_topPlan;
+       epqstate->es_plannedstmt = estate->es_plannedstmt;
 
        /*
         * Each epqstate must have its own es_evTupleNull state, but all the stack
@@ -2299,7 +2287,7 @@ EvalPlanQualStart(evalPlanQual *epq, EState *estate, evalPlanQual *priorepq)
        epqstate->es_tupleTable =
                ExecCreateTupleTable(estate->es_tupleTable->size);
 
-       epq->planstate = ExecInitNode(estate->es_topPlan, epqstate, 0);
+       epq->planstate = ExecInitNode(estate->es_plannedstmt->planTree, epqstate, 0);
 
        MemoryContextSwitchTo(oldcontext);
 }
@@ -2365,7 +2353,7 @@ typedef struct
 static void
 OpenIntoRel(QueryDesc *queryDesc)
 {
-       Query      *parseTree = queryDesc->parsetree;
+       IntoClause *into = queryDesc->plannedstmt->into;
        EState     *estate = queryDesc->estate;
        Relation        intoRelationDesc;
        char       *intoName;
@@ -2377,10 +2365,12 @@ OpenIntoRel(QueryDesc *queryDesc)
        TupleDesc       tupdesc;
        DR_intorel *myState;
 
+       Assert(into);
+
        /*
         * Check consistency of arguments
         */
-       if (parseTree->intoOnCommit != ONCOMMIT_NOOP && !parseTree->into->istemp)
+       if (into->onCommit != ONCOMMIT_NOOP && !into->rel->istemp)
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_TABLE_DEFINITION),
                                 errmsg("ON COMMIT can only be used on temporary tables")));
@@ -2388,8 +2378,8 @@ OpenIntoRel(QueryDesc *queryDesc)
        /*
         * Find namespace to create in, check its permissions
         */
-       intoName = parseTree->into->relname;
-       namespaceId = RangeVarGetCreationNamespace(parseTree->into);
+       intoName = into->rel->relname;
+       namespaceId = RangeVarGetCreationNamespace(into->rel);
 
        aclresult = pg_namespace_aclcheck(namespaceId, GetUserId(),
                                                                          ACL_CREATE);
@@ -2401,16 +2391,16 @@ OpenIntoRel(QueryDesc *queryDesc)
         * Select tablespace to use.  If not specified, use default_tablespace
         * (which may in turn default to database's default).
         */
-       if (parseTree->intoTableSpaceName)
+       if (into->tableSpaceName)
        {
-               tablespaceId = get_tablespace_oid(parseTree->intoTableSpaceName);
+               tablespaceId = get_tablespace_oid(into->tableSpaceName);
                if (!OidIsValid(tablespaceId))
                        ereport(ERROR,
                                        (errcode(ERRCODE_UNDEFINED_OBJECT),
                                         errmsg("tablespace \"%s\" does not exist",
-                                                       parseTree->intoTableSpaceName)));
+                                                       into->tableSpaceName)));
        }
-       else if (parseTree->into->istemp)
+       else if (into->rel->istemp)
        {
                tablespaceId = GetTempTablespace();
        }
@@ -2435,7 +2425,7 @@ OpenIntoRel(QueryDesc *queryDesc)
 
        /* Parse and validate any reloptions */
        reloptions = transformRelOptions((Datum) 0,
-                                                                        parseTree->intoOptions,
+                                                                        into->options,
                                                                         true,
                                                                         false);
        (void) heap_reloptions(RELKIND_RELATION, reloptions, true);
@@ -2454,7 +2444,7 @@ OpenIntoRel(QueryDesc *queryDesc)
                                                                                          false,
                                                                                          true,
                                                                                          0,
-                                                                                         parseTree->intoOnCommit,
+                                                                                         into->onCommit,
                                                                                          reloptions,
                                                                                          allowSystemTableMods);
 
index 91efba011ca139f7b9e353ec193b028c1633c3ae..d9957573883b3bf909c44f2a5ef775feec3f5b77 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.144 2007/02/06 17:35:20 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.145 2007/02/20 17:32:14 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -242,7 +242,7 @@ InternalCreateExecutorState(MemoryContext qcontext, bool is_subquery)
 
        estate->es_per_tuple_exprcontext = NULL;
 
-       estate->es_topPlan = NULL;
+       estate->es_plannedstmt = NULL;
        estate->es_evalPlanQual = NULL;
        estate->es_evTupleNull = NULL;
        estate->es_evTuple = NULL;
index 78044b2d614139f2e655dbbe35a943f53c9f9449..596a482fa137b39a7df020451e12ad45284173f3 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.110 2007/02/02 00:02:55 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.111 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -33,8 +33,8 @@
 
 /*
  * We have an execution_state record for each query in a function.     Each
- * record contains a querytree and plantree for its query.     If the query
- * is currently in F_EXEC_RUN state then there's a QueryDesc too.
+ * record contains a plantree for its query.  If the query is currently in
+ * F_EXEC_RUN state then there's a QueryDesc too.
  */
 typedef enum
 {
@@ -45,8 +45,7 @@ typedef struct local_es
 {
        struct local_es *next;
        ExecStatus      status;
-       Query      *query;
-       Plan       *plan;
+       Node       *stmt;                       /* PlannedStmt or utility statement */
        QueryDesc  *qd;                         /* null unless status == RUN */
 } execution_state;
 
@@ -105,26 +104,30 @@ init_execution_state(List *queryTree_list, bool readonly_func)
        foreach(qtl_item, queryTree_list)
        {
                Query      *queryTree = lfirst(qtl_item);
-               Plan       *planTree;
+               Node       *stmt;
                execution_state *newes;
 
+               Assert(IsA(queryTree, Query));
+
+               if (queryTree->commandType == CMD_UTILITY)
+                       stmt = queryTree->utilityStmt;
+               else
+                       stmt = (Node *) pg_plan_query(queryTree, NULL);
+
                /* Precheck all commands for validity in a function */
-               if (queryTree->commandType == CMD_UTILITY &&
-                       IsA(queryTree->utilityStmt, TransactionStmt))
+               if (IsA(stmt, TransactionStmt))
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        /* translator: %s is a SQL statement name */
                                         errmsg("%s is not allowed in a SQL function",
-                                                       CreateQueryTag(queryTree))));
+                                                       CreateCommandTag(stmt))));
 
-               if (readonly_func && !QueryIsReadOnly(queryTree))
+               if (readonly_func && !CommandIsReadOnly(stmt))
                        ereport(ERROR,
                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                        /* translator: %s is a SQL statement name */
                                         errmsg("%s is not allowed in a non-volatile function",
-                                                       CreateQueryTag(queryTree))));
-
-               planTree = pg_plan_query(queryTree, NULL);
+                                                       CreateCommandTag(stmt))));
 
                newes = (execution_state *) palloc(sizeof(execution_state));
                if (preves)
@@ -134,8 +137,7 @@ init_execution_state(List *queryTree_list, bool readonly_func)
 
                newes->next = NULL;
                newes->status = F_EXEC_START;
-               newes->query = queryTree;
-               newes->plan = planTree;
+               newes->stmt = stmt;
                newes->qd = NULL;
 
                preves = newes;
@@ -298,10 +300,16 @@ postquel_start(execution_state *es, SQLFunctionCachePtr fcache)
                snapshot = CopySnapshot(GetTransactionSnapshot());
        }
 
-       es->qd = CreateQueryDesc(es->query, es->plan,
-                                                        snapshot, InvalidSnapshot,
-                                                        None_Receiver,
-                                                        fcache->paramLI, false);
+       if (IsA(es->stmt, PlannedStmt))
+               es->qd = CreateQueryDesc((PlannedStmt *) es->stmt,
+                                                                snapshot, InvalidSnapshot,
+                                                                None_Receiver,
+                                                                fcache->paramLI, false);
+       else
+               es->qd = CreateUtilityQueryDesc(es->stmt,
+                                                                               snapshot,
+                                                                               None_Receiver,
+                                                                               fcache->paramLI);
 
        /* We assume we don't need to set up ActiveSnapshot for ExecutorStart */
 
@@ -337,7 +345,7 @@ postquel_getnext(execution_state *es)
 
                if (es->qd->operation == CMD_UTILITY)
                {
-                       ProcessUtility(es->qd->parsetree->utilityStmt, es->qd->params,
+                       ProcessUtility(es->qd->utilitystmt, es->qd->params,
                                                   es->qd->dest, NULL);
                        result = NULL;
                }
@@ -351,7 +359,7 @@ postquel_getnext(execution_state *es)
                         */
                        if (LAST_POSTQUEL_COMMAND(es) &&
                                es->qd->operation == CMD_SELECT &&
-                               es->qd->parsetree->into == NULL)
+                               es->qd->plannedstmt->into == NULL)
                                count = 1L;
                        else
                                count = 0L;
index a565ba3cd2b9bac9c501780b910da6dbadcb29e9..33ec21286d96d291502a3617992bcac5477cf9d1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.169 2007/01/09 22:00:59 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.170 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -831,8 +831,7 @@ SPI_cursor_open(const char *name, void *plan,
                                bool read_only)
 {
        _SPI_plan  *spiplan = (_SPI_plan *) plan;
-       List       *qtlist;
-       List       *ptlist;
+       List       *stmt_list;
        ParamListInfo paramLI;
        Snapshot        snapshot;
        MemoryContext oldcontext;
@@ -846,29 +845,22 @@ SPI_cursor_open(const char *name, void *plan,
        if (!SPI_is_cursor_plan(spiplan))
        {
                /* try to give a good error message */
-               Query      *queryTree;
+               Node       *stmt;
 
-               if (list_length(spiplan->qtlist) != 1)
+               if (list_length(spiplan->stmt_list_list) != 1)
                        ereport(ERROR,
                                        (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
                                         errmsg("cannot open multi-query plan as cursor")));
-               queryTree = PortalListGetPrimaryQuery((List *) linitial(spiplan->qtlist));
-               if (queryTree == NULL)
-                       ereport(ERROR,
-                                       (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
-                                        errmsg("cannot open empty query as cursor")));
+               stmt = PortalListGetPrimaryStmt((List *) linitial(spiplan->stmt_list_list));
                ereport(ERROR,
                                (errcode(ERRCODE_INVALID_CURSOR_DEFINITION),
                /* translator: %s is name of a SQL command, eg INSERT */
                                 errmsg("cannot open %s query as cursor",
-                                               CreateQueryTag(queryTree))));
+                                               CreateCommandTag(stmt))));
        }
 
-       Assert(list_length(spiplan->qtlist) == 1);
-       qtlist = (List *) linitial(spiplan->qtlist);
-       ptlist = spiplan->ptlist;
-       if (list_length(qtlist) != list_length(ptlist))
-               elog(ERROR, "corrupted SPI plan lists");
+       Assert(list_length(spiplan->stmt_list_list) == 1);
+       stmt_list = (List *) linitial(spiplan->stmt_list_list);
 
        /* Reset SPI result (note we deliberately don't touch lastoid) */
        SPI_processed = 0;
@@ -888,10 +880,9 @@ SPI_cursor_open(const char *name, void *plan,
                portal = CreatePortal(name, false, false);
        }
 
-       /* Switch to portal's memory and copy the parsetrees and plans to there */
+       /* Switch to portal's memory and copy the plans to there */
        oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-       qtlist = copyObject(qtlist);
-       ptlist = copyObject(ptlist);
+       stmt_list = copyObject(stmt_list);
 
        /* If the plan has parameters, set them up */
        if (spiplan->nargs > 0)
@@ -934,9 +925,8 @@ SPI_cursor_open(const char *name, void *plan,
        PortalDefineQuery(portal,
                                          NULL,         /* no statement name */
                                          spiplan->query,
-                                         CreateQueryTag(PortalListGetPrimaryQuery(qtlist)),
-                                         qtlist,
-                                         ptlist,
+                                         CreateCommandTag(PortalListGetPrimaryStmt(stmt_list)),
+                                         stmt_list,
                                          PortalGetHeapMemory(portal));
 
        MemoryContextSwitchTo(oldcontext);
@@ -945,8 +935,9 @@ SPI_cursor_open(const char *name, void *plan,
         * Set up options for portal.
         */
        portal->cursorOptions &= ~(CURSOR_OPT_SCROLL | CURSOR_OPT_NO_SCROLL);
-       if (list_length(ptlist) == 1 &&
-               ExecSupportsBackwardScan((Plan *) linitial(ptlist)))
+       if (list_length(stmt_list) == 1 &&
+               IsA((Node *) linitial(stmt_list), PlannedStmt) &&
+               ExecSupportsBackwardScan(((PlannedStmt *) linitial(stmt_list))->planTree))
                portal->cursorOptions |= CURSOR_OPT_SCROLL;
        else
                portal->cursorOptions |= CURSOR_OPT_NO_SCROLL;
@@ -1076,10 +1067,10 @@ SPI_is_cursor_plan(void *plan)
                return false;
        }
 
-       if (list_length(spiplan->qtlist) != 1)
+       if (list_length(spiplan->stmt_list_list) != 1)
                return false;                   /* not exactly 1 pre-rewrite command */
 
-       switch (ChoosePortalStrategy((List *) linitial(spiplan->qtlist)))
+       switch (ChoosePortalStrategy((List *) linitial(spiplan->stmt_list_list)))
        {
                case PORTAL_ONE_SELECT:
                case PORTAL_ONE_RETURNING:
@@ -1257,14 +1248,13 @@ spi_printtup(TupleTableSlot *slot, DestReceiver *self)
  *
  * At entry, plan->argtypes and plan->nargs must be valid.
  *
- * Query and plan lists are stored into *plan.
+ * Result lists are stored into *plan.
  */
 static void
 _SPI_prepare_plan(const char *src, _SPI_plan *plan)
 {
        List       *raw_parsetree_list;
-       List       *query_list_list;
-       List       *plan_list;
+       List       *stmt_list_list;
        ListCell   *list_item;
        ErrorContextCallback spierrcontext;
        Oid                *argtypes = plan->argtypes;
@@ -1294,12 +1284,11 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan)
        /*
         * Do parse analysis and rule rewrite for each raw parsetree.
         *
-        * We save the querytrees from each raw parsetree as a separate sublist.
+        * We save the results from each raw parsetree as a separate sublist.
         * This allows _SPI_execute_plan() to know where the boundaries between
         * original queries fall.
         */
-       query_list_list = NIL;
-       plan_list = NIL;
+       stmt_list_list = NIL;
 
        foreach(list_item, raw_parsetree_list)
        {
@@ -1308,14 +1297,11 @@ _SPI_prepare_plan(const char *src, _SPI_plan *plan)
 
                query_list = pg_analyze_and_rewrite(parsetree, src, argtypes, nargs);
 
-               query_list_list = lappend(query_list_list, query_list);
-
-               plan_list = list_concat(plan_list,
-                                                               pg_plan_queries(query_list, NULL, false));
+               stmt_list_list = lappend(stmt_list_list,
+                                                                pg_plan_queries(query_list, NULL, false));
        }
 
-       plan->qtlist = query_list_list;
-       plan->ptlist = plan_list;
+       plan->stmt_list_list = stmt_list_list;
 
        /*
         * Pop the error context stack
@@ -1348,9 +1334,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
        saveActiveSnapshot = ActiveSnapshot;
        PG_TRY();
        {
-               List       *query_list_list = plan->qtlist;
-               ListCell   *plan_list_item = list_head(plan->ptlist);
-               ListCell   *query_list_list_item;
+               ListCell   *stmt_list_list_item;
                ErrorContextCallback spierrcontext;
                int                     nargs = plan->nargs;
                ParamListInfo paramLI;
@@ -1386,57 +1370,61 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
                spierrcontext.previous = error_context_stack;
                error_context_stack = &spierrcontext;
 
-               foreach(query_list_list_item, query_list_list)
+               foreach(stmt_list_list_item, plan->stmt_list_list)
                {
-                       List       *query_list = lfirst(query_list_list_item);
-                       ListCell   *query_list_item;
+                       List       *stmt_list = (List *) lfirst(stmt_list_list_item);
+                       ListCell   *stmt_list_item;
 
-                       foreach(query_list_item, query_list)
+                       foreach(stmt_list_item, stmt_list)
                        {
-                               Query      *queryTree = (Query *) lfirst(query_list_item);
-                               Plan       *planTree;
+                               Node       *stmt = (Node *) lfirst(stmt_list_item);
+                               bool            canSetTag;
                                QueryDesc  *qdesc;
                                DestReceiver *dest;
 
-                               planTree = lfirst(plan_list_item);
-                               plan_list_item = lnext(plan_list_item);
-
                                _SPI_current->processed = 0;
                                _SPI_current->lastoid = InvalidOid;
                                _SPI_current->tuptable = NULL;
 
-                               if (queryTree->commandType == CMD_UTILITY)
+                               if (IsA(stmt, PlannedStmt))
                                {
-                                       if (IsA(queryTree->utilityStmt, CopyStmt))
+                                       canSetTag = ((PlannedStmt *) stmt)->canSetTag;
+                               }
+                               else
+                               {
+                                       /* utilities are canSetTag if only thing in list */
+                                       canSetTag = (list_length(stmt_list) == 1);
+
+                                       if (IsA(stmt, CopyStmt))
                                        {
-                                               CopyStmt   *stmt = (CopyStmt *) queryTree->utilityStmt;
+                                               CopyStmt   *cstmt = (CopyStmt *) stmt;
 
-                                               if (stmt->filename == NULL)
+                                               if (cstmt->filename == NULL)
                                                {
                                                        my_res = SPI_ERROR_COPY;
                                                        goto fail;
                                                }
                                        }
-                                       else if (IsA(queryTree->utilityStmt, DeclareCursorStmt) ||
-                                                        IsA(queryTree->utilityStmt, ClosePortalStmt) ||
-                                                        IsA(queryTree->utilityStmt, FetchStmt))
+                                       else if (IsA(stmt, DeclareCursorStmt) ||
+                                                        IsA(stmt, ClosePortalStmt) ||
+                                                        IsA(stmt, FetchStmt))
                                        {
                                                my_res = SPI_ERROR_CURSOR;
                                                goto fail;
                                        }
-                                       else if (IsA(queryTree->utilityStmt, TransactionStmt))
+                                       else if (IsA(stmt, TransactionStmt))
                                        {
                                                my_res = SPI_ERROR_TRANSACTION;
                                                goto fail;
                                        }
                                }
 
-                               if (read_only && !QueryIsReadOnly(queryTree))
+                               if (read_only && !CommandIsReadOnly(stmt))
                                        ereport(ERROR,
                                                        (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                        /* translator: %s is a SQL statement name */
                                           errmsg("%s is not allowed in a non-volatile function",
-                                                         CreateQueryTag(queryTree))));
+                                                         CreateCommandTag(stmt))));
 
                                /*
                                 * If not read-only mode, advance the command counter before
@@ -1445,7 +1433,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
                                if (!read_only)
                                        CommandCounterIncrement();
 
-                               dest = CreateDestReceiver(queryTree->canSetTag ? DestSPI : DestNone,
+                               dest = CreateDestReceiver(canSetTag ? DestSPI : DestNone,
                                                                                  NULL);
 
                                if (snapshot == InvalidSnapshot)
@@ -1471,26 +1459,24 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
                                                ActiveSnapshot->curcid = GetCurrentCommandId();
                                }
 
-                               if (queryTree->commandType == CMD_UTILITY)
-                               {
-                                       ProcessUtility(queryTree->utilityStmt, paramLI,
-                                                                  dest, NULL);
-                                       /* Update "processed" if stmt returned tuples */
-                                       if (_SPI_current->tuptable)
-                                               _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
-                                       res = SPI_OK_UTILITY;
-                               }
-                               else
+                               if (IsA(stmt, PlannedStmt))
                                {
-                                       qdesc = CreateQueryDesc(queryTree, planTree,
+                                       qdesc = CreateQueryDesc((PlannedStmt *) stmt,
                                                                                        ActiveSnapshot,
                                                                                        crosscheck_snapshot,
                                                                                        dest,
                                                                                        paramLI, false);
-                                       res = _SPI_pquery(qdesc,
-                                                                         queryTree->canSetTag ? tcount : 0);
+                                       res = _SPI_pquery(qdesc, canSetTag ? tcount : 0);
                                        FreeQueryDesc(qdesc);
                                }
+                               else
+                               {
+                                       ProcessUtility(stmt, paramLI, dest, NULL);
+                                       /* Update "processed" if stmt returned tuples */
+                                       if (_SPI_current->tuptable)
+                                               _SPI_current->processed = _SPI_current->tuptable->alloced - _SPI_current->tuptable->free;
+                                       res = SPI_OK_UTILITY;
+                               }
                                FreeSnapshot(ActiveSnapshot);
                                ActiveSnapshot = NULL;
 
@@ -1499,7 +1485,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
                                 * the caller.  Be careful to free any tuptables not returned,
                                 * to avoid intratransaction memory leak.
                                 */
-                               if (queryTree->canSetTag)
+                               if (canSetTag)
                                {
                                        my_processed = _SPI_current->processed;
                                        my_lastoid = _SPI_current->lastoid;
@@ -1565,7 +1551,7 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
        switch (operation)
        {
                case CMD_SELECT:
-                       if (queryDesc->parsetree->into)         /* select into table? */
+                       if (queryDesc->plannedstmt->into)               /* select into table? */
                                res = SPI_OK_SELINTO;
                        else if (queryDesc->dest->mydest != DestSPI)
                        {
@@ -1576,19 +1562,19 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
                                res = SPI_OK_SELECT;
                        break;
                case CMD_INSERT:
-                       if (queryDesc->parsetree->returningList)
+                       if (queryDesc->plannedstmt->returningLists)
                                res = SPI_OK_INSERT_RETURNING;
                        else
                                res = SPI_OK_INSERT;
                        break;
                case CMD_DELETE:
-                       if (queryDesc->parsetree->returningList)
+                       if (queryDesc->plannedstmt->returningLists)
                                res = SPI_OK_DELETE_RETURNING;
                        else
                                res = SPI_OK_DELETE;
                        break;
                case CMD_UPDATE:
-                       if (queryDesc->parsetree->returningList)
+                       if (queryDesc->plannedstmt->returningLists)
                                res = SPI_OK_UPDATE_RETURNING;
                        else
                                res = SPI_OK_UPDATE;
@@ -1611,7 +1597,7 @@ _SPI_pquery(QueryDesc *queryDesc, long tcount)
        _SPI_current->processed = queryDesc->estate->es_processed;
        _SPI_current->lastoid = queryDesc->estate->es_lastoid;
 
-       if ((res == SPI_OK_SELECT || queryDesc->parsetree->returningList) &&
+       if ((res == SPI_OK_SELECT || queryDesc->plannedstmt->returningLists) &&
                queryDesc->dest->mydest == DestSPI)
        {
                if (_SPI_checktuples())
@@ -1813,8 +1799,7 @@ _SPI_copy_plan(_SPI_plan *plan, int location)
        newplan = (_SPI_plan *) palloc(sizeof(_SPI_plan));
        newplan->plancxt = plancxt;
        newplan->query = pstrdup(plan->query);
-       newplan->qtlist = (List *) copyObject(plan->qtlist);
-       newplan->ptlist = (List *) copyObject(plan->ptlist);
+       newplan->stmt_list_list = (List *) copyObject(plan->stmt_list_list);
        newplan->nargs = plan->nargs;
        if (plan->nargs > 0)
        {
index cdf98de568a6e158c0e496ccff8a2280c77ebe04..4d10afc022db95447f238c1fc51894d048fb9bf0 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.366 2007/02/19 02:23:11 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.367 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  * ****************************************************************
  */
 
+/*
+ * _copyPlannedStmt
+ */
+static PlannedStmt *
+_copyPlannedStmt(PlannedStmt *from)
+{
+       PlannedStmt        *newnode = makeNode(PlannedStmt);
+
+       COPY_SCALAR_FIELD(commandType);
+       COPY_SCALAR_FIELD(canSetTag);
+       COPY_NODE_FIELD(planTree);
+       COPY_NODE_FIELD(rtable);
+       COPY_NODE_FIELD(resultRelations);
+       COPY_NODE_FIELD(into);
+       COPY_NODE_FIELD(returningLists);
+       COPY_NODE_FIELD(rowMarks);
+       COPY_SCALAR_FIELD(nParamExec);
+
+       return newnode;
+}
+
 /*
  * CopyPlanFields
  *
@@ -84,7 +105,6 @@ CopyPlanFields(Plan *from, Plan *newnode)
        COPY_NODE_FIELD(initPlan);
        COPY_BITMAPSET_FIELD(extParam);
        COPY_BITMAPSET_FIELD(allParam);
-       COPY_SCALAR_FIELD(nParamExec);
 }
 
 /*
@@ -698,6 +718,23 @@ _copyRangeVar(RangeVar *from)
        return newnode;
 }
 
+/*
+ * _copyIntoClause
+ */
+static IntoClause *
+_copyIntoClause(IntoClause *from)
+{
+       IntoClause   *newnode = makeNode(IntoClause);
+
+       COPY_NODE_FIELD(rel);
+       COPY_NODE_FIELD(colNames);
+       COPY_NODE_FIELD(options);
+       COPY_SCALAR_FIELD(onCommit);
+       COPY_STRING_FIELD(tableSpaceName);
+
+       return newnode;
+}
+
 /*
  * We don't need a _copyExpr because Expr is an abstract supertype which
  * should never actually get instantiated.     Also, since it has no common
@@ -1762,9 +1799,6 @@ _copyQuery(Query *from)
        COPY_NODE_FIELD(utilityStmt);
        COPY_SCALAR_FIELD(resultRelation);
        COPY_NODE_FIELD(into);
-       COPY_NODE_FIELD(intoOptions);
-       COPY_SCALAR_FIELD(intoOnCommit);
-       COPY_STRING_FIELD(intoTableSpaceName);
        COPY_SCALAR_FIELD(hasAggs);
        COPY_SCALAR_FIELD(hasSubLinks);
        COPY_NODE_FIELD(rtable);
@@ -1779,8 +1813,6 @@ _copyQuery(Query *from)
        COPY_NODE_FIELD(limitCount);
        COPY_NODE_FIELD(rowMarks);
        COPY_NODE_FIELD(setOperations);
-       COPY_NODE_FIELD(resultRelations);
-       COPY_NODE_FIELD(returningLists);
 
        return newnode;
 }
@@ -1832,10 +1864,6 @@ _copySelectStmt(SelectStmt *from)
 
        COPY_NODE_FIELD(distinctClause);
        COPY_NODE_FIELD(into);
-       COPY_NODE_FIELD(intoColNames);
-       COPY_NODE_FIELD(intoOptions);
-       COPY_SCALAR_FIELD(intoOnCommit);
-       COPY_STRING_FIELD(intoTableSpaceName);
        COPY_NODE_FIELD(targetList);
        COPY_NODE_FIELD(fromClause);
        COPY_NODE_FIELD(whereClause);
@@ -2768,9 +2796,6 @@ _copyExecuteStmt(ExecuteStmt *from)
 
        COPY_STRING_FIELD(name);
        COPY_NODE_FIELD(into);
-       COPY_NODE_FIELD(intoOptions);
-       COPY_SCALAR_FIELD(into_on_commit);
-       COPY_STRING_FIELD(into_tbl_space);
        COPY_NODE_FIELD(params);
 
        return newnode;
@@ -2902,6 +2927,9 @@ copyObject(void *from)
                        /*
                         * PLAN NODES
                         */
+               case T_PlannedStmt:
+                       retval = _copyPlannedStmt(from);
+                       break;
                case T_Plan:
                        retval = _copyPlan(from);
                        break;
@@ -2990,6 +3018,9 @@ copyObject(void *from)
                case T_RangeVar:
                        retval = _copyRangeVar(from);
                        break;
+               case T_IntoClause:
+                       retval = _copyIntoClause(from);
+                       break;
                case T_Var:
                        retval = _copyVar(from);
                        break;
index c17a40bbbb246013f89a3c66be2771a1404667d4..dafa15f0287dcd849e36d1a8e3222a1de9acd5b6 100644 (file)
@@ -18,7 +18,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.298 2007/02/03 14:06:54 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/equalfuncs.c,v 1.299 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -102,6 +102,18 @@ _equalRangeVar(RangeVar *a, RangeVar *b)
        return true;
 }
 
+static bool
+_equalIntoClause(IntoClause *a, IntoClause *b)
+{
+       COMPARE_NODE_FIELD(rel);
+       COMPARE_NODE_FIELD(colNames);
+       COMPARE_NODE_FIELD(options);
+       COMPARE_SCALAR_FIELD(onCommit);
+       COMPARE_STRING_FIELD(tableSpaceName);
+
+       return true;
+}
+
 /*
  * We don't need an _equalExpr because Expr is an abstract supertype which
  * should never actually get instantiated.     Also, since it has no common
@@ -690,9 +702,6 @@ _equalQuery(Query *a, Query *b)
        COMPARE_NODE_FIELD(utilityStmt);
        COMPARE_SCALAR_FIELD(resultRelation);
        COMPARE_NODE_FIELD(into);
-       COMPARE_NODE_FIELD(intoOptions);
-       COMPARE_SCALAR_FIELD(intoOnCommit);
-       COMPARE_STRING_FIELD(intoTableSpaceName);
        COMPARE_SCALAR_FIELD(hasAggs);
        COMPARE_SCALAR_FIELD(hasSubLinks);
        COMPARE_NODE_FIELD(rtable);
@@ -707,8 +716,6 @@ _equalQuery(Query *a, Query *b)
        COMPARE_NODE_FIELD(limitCount);
        COMPARE_NODE_FIELD(rowMarks);
        COMPARE_NODE_FIELD(setOperations);
-       COMPARE_NODE_FIELD(resultRelations);
-       COMPARE_NODE_FIELD(returningLists);
 
        return true;
 }
@@ -752,10 +759,6 @@ _equalSelectStmt(SelectStmt *a, SelectStmt *b)
 {
        COMPARE_NODE_FIELD(distinctClause);
        COMPARE_NODE_FIELD(into);
-       COMPARE_NODE_FIELD(intoColNames);
-       COMPARE_NODE_FIELD(intoOptions);
-       COMPARE_SCALAR_FIELD(intoOnCommit);
-       COMPARE_STRING_FIELD(intoTableSpaceName);
        COMPARE_NODE_FIELD(targetList);
        COMPARE_NODE_FIELD(fromClause);
        COMPARE_NODE_FIELD(whereClause);
@@ -1545,9 +1548,6 @@ _equalExecuteStmt(ExecuteStmt *a, ExecuteStmt *b)
 {
        COMPARE_STRING_FIELD(name);
        COMPARE_NODE_FIELD(into);
-       COMPARE_NODE_FIELD(intoOptions);
-       COMPARE_SCALAR_FIELD(into_on_commit);
-       COMPARE_STRING_FIELD(into_tbl_space);
        COMPARE_NODE_FIELD(params);
 
        return true;
@@ -1967,6 +1967,9 @@ equal(void *a, void *b)
                case T_RangeVar:
                        retval = _equalRangeVar(a, b);
                        break;
+               case T_IntoClause:
+                       retval = _equalIntoClause(a, b);
+                       break;
                case T_Var:
                        retval = _equalVar(a, b);
                        break;
index 0600f63b5567616427dab633f0f4c3d5793d5623..c8cc25abb1330ce9c8cc25d8dd90375bafbf0f6c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.299 2007/02/19 07:03:27 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.300 2007/02/20 17:32:15 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -234,6 +234,22 @@ _outDatum(StringInfo str, Datum value, int typlen, bool typbyval)
  *     Stuff from plannodes.h
  */
 
+static void
+_outPlannedStmt(StringInfo str, PlannedStmt *node)
+{
+       WRITE_NODE_TYPE("PLANNEDSTMT");
+
+       WRITE_ENUM_FIELD(commandType, CmdType);
+       WRITE_BOOL_FIELD(canSetTag);
+       WRITE_NODE_FIELD(planTree);
+       WRITE_NODE_FIELD(rtable);
+       WRITE_NODE_FIELD(resultRelations);
+       WRITE_NODE_FIELD(into);
+       WRITE_NODE_FIELD(returningLists);
+       WRITE_NODE_FIELD(rowMarks);
+       WRITE_INT_FIELD(nParamExec);
+}
+
 /*
  * print the basic stuff of all nodes that inherit from Plan
  */
@@ -251,7 +267,6 @@ _outPlanInfo(StringInfo str, Plan *node)
        WRITE_NODE_FIELD(initPlan);
        WRITE_BITMAPSET_FIELD(extParam);
        WRITE_BITMAPSET_FIELD(allParam);
-       WRITE_INT_FIELD(nParamExec);
 }
 
 /*
@@ -635,6 +650,18 @@ _outRangeVar(StringInfo str, RangeVar *node)
        WRITE_NODE_FIELD(alias);
 }
 
+static void
+_outIntoClause(StringInfo str, IntoClause *node)
+{
+       WRITE_NODE_TYPE("INTOCLAUSE");
+
+       WRITE_NODE_FIELD(rel);
+       WRITE_NODE_FIELD(colNames);
+       WRITE_NODE_FIELD(options);
+       WRITE_ENUM_FIELD(onCommit, OnCommitAction);
+       WRITE_STRING_FIELD(tableSpaceName);
+}
+
 static void
 _outVar(StringInfo str, Var *node)
 {
@@ -1245,6 +1272,8 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
        WRITE_NODE_FIELD(glob);
        WRITE_UINT_FIELD(query_level);
        WRITE_NODE_FIELD(join_rel_list);
+       WRITE_NODE_FIELD(resultRelations);
+       WRITE_NODE_FIELD(returningLists);
        WRITE_NODE_FIELD(init_plans);
        WRITE_NODE_FIELD(eq_classes);
        WRITE_NODE_FIELD(canon_pathkeys);
@@ -1502,10 +1531,6 @@ _outSelectStmt(StringInfo str, SelectStmt *node)
 
        WRITE_NODE_FIELD(distinctClause);
        WRITE_NODE_FIELD(into);
-       WRITE_NODE_FIELD(intoColNames);
-       WRITE_NODE_FIELD(intoOptions);
-       WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction);
-       WRITE_STRING_FIELD(intoTableSpaceName);
        WRITE_NODE_FIELD(targetList);
        WRITE_NODE_FIELD(fromClause);
        WRITE_NODE_FIELD(whereClause);
@@ -1651,9 +1676,6 @@ _outQuery(StringInfo str, Query *node)
 
        WRITE_INT_FIELD(resultRelation);
        WRITE_NODE_FIELD(into);
-       WRITE_NODE_FIELD(intoOptions);
-       WRITE_ENUM_FIELD(intoOnCommit, OnCommitAction);
-       WRITE_STRING_FIELD(intoTableSpaceName);
        WRITE_BOOL_FIELD(hasAggs);
        WRITE_BOOL_FIELD(hasSubLinks);
        WRITE_NODE_FIELD(rtable);
@@ -1668,8 +1690,6 @@ _outQuery(StringInfo str, Query *node)
        WRITE_NODE_FIELD(limitCount);
        WRITE_NODE_FIELD(rowMarks);
        WRITE_NODE_FIELD(setOperations);
-       WRITE_NODE_FIELD(resultRelations);
-       WRITE_NODE_FIELD(returningLists);
 }
 
 static void
@@ -1988,6 +2008,9 @@ _outNode(StringInfo str, void *obj)
                appendStringInfoChar(str, '{');
                switch (nodeTag(obj))
                {
+                       case T_PlannedStmt:
+                               _outPlannedStmt(str, obj);
+                               break;
                        case T_Plan:
                                _outPlan(str, obj);
                                break;
@@ -2072,6 +2095,9 @@ _outNode(StringInfo str, void *obj)
                        case T_RangeVar:
                                _outRangeVar(str, obj);
                                break;
+                       case T_IntoClause:
+                               _outIntoClause(str, obj);
+                               break;
                        case T_Var:
                                _outVar(str, obj);
                                break;
index 17d36b4efe6db40a92b054b9bf9a6ad988755fe2..6478dce4b1c14e5a0b7a24379d6d07f08b4f97ac 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.202 2007/02/03 14:06:54 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/readfuncs.c,v 1.203 2007/02/20 17:32:15 tgl Exp $
  *
  * NOTES
  *       Path and Plan nodes do not have any readfuncs support, because we
@@ -140,9 +140,6 @@ _readQuery(void)
        READ_NODE_FIELD(utilityStmt);
        READ_INT_FIELD(resultRelation);
        READ_NODE_FIELD(into);
-       READ_NODE_FIELD(intoOptions);
-       READ_ENUM_FIELD(intoOnCommit, OnCommitAction);
-       READ_STRING_FIELD(intoTableSpaceName);
        READ_BOOL_FIELD(hasAggs);
        READ_BOOL_FIELD(hasSubLinks);
        READ_NODE_FIELD(rtable);
@@ -157,8 +154,6 @@ _readQuery(void)
        READ_NODE_FIELD(limitCount);
        READ_NODE_FIELD(rowMarks);
        READ_NODE_FIELD(setOperations);
-       READ_NODE_FIELD(resultRelations);
-       READ_NODE_FIELD(returningLists);
 
        READ_DONE();
 }
@@ -287,6 +282,20 @@ _readRangeVar(void)
        READ_DONE();
 }
 
+static IntoClause *
+_readIntoClause(void)
+{
+       READ_LOCALS(IntoClause);
+
+       READ_NODE_FIELD(rel);
+       READ_NODE_FIELD(colNames);
+       READ_NODE_FIELD(options);
+       READ_ENUM_FIELD(onCommit, OnCommitAction);
+       READ_STRING_FIELD(tableSpaceName);
+
+       READ_DONE();
+}
+
 /*
  * _readVar
  */
@@ -984,6 +993,8 @@ parseNodeString(void)
                return_value = _readAlias();
        else if (MATCH("RANGEVAR", 8))
                return_value = _readRangeVar();
+       else if (MATCH("INTOCLAUSE", 10))
+               return_value = _readIntoClause();
        else if (MATCH("VAR", 3))
                return_value = _readVar();
        else if (MATCH("CONST", 5))
index 1cb1d86be1b58374dc2c0f94a328e29e94f58dc9..6c6e80071c1ccfc12bbeed1a9d0c92373a750bb4 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.159 2007/02/19 07:03:28 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.160 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -444,8 +444,8 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
        Query      *subquery = rte->subquery;
        bool       *differentTypes;
        double          tuple_fraction;
+       PlannerInfo *subroot;
        List       *pathkeys;
-       List       *subquery_pathkeys;
 
        /* We need a workspace for keeping track of set-op type coercions */
        differentTypes = (bool *)
@@ -520,7 +520,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
        rel->subplan = subquery_planner(root->glob, subquery,
                                                                        root->query_level + 1,
                                                                        tuple_fraction,
-                                                                       &subquery_pathkeys);
+                                                                       &subroot);
 
        /* Copy number of output rows from subplan */
        rel->tuples = rel->subplan->plan_rows;
@@ -529,7 +529,7 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
        set_baserel_size_estimates(root, rel);
 
        /* Convert subquery pathkeys to outer representation */
-       pathkeys = convert_subquery_pathkeys(root, rel, subquery_pathkeys);
+       pathkeys = convert_subquery_pathkeys(root, rel, subroot->query_pathkeys);
 
        /* Generate appropriate path */
        add_path(rel, create_subqueryscan_path(rel, pathkeys));
index be26d17a28a2bca78bffb6a63e3a483e2e5677fe..406cc9dd49665845ef9d889565dbd1226c72b236 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.27 2007/02/19 07:03:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.28 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -453,8 +453,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
        subroot.init_plans = NIL;
        subparse->commandType = CMD_SELECT;
        subparse->resultRelation = 0;
-       subparse->resultRelations = NIL;
-       subparse->returningLists = NIL;
+       subparse->returningList = NIL;
        subparse->into = NULL;
        subparse->hasAggs = false;
        subparse->groupClause = NIL;
index f4a940175ea5c89c08ed9c8bd2e703072fcd585a..3bb603a0f614bb53ff4cbb0eebefee770afbd819 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.213 2007/02/19 07:03:29 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.214 2007/02/20 17:32:15 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -79,13 +79,15 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
  *        Query optimizer entry point
  *
  *****************************************************************************/
-Plan *
+PlannedStmt *
 planner(Query *parse, bool isCursor, int cursorOptions,
                ParamListInfo boundParams)
 {
+       PlannedStmt *result;
        PlannerGlobal *glob;
        double          tuple_fraction;
-       Plan       *result_plan;
+       PlannerInfo *root;
+       Plan       *top_plan;
 
        /*
         * Set up global state for this planner invocation.  This data is needed
@@ -117,7 +119,7 @@ planner(Query *parse, bool isCursor, int cursorOptions,
        }
 
        /* primary planning entry point (may recurse for subqueries) */
-       result_plan = subquery_planner(glob, parse, 1, tuple_fraction, NULL);
+       top_plan = subquery_planner(glob, parse, 1, tuple_fraction, &root);
 
        /*
         * If creating a plan for a scrollable cursor, make sure it can run
@@ -125,17 +127,27 @@ planner(Query *parse, bool isCursor, int cursorOptions,
         */
        if (isCursor && (cursorOptions & CURSOR_OPT_SCROLL))
        {
-               if (!ExecSupportsBackwardScan(result_plan))
-                       result_plan = materialize_finished_plan(result_plan);
+               if (!ExecSupportsBackwardScan(top_plan))
+                       top_plan = materialize_finished_plan(top_plan);
        }
 
        /* final cleanup of the plan */
-       result_plan = set_plan_references(result_plan, parse->rtable);
-
-       /* executor wants to know total number of Params used overall */
-       result_plan->nParamExec = list_length(glob->paramlist);
-
-       return result_plan;
+       top_plan = set_plan_references(top_plan, parse->rtable);
+
+       /* build the PlannedStmt result */
+       result = makeNode(PlannedStmt);
+
+       result->commandType = parse->commandType;
+       result->canSetTag = parse->canSetTag;
+       result->planTree = top_plan;
+       result->rtable = parse->rtable;
+       result->resultRelations = root->resultRelations;
+       result->into = parse->into;
+       result->returningLists = root->returningLists;
+       result->rowMarks = parse->rowMarks;
+       result->nParamExec = list_length(glob->paramlist);
+
+       return result;
 }
 
 
@@ -150,8 +162,8 @@ planner(Query *parse, bool isCursor, int cursorOptions,
  * tuple_fraction is the fraction of tuples we expect will be retrieved.
  * tuple_fraction is interpreted as explained for grouping_planner, below.
  *
- * If subquery_pathkeys isn't NULL, it receives a list of pathkeys indicating
- * the output sort ordering of the completed plan.
+ * If subroot isn't NULL, we pass back the query's final PlannerInfo struct;
+ * among other things this tells the output sort ordering of the plan.
  *
  * Basically, this routine does the stuff that should only be done once
  * per Query object.  It then calls grouping_planner.  At one time,
@@ -168,7 +180,7 @@ planner(Query *parse, bool isCursor, int cursorOptions,
 Plan *
 subquery_planner(PlannerGlobal *glob, Query *parse,
                                 Index level, double tuple_fraction,
-                                List **subquery_pathkeys)
+                                PlannerInfo **subroot)
 {
        int                     saved_plan_id = glob->next_plan_id;
        PlannerInfo *root;
@@ -375,9 +387,9 @@ subquery_planner(PlannerGlobal *glob, Query *parse,
        if (root->glob->next_plan_id != saved_plan_id || root->query_level > 1)
                SS_finalize_plan(root, plan);
 
-       /* Return sort ordering info if caller wants it */
-       if (subquery_pathkeys)
-               *subquery_pathkeys = root->query_pathkeys;
+       /* Return internal info if caller wants it */
+       if (subroot)
+               *subroot = root;
 
        return plan;
 }
@@ -593,14 +605,14 @@ inheritance_planner(PlannerInfo *root)
                /* Build list of per-relation RETURNING targetlists */
                if (parse->returningList)
                {
-                       Assert(list_length(subroot.parse->returningLists) == 1);
+                       Assert(list_length(subroot.returningLists) == 1);
                        returningLists = list_concat(returningLists,
-                                                                                subroot.parse->returningLists);
+                                                                                subroot.returningLists);
                }
        }
 
-       parse->resultRelations = resultRelations;
-       parse->returningLists = returningLists;
+       root->resultRelations = resultRelations;
+       root->returningLists = returningLists;
 
        /* Mark result as unordered (probably unnecessary) */
        root->query_pathkeys = NIL;
@@ -1101,8 +1113,16 @@ grouping_planner(PlannerInfo *root, double tuple_fraction)
                rlist = set_returning_clause_references(parse->returningList,
                                                                                                result_plan,
                                                                                                parse->resultRelation);
-               parse->returningLists = list_make1(rlist);
+               root->returningLists = list_make1(rlist);
        }
+       else
+               root->returningLists = NIL;
+
+       /* Compute result-relations list if needed */
+       if (parse->resultRelation)
+               root->resultRelations = list_make1_int(parse->resultRelation);
+       else
+               root->resultRelations = NIL;
 
        /*
         * Return the actual output ordering in query_pathkeys for possible use by
index 0eb81d6d8982d0dbc54e283bfd9efa2d5302e07d..63a5999a401d29cca1130518e198820d450c6f2d 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.360 2007/02/01 19:10:27 momjian Exp $
+ *     $PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.361 2007/02/20 17:32:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2143,11 +2143,8 @@ transformSelectStmt(ParseState *pstate, SelectStmt *stmt)
        if (stmt->into)
        {
                qry->into = stmt->into;
-               if (stmt->intoColNames)
-                       applyColumnNames(qry->targetList, stmt->intoColNames);
-               qry->intoOptions = copyObject(stmt->intoOptions);
-               qry->intoOnCommit = stmt->intoOnCommit;
-               qry->intoTableSpaceName = stmt->intoTableSpaceName;
+               if (stmt->into->colNames)
+                       applyColumnNames(qry->targetList, stmt->into->colNames);
        }
 
        qry->rtable = pstate->p_rtable;
@@ -2315,11 +2312,8 @@ transformValuesClause(ParseState *pstate, SelectStmt *stmt)
        if (stmt->into)
        {
                qry->into = stmt->into;
-               if (stmt->intoColNames)
-                       applyColumnNames(qry->targetList, stmt->intoColNames);
-               qry->intoOptions = copyObject(stmt->intoOptions);
-               qry->intoOnCommit = stmt->intoOnCommit;
-               qry->intoTableSpaceName = stmt->intoTableSpaceName;
+               if (stmt->into->colNames)
+                       applyColumnNames(qry->targetList, stmt->into->colNames);
        }
 
        /*
@@ -2399,9 +2393,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
 
        /*
         * Find leftmost leaf SelectStmt; extract the one-time-only items from it
-        * and from the top-level node.  (Most of the INTO options can be
-        * transferred to the Query immediately, but intoColNames has to be saved
-        * to apply below.)
+        * and from the top-level node.
         */
        leftmostSelect = stmt->larg;
        while (leftmostSelect && leftmostSelect->op != SETOP_NONE)
@@ -2411,10 +2403,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
        if (leftmostSelect->into)
        {
                qry->into = leftmostSelect->into;
-               intoColNames = leftmostSelect->intoColNames;
-               qry->intoOptions = copyObject(leftmostSelect->intoOptions);
-               qry->intoOnCommit = leftmostSelect->intoOnCommit;
-               qry->intoTableSpaceName = leftmostSelect->intoTableSpaceName;
+               intoColNames = leftmostSelect->into->colNames;
        }
 
        /* clear this to prevent complaints in transformSetOperationTree() */
index cf25c5607a64e439e3d9c427f0318fb324856676..3204d0a401ae2039fc807fc1fa33c5a6b9bce327 100644 (file)
@@ -11,7 +11,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.579 2007/02/03 14:06:54 petere Exp $
+ *       $PostgreSQL: pgsql/src/backend/parser/gram.y,v 2.580 2007/02/20 17:32:16 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -139,6 +139,7 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
        IndexElem                       *ielem;
        Alias                           *alias;
        RangeVar                        *range;
+       IntoClause                      *into;
        A_Indices                       *aind;
        ResTarget                       *target;
        PrivTarget                      *privtarget;
@@ -248,7 +249,8 @@ static Node *makeXmlExpr(XmlExprOp op, char *name, List *named_args, List *args)
                                prep_type_clause
                                execute_param_clause using_clause returning_clause
 
-%type <range>  into_clause OptTempTableName
+%type <range>  OptTempTableName
+%type <into>   into_clause create_as_target
 
 %type <defelt> createfunc_opt_item common_func_opt_item
 %type <fun_param> func_arg
@@ -2253,8 +2255,7 @@ OptConsTableSpace:   USING INDEX TABLESPACE name  { $$ = $4; }
  */
 
 CreateAsStmt:
-               CREATE OptTemp TABLE qualified_name OptCreateAs
-                       OptWith OnCommitOption OptTableSpace AS SelectStmt
+               CREATE OptTemp TABLE create_as_target AS SelectStmt
                                {
                                        /*
                                         * When the SelectStmt is a set-operation tree, we must
@@ -2263,18 +2264,26 @@ CreateAsStmt:
                                         * to find it.  Similarly, the output column names must
                                         * be attached to that Select's target list.
                                         */
-                                       SelectStmt *n = findLeftmostSelect((SelectStmt *) $10);
+                                       SelectStmt *n = findLeftmostSelect((SelectStmt *) $6);
                                        if (n->into != NULL)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_SYNTAX_ERROR),
                                                                 errmsg("CREATE TABLE AS cannot specify INTO")));
-                                       $4->istemp = $2;
+                                       $4->rel->istemp = $2;
                                        n->into = $4;
-                                       n->intoColNames = $5;
-                                       n->intoOptions = $6;
-                                       n->intoOnCommit = $7;
-                                       n->intoTableSpaceName = $8;
-                                       $$ = $10;
+                                       $$ = $6;
+                               }
+               ;
+
+create_as_target:
+                       qualified_name OptCreateAs OptWith OnCommitOption OptTableSpace
+                               {
+                                       $$ = makeNode(IntoClause);
+                                       $$->rel = $1;
+                                       $$->colNames = $2;
+                                       $$->options = $3;
+                                       $$->onCommit = $4;
+                                       $$->tableSpaceName = $5;
                                }
                ;
 
@@ -5459,19 +5468,15 @@ ExecuteStmt: EXECUTE name execute_param_clause
                                        n->into = NULL;
                                        $$ = (Node *) n;
                                }
-                       | CREATE OptTemp TABLE qualified_name OptCreateAs
-                               OptWith OnCommitOption OptTableSpace AS
+                       | CREATE OptTemp TABLE create_as_target AS
                                EXECUTE name execute_param_clause
                                {
                                        ExecuteStmt *n = makeNode(ExecuteStmt);
-                                       n->name = $11;
-                                       n->params = $12;
-                                       $4->istemp = $2;
+                                       n->name = $7;
+                                       n->params = $8;
+                                       $4->rel->istemp = $2;
                                        n->into = $4;
-                                       n->intoOptions = $6;
-                                       n->into_on_commit = $7;
-                                       n->into_tbl_space = $8;
-                                       if ($5)
+                                       if ($4->colNames)
                                                ereport(ERROR,
                                                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
                                                                 errmsg("column name list not allowed in CREATE TABLE / AS EXECUTE")));
@@ -5854,7 +5859,6 @@ simple_select:
                                        n->distinctClause = $2;
                                        n->targetList = $3;
                                        n->into = $4;
-                                       n->intoColNames = NIL;
                                        n->fromClause = $5;
                                        n->whereClause = $6;
                                        n->groupClause = $7;
@@ -5877,8 +5881,17 @@ simple_select:
                ;
 
 into_clause:
-                       INTO OptTempTableName                                   { $$ = $2; }
-                       | /*EMPTY*/                                                             { $$ = NULL; }
+                       INTO OptTempTableName
+                               {
+                                       $$ = makeNode(IntoClause);
+                                       $$->rel = $2;
+                                       $$->colNames = NIL;
+                                       $$->options = NIL;
+                                       $$->onCommit = ONCOMMIT_NOOP;
+                                       $$->tableSpaceName = NULL;
+                               }
+                       | /*EMPTY*/
+                               { $$ = NULL; }
                ;
 
 /*
index f00897ee6222e0a4c2353638acbd9ccc5d614bbb..1c40a8752e953e34e2f23924b679676ebf4bbacf 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.524 2007/02/17 19:33:32 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.525 2007/02/20 17:32:16 tgl Exp $
  *
  * NOTES
  *       this is the "main" module of the postgres backend and
@@ -165,8 +165,7 @@ static int  InteractiveBackend(StringInfo inBuf);
 static int     SocketBackend(StringInfo inBuf);
 static int     ReadCommand(StringInfo inBuf);
 static List *pg_rewrite_queries(List *querytree_list);
-static bool check_log_statement_raw(List *raw_parsetree_list);
-static bool check_log_statement_cooked(List *parsetree_list);
+static bool check_log_statement(List *stmt_list);
 static int     errdetail_execute(List *raw_parsetree_list);
 static int     errdetail_params(ParamListInfo params);
 static void start_xact_command(void);
@@ -659,10 +658,10 @@ pg_rewrite_queries(List *querytree_list)
 
 
 /* Generate a plan for a single already-rewritten query. */
-Plan *
+PlannedStmt *
 pg_plan_query(Query *querytree, ParamListInfo boundParams)
 {
-       Plan       *plan;
+       PlannedStmt *plan;
 
        /* Utility commands have no plans. */
        if (querytree->commandType == CMD_UTILITY)
@@ -680,7 +679,7 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams)
 #ifdef COPY_PARSE_PLAN_TREES
        /* Optional debugging check: pass plan output through copyObject() */
        {
-               Plan       *new_plan = (Plan *) copyObject(plan);
+               PlannedStmt *new_plan = (PlannedStmt *) copyObject(plan);
 
                /*
                 * equal() currently does not have routines to compare Plan nodes, so
@@ -715,23 +714,26 @@ pg_plan_query(Query *querytree, ParamListInfo boundParams)
  * utility statements depend on not having frozen the snapshot yet.
  * (We assume that such statements cannot appear together with plannable
  * statements in the rewriter's output.)
+ *
+ * Normal optimizable statements generate PlannedStmt entries in the result
+ * list.  Utility statements are simply represented by their statement nodes.
  */
 List *
 pg_plan_queries(List *querytrees, ParamListInfo boundParams,
                                bool needSnapshot)
 {
-       List       *plan_list = NIL;
+       List       *stmt_list = NIL;
        ListCell   *query_list;
 
        foreach(query_list, querytrees)
        {
                Query      *query = (Query *) lfirst(query_list);
-               Plan       *plan;
+               Node       *stmt;
 
                if (query->commandType == CMD_UTILITY)
                {
                        /* Utility commands have no plans. */
-                       plan = NULL;
+                       stmt = query->utilityStmt;
                }
                else
                {
@@ -740,13 +742,13 @@ pg_plan_queries(List *querytrees, ParamListInfo boundParams,
                                ActiveSnapshot = CopySnapshot(GetTransactionSnapshot());
                                needSnapshot = false;
                        }
-                       plan = pg_plan_query(query, boundParams);
+                       stmt = (Node *) pg_plan_query(query, boundParams);
                }
 
-               plan_list = lappend(plan_list, plan);
+               stmt_list = lappend(stmt_list, stmt);
        }
 
-       return plan_list;
+       return stmt_list;
 }
 
 
@@ -817,7 +819,7 @@ exec_simple_query(const char *query_string)
        parsetree_list = pg_parse_query(query_string);
 
        /* Log immediately if dictated by log_statement */
-       if (check_log_statement_raw(parsetree_list))
+       if (check_log_statement(parsetree_list))
        {
                ereport(LOG,
                                (errmsg("statement: %s", query_string),
@@ -905,7 +907,6 @@ exec_simple_query(const char *query_string)
                                                  NULL,
                                                  query_string,
                                                  commandTag,
-                                                 querytree_list,
                                                  plantree_list,
                                                  MessageContext);
 
@@ -1050,9 +1051,10 @@ exec_parse_message(const char *query_string,     /* string to execute */
        List       *parsetree_list;
        const char *commandTag;
        List       *querytree_list,
-                          *plantree_list,
+                          *stmt_list,
                           *param_list;
        bool            is_named;
+       bool            fully_planned;
        bool            save_log_statement_stats = log_statement_stats;
        char            msec_str[32];
 
@@ -1202,17 +1204,23 @@ exec_parse_message(const char *query_string,    /* string to execute */
                 * planning until Bind.  Otherwise do it now.
                 */
                if (!is_named && numParams > 0)
-                       plantree_list = NIL;
+               {
+                       stmt_list = querytree_list;
+                       fully_planned = false;
+               }
                else
-                       plantree_list = pg_plan_queries(querytree_list, NULL, true);
+               {
+                       stmt_list = pg_plan_queries(querytree_list, NULL, true);
+                       fully_planned = true;
+               }
        }
        else
        {
                /* Empty input string.  This is legal. */
                commandTag = NULL;
-               querytree_list = NIL;
-               plantree_list = NIL;
+               stmt_list = NIL;
                param_list = NIL;
+               fully_planned = true;
        }
 
        /* If we got a cancel signal in analysis or planning, quit */
@@ -1226,9 +1234,9 @@ exec_parse_message(const char *query_string,      /* string to execute */
                StorePreparedStatement(stmt_name,
                                                           query_string,
                                                           commandTag,
-                                                          querytree_list,
-                                                          plantree_list,
+                                                          stmt_list,
                                                           param_list,
+                                                          fully_planned,
                                                           false);
        }
        else
@@ -1240,9 +1248,9 @@ exec_parse_message(const char *query_string,      /* string to execute */
                pstmt->query_string = pstrdup(query_string);
                /* the rest is there already */
                pstmt->commandTag = commandTag;
-               pstmt->query_list = querytree_list;
-               pstmt->plan_list = plantree_list;
+               pstmt->stmt_list = stmt_list;
                pstmt->argtype_list = param_list;
+               pstmt->fully_planned = fully_planned;
                pstmt->from_sql = false;
                pstmt->context = unnamed_stmt_context;
                /* Now the unnamed statement is complete and valid */
@@ -1393,7 +1401,7 @@ exec_bind_message(StringInfo input_message)
         * functions.
         */
        if (IsAbortedTransactionBlockState() &&
-               (!IsTransactionExitStmtList(pstmt->query_list) ||
+               (!IsTransactionExitStmtList(pstmt->stmt_list) ||
                 numParams != 0))
                ereport(ERROR,
                                (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
@@ -1581,22 +1589,21 @@ exec_bind_message(StringInfo input_message)
         * portal's queryContext becomes its own heap context rather than the
         * prepared statement's context.  FIXME someday
         */
-       if (pstmt->plan_list == NIL && pstmt->query_list != NIL)
+       if (pstmt->fully_planned)
+       {
+               plan_list = pstmt->stmt_list;
+               qContext = pstmt->context;
+       }
+       else
        {
                MemoryContext oldContext;
 
                qContext = PortalGetHeapMemory(portal);
                oldContext = MemoryContextSwitchTo(qContext);
-               query_list = copyObject(pstmt->query_list);
+               query_list = copyObject(pstmt->stmt_list);
                plan_list = pg_plan_queries(query_list, params, true);
                MemoryContextSwitchTo(oldContext);
        }
-       else
-       {
-               query_list = pstmt->query_list;
-               plan_list = pstmt->plan_list;
-               qContext = pstmt->context;
-       }
 
        /*
         * Define portal and start execution.
@@ -1605,7 +1612,6 @@ exec_bind_message(StringInfo input_message)
                                          *pstmt->stmt_name ? pstmt->stmt_name : NULL,
                                          pstmt->query_string,
                                          pstmt->commandTag,
-                                         query_list,
                                          plan_list,
                                          qContext);
 
@@ -1688,13 +1694,13 @@ exec_execute_message(const char *portal_name, long max_rows)
         */
        if (portal->commandTag == NULL)
        {
-               Assert(portal->parseTrees == NIL);
+               Assert(portal->stmts == NIL);
                NullCommand(dest);
                return;
        }
 
        /* Does the portal contain a transaction command? */
-       is_xact_command = IsTransactionStmtList(portal->parseTrees);
+       is_xact_command = IsTransactionStmtList(portal->stmts);
 
        /*
         * We must copy the sourceText and prepStmtName into MessageContext in
@@ -1760,7 +1766,7 @@ exec_execute_message(const char *portal_name, long max_rows)
        execute_is_fetch = !portal->atStart;
 
        /* Log immediately if dictated by log_statement */
-       if (check_log_statement_cooked(portal->parseTrees))
+       if (check_log_statement(portal->stmts))
        {
                ereport(LOG,
                                (errmsg("%s %s%s%s%s%s",
@@ -1781,7 +1787,7 @@ exec_execute_message(const char *portal_name, long max_rows)
         * actually run are those containing COMMIT or ROLLBACK commands.
         */
        if (IsAbortedTransactionBlockState() &&
-               !IsTransactionExitStmtList(portal->parseTrees))
+               !IsTransactionExitStmtList(portal->stmts))
                ereport(ERROR,
                                (errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
                                 errmsg("current transaction is aborted, "
@@ -1865,15 +1871,16 @@ exec_execute_message(const char *portal_name, long max_rows)
 }
 
 /*
- * check_log_statement_raw
+ * check_log_statement
  *             Determine whether command should be logged because of log_statement
  *
- * raw_parsetree_list is the raw grammar output
+ * parsetree_list can be either raw grammar output or a list of planned
+ * statements
  */
 static bool
-check_log_statement_raw(List *raw_parsetree_list)
+check_log_statement(List *stmt_list)
 {
-       ListCell   *parsetree_item;
+       ListCell   *stmt_item;
 
        if (log_statement == LOGSTMT_NONE)
                return false;
@@ -1881,37 +1888,11 @@ check_log_statement_raw(List *raw_parsetree_list)
                return true;
 
        /* Else we have to inspect the statement(s) to see whether to log */
-       foreach(parsetree_item, raw_parsetree_list)
+       foreach(stmt_item, stmt_list)
        {
-               Node       *parsetree = (Node *) lfirst(parsetree_item);
+               Node       *stmt = (Node *) lfirst(stmt_item);
 
-               if (GetCommandLogLevel(parsetree) <= log_statement)
-                       return true;
-       }
-
-       return false;
-}
-
-/*
- * check_log_statement_cooked
- *             As above, but work from already-analyzed querytrees
- */
-static bool
-check_log_statement_cooked(List *parsetree_list)
-{
-       ListCell   *parsetree_item;
-
-       if (log_statement == LOGSTMT_NONE)
-               return false;
-       if (log_statement == LOGSTMT_ALL)
-               return true;
-
-       /* Else we have to inspect the statement(s) to see whether to log */
-       foreach(parsetree_item, parsetree_list)
-       {
-               Query      *parsetree = (Query *) lfirst(parsetree_item);
-
-               if (GetQueryLogLevel(parsetree) <= log_statement)
+               if (GetCommandLogLevel(stmt) <= log_statement)
                        return true;
        }
 
@@ -2259,6 +2240,7 @@ finish_xact_command(void)
  * ones that we allow in transaction-aborted state.
  */
 
+/* Test a bare parsetree */
 static bool
 IsTransactionExitStmt(Node *parsetree)
 {
@@ -2275,29 +2257,45 @@ IsTransactionExitStmt(Node *parsetree)
        return false;
 }
 
+/* Test a list that might contain Query nodes or bare parsetrees */
 static bool
 IsTransactionExitStmtList(List *parseTrees)
 {
        if (list_length(parseTrees) == 1)
        {
-               Query      *query = (Query *) linitial(parseTrees);
+               Node       *stmt = (Node *) linitial(parseTrees);
+
+               if (IsA(stmt, Query))
+               {
+                       Query      *query = (Query *) stmt;
 
-               if (query->commandType == CMD_UTILITY &&
-                       IsTransactionExitStmt(query->utilityStmt))
+                       if (query->commandType == CMD_UTILITY &&
+                               IsTransactionExitStmt(query->utilityStmt))
+                               return true;
+               }
+               else if (IsTransactionExitStmt(stmt))
                        return true;
        }
        return false;
 }
 
+/* Test a list that might contain Query nodes or bare parsetrees */
 static bool
 IsTransactionStmtList(List *parseTrees)
 {
        if (list_length(parseTrees) == 1)
        {
-               Query      *query = (Query *) linitial(parseTrees);
+               Node       *stmt = (Node *) linitial(parseTrees);
 
-               if (query->commandType == CMD_UTILITY &&
-                       query->utilityStmt && IsA(query->utilityStmt, TransactionStmt))
+               if (IsA(stmt, Query))
+               {
+                       Query      *query = (Query *) stmt;
+
+                       if (query->commandType == CMD_UTILITY &&
+                               IsA(query->utilityStmt, TransactionStmt))
+                               return true;
+               }
+               else if (IsA(stmt, TransactionStmt))
                        return true;
        }
        return false;
index f6f157e0cbbcdb30b42861e4e67c132767ac919e..97a003ac89da9246ea909589f3488cae748fdc61 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.113 2007/02/18 19:49:25 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.114 2007/02/20 17:32:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -32,8 +32,7 @@
 Portal         ActivePortal = NULL;
 
 
-static void ProcessQuery(Query *parsetree,
-                        Plan *plan,
+static void ProcessQuery(PlannedStmt *plan,
                         ParamListInfo params,
                         DestReceiver *dest,
                         char *completionTag);
@@ -42,7 +41,7 @@ static uint32 RunFromStore(Portal portal, ScanDirection direction, long count,
                         DestReceiver *dest);
 static long PortalRunSelect(Portal portal, bool forward, long count,
                                DestReceiver *dest);
-static void PortalRunUtility(Portal portal, Query *query,
+static void PortalRunUtility(Portal portal, Node *utilityStmt,
                                 DestReceiver *dest, char *completionTag);
 static void PortalRunMulti(Portal portal,
                           DestReceiver *dest, DestReceiver *altdest,
@@ -58,8 +57,7 @@ static void DoPortalRewind(Portal portal);
  * CreateQueryDesc
  */
 QueryDesc *
-CreateQueryDesc(Query *parsetree,
-                               Plan *plantree,
+CreateQueryDesc(PlannedStmt *plannedstmt,
                                Snapshot snapshot,
                                Snapshot crosscheck_snapshot,
                                DestReceiver *dest,
@@ -68,10 +66,10 @@ CreateQueryDesc(Query *parsetree,
 {
        QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
 
-       qd->operation = parsetree->commandType;         /* operation */
-       qd->parsetree = parsetree;      /* parse tree */
-       qd->plantree = plantree;        /* plan */
-       qd->snapshot = snapshot;        /* snapshot */
+       qd->operation = plannedstmt->commandType;       /* operation */
+       qd->plannedstmt = plannedstmt;                          /* plan */
+       qd->utilitystmt = NULL;
+       qd->snapshot = snapshot;                                        /* snapshot */
        qd->crosscheck_snapshot = crosscheck_snapshot;          /* RI check snapshot */
        qd->dest = dest;                        /* output dest */
        qd->params = params;            /* parameter values passed into query */
@@ -85,6 +83,34 @@ CreateQueryDesc(Query *parsetree,
        return qd;
 }
 
+/*
+ * CreateUtilityQueryDesc
+ */
+QueryDesc *
+CreateUtilityQueryDesc(Node *utilitystmt,
+                                          Snapshot snapshot,
+                                          DestReceiver *dest,
+                                          ParamListInfo params)
+{
+       QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
+
+       qd->operation = CMD_UTILITY;                            /* operation */
+       qd->plannedstmt = NULL;
+       qd->utilitystmt = utilitystmt;                          /* utility command */
+       qd->snapshot = snapshot;                                        /* snapshot */
+       qd->crosscheck_snapshot = InvalidSnapshot;      /* RI check snapshot */
+       qd->dest = dest;                        /* output dest */
+       qd->params = params;            /* parameter values passed into query */
+       qd->doInstrument = false;       /* uninteresting for utilities */
+
+       /* null these fields until set by ExecutorStart */
+       qd->tupDesc = NULL;
+       qd->estate = NULL;
+       qd->planstate = NULL;
+
+       return qd;
+}
+
 /*
  * FreeQueryDesc
  */
@@ -103,7 +129,6 @@ FreeQueryDesc(QueryDesc *qdesc)
  *             Execute a single plannable query within a PORTAL_MULTI_QUERY
  *             or PORTAL_ONE_RETURNING portal
  *
- *     parsetree: the query tree
  *     plan: the plan tree for the query
  *     params: any parameters needed
  *     dest: where to send results
@@ -116,13 +141,11 @@ FreeQueryDesc(QueryDesc *qdesc)
  * error; otherwise the executor's memory usage will be leaked.
  */
 static void
-ProcessQuery(Query *parsetree,
-                        Plan *plan,
+ProcessQuery(PlannedStmt *plan,
                         ParamListInfo params,
                         DestReceiver *dest,
                         char *completionTag)
 {
-       int                     operation = parsetree->commandType;
        QueryDesc  *queryDesc;
 
        ereport(DEBUG3,
@@ -137,7 +160,7 @@ ProcessQuery(Query *parsetree,
        /*
         * Create the QueryDesc object
         */
-       queryDesc = CreateQueryDesc(parsetree, plan,
+       queryDesc = CreateQueryDesc(plan,
                                                                ActiveSnapshot, InvalidSnapshot,
                                                                dest, params, false);
 
@@ -163,7 +186,7 @@ ProcessQuery(Query *parsetree,
        {
                Oid                     lastOid;
 
-               switch (operation)
+               switch (queryDesc->operation)
                {
                        case CMD_SELECT:
                                strcpy(completionTag, "SELECT");
@@ -206,40 +229,67 @@ ProcessQuery(Query *parsetree,
 
 /*
  * ChoosePortalStrategy
- *             Select portal execution strategy given the intended query list.
+ *             Select portal execution strategy given the intended statement list.
+ *
+ * The list elements can be Querys, PlannedStmts, or utility statements.
+ * That's more general than portals need, but we use this for prepared
+ * statements as well.
  *
  * See the comments in portal.h.
  */
 PortalStrategy
-ChoosePortalStrategy(List *parseTrees)
+ChoosePortalStrategy(List *stmts)
 {
        int                     nSetTag;
        ListCell   *lc;
 
        /*
         * PORTAL_ONE_SELECT and PORTAL_UTIL_SELECT need only consider the
-        * single-Query-struct case, since there are no rewrite rules that can add
+        * single-statement case, since there are no rewrite rules that can add
         * auxiliary queries to a SELECT or a utility command.
         */
-       if (list_length(parseTrees) == 1)
+       if (list_length(stmts) == 1)
        {
-               Query      *query = (Query *) linitial(parseTrees);
+               Node       *stmt = (Node *) linitial(stmts);
 
-               Assert(IsA(query, Query));
-               if (query->canSetTag)
+               if (IsA(stmt, Query))
                {
-                       if (query->commandType == CMD_SELECT &&
-                               query->into == NULL)
-                               return PORTAL_ONE_SELECT;
-                       if (query->commandType == CMD_UTILITY &&
-                               query->utilityStmt != NULL)
+                       Query      *query = (Query *) stmt;
+
+                       if (query->canSetTag)
                        {
-                               if (UtilityReturnsTuples(query->utilityStmt))
-                                       return PORTAL_UTIL_SELECT;
-                               /* it can't be ONE_RETURNING, so give up */
-                               return PORTAL_MULTI_QUERY;
+                               if (query->commandType == CMD_SELECT &&
+                                       query->into == NULL)
+                                       return PORTAL_ONE_SELECT;
+                               if (query->commandType == CMD_UTILITY &&
+                                       query->utilityStmt != NULL)
+                               {
+                                       if (UtilityReturnsTuples(query->utilityStmt))
+                                               return PORTAL_UTIL_SELECT;
+                                       /* it can't be ONE_RETURNING, so give up */
+                                       return PORTAL_MULTI_QUERY;
+                               }
                        }
                }
+               else if (IsA(stmt, PlannedStmt))
+               {
+                       PlannedStmt *pstmt = (PlannedStmt *) stmt;
+
+                       if (pstmt->canSetTag)
+                       {
+                               if (pstmt->commandType == CMD_SELECT &&
+                                       pstmt->into == NULL)
+                                       return PORTAL_ONE_SELECT;
+                       }
+               }
+               else
+               {
+                       /* must be a utility command; assume it's canSetTag */
+                       if (UtilityReturnsTuples(stmt))
+                               return PORTAL_UTIL_SELECT;
+                       /* it can't be ONE_RETURNING, so give up */
+                       return PORTAL_MULTI_QUERY;
+               }
        }
 
        /*
@@ -248,18 +298,35 @@ ChoosePortalStrategy(List *parseTrees)
         * it has a RETURNING list.
         */
        nSetTag = 0;
-       foreach(lc, parseTrees)
+       foreach(lc, stmts)
        {
-               Query      *query = (Query *) lfirst(lc);
+               Node       *stmt = (Node *) lfirst(lc);
 
-               Assert(IsA(query, Query));
-               if (query->canSetTag)
+               if (IsA(stmt, Query))
                {
-                       if (++nSetTag > 1)
-                               return PORTAL_MULTI_QUERY;              /* no need to look further */
-                       if (query->returningList == NIL)
-                               return PORTAL_MULTI_QUERY;              /* no need to look further */
+                       Query      *query = (Query *) stmt;
+
+                       if (query->canSetTag)
+                       {
+                               if (++nSetTag > 1)
+                                       return PORTAL_MULTI_QUERY;      /* no need to look further */
+                               if (query->returningList == NIL)
+                                       return PORTAL_MULTI_QUERY;      /* no need to look further */
+                       }
                }
+               else if (IsA(stmt, PlannedStmt))
+               {
+                       PlannedStmt *pstmt = (PlannedStmt *) stmt;
+
+                       if (pstmt->canSetTag)
+                       {
+                               if (++nSetTag > 1)
+                                       return PORTAL_MULTI_QUERY;      /* no need to look further */
+                               if (pstmt->returningLists == NIL)
+                                       return PORTAL_MULTI_QUERY;      /* no need to look further */
+                       }
+               }
+               /* otherwise, utility command, assumed not canSetTag */
        }
        if (nSetTag == 1)
                return PORTAL_ONE_RETURNING;
@@ -274,48 +341,84 @@ ChoosePortalStrategy(List *parseTrees)
  *             Returns NIL if the portal doesn't have a determinable targetlist.
  *
  * Note: do not modify the result.
- *
- * XXX be careful to keep this in sync with FetchPreparedStatementTargetList,
- * and with UtilityReturnsTuples.
  */
 List *
 FetchPortalTargetList(Portal portal)
 {
-       if (portal->strategy == PORTAL_ONE_SELECT)
-               return ((Query *) linitial(portal->parseTrees))->targetList;
-       if (portal->strategy == PORTAL_ONE_RETURNING)
-               return (PortalGetPrimaryQuery(portal))->returningList;
-       if (portal->strategy == PORTAL_UTIL_SELECT)
+       /* no point in looking if we determined it doesn't return tuples */
+       if (portal->strategy == PORTAL_MULTI_QUERY)
+               return NIL;
+       /* get the primary statement and find out what it returns */
+       return FetchStatementTargetList(PortalGetPrimaryStmt(portal));
+}
+
+/*
+ * FetchStatementTargetList
+ *             Given a statement that returns tuples, extract the query targetlist.
+ *             Returns NIL if the statement doesn't have a determinable targetlist.
+ *
+ * This can be applied to a Query, a PlannedStmt, or a utility statement.
+ * That's more general than portals need, but we use this for prepared
+ * statements as well.
+ *
+ * Note: do not modify the result.
+ *
+ * XXX be careful to keep this in sync with UtilityReturnsTuples.
+ */
+List *
+FetchStatementTargetList(Node *stmt)
+{
+       if (stmt == NULL)
+               return NIL;
+       if (IsA(stmt, Query))
        {
-               Node       *utilityStmt;
+               Query      *query = (Query *) stmt;
 
-               utilityStmt = ((Query *) linitial(portal->parseTrees))->utilityStmt;
-               switch (nodeTag(utilityStmt))
+               if (query->commandType == CMD_UTILITY &&
+                       query->utilityStmt != NULL)
                {
-                       case T_FetchStmt:
-                               {
-                                       FetchStmt  *substmt = (FetchStmt *) utilityStmt;
-                                       Portal          subportal;
-
-                                       Assert(!substmt->ismove);
-                                       subportal = GetPortalByName(substmt->portalname);
-                                       Assert(PortalIsValid(subportal));
-                                       return FetchPortalTargetList(subportal);
-                               }
-
-                       case T_ExecuteStmt:
-                               {
-                                       ExecuteStmt *substmt = (ExecuteStmt *) utilityStmt;
-                                       PreparedStatement *entry;
+                       /* transfer attention to utility statement */
+                       stmt = query->utilityStmt;
+               }
+               else
+               {
+                       if (query->commandType == CMD_SELECT &&
+                               query->into == NULL)
+                               return query->targetList;
+                       if (query->returningList)
+                               return query->returningList;
+                       return NIL;
+               }
+       }
+       if (IsA(stmt, PlannedStmt))
+       {
+               PlannedStmt *pstmt = (PlannedStmt *) stmt;
+
+               if (pstmt->commandType == CMD_SELECT &&
+                       pstmt->into == NULL)
+                       return pstmt->planTree->targetlist;
+               if (pstmt->returningLists)
+                       return (List *) linitial(pstmt->returningLists);
+               return NIL;
+       }
+       if (IsA(stmt, FetchStmt))
+       {
+               FetchStmt  *fstmt = (FetchStmt *) stmt;
+               Portal          subportal;
 
-                                       Assert(!substmt->into);
-                                       entry = FetchPreparedStatement(substmt->name, true);
-                                       return FetchPreparedStatementTargetList(entry);
-                               }
+               Assert(!fstmt->ismove);
+               subportal = GetPortalByName(fstmt->portalname);
+               Assert(PortalIsValid(subportal));
+               return FetchPortalTargetList(subportal);
+       }
+       if (IsA(stmt, ExecuteStmt))
+       {
+               ExecuteStmt *estmt = (ExecuteStmt *) stmt;
+               PreparedStatement *entry;
 
-                       default:
-                               break;
-               }
+               Assert(!estmt->into);
+               entry = FetchPreparedStatement(estmt->name, true);
+               return FetchPreparedStatementTargetList(entry);
        }
        return NIL;
 }
@@ -374,7 +477,7 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
                /*
                 * Determine the portal execution strategy
                 */
-               portal->strategy = ChoosePortalStrategy(portal->parseTrees);
+               portal->strategy = ChoosePortalStrategy(portal->stmts);
 
                /*
                 * Fire her up according to the strategy
@@ -396,8 +499,7 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
                                 * Create QueryDesc in portal's context; for the moment, set
                                 * the destination to DestNone.
                                 */
-                               queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees),
-                                                                               (Plan *) linitial(portal->planTrees),
+                               queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts),
                                                                                        ActiveSnapshot,
                                                                                        InvalidSnapshot,
                                                                                        None_Receiver,
@@ -450,8 +552,16 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
                                 * We don't start the executor until we are told to run the
                                 * portal.      We do need to set up the result tupdesc.
                                 */
-                               portal->tupDesc =
-                                       ExecCleanTypeFromTL((PortalGetPrimaryQuery(portal))->returningList, false);
+                               {
+                                       PlannedStmt *pstmt;
+
+                                       pstmt = (PlannedStmt *) PortalGetPrimaryStmt(portal);
+                                       Assert(IsA(pstmt, PlannedStmt));
+                                       Assert(pstmt->returningLists);
+                                       portal->tupDesc =
+                                               ExecCleanTypeFromTL((List *) linitial(pstmt->returningLists),
+                                                                                       false);
+                               }
 
                                /*
                                 * Reset cursor position data to "start of query"
@@ -468,8 +578,12 @@ PortalStart(Portal portal, ParamListInfo params, Snapshot snapshot)
                                 * We don't set snapshot here, because PortalRunUtility will
                                 * take care of it if needed.
                                 */
-                               portal->tupDesc =
-                                       UtilityTupleDescriptor(((Query *) linitial(portal->parseTrees))->utilityStmt);
+                               {
+                                       Node *ustmt = PortalGetPrimaryStmt(portal);
+
+                                       Assert(!IsA(ustmt, PlannedStmt));
+                                       portal->tupDesc = UtilityTupleDescriptor(ustmt);
+                               }
 
                                /*
                                 * Reset cursor position data to "start of query"
@@ -934,7 +1048,7 @@ FillPortalStore(Portal portal)
                        break;
 
                case PORTAL_UTIL_SELECT:
-                       PortalRunUtility(portal, linitial(portal->parseTrees),
+                       PortalRunUtility(portal, (Node *) linitial(portal->stmts),
                                                         treceiver, completionTag);
                        break;
 
@@ -1023,11 +1137,9 @@ RunFromStore(Portal portal, ScanDirection direction, long count,
  *             Execute a utility statement inside a portal.
  */
 static void
-PortalRunUtility(Portal portal, Query *query,
+PortalRunUtility(Portal portal, Node *utilityStmt,
                                 DestReceiver *dest, char *completionTag)
 {
-       Node       *utilityStmt = query->utilityStmt;
-
        ereport(DEBUG3,
                        (errmsg_internal("ProcessUtility")));
 
@@ -1061,18 +1173,7 @@ PortalRunUtility(Portal portal, Query *query,
        else
                ActiveSnapshot = NULL;
 
-       if (query->canSetTag)
-       {
-               /* utility statement can override default tag string */
-               ProcessUtility(utilityStmt, portal->portalParams, dest, completionTag);
-               if (completionTag && completionTag[0] == '\0' && portal->commandTag)
-                       strcpy(completionTag, portal->commandTag);      /* use the default */
-       }
-       else
-       {
-               /* utility added by rewrite cannot set tag */
-               ProcessUtility(utilityStmt, portal->portalParams, dest, NULL);
-       }
+       ProcessUtility(utilityStmt, portal->portalParams, dest, completionTag);
 
        /* Some utility statements may change context on us */
        MemoryContextSwitchTo(PortalGetHeapMemory(portal));
@@ -1092,8 +1193,7 @@ PortalRunMulti(Portal portal,
                           DestReceiver *dest, DestReceiver *altdest,
                           char *completionTag)
 {
-       ListCell   *querylist_item;
-       ListCell   *planlist_item;
+       ListCell   *stmtlist_item;
 
        /*
         * If the destination is DestRemoteExecute, change to DestNone.  The
@@ -1114,47 +1214,36 @@ PortalRunMulti(Portal portal,
         * Loop to handle the individual queries generated from a single parsetree
         * by analysis and rewrite.
         */
-       forboth(querylist_item, portal->parseTrees,
-                       planlist_item, portal->planTrees)
+       foreach(stmtlist_item, portal->stmts)
        {
-               Query      *query = (Query *) lfirst(querylist_item);
-               Plan       *plan = (Plan *) lfirst(planlist_item);
+               Node   *stmt = (Node *) lfirst(stmtlist_item);
 
                /*
                 * If we got a cancel signal in prior command, quit
                 */
                CHECK_FOR_INTERRUPTS();
 
-               if (query->commandType == CMD_UTILITY)
-               {
-                       /*
-                        * process utility functions (create, destroy, etc..)
-                        */
-                       Assert(plan == NULL);
-
-                       PortalRunUtility(portal, query,
-                                                        query->canSetTag ? dest : altdest,
-                                                        completionTag);
-               }
-               else
+               if (IsA(stmt, PlannedStmt))
                {
                        /*
                         * process a plannable query.
                         */
+                       PlannedStmt *pstmt = (PlannedStmt *) stmt;
+
                        if (log_executor_stats)
                                ResetUsage();
 
-                       if (query->canSetTag)
+                       if (pstmt->canSetTag)
                        {
                                /* statement can set tag string */
-                               ProcessQuery(query, plan,
+                               ProcessQuery(pstmt,
                                                         portal->portalParams,
                                                         dest, completionTag);
                        }
                        else
                        {
                                /* stmt added by rewrite cannot set tag */
-                               ProcessQuery(query, plan,
+                               ProcessQuery(pstmt,
                                                         portal->portalParams,
                                                         altdest, NULL);
                        }
@@ -1162,12 +1251,25 @@ PortalRunMulti(Portal portal,
                        if (log_executor_stats)
                                ShowUsage("EXECUTOR STATISTICS");
                }
+               else
+               {
+                       /*
+                        * process utility functions (create, destroy, etc..)
+                        *
+                        * These are assumed canSetTag if they're the only stmt in the
+                        * portal.
+                        */
+                       if (list_length(portal->stmts) == 1)
+                               PortalRunUtility(portal, stmt, dest, completionTag);
+                       else
+                               PortalRunUtility(portal, stmt, altdest, NULL);
+               }
 
                /*
                 * Increment command counter between queries, but not after the last
                 * one.
                 */
-               if (lnext(planlist_item) != NULL)
+               if (lnext(stmtlist_item) != NULL)
                        CommandCounterIncrement();
 
                /*
index 5cabec2970b27cb48ff43d500707f24e22109852..47051ad1ed2c9bb24794ac45f2bff2f6e07a0b6c 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.272 2007/02/14 01:58:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/tcop/utility.c,v 1.273 2007/02/20 17:32:16 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -248,36 +248,41 @@ CheckRelationOwnership(RangeVar *rel, bool noCatalogs)
 
 
 /*
- * QueryIsReadOnly: is an analyzed/rewritten query read-only?
+ * CommandIsReadOnly: is an executable query read-only?
  *
  * This is a much stricter test than we apply for XactReadOnly mode;
  * the query must be *in truth* read-only, because the caller wishes
  * not to do CommandCounterIncrement for it.
+ *
+ * Note: currently no need to support Query nodes here
  */
 bool
-QueryIsReadOnly(Query *parsetree)
+CommandIsReadOnly(Node *parsetree)
 {
-       switch (parsetree->commandType)
+       if (IsA(parsetree, PlannedStmt))
        {
-               case CMD_SELECT:
-                       if (parsetree->into != NULL)
-                               return false;   /* SELECT INTO */
-                       else if (parsetree->rowMarks != NIL)
-                               return false;   /* SELECT FOR UPDATE/SHARE */
-                       else
-                               return true;
-               case CMD_UPDATE:
-               case CMD_INSERT:
-               case CMD_DELETE:
-                       return false;
-               case CMD_UTILITY:
-                       /* For now, treat all utility commands as read/write */
-                       return false;
-               default:
-                       elog(WARNING, "unrecognized commandType: %d",
-                                (int) parsetree->commandType);
-                       break;
+               PlannedStmt *stmt = (PlannedStmt *) parsetree;
+
+               switch (stmt->commandType)
+               {
+                       case CMD_SELECT:
+                               if (stmt->into != NULL)
+                                       return false;   /* SELECT INTO */
+                               else if (stmt->rowMarks != NIL)
+                                       return false;   /* SELECT FOR UPDATE/SHARE */
+                               else
+                                       return true;
+                       case CMD_UPDATE:
+                       case CMD_INSERT:
+                       case CMD_DELETE:
+                               return false;
+                       default:
+                               elog(WARNING, "unrecognized commandType: %d",
+                                        (int) stmt->commandType);
+                               break;
+               }
        }
+       /* For now, treat all utility commands as read/write */
        return false;
 }
 
@@ -1161,7 +1166,7 @@ UtilityReturnsTuples(Node *parsetree)
                                entry = FetchPreparedStatement(stmt->name, false);
                                if (!entry)
                                        return false;           /* not our business to raise error */
-                               switch (ChoosePortalStrategy(entry->query_list))
+                               switch (ChoosePortalStrategy(entry->stmt_list))
                                {
                                        case PORTAL_ONE_SELECT:
                                        case PORTAL_ONE_RETURNING:
@@ -1244,6 +1249,7 @@ UtilityTupleDescriptor(Node *parsetree)
  * QueryReturnsTuples
  *             Return "true" if this Query will send output to the destination.
  */
+#ifdef NOT_USED
 bool
 QueryReturnsTuples(Query *parsetree)
 {
@@ -1270,14 +1276,15 @@ QueryReturnsTuples(Query *parsetree)
        }
        return false;                           /* default */
 }
+#endif
 
 
 /*
  * CreateCommandTag
- *             utility to get a string representation of the
- *             command operation, given a raw (un-analyzed) parsetree.
+ *             utility to get a string representation of the command operation,
+ *             given either a raw (un-analyzed) parsetree or a planned query.
  *
- * This must handle all raw command types, but since the vast majority
+ * This must handle all command types, but since the vast majority
  * of 'em are utility commands, it seems sensible to keep it here.
  *
  * NB: all result strings must be shorter than COMPLETION_TAG_BUFSIZE.
@@ -1290,6 +1297,7 @@ CreateCommandTag(Node *parsetree)
 
        switch (nodeTag(parsetree))
        {
+               /* raw plannable queries */
                case T_InsertStmt:
                        tag = "INSERT";
                        break;
@@ -1306,6 +1314,7 @@ CreateCommandTag(Node *parsetree)
                        tag = "SELECT";
                        break;
 
+               /* utility statements --- same whether raw or cooked */
                case T_TransactionStmt:
                        {
                                TransactionStmt *stmt = (TransactionStmt *) parsetree;
@@ -1826,65 +1835,98 @@ CreateCommandTag(Node *parsetree)
                        tag = "DEALLOCATE";
                        break;
 
-               default:
-                       elog(WARNING, "unrecognized node type: %d",
-                                (int) nodeTag(parsetree));
-                       tag = "???";
-                       break;
-       }
-
-       return tag;
-}
-
-/*
- * CreateQueryTag
- *             utility to get a string representation of a Query operation.
- *
- * This is exactly like CreateCommandTag, except it works on a Query
- * that has already been through parse analysis (and possibly further).
- */
-const char *
-CreateQueryTag(Query *parsetree)
-{
-       const char *tag;
-
-       Assert(IsA(parsetree, Query));
+               /* already-planned queries */
+               case T_PlannedStmt:
+                       {
+                               PlannedStmt *stmt = (PlannedStmt *) parsetree;
 
-       switch (parsetree->commandType)
-       {
-               case CMD_SELECT:
+                               switch (stmt->commandType)
+                               {
+                                       case CMD_SELECT:
+                                               /*
+                                                * We take a little extra care here so that the result
+                                                * will be useful for complaints about read-only
+                                                * statements
+                                                */
+                                               if (stmt->into != NULL)
+                                                       tag = "SELECT INTO";
+                                               else if (stmt->rowMarks != NIL)
+                                               {
+                                                       if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
+                                                               tag = "SELECT FOR UPDATE";
+                                                       else
+                                                               tag = "SELECT FOR SHARE";
+                                               }
+                                               else
+                                                       tag = "SELECT";
+                                               break;
+                                       case CMD_UPDATE:
+                                               tag = "UPDATE";
+                                               break;
+                                       case CMD_INSERT:
+                                               tag = "INSERT";
+                                               break;
+                                       case CMD_DELETE:
+                                               tag = "DELETE";
+                                               break;
+                                       default:
+                                               elog(WARNING, "unrecognized commandType: %d",
+                                                        (int) stmt->commandType);
+                                               tag = "???";
+                                               break;
+                               }
+                       }
+                       break;
 
-                       /*
-                        * We take a little extra care here so that the result will be
-                        * useful for complaints about read-only statements
-                        */
-                       if (parsetree->into != NULL)
-                               tag = "SELECT INTO";
-                       else if (parsetree->rowMarks != NIL)
+               /* parsed-and-rewritten-but-not-planned queries */
+               case T_Query:
                        {
-                               if (((RowMarkClause *) linitial(parsetree->rowMarks))->forUpdate)
-                                       tag = "SELECT FOR UPDATE";
-                               else
-                                       tag = "SELECT FOR SHARE";
+                               Query *stmt = (Query *) parsetree;
+
+                               switch (stmt->commandType)
+                               {
+                                       case CMD_SELECT:
+                                               /*
+                                                * We take a little extra care here so that the result
+                                                * will be useful for complaints about read-only
+                                                * statements
+                                                */
+                                               if (stmt->into != NULL)
+                                                       tag = "SELECT INTO";
+                                               else if (stmt->rowMarks != NIL)
+                                               {
+                                                       if (((RowMarkClause *) linitial(stmt->rowMarks))->forUpdate)
+                                                               tag = "SELECT FOR UPDATE";
+                                                       else
+                                                               tag = "SELECT FOR SHARE";
+                                               }
+                                               else
+                                                       tag = "SELECT";
+                                               break;
+                                       case CMD_UPDATE:
+                                               tag = "UPDATE";
+                                               break;
+                                       case CMD_INSERT:
+                                               tag = "INSERT";
+                                               break;
+                                       case CMD_DELETE:
+                                               tag = "DELETE";
+                                               break;
+                                       case CMD_UTILITY:
+                                               tag = CreateCommandTag(stmt->utilityStmt);
+                                               break;
+                                       default:
+                                               elog(WARNING, "unrecognized commandType: %d",
+                                                        (int) stmt->commandType);
+                                               tag = "???";
+                                               break;
+                               }
                        }
-                       else
-                               tag = "SELECT";
-                       break;
-               case CMD_UPDATE:
-                       tag = "UPDATE";
-                       break;
-               case CMD_INSERT:
-                       tag = "INSERT";
-                       break;
-               case CMD_DELETE:
-                       tag = "DELETE";
-                       break;
-               case CMD_UTILITY:
-                       tag = CreateCommandTag(parsetree->utilityStmt);
                        break;
+
                default:
-                       elog(WARNING, "unrecognized commandType: %d",
-                                (int) parsetree->commandType);
+                       elog(WARNING, "unrecognized node type: %d",
+                                (int) nodeTag(parsetree));
                        tag = "???";
                        break;
        }
@@ -1896,9 +1938,9 @@ CreateQueryTag(Query *parsetree)
 /*
  * GetCommandLogLevel
  *             utility to get the minimum log_statement level for a command,
- *             given a raw (un-analyzed) parsetree.
+ *             given either a raw (un-analyzed) parsetree or a planned query.
  *
- * This must handle all raw command types, but since the vast majority
+ * This must handle all command types, but since the vast majority
  * of 'em are utility commands, it seems sensible to keep it here.
  */
 LogStmtLevel
@@ -1908,6 +1950,7 @@ GetCommandLogLevel(Node *parsetree)
 
        switch (nodeTag(parsetree))
        {
+               /* raw plannable queries */
                case T_InsertStmt:
                case T_DeleteStmt:
                case T_UpdateStmt:
@@ -1921,6 +1964,7 @@ GetCommandLogLevel(Node *parsetree)
                                lev = LOGSTMT_ALL;
                        break;
 
+               /* utility statements --- same whether raw or cooked */
                case T_TransactionStmt:
                        lev = LOGSTMT_ALL;
                        break;
@@ -2216,12 +2260,12 @@ GetCommandLogLevel(Node *parsetree)
                                pstmt = FetchPreparedStatement(stmt->name, false);
                                if (pstmt)
                                {
-                                       foreach(l, pstmt->query_list)
+                                       foreach(l, pstmt->stmt_list)
                                        {
-                                               Query      *query = (Query *) lfirst(l);
+                                               Node       *substmt = (Node *) lfirst(l);
                                                LogStmtLevel stmt_lev;
 
-                                               stmt_lev = GetQueryLogLevel(query);
+                                               stmt_lev = GetCommandLogLevel(substmt);
                                                lev = Min(lev, stmt_lev);
                                        }
                                }
@@ -2232,62 +2276,72 @@ GetCommandLogLevel(Node *parsetree)
                        lev = LOGSTMT_ALL;
                        break;
 
-               case T_Query:
+               /* already-planned queries */
+               case T_PlannedStmt:
+                       {
+                               PlannedStmt *stmt = (PlannedStmt *) parsetree;
 
-                       /*
-                        * In complicated situations (eg, EXPLAIN ANALYZE in an extended
-                        * Query protocol), we might find an already-analyzed query within
-                        * a utility statement.  Cope.
-                        */
-                       lev = GetQueryLogLevel((Query *) parsetree);
-                       break;
+                               switch (stmt->commandType)
+                               {
+                                       case CMD_SELECT:
+                                               if (stmt->into != NULL)
+                                                       lev = LOGSTMT_DDL;      /* CREATE AS, SELECT INTO */
+                                               else
+                                                       lev = LOGSTMT_ALL;
+                                               break;
 
-               default:
-                       elog(WARNING, "unrecognized node type: %d",
-                                (int) nodeTag(parsetree));
-                       lev = LOGSTMT_ALL;
+                                       case CMD_UPDATE:
+                                       case CMD_INSERT:
+                                       case CMD_DELETE:
+                                               lev = LOGSTMT_MOD;
+                                               break;
+
+                                       default:
+                                               elog(WARNING, "unrecognized commandType: %d",
+                                                        (int) stmt->commandType);
+                                               lev = LOGSTMT_ALL;
+                                               break;
+                               }
+                       }
                        break;
-       }
 
-       return lev;
-}
+               /* parsed-and-rewritten-but-not-planned queries */
+               case T_Query:
+                       {
+                               Query *stmt = (Query *) parsetree;
 
-/*
- * GetQueryLogLevel
- *             utility to get the minimum log_statement level for a Query operation.
- *
- * This is exactly like GetCommandLogLevel, except it works on a Query
- * that has already been through parse analysis (and possibly further).
- */
-LogStmtLevel
-GetQueryLogLevel(Query *parsetree)
-{
-       LogStmtLevel lev;
+                               switch (stmt->commandType)
+                               {
+                                       case CMD_SELECT:
+                                               if (stmt->into != NULL)
+                                                       lev = LOGSTMT_DDL;      /* CREATE AS, SELECT INTO */
+                                               else
+                                                       lev = LOGSTMT_ALL;
+                                               break;
 
-       Assert(IsA(parsetree, Query));
+                                       case CMD_UPDATE:
+                                       case CMD_INSERT:
+                                       case CMD_DELETE:
+                                               lev = LOGSTMT_MOD;
+                                               break;
 
-       switch (parsetree->commandType)
-       {
-               case CMD_SELECT:
-                       if (parsetree->into != NULL)
-                               lev = LOGSTMT_DDL;              /* CREATE AS, SELECT INTO */
-                       else
-                               lev = LOGSTMT_ALL;
-                       break;
+                                       case CMD_UTILITY:
+                                               lev = GetCommandLogLevel(stmt->utilityStmt);
+                                               break;
 
-               case CMD_UPDATE:
-               case CMD_INSERT:
-               case CMD_DELETE:
-                       lev = LOGSTMT_MOD;
-                       break;
+                                       default:
+                                               elog(WARNING, "unrecognized commandType: %d",
+                                                        (int) stmt->commandType);
+                                               lev = LOGSTMT_ALL;
+                                               break;
+                               }
 
-               case CMD_UTILITY:
-                       lev = GetCommandLogLevel(parsetree->utilityStmt);
+                       }
                        break;
 
                default:
-                       elog(WARNING, "unrecognized commandType: %d",
-                                (int) parsetree->commandType);
+                       elog(WARNING, "unrecognized node type: %d",
+                                (int) nodeTag(parsetree));
                        lev = LOGSTMT_ALL;
                        break;
        }
index 8c9d58422ef538438758dd482cf5f8b65cfa8a03..3bd2ee6397f5daa84456c7bfaf1648d10a70334a 100644 (file)
@@ -12,7 +12,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.98 2007/01/05 22:19:47 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.99 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -141,29 +141,45 @@ GetPortalByName(const char *name)
 }
 
 /*
- * PortalListGetPrimaryQuery
- *             Get the "primary" Query within a portal, ie, the one marked canSetTag.
+ * PortalListGetPrimaryStmt
+ *             Get the "primary" stmt within a portal, ie, the one marked canSetTag.
  *
- * Returns NULL if no such Query.  If multiple Query structs within the
+ * Returns NULL if no such stmt.  If multiple PlannedStmt structs within the
  * portal are marked canSetTag, returns the first one. Neither of these
  * cases should occur in present usages of this function.
  *
+ * Copes if given a list of Querys --- can't happen in a portal, but this
+ * code also supports prepared statements, which need both cases.
+ *
  * Note: the reason this is just handed a List is so that prepared statements
- * can share the code. For use with a portal, use PortalGetPrimaryQuery
+ * can share the code. For use with a portal, use PortalGetPrimaryStmt
  * rather than calling this directly.
  */
-Query *
-PortalListGetPrimaryQuery(List *parseTrees)
+Node *
+PortalListGetPrimaryStmt(List *stmts)
 {
        ListCell   *lc;
 
-       foreach(lc, parseTrees)
+       foreach(lc, stmts)
        {
-               Query      *query = (Query *) lfirst(lc);
+               Node   *stmt = (Node *) lfirst(lc);
 
-               Assert(IsA(query, Query));
-               if (query->canSetTag)
-                       return query;
+               if (IsA(stmt, PlannedStmt))
+               {
+                       if (((PlannedStmt *) stmt)->canSetTag)
+                               return stmt;
+               }
+               else if (IsA(stmt, Query))
+               {
+                       if (((Query *) stmt)->canSetTag)
+                               return stmt;
+               }
+               else
+               {
+                       /* Utility stmts are assumed canSetTag if they're the only stmt */
+                       if (list_length(stmts) == 1)
+                               return stmt;
+               }
        }
        return NULL;
 }
@@ -261,30 +277,25 @@ CreateNewPortal(void)
  * (before rewriting) was an empty string.     Also, the passed commandTag must
  * be a pointer to a constant string, since it is not copied.  The caller is
  * responsible for ensuring that the passed prepStmtName (if any), sourceText
- * (if any), parse and plan trees have adequate lifetime.  Also, queryContext
- * must accurately describe the location of the parse trees.
+ * (if any), and plan trees have adequate lifetime.
  */
 void
 PortalDefineQuery(Portal portal,
                                  const char *prepStmtName,
                                  const char *sourceText,
                                  const char *commandTag,
-                                 List *parseTrees,
-                                 List *planTrees,
+                                 List *stmts,
                                  MemoryContext queryContext)
 {
        AssertArg(PortalIsValid(portal));
        AssertState(portal->queryContext == NULL);      /* else defined already */
 
-       Assert(list_length(parseTrees) == list_length(planTrees));
-
-       Assert(commandTag != NULL || parseTrees == NIL);
+       Assert(commandTag != NULL || stmts == NIL);
 
        portal->prepStmtName = prepStmtName;
        portal->sourceText = sourceText;
        portal->commandTag = commandTag;
-       portal->parseTrees = parseTrees;
-       portal->planTrees = planTrees;
+       portal->stmts = stmts;
        portal->queryContext = queryContext;
 }
 
index 20d6e24e053e03713f49545fbebd3a17ef2e8f3a..8c53a2df2ac7be441278ef63288094beb31cdacc 100644 (file)
@@ -37,7 +37,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.387 2007/02/20 10:00:25 petere Exp $
+ * $PostgreSQL: pgsql/src/include/catalog/catversion.h,v 1.388 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -53,6 +53,6 @@
  */
 
 /*                                                     yyyymmddN */
-#define CATALOG_VERSION_NO     200702201
+#define CATALOG_VERSION_NO     200702202
 
 #endif
index 4a17ddb767a45c1ca117822928d5becba934ff61..50fe2f132843ec65d8be2cc2d111c3db63292d5e 100644 (file)
@@ -7,13 +7,14 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.20 2007/01/05 22:19:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/portalcmds.h,v 1.21 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PORTALCMDS_H
 #define PORTALCMDS_H
 
+#include "nodes/parsenodes.h"
 #include "utils/portal.h"
 
 
index c1ee47fe7e887391ab0e8d4a2d0451a45e98490d..a921bf1b0451bb52866a3c31f5d233adeb5e71f2 100644 (file)
@@ -6,7 +6,7 @@
  *
  * Copyright (c) 2002-2007, PostgreSQL Global Development Group
  *
- * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.23 2007/01/05 22:19:53 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/commands/prepare.h,v 1.24 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 /*
  * The data structure representing a prepared statement
  *
+ * A prepared statement might be fully planned, or only parsed-and-rewritten.
+ * If fully planned, stmt_list contains PlannedStmts and/or utility statements;
+ * if not, it contains Query nodes.
+ *
  * Note: all subsidiary storage lives in the context denoted by the context
  * field.  However, the string referenced by commandTag is not subsidiary
  * storage; it is assumed to be a compile-time-constant string.  As with
@@ -31,11 +35,11 @@ typedef struct
        char            stmt_name[NAMEDATALEN];
        char       *query_string;       /* text of query, or NULL */
        const char *commandTag;         /* command tag (a constant!), or NULL */
-       List       *query_list;         /* list of queries, rewritten */
-       List       *plan_list;          /* list of plans */
+       List       *stmt_list;          /* list of statement or Query nodes */
        List       *argtype_list;       /* list of parameter type OIDs */
+       bool            fully_planned;  /* what is in stmt_list, exactly? */
+       bool            from_sql;               /* prepared via SQL, not FE/BE protocol? */
        TimestampTz prepare_time;       /* the time when the stmt was prepared */
-       bool            from_sql;               /* stmt prepared via SQL, not FE/BE protocol? */
        MemoryContext context;          /* context containing this query */
 } PreparedStatement;
 
@@ -52,9 +56,9 @@ extern void ExplainExecuteQuery(ExplainStmt *stmt, ParamListInfo params,
 extern void StorePreparedStatement(const char *stmt_name,
                                           const char *query_string,
                                           const char *commandTag,
-                                          List *query_list,
-                                          List *plan_list,
+                                          List *stmt_list,
                                           List *argtype_list,
+                                          bool fully_planned,
                                           bool from_sql);
 extern PreparedStatement *FetchPreparedStatement(const char *stmt_name,
                                           bool throwError);
index cf991125d4beda9db8d4c554a103ee199e382614..d5ae745a296a62b03adc9ddbf01c85b03732f81d 100644 (file)
@@ -8,7 +8,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/execdesc.h,v 1.33 2007/01/05 22:19:54 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/execdesc.h,v 1.34 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -16,7 +16,7 @@
 #define EXECDESC_H
 
 #include "nodes/execnodes.h"
-#include "nodes/parsenodes.h"
+#include "nodes/plannodes.h"
 #include "tcop/dest.h"
 
 
  *             query descriptor:
  *
  *     a QueryDesc encapsulates everything that the executor
- *     needs to execute the query
+ *     needs to execute the query.
+ *
+ *     For the convenience of SQL-language functions, we also support QueryDescs
+ *     containing utility statements; these must not be passed to the executor
+ *     however.
  * ---------------------
  */
 typedef struct QueryDesc
 {
        /* These fields are provided by CreateQueryDesc */
        CmdType         operation;              /* CMD_SELECT, CMD_UPDATE, etc. */
-       Query      *parsetree;          /* rewritten parsetree */
-       Plan       *plantree;           /* planner's output */
+       PlannedStmt     *plannedstmt;   /* planner's output, or null if utility */
+       Node       *utilitystmt;        /* utility statement, or null */
        Snapshot        snapshot;               /* snapshot to use for query */
        Snapshot        crosscheck_snapshot;    /* crosscheck for RI update/delete */
        DestReceiver *dest;                     /* the destination for tuple output */
@@ -46,13 +50,18 @@ typedef struct QueryDesc
 } QueryDesc;
 
 /* in pquery.c */
-extern QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree,
+extern QueryDesc *CreateQueryDesc(PlannedStmt *plannedstmt,
                                Snapshot snapshot,
                                Snapshot crosscheck_snapshot,
                                DestReceiver *dest,
                                ParamListInfo params,
                                bool doInstrument);
 
+extern QueryDesc *CreateUtilityQueryDesc(Node *utilitystmt,
+                               Snapshot snapshot,
+                               DestReceiver *dest,
+                               ParamListInfo params);
+
 extern void FreeQueryDesc(QueryDesc *qdesc);
 
 #endif   /* EXECDESC_H  */
index bfbe1ba2f3886739d872c6258c0d2bb5a3c62ab9..38260b5ecd6c211dcd9b18ed590f688b0d04e1ee 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.136 2007/02/06 02:59:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/executor/executor.h,v 1.137 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -15,6 +15,7 @@
 #define EXECUTOR_H
 
 #include "executor/execdesc.h"
+#include "nodes/parsenodes.h"
 
 
 /*
index 3bfc870159fca697e9171c524f3f0306f91106c8..5e65bd750aeaaeba4dbc8639b4a4398a92603751 100644 (file)
@@ -6,7 +6,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/executor/spi_priv.h,v 1.26 2007/01/05 22:19:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/executor/spi_priv.h,v 1.27 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -35,10 +35,11 @@ typedef struct
        MemoryContext plancxt;
        /* Original query string (used for error reporting) */
        const char *query;
-       /* List of List of querytrees; one sublist per original parsetree */
-       List       *qtlist;
-       /* List of plan trees --- length == # of querytrees, but flat list */
-       List       *ptlist;
+       /*
+        * List of List of PlannedStmts and utility stmts; one sublist per
+        * original parsetree
+        */
+       List       *stmt_list_list;
        /* Argument types, if a prepared plan */
        int                     nargs;
        Oid                *argtypes;
index 35a0ab3a6071408f8073411577ce83a9f7e44ae9..b576f4610e3e75e7b7e84de5bb6b52b676db18ee 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.167 2007/02/06 02:59:13 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/execnodes.h,v 1.168 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -344,7 +344,7 @@ typedef struct EState
        ExprContext *es_per_tuple_exprcontext;
 
        /* Below is to re-evaluate plan qual in READ COMMITTED mode */
-       Plan       *es_topPlan;         /* link to top of plan tree */
+       PlannedStmt *es_plannedstmt;    /* link to top of plan tree */
        struct evalPlanQual *es_evalPlanQual;           /* chain of PlanQual states */
        bool       *es_evTupleNull; /* local array of EPQ status */
        HeapTuple  *es_evTuple;         /* shared array of EPQ substitute tuples */
index 44175591e7502c38910a2286bfecff1bd57a8940..53bd13b5fbe58271eee4f1e824b0c99ecc87eac2 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.195 2007/02/19 07:03:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/nodes.h,v 1.196 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -141,6 +141,7 @@ typedef enum NodeTag
        T_RangeTblRef,
        T_JoinExpr,
        T_FromExpr,
+       T_IntoClause,
 
        /*
         * TAGS FOR EXPRESSION STATE NODES (execnodes.h)
@@ -225,9 +226,10 @@ typedef enum NodeTag
        T_OidList,
 
        /*
-        * TAGS FOR PARSE TREE NODES (parsenodes.h)
+        * TAGS FOR STATEMENT NODES (mostly in parsenodes.h)
         */
        T_Query = 700,
+       T_PlannedStmt,
        T_InsertStmt,
        T_DeleteStmt,
        T_UpdateStmt,
@@ -302,8 +304,12 @@ typedef enum NodeTag
        T_AlterOwnerStmt,
        T_DropOwnedStmt,
        T_ReassignOwnedStmt,
+       T_CompositeTypeStmt,
 
-       T_A_Expr = 800,
+       /*
+        * TAGS FOR PARSE TREE NODES (parsenodes.h)
+        */
+       T_A_Expr = 900,
        T_ColumnRef,
        T_ParamRef,
        T_A_Const,
@@ -328,7 +334,6 @@ typedef enum NodeTag
        T_FuncWithArgs,
        T_PrivTarget,
        T_CreateOpClassItem,
-       T_CompositeTypeStmt,
        T_InhRelation,
        T_FunctionParameter,
        T_LockingClause,
@@ -343,7 +348,7 @@ typedef enum NodeTag
         * purposes (usually because they are involved in APIs where we want to
         * pass multiple object types through the same pointer).
         */
-       T_TriggerData = 900,            /* in commands/trigger.h */
+       T_TriggerData = 950,            /* in commands/trigger.h */
        T_ReturnSetInfo,                        /* in nodes/execnodes.h */
        T_TIDBitmap                                     /* in nodes/tidbitmap.h */
 } NodeTag;
@@ -430,10 +435,9 @@ typedef double Cost;                       /* execution cost (in page-access units) */
 
 /*
  * CmdType -
- *       enums for type of operation represented by a Query
+ *       enums for type of operation represented by a Query or PlannedStmt
  *
- * ??? could have put this in parsenodes.h but many files not in the
- *       optimizer also need this...
+ * This is needed in both parsenodes.h and plannodes.h, so put it here...
  */
 typedef enum CmdType
 {
index 0db72763021e2e23f5806bfcdc1d6b9ee2f0f7df..ec9ccb6ce30c15827e8c4671b5b77cd4c0718370 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.340 2007/02/03 14:06:55 petere Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/parsenodes.h,v 1.341 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -27,15 +27,6 @@ typedef enum QuerySource
        QSRC_NON_INSTEAD_RULE           /* added by non-INSTEAD rule */
 } QuerySource;
 
-/* What to do at commit time for temporary relations */
-typedef enum OnCommitAction
-{
-       ONCOMMIT_NOOP,                          /* No ON COMMIT clause (do nothing) */
-       ONCOMMIT_PRESERVE_ROWS,         /* ON COMMIT PRESERVE ROWS (do nothing) */
-       ONCOMMIT_DELETE_ROWS,           /* ON COMMIT DELETE ROWS */
-       ONCOMMIT_DROP                           /* ON COMMIT DROP */
-} OnCommitAction;
-
 /* Sort ordering options for ORDER BY and CREATE INDEX */
 typedef enum SortByDir
 {
@@ -86,11 +77,14 @@ typedef uint32 AclMode;                     /* a bitmask of privilege bits */
 
 /*
  * Query -
- *       all statements are turned into a Query tree (via transformStmt)
- *       for further processing by the optimizer
+ *       Parse analysis turns all statements into a Query tree (via transformStmt)
+ *       for further processing by the rewriter and planner.
  *
- *       utility statements (i.e. non-optimizable statements) have the
+ *       Utility statements (i.e. non-optimizable statements) have the
  *       utilityStmt field set, and the Query itself is mostly dummy.
+ *
+ *       Planning converts a Query tree into a Plan tree headed by a PlannedStmt
+ *       noded --- the Query structure is not used by the executor.
  */
 typedef struct Query
 {
@@ -108,10 +102,7 @@ typedef struct Query
        int                     resultRelation; /* rtable index of target relation for
                                                                 * INSERT/UPDATE/DELETE; 0 for SELECT */
 
-       RangeVar   *into;                       /* target relation for SELECT INTO */
-       List       *intoOptions;        /* options from WITH clause */
-       OnCommitAction intoOnCommit;    /* what do we do at COMMIT? */
-       char       *intoTableSpaceName;         /* table space to use, or NULL */
+       IntoClause *into;                       /* target for SELECT INTO / CREATE TABLE AS */
 
        bool            hasAggs;                /* has aggregates in tlist or havingQual */
        bool            hasSubLinks;    /* has subquery SubLink */
@@ -138,29 +129,6 @@ typedef struct Query
 
        Node       *setOperations;      /* set-operation tree if this is top level of
                                                                 * a UNION/INTERSECT/EXCEPT query */
-
-       /*
-        * If the resultRelation turns out to be the parent of an inheritance
-        * tree, the planner will add all the child tables to the rtable and store
-        * a list of the rtindexes of all the result relations here. This is done
-        * at plan time, not parse time, since we don't want to commit to the
-        * exact set of child tables at parse time.  XXX This field ought to go in
-        * some sort of TopPlan plan node, not in the Query.
-        */
-       List       *resultRelations;    /* integer list of RT indexes, or NIL */
-
-       /*
-        * If the query has a returningList then the planner will store a list of
-        * processed targetlists (one per result relation) here.  We must have a
-        * separate RETURNING targetlist for each result rel because column
-        * numbers may vary within an inheritance tree.  In the targetlists, Vars
-        * referencing the result relation will have their original varno and
-        * varattno, while Vars referencing other rels will be converted to have
-        * varno OUTER and varattno referencing a resjunk entry in the top plan
-        * node's targetlist.  XXX This field ought to go in some sort of TopPlan
-        * plan node, not in the Query.
-        */
-       List       *returningLists; /* list of lists of TargetEntry, or NIL */
 } Query;
 
 
@@ -761,17 +729,10 @@ typedef struct SelectStmt
 
        /*
         * These fields are used only in "leaf" SelectStmts.
-        *
-        * into, intoColNames, intoOptions, intoOnCommit, and intoTableSpaceName
-        * are a kluge; they belong somewhere else...
         */
        List       *distinctClause; /* NULL, list of DISTINCT ON exprs, or
                                                                 * lcons(NIL,NIL) for all (SELECT DISTINCT) */
-       RangeVar   *into;                       /* target table (for select into table) */
-       List       *intoColNames;       /* column names for into table */
-       List       *intoOptions;        /* options from WITH clause */
-       OnCommitAction intoOnCommit;    /* what do we do at COMMIT? */
-       char       *intoTableSpaceName;         /* table space to use, or NULL */
+       IntoClause *into;                       /* target for SELECT INTO / CREATE TABLE AS */
        List       *targetList;         /* the target list (of ResTarget) */
        List       *fromClause;         /* the FROM clause */
        Node       *whereClause;        /* WHERE qualification */
@@ -1994,10 +1955,7 @@ typedef struct ExecuteStmt
 {
        NodeTag         type;
        char       *name;                       /* The name of the plan to execute */
-       RangeVar   *into;                       /* Optional table to store results in */
-       List       *intoOptions;        /* Options from WITH clause */
-       OnCommitAction into_on_commit;          /* What do we do at COMMIT? */
-       char       *into_tbl_space; /* Tablespace to use, or NULL */
+       IntoClause *into;                       /* Optional table to store results in */
        List       *params;                     /* Values to assign to parameters */
 } ExecuteStmt;
 
index cdd7b4d2e43707fb574fb0ae2e7c040a2117d2f3..537981462b23e7b51585f63ab97e9116e8c37106 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.90 2007/02/19 02:23:12 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/plannodes.h,v 1.91 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
  * ----------------------------------------------------------------
  */
 
+/* ----------------
+ *             PlannedStmt node
+ *
+ * The output of the planner is a Plan tree headed by a PlannedStmt node.
+ * PlannedStmt holds the "one time" information needed by the executor.
+ * ----------------
+ */
+typedef struct PlannedStmt
+{
+       NodeTag         type;
+
+       CmdType         commandType;    /* select|insert|update|delete */
+
+       bool            canSetTag;              /* do I set the command result tag? */
+
+       struct Plan *planTree;          /* tree of Plan nodes */
+
+       List       *rtable;                     /* list of RangeTblEntry nodes */
+
+       /* rtable indexes of target relations for INSERT/UPDATE/DELETE */
+       List       *resultRelations;    /* integer list of RT indexes, or NIL */
+
+       IntoClause *into;                       /* target for SELECT INTO / CREATE TABLE AS */
+
+       /*
+        * If the query has a returningList then the planner will store a list of
+        * processed targetlists (one per result relation) here.  We must have a
+        * separate RETURNING targetlist for each result rel because column
+        * numbers may vary within an inheritance tree.  In the targetlists, Vars
+        * referencing the result relation will have their original varno and
+        * varattno, while Vars referencing other rels will be converted to have
+        * varno OUTER and varattno referencing a resjunk entry in the top plan
+        * node's targetlist.
+        */
+       List       *returningLists; /* list of lists of TargetEntry, or NIL */
+
+       List       *rowMarks;           /* a list of RowMarkClause's */
+
+       int                     nParamExec;             /* number of PARAM_EXEC Params used */
+} PlannedStmt;
+
+
 /* ----------------
  *             Plan node
  *
@@ -75,15 +117,6 @@ typedef struct Plan
         */
        Bitmapset  *extParam;
        Bitmapset  *allParam;
-
-       /*
-        * We really need in some TopPlan node to store range table and
-        * resultRelation from Query there and get rid of Query itself from
-        * Executor. Some other stuff like below could be put there, too.
-        */
-       int                     nParamExec;             /* Number of them in entire query. This is to
-                                                                * get Executor know about how many PARAM_EXEC
-                                                                * there are in query plan. */
 } Plan;
 
 /* ----------------
index caa689e262379074e18b09fd35dcd769fe068b29..185673f729a85f90750eff29f7e30ef2c720181b 100644 (file)
@@ -10,7 +10,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.125 2007/02/19 07:03:31 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/primnodes.h,v 1.126 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -49,6 +49,15 @@ typedef enum InhOption
        INH_DEFAULT                                     /* Use current SQL_inheritance option */
 } InhOption;
 
+/* What to do at commit time for temporary relations */
+typedef enum OnCommitAction
+{
+       ONCOMMIT_NOOP,                          /* No ON COMMIT clause (do nothing) */
+       ONCOMMIT_PRESERVE_ROWS,         /* ON COMMIT PRESERVE ROWS (do nothing) */
+       ONCOMMIT_DELETE_ROWS,           /* ON COMMIT DELETE ROWS */
+       ONCOMMIT_DROP                           /* ON COMMIT DROP */
+} OnCommitAction;
+
 /*
  * RangeVar - range variable, used in FROM clauses
  *
@@ -69,6 +78,20 @@ typedef struct RangeVar
        Alias      *alias;                      /* table alias & optional column aliases */
 } RangeVar;
 
+/*
+ * IntoClause - target information for SELECT INTO and CREATE TABLE AS
+ */
+typedef struct IntoClause
+{
+       NodeTag         type;
+
+       RangeVar   *rel;                        /* target relation name */
+       List       *colNames;           /* column names to assign, or NIL */
+       List       *options;            /* options from WITH clause */
+       OnCommitAction onCommit;        /* what do we do at COMMIT? */
+       char       *tableSpaceName;     /* table space to use, or NULL */
+} IntoClause;
+
 
 /* ----------------------------------------------------------------
  *                                     node types for executable expressions
index 6de06ebc918f769327cf32ca075b3ab26ff9262a..59ec830f3ff6a23d1c065d7715a773d38bdb4037 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.136 2007/02/19 07:03:33 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.137 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -110,6 +110,10 @@ typedef struct PlannerInfo
        List       *join_rel_list;      /* list of join-relation RelOptInfos */
        struct HTAB *join_rel_hash; /* optional hashtable for join relations */
 
+       List       *resultRelations;    /* integer list of RT indexes, or NIL */
+
+       List       *returningLists;             /* list of lists of TargetEntry, or NIL */
+
        List       *init_plans;                         /* init subplans for query */
 
        List       *eq_classes;                         /* list of active EquivalenceClasses */
index 44d03602694120f59dd557b3328ea1f2005f6420..c243cdbc356aa2206bf81484a905549943213fe4 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.37 2007/02/19 07:03:34 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.38 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "nodes/relation.h"
 
 
-extern Plan *planner(Query *parse, bool isCursor, int cursorOptions,
+extern PlannedStmt *planner(Query *parse, bool isCursor, int cursorOptions,
                ParamListInfo boundParams);
 extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse,
                                                          Index level, double tuple_fraction,
-                                                         List **subquery_pathkeys);
+                                                         PlannerInfo **subroot);
 
 #endif   /* PLANNER_H */
index 353135302711e06c60d43e5939fc1f0451d638ea..5cab498c13a579076741440c6b4f1fcbf7961428 100644 (file)
@@ -7,23 +7,26 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/pquery.h,v 1.40 2007/01/05 22:19:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/pquery.h,v 1.41 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #ifndef PQUERY_H
 #define PQUERY_H
 
+#include "nodes/parsenodes.h"
 #include "utils/portal.h"
 
 
 extern DLLIMPORT Portal ActivePortal;
 
 
-extern PortalStrategy ChoosePortalStrategy(List *parseTrees);
+extern PortalStrategy ChoosePortalStrategy(List *stmts);
 
 extern List *FetchPortalTargetList(Portal portal);
 
+extern List *FetchStatementTargetList(Node *stmt);
+
 extern void PortalStart(Portal portal, ParamListInfo params,
                        Snapshot snapshot);
 
index ad66a61dace10752540cb634f59e71540a457143..2a5512557669e04b69f50ecb4b990181ae1c89c9 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.86 2007/01/05 22:19:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.87 2007/02/20 17:32:17 tgl Exp $
  *
  * OLD COMMENTS
  *       This file was created so that other c files could get the two
@@ -20,6 +20,7 @@
 #define TCOPPROT_H
 
 #include "executor/execdesc.h"
+#include "nodes/parsenodes.h"
 #include "utils/guc.h"
 
 
@@ -50,7 +51,7 @@ extern List *pg_parse_and_rewrite(const char *query_string,
 extern List *pg_parse_query(const char *query_string);
 extern List *pg_analyze_and_rewrite(Node *parsetree, const char *query_string,
                                           Oid *paramTypes, int numParams);
-extern Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams);
+extern PlannedStmt *pg_plan_query(Query *querytree, ParamListInfo boundParams);
 extern List *pg_plan_queries(List *querytrees, ParamListInfo boundParams,
                                bool needSnapshot);
 
index ebcaf5977290f62088d8002662c80e2675a0c454..52c02253068c5acdba60a6507658716662738cb3 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.30 2007/01/05 22:19:58 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/utility.h,v 1.31 2007/02/20 17:32:17 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,15 +26,9 @@ extern TupleDesc UtilityTupleDescriptor(Node *parsetree);
 
 extern const char *CreateCommandTag(Node *parsetree);
 
-extern const char *CreateQueryTag(Query *parsetree);
-
 extern LogStmtLevel GetCommandLogLevel(Node *parsetree);
 
-extern LogStmtLevel GetQueryLogLevel(Query *parsetree);
-
-extern bool QueryReturnsTuples(Query *parsetree);
-
-extern bool QueryIsReadOnly(Query *parsetree);
+extern bool CommandIsReadOnly(Node *parsetree);
 
 extern void CheckRelationOwnership(RangeVar *rel, bool noCatalogs);
 
index 5eb2c715e30b36a7971bac9840490ff921c11104..aa432abb8768adb0a32a12db24fcb6c295d5bf3d 100644 (file)
@@ -12,7 +12,7 @@
  * to let the client suspend an update-type query partway through!     Because
  * the query rewriter does not allow arbitrary ON SELECT rewrite rules,
  * only queries that were originally update-type could produce multiple
- * parse/plan trees; so the restriction to a single query is not a problem
+ * plan trees; so the restriction to a single query is not a problem
  * in practice.
  *
  * For SQL cursors, we support three kinds of scroll behavior:
@@ -39,7 +39,7 @@
  * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.72 2007/01/05 22:19:59 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.73 2007/02/20 17:32:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -124,9 +124,8 @@ typedef struct PortalData
        /* The query or queries the portal will execute */
        const char *sourceText;         /* text of query, if known (may be NULL) */
        const char *commandTag;         /* command tag for original query */
-       List       *parseTrees;         /* parse tree(s) */
-       List       *planTrees;          /* plan tree(s) */
-       MemoryContext queryContext; /* where the parse trees live */
+       List       *stmts;                      /* PlannedStmts and/or utility statements */
+       MemoryContext queryContext; /* where the plan trees live */
 
        /*
         * Note: queryContext effectively identifies which prepared statement the
@@ -191,7 +190,7 @@ typedef struct PortalData
  */
 #define PortalGetQueryDesc(portal)     ((portal)->queryDesc)
 #define PortalGetHeapMemory(portal) ((portal)->heap)
-#define PortalGetPrimaryQuery(portal) PortalListGetPrimaryQuery((portal)->parseTrees)
+#define PortalGetPrimaryStmt(portal) PortalListGetPrimaryStmt((portal)->stmts)
 
 
 /* Prototypes for functions in utils/mmgr/portalmem.c */
@@ -217,10 +216,9 @@ extern void PortalDefineQuery(Portal portal,
                                  const char *prepStmtName,
                                  const char *sourceText,
                                  const char *commandTag,
-                                 List *parseTrees,
-                                 List *planTrees,
+                                 List *stmts,
                                  MemoryContext queryContext);
-extern Query *PortalListGetPrimaryQuery(List *parseTrees);
+extern Node *PortalListGetPrimaryStmt(List *stmts);
 extern void PortalCreateHoldStore(Portal portal);
 
 #endif   /* PORTAL_H */
index 09f7a99097dda5c9ac2b06accb18b4dc8a016646..68a68a6634cdfea1a3558057245ec4378adda010 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.188 2007/02/08 18:37:30 tgl Exp $
+ *       $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.189 2007/02/20 17:32:18 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -2380,20 +2380,20 @@ exec_stmt_execsql(PLpgSQL_execstate *estate,
                exec_prepare_plan(estate, expr);
                stmt->mod_stmt = false;
                spi_plan = (_SPI_plan *) expr->plan;
-               foreach(l, spi_plan->qtlist)
+               foreach(l, spi_plan->stmt_list_list)
                {
                        ListCell   *l2;
 
                        foreach(l2, (List *) lfirst(l))
                        {
-                               Query      *q = (Query *) lfirst(l2);
+                               PlannedStmt *p = (PlannedStmt *) lfirst(l2);
 
-                               Assert(IsA(q, Query));
-                               if (q->canSetTag)
+                               if (IsA(p, PlannedStmt) &&
+                                       p->canSetTag)
                                {
-                                       if (q->commandType == CMD_INSERT ||
-                                               q->commandType == CMD_UPDATE ||
-                                               q->commandType == CMD_DELETE)
+                                       if (p->commandType == CMD_INSERT ||
+                                               p->commandType == CMD_UPDATE ||
+                                               p->commandType == CMD_DELETE)
                                                stmt->mod_stmt = true;
                                }
                        }
@@ -4674,6 +4674,8 @@ static void
 exec_simple_check_plan(PLpgSQL_expr *expr)
 {
        _SPI_plan  *spi_plan = (_SPI_plan *) expr->plan;
+       List       *sublist;
+       PlannedStmt *stmt;
        Plan       *plan;
        TargetEntry *tle;
 
@@ -4683,17 +4685,20 @@ exec_simple_check_plan(PLpgSQL_expr *expr)
         * 1. We can only evaluate queries that resulted in one single execution
         * plan
         */
-       if (list_length(spi_plan->ptlist) != 1)
+       if (list_length(spi_plan->stmt_list_list) != 1)
+               return;
+       sublist = (List *) linitial(spi_plan->stmt_list_list);
+       if (list_length(sublist) != 1)
                return;
 
-       plan = (Plan *) linitial(spi_plan->ptlist);
+       stmt = (PlannedStmt *) linitial(sublist);
 
        /*
         * 2. It must be a RESULT plan --> no scan's required
         */
-       if (plan == NULL)                       /* utility statement produces this */
+       if (!IsA(stmt, PlannedStmt))
                return;
-
+       plan = stmt->planTree;
        if (!IsA(plan, Result))
                return;