Header And Logo

PostgreSQL
| The world's most advanced open source database.

Functions | Variables

pquery.c File Reference

#include "postgres.h"
#include "access/xact.h"
#include "commands/prepare.h"
#include "executor/tstoreReceiver.h"
#include "miscadmin.h"
#include "pg_trace.h"
#include "tcop/pquery.h"
#include "tcop/utility.h"
#include "utils/memutils.h"
#include "utils/snapmgr.h"
Include dependency graph for pquery.c:

Go to the source code of this file.

Functions

static void ProcessQuery (PlannedStmt *plan, const char *sourceText, ParamListInfo params, DestReceiver *dest, char *completionTag)
static void FillPortalStore (Portal portal, bool isTopLevel)
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, Node *utilityStmt, bool isTopLevel, DestReceiver *dest, char *completionTag)
static void PortalRunMulti (Portal portal, bool isTopLevel, DestReceiver *dest, DestReceiver *altdest, char *completionTag)
static long DoPortalRunFetch (Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)
static void DoPortalRewind (Portal portal)
QueryDescCreateQueryDesc (PlannedStmt *plannedstmt, const char *sourceText, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, int instrument_options)
QueryDescCreateUtilityQueryDesc (Node *utilitystmt, const char *sourceText, Snapshot snapshot, DestReceiver *dest, ParamListInfo params)
void FreeQueryDesc (QueryDesc *qdesc)
PortalStrategy ChoosePortalStrategy (List *stmts)
ListFetchPortalTargetList (Portal portal)
ListFetchStatementTargetList (Node *stmt)
void PortalStart (Portal portal, ParamListInfo params, int eflags, Snapshot snapshot)
void PortalSetResultFormat (Portal portal, int nFormats, int16 *formats)
bool PortalRun (Portal portal, long count, bool isTopLevel, DestReceiver *dest, DestReceiver *altdest, char *completionTag)
long PortalRunFetch (Portal portal, FetchDirection fdirection, long count, DestReceiver *dest)

Variables

Portal ActivePortal = NULL

Function Documentation

PortalStrategy ChoosePortalStrategy ( List stmts  ) 

Definition at line 241 of file pquery.c.

References PlannedStmt::canSetTag, Query::canSetTag, CMD_SELECT, CMD_UTILITY, PlannedStmt::commandType, Query::commandType, PlannedStmt::hasModifyingCTE, Query::hasModifyingCTE, PlannedStmt::hasReturning, IsA, lfirst, linitial, list_length(), NIL, NULL, PORTAL_UTIL_SELECT, Query::returningList, UtilityReturnsTuples(), PlannedStmt::utilityStmt, and Query::utilityStmt.

Referenced by PlanCacheComputeResultDesc(), and PortalStart().

{
    int         nSetTag;
    ListCell   *lc;

    /*
     * PORTAL_ONE_SELECT and PORTAL_UTIL_SELECT need only consider the
     * single-statement case, since there are no rewrite rules that can add
     * auxiliary queries to a SELECT or a utility command. PORTAL_ONE_MOD_WITH
     * likewise allows only one top-level statement.
     */
    if (list_length(stmts) == 1)
    {
        Node       *stmt = (Node *) linitial(stmts);

        if (IsA(stmt, Query))
        {
            Query      *query = (Query *) stmt;

            if (query->canSetTag)
            {
                if (query->commandType == CMD_SELECT &&
                    query->utilityStmt == NULL)
                {
                    if (query->hasModifyingCTE)
                        return PORTAL_ONE_MOD_WITH;
                    else
                        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->utilityStmt == NULL)
                {
                    if (pstmt->hasModifyingCTE)
                        return PORTAL_ONE_MOD_WITH;
                    else
                        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;
        }
    }

    /*
     * PORTAL_ONE_RETURNING has to allow auxiliary queries added by rewrite.
     * Choose PORTAL_ONE_RETURNING if there is exactly one canSetTag query and
     * it has a RETURNING list.
     */
    nSetTag = 0;
    foreach(lc, stmts)
    {
        Node       *stmt = (Node *) lfirst(lc);

        if (IsA(stmt, Query))
        {
            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->hasReturning)
                    return PORTAL_MULTI_QUERY;  /* no need to look further */
            }
        }
        /* otherwise, utility command, assumed not canSetTag */
    }
    if (nSetTag == 1)
        return PORTAL_ONE_RETURNING;

    /* Else, it's the general case... */
    return PORTAL_MULTI_QUERY;
}

QueryDesc* CreateQueryDesc ( PlannedStmt plannedstmt,
const char *  sourceText,
Snapshot  snapshot,
Snapshot  crosscheck_snapshot,
DestReceiver dest,
ParamListInfo  params,
int  instrument_options 
)

Definition at line 62 of file pquery.c.

References PlannedStmt::commandType, QueryDesc::crosscheck_snapshot, QueryDesc::dest, QueryDesc::estate, QueryDesc::instrument_options, QueryDesc::operation, palloc(), QueryDesc::params, QueryDesc::plannedstmt, QueryDesc::planstate, RegisterSnapshot(), QueryDesc::snapshot, QueryDesc::sourceText, QueryDesc::totaltime, QueryDesc::tupDesc, PlannedStmt::utilityStmt, and QueryDesc::utilitystmt.

Referenced by _SPI_execute_plan(), BeginCopy(), ExecCreateTableAs(), execute_sql_string(), ExplainOnePlan(), PortalStart(), postquel_start(), ProcessQuery(), and refresh_matview_datafill().

{
    QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));

    qd->operation = plannedstmt->commandType;   /* operation */
    qd->plannedstmt = plannedstmt;      /* plan */
    qd->utilitystmt = plannedstmt->utilityStmt; /* in case DECLARE CURSOR */
    qd->sourceText = sourceText;    /* query text */
    qd->snapshot = RegisterSnapshot(snapshot);  /* snapshot */
    /* RI check snapshot */
    qd->crosscheck_snapshot = RegisterSnapshot(crosscheck_snapshot);
    qd->dest = dest;            /* output dest */
    qd->params = params;        /* parameter values passed into query */
    qd->instrument_options = instrument_options;        /* instrumentation
                                                         * wanted? */

    /* null these fields until set by ExecutorStart */
    qd->tupDesc = NULL;
    qd->estate = NULL;
    qd->planstate = NULL;
    qd->totaltime = NULL;

    return qd;
}

QueryDesc* CreateUtilityQueryDesc ( Node utilitystmt,
const char *  sourceText,
Snapshot  snapshot,
DestReceiver dest,
ParamListInfo  params 
)

Definition at line 97 of file pquery.c.

References QueryDesc::crosscheck_snapshot, QueryDesc::dest, QueryDesc::estate, QueryDesc::instrument_options, QueryDesc::operation, palloc(), QueryDesc::params, QueryDesc::plannedstmt, QueryDesc::planstate, RegisterSnapshot(), QueryDesc::snapshot, QueryDesc::sourceText, QueryDesc::totaltime, QueryDesc::tupDesc, and QueryDesc::utilitystmt.

Referenced by postquel_start().

{
    QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));

    qd->operation = CMD_UTILITY;    /* operation */
    qd->plannedstmt = NULL;
    qd->utilitystmt = utilitystmt;      /* utility command */
    qd->sourceText = sourceText;    /* query text */
    qd->snapshot = RegisterSnapshot(snapshot);  /* snapshot */
    qd->crosscheck_snapshot = InvalidSnapshot;  /* RI check snapshot */
    qd->dest = dest;            /* output dest */
    qd->params = params;        /* parameter values passed into query */
    qd->instrument_options = false;     /* uninteresting for utilities */

    /* null these fields until set by ExecutorStart */
    qd->tupDesc = NULL;
    qd->estate = NULL;
    qd->planstate = NULL;
    qd->totaltime = NULL;

    return qd;
}

static void DoPortalRewind ( Portal  portal  )  [static]
static long DoPortalRunFetch ( Portal  portal,
FetchDirection  fdirection,
long  count,
DestReceiver dest 
) [static]

Definition at line 1481 of file pquery.c.

References Assert, PortalData::atEnd, PortalData::atStart, DestNone, DoPortalRewind(), elog, ERROR, FETCH_ABSOLUTE, FETCH_ALL, FETCH_BACKWARD, FETCH_FORWARD, FETCH_RELATIVE, _DestReceiver::mydest, None_Receiver, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_UTIL_SELECT, PortalData::portalPos, PortalRunSelect(), PortalData::posOverflow, and PortalData::strategy.

Referenced by PortalRunFetch().

{
    bool        forward;

    Assert(portal->strategy == PORTAL_ONE_SELECT ||
           portal->strategy == PORTAL_ONE_RETURNING ||
           portal->strategy == PORTAL_ONE_MOD_WITH ||
           portal->strategy == PORTAL_UTIL_SELECT);

    switch (fdirection)
    {
        case FETCH_FORWARD:
            if (count < 0)
            {
                fdirection = FETCH_BACKWARD;
                count = -count;
            }
            /* fall out of switch to share code with FETCH_BACKWARD */
            break;
        case FETCH_BACKWARD:
            if (count < 0)
            {
                fdirection = FETCH_FORWARD;
                count = -count;
            }
            /* fall out of switch to share code with FETCH_FORWARD */
            break;
        case FETCH_ABSOLUTE:
            if (count > 0)
            {
                /*
                 * Definition: Rewind to start, advance count-1 rows, return
                 * next row (if any).  In practice, if the goal is less than
                 * halfway back to the start, it's better to scan from where
                 * we are.  In any case, we arrange to fetch the target row
                 * going forwards.
                 */
                if (portal->posOverflow || portal->portalPos == LONG_MAX ||
                    count - 1 <= portal->portalPos / 2)
                {
                    DoPortalRewind(portal);
                    if (count > 1)
                        PortalRunSelect(portal, true, count - 1,
                                        None_Receiver);
                }
                else
                {
                    long        pos = portal->portalPos;

                    if (portal->atEnd)
                        pos++;  /* need one extra fetch if off end */
                    if (count <= pos)
                        PortalRunSelect(portal, false, pos - count + 1,
                                        None_Receiver);
                    else if (count > pos + 1)
                        PortalRunSelect(portal, true, count - pos - 1,
                                        None_Receiver);
                }
                return PortalRunSelect(portal, true, 1L, dest);
            }
            else if (count < 0)
            {
                /*
                 * Definition: Advance to end, back up abs(count)-1 rows,
                 * return prior row (if any).  We could optimize this if we
                 * knew in advance where the end was, but typically we won't.
                 * (Is it worth considering case where count > half of size of
                 * query?  We could rewind once we know the size ...)
                 */
                PortalRunSelect(portal, true, FETCH_ALL, None_Receiver);
                if (count < -1)
                    PortalRunSelect(portal, false, -count - 1, None_Receiver);
                return PortalRunSelect(portal, false, 1L, dest);
            }
            else
            {
                /* count == 0 */
                /* Rewind to start, return zero rows */
                DoPortalRewind(portal);
                return PortalRunSelect(portal, true, 0L, dest);
            }
            break;
        case FETCH_RELATIVE:
            if (count > 0)
            {
                /*
                 * Definition: advance count-1 rows, return next row (if any).
                 */
                if (count > 1)
                    PortalRunSelect(portal, true, count - 1, None_Receiver);
                return PortalRunSelect(portal, true, 1L, dest);
            }
            else if (count < 0)
            {
                /*
                 * Definition: back up abs(count)-1 rows, return prior row (if
                 * any).
                 */
                if (count < -1)
                    PortalRunSelect(portal, false, -count - 1, None_Receiver);
                return PortalRunSelect(portal, false, 1L, dest);
            }
            else
            {
                /* count == 0 */
                /* Same as FETCH FORWARD 0, so fall out of switch */
                fdirection = FETCH_FORWARD;
            }
            break;
        default:
            elog(ERROR, "bogus direction");
            break;
    }

    /*
     * Get here with fdirection == FETCH_FORWARD or FETCH_BACKWARD, and count
     * >= 0.
     */
    forward = (fdirection == FETCH_FORWARD);

    /*
     * Zero count means to re-fetch the current row, if any (per SQL)
     */
    if (count == 0)
    {
        bool        on_row;

        /* Are we sitting on a row? */
        on_row = (!portal->atStart && !portal->atEnd);

        if (dest->mydest == DestNone)
        {
            /* MOVE 0 returns 0/1 based on if FETCH 0 would return a row */
            return on_row ? 1L : 0L;
        }
        else
        {
            /*
             * If we are sitting on a row, back up one so we can re-fetch it.
             * If we are not sitting on a row, we still have to start up and
             * shut down the executor so that the destination is initialized
             * and shut down correctly; so keep going.  To PortalRunSelect,
             * count == 0 means we will retrieve no row.
             */
            if (on_row)
            {
                PortalRunSelect(portal, false, 1L, None_Receiver);
                /* Set up to fetch one row forward */
                count = 1;
                forward = true;
            }
        }
    }

    /*
     * Optimize MOVE BACKWARD ALL into a Rewind.
     */
    if (!forward && count == FETCH_ALL && dest->mydest == DestNone)
    {
        long        result = portal->portalPos;

        if (result > 0 && !portal->atEnd)
            result--;
        DoPortalRewind(portal);
        /* result is bogus if pos had overflowed, but it's best we can do */
        return result;
    }

    return PortalRunSelect(portal, forward, count, dest);
}

List* FetchPortalTargetList ( Portal  portal  ) 

Definition at line 357 of file pquery.c.

References FetchStatementTargetList(), PORTAL_MULTI_QUERY, PortalGetPrimaryStmt, and PortalData::strategy.

Referenced by exec_describe_portal_message(), FetchStatementTargetList(), and printtup_startup().

{
    /* 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));
}

List* FetchStatementTargetList ( Node stmt  ) 

Definition at line 379 of file pquery.c.

References Assert, CMD_SELECT, CMD_UTILITY, PlannedStmt::commandType, Query::commandType, FetchPortalTargetList(), FetchPreparedStatement(), FetchPreparedStatementTargetList(), GetPortalByName(), PlannedStmt::hasReturning, IsA, FetchStmt::ismove, ExecuteStmt::name, NULL, PlannedStmt::planTree, PortalIsValid, FetchStmt::portalname, Query::returningList, Plan::targetlist, Query::targetList, PlannedStmt::utilityStmt, and Query::utilityStmt.

Referenced by CachedPlanGetTargetList(), and FetchPortalTargetList().

{
    if (stmt == NULL)
        return NIL;
    if (IsA(stmt, Query))
    {
        Query      *query = (Query *) stmt;

        if (query->commandType == CMD_UTILITY &&
            query->utilityStmt != NULL)
        {
            /* transfer attention to utility statement */
            stmt = query->utilityStmt;
        }
        else
        {
            if (query->commandType == CMD_SELECT &&
                query->utilityStmt == 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->utilityStmt == NULL)
            return pstmt->planTree->targetlist;
        if (pstmt->hasReturning)
            return pstmt->planTree->targetlist;
        return NIL;
    }
    if (IsA(stmt, FetchStmt))
    {
        FetchStmt  *fstmt = (FetchStmt *) stmt;
        Portal      subportal;

        Assert(!fstmt->ismove);
        subportal = GetPortalByName(fstmt->portalname);
        Assert(PortalIsValid(subportal));
        return FetchPortalTargetList(subportal);
    }
    if (IsA(stmt, ExecuteStmt))
    {
        ExecuteStmt *estmt = (ExecuteStmt *) stmt;
        PreparedStatement *entry;

        entry = FetchPreparedStatement(estmt->name, true);
        return FetchPreparedStatementTargetList(entry);
    }
    return NIL;
}

static void FillPortalStore ( Portal  portal,
bool  isTopLevel 
) [static]

Definition at line 1030 of file pquery.c.

References PortalData::commandTag, CreateDestReceiver(), DestTuplestore, elog, ERROR, PortalData::holdContext, PortalData::holdStore, linitial, None_Receiver, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_UTIL_SELECT, PortalCreateHoldStore(), PortalRunMulti(), PortalRunUtility(), pstrdup(), _DestReceiver::rDestroy, SetTuplestoreDestReceiverParams(), PortalData::stmts, and PortalData::strategy.

Referenced by PortalRun(), and PortalRunFetch().

{
    DestReceiver *treceiver;
    char        completionTag[COMPLETION_TAG_BUFSIZE];

    PortalCreateHoldStore(portal);
    treceiver = CreateDestReceiver(DestTuplestore);
    SetTuplestoreDestReceiverParams(treceiver,
                                    portal->holdStore,
                                    portal->holdContext,
                                    false);

    completionTag[0] = '\0';

    switch (portal->strategy)
    {
        case PORTAL_ONE_RETURNING:
        case PORTAL_ONE_MOD_WITH:

            /*
             * Run the portal to completion just as for the default
             * MULTI_QUERY case, but send the primary query's output to the
             * tuplestore. Auxiliary query outputs are discarded.
             */
            PortalRunMulti(portal, isTopLevel,
                           treceiver, None_Receiver, completionTag);
            break;

        case PORTAL_UTIL_SELECT:
            PortalRunUtility(portal, (Node *) linitial(portal->stmts),
                             isTopLevel, treceiver, completionTag);
            break;

        default:
            elog(ERROR, "unsupported portal strategy: %d",
                 (int) portal->strategy);
            break;
    }

    /* Override default completion tag with actual command result */
    if (completionTag[0] != '\0')
        portal->commandTag = pstrdup(completionTag);

    (*treceiver->rDestroy) (treceiver);
}

void FreeQueryDesc ( QueryDesc qdesc  ) 
bool PortalRun ( Portal  portal,
long  count,
bool  isTopLevel,
DestReceiver dest,
DestReceiver altdest,
char *  completionTag 
)

Definition at line 705 of file pquery.c.

References AssertArg, PortalData::atEnd, PortalData::commandTag, COMPLETION_TAG_BUFSIZE, CurrentMemoryContext, CurrentResourceOwner, DEBUG3, elog, ereport, errcode(), errmsg(), ERROR, FillPortalStore(), PortalData::holdStore, log_executor_stats, MarkPortalDone(), MarkPortalFailed(), MemoryContextSwitchTo(), PortalData::name, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PORTAL_MULTI_QUERY, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_READY, PORTAL_UTIL_SELECT, PortalContext, PortalGetHeapMemory, PortalIsValid, PortalRunMulti(), PortalRunSelect(), ResetUsage(), PortalData::resowner, ShowUsage(), snprintf(), PortalData::status, PortalData::strategy, TopTransactionContext, and TopTransactionResourceOwner.

Referenced by exec_execute_message(), exec_simple_query(), and ExecuteQuery().

{
    bool        result;
    uint32      nprocessed;
    ResourceOwner saveTopTransactionResourceOwner;
    MemoryContext saveTopTransactionContext;
    Portal      saveActivePortal;
    ResourceOwner saveResourceOwner;
    MemoryContext savePortalContext;
    MemoryContext saveMemoryContext;

    AssertArg(PortalIsValid(portal));

    TRACE_POSTGRESQL_QUERY_EXECUTE_START();

    /* Initialize completion tag to empty string */
    if (completionTag)
        completionTag[0] = '\0';

    if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
    {
        elog(DEBUG3, "PortalRun");
        /* PORTAL_MULTI_QUERY logs its own stats per query */
        ResetUsage();
    }

    /*
     * Check for improper portal use, and mark portal active.
     */
    if (portal->status != PORTAL_READY)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("portal \"%s\" cannot be run", portal->name)));
    portal->status = PORTAL_ACTIVE;

    /*
     * Set up global portal context pointers.
     *
     * We have to play a special game here to support utility commands like
     * VACUUM and CLUSTER, which internally start and commit transactions.
     * When we are called to execute such a command, CurrentResourceOwner will
     * be pointing to the TopTransactionResourceOwner --- which will be
     * destroyed and replaced in the course of the internal commit and
     * restart.  So we need to be prepared to restore it as pointing to the
     * exit-time TopTransactionResourceOwner.  (Ain't that ugly?  This idea of
     * internally starting whole new transactions is not good.)
     * CurrentMemoryContext has a similar problem, but the other pointers we
     * save here will be NULL or pointing to longer-lived objects.
     */
    saveTopTransactionResourceOwner = TopTransactionResourceOwner;
    saveTopTransactionContext = TopTransactionContext;
    saveActivePortal = ActivePortal;
    saveResourceOwner = CurrentResourceOwner;
    savePortalContext = PortalContext;
    saveMemoryContext = CurrentMemoryContext;
    PG_TRY();
    {
        ActivePortal = portal;
        CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);

        MemoryContextSwitchTo(PortalContext);

        switch (portal->strategy)
        {
            case PORTAL_ONE_SELECT:
            case PORTAL_ONE_RETURNING:
            case PORTAL_ONE_MOD_WITH:
            case PORTAL_UTIL_SELECT:

                /*
                 * If we have not yet run the command, do so, storing its
                 * results in the portal's tuplestore.  But we don't do that
                 * for the PORTAL_ONE_SELECT case.
                 */
                if (portal->strategy != PORTAL_ONE_SELECT && !portal->holdStore)
                    FillPortalStore(portal, isTopLevel);

                /*
                 * Now fetch desired portion of results.
                 */
                nprocessed = PortalRunSelect(portal, true, count, dest);

                /*
                 * If the portal result contains a command tag and the caller
                 * gave us a pointer to store it, copy it. Patch the "SELECT"
                 * tag to also provide the rowcount.
                 */
                if (completionTag && portal->commandTag)
                {
                    if (strcmp(portal->commandTag, "SELECT") == 0)
                        snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
                                 "SELECT %u", nprocessed);
                    else
                        strcpy(completionTag, portal->commandTag);
                }

                /* Mark portal not active */
                portal->status = PORTAL_READY;

                /*
                 * Since it's a forward fetch, say DONE iff atEnd is now true.
                 */
                result = portal->atEnd;
                break;

            case PORTAL_MULTI_QUERY:
                PortalRunMulti(portal, isTopLevel,
                               dest, altdest, completionTag);

                /* Prevent portal's commands from being re-executed */
                MarkPortalDone(portal);

                /* Always complete at end of RunMulti */
                result = true;
                break;

            default:
                elog(ERROR, "unrecognized portal strategy: %d",
                     (int) portal->strategy);
                result = false; /* keep compiler quiet */
                break;
        }
    }
    PG_CATCH();
    {
        /* Uncaught error while executing portal: mark it dead */
        MarkPortalFailed(portal);

        /* Restore global vars and propagate error */
        if (saveMemoryContext == saveTopTransactionContext)
            MemoryContextSwitchTo(TopTransactionContext);
        else
            MemoryContextSwitchTo(saveMemoryContext);
        ActivePortal = saveActivePortal;
        if (saveResourceOwner == saveTopTransactionResourceOwner)
            CurrentResourceOwner = TopTransactionResourceOwner;
        else
            CurrentResourceOwner = saveResourceOwner;
        PortalContext = savePortalContext;

        PG_RE_THROW();
    }
    PG_END_TRY();

    if (saveMemoryContext == saveTopTransactionContext)
        MemoryContextSwitchTo(TopTransactionContext);
    else
        MemoryContextSwitchTo(saveMemoryContext);
    ActivePortal = saveActivePortal;
    if (saveResourceOwner == saveTopTransactionResourceOwner)
        CurrentResourceOwner = TopTransactionResourceOwner;
    else
        CurrentResourceOwner = saveResourceOwner;
    PortalContext = savePortalContext;

    if (log_executor_stats && portal->strategy != PORTAL_MULTI_QUERY)
        ShowUsage("EXECUTOR STATISTICS");

    TRACE_POSTGRESQL_QUERY_EXECUTE_DONE();

    return result;
}

long PortalRunFetch ( Portal  portal,
FetchDirection  fdirection,
long  count,
DestReceiver dest 
)

Definition at line 1383 of file pquery.c.

References AssertArg, CurrentResourceOwner, DoPortalRunFetch(), elog, ereport, errcode(), errmsg(), ERROR, FillPortalStore(), PortalData::holdStore, MarkPortalFailed(), MemoryContextSwitchTo(), PortalData::name, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_READY, PORTAL_UTIL_SELECT, PortalContext, PortalGetHeapMemory, PortalIsValid, PortalData::resowner, PortalData::status, and PortalData::strategy.

Referenced by _SPI_cursor_operation(), and PerformPortalFetch().

{
    long        result;
    Portal      saveActivePortal;
    ResourceOwner saveResourceOwner;
    MemoryContext savePortalContext;
    MemoryContext oldContext;

    AssertArg(PortalIsValid(portal));

    /*
     * Check for improper portal use, and mark portal active.
     */
    if (portal->status != PORTAL_READY)
        ereport(ERROR,
                (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                 errmsg("portal \"%s\" cannot be run", portal->name)));
    portal->status = PORTAL_ACTIVE;

    /*
     * Set up global portal context pointers.
     */
    saveActivePortal = ActivePortal;
    saveResourceOwner = CurrentResourceOwner;
    savePortalContext = PortalContext;
    PG_TRY();
    {
        ActivePortal = portal;
        CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);

        oldContext = MemoryContextSwitchTo(PortalContext);

        switch (portal->strategy)
        {
            case PORTAL_ONE_SELECT:
                result = DoPortalRunFetch(portal, fdirection, count, dest);
                break;

            case PORTAL_ONE_RETURNING:
            case PORTAL_ONE_MOD_WITH:
            case PORTAL_UTIL_SELECT:

                /*
                 * If we have not yet run the command, do so, storing its
                 * results in the portal's tuplestore.
                 */
                if (!portal->holdStore)
                    FillPortalStore(portal, false /* isTopLevel */ );

                /*
                 * Now fetch desired portion of results.
                 */
                result = DoPortalRunFetch(portal, fdirection, count, dest);
                break;

            default:
                elog(ERROR, "unsupported portal strategy");
                result = 0;     /* keep compiler quiet */
                break;
        }
    }
    PG_CATCH();
    {
        /* Uncaught error while executing portal: mark it dead */
        MarkPortalFailed(portal);

        /* Restore global vars and propagate error */
        ActivePortal = saveActivePortal;
        CurrentResourceOwner = saveResourceOwner;
        PortalContext = savePortalContext;

        PG_RE_THROW();
    }
    PG_END_TRY();

    MemoryContextSwitchTo(oldContext);

    /* Mark portal not active */
    portal->status = PORTAL_READY;

    ActivePortal = saveActivePortal;
    CurrentResourceOwner = saveResourceOwner;
    PortalContext = savePortalContext;

    return result;
}

static void PortalRunMulti ( Portal  portal,
bool  isTopLevel,
DestReceiver dest,
DestReceiver altdest,
char *  completionTag 
) [static]

Definition at line 1212 of file pquery.c.

References Assert, PlannedStmt::canSetTag, CHECK_FOR_INTERRUPTS, CommandCounterIncrement(), PortalData::commandTag, CurrentMemoryContext, DestRemoteExecute, GetTransactionSnapshot(), IsA, lfirst, list_length(), lnext, log_executor_stats, MemoryContextDeleteChildren(), _DestReceiver::mydest, None_Receiver, NULL, PopActiveSnapshot(), PortalGetHeapMemory, PortalData::portalParams, PortalRunUtility(), ProcessQuery(), PushActiveSnapshot(), ResetUsage(), ShowUsage(), PortalData::sourceText, PortalData::stmts, and UpdateActiveSnapshotCommandId().

Referenced by FillPortalStore(), and PortalRun().

{
    bool        active_snapshot_set = false;
    ListCell   *stmtlist_item;

    /*
     * If the destination is DestRemoteExecute, change to DestNone.  The
     * reason is that the client won't be expecting any tuples, and indeed has
     * no way to know what they are, since there is no provision for Describe
     * to send a RowDescription message when this portal execution strategy is
     * in effect.  This presently will only affect SELECT commands added to
     * non-SELECT queries by rewrite rules: such commands will be executed,
     * but the results will be discarded unless you use "simple Query"
     * protocol.
     */
    if (dest->mydest == DestRemoteExecute)
        dest = None_Receiver;
    if (altdest->mydest == DestRemoteExecute)
        altdest = None_Receiver;

    /*
     * Loop to handle the individual queries generated from a single parsetree
     * by analysis and rewrite.
     */
    foreach(stmtlist_item, portal->stmts)
    {
        Node       *stmt = (Node *) lfirst(stmtlist_item);

        /*
         * If we got a cancel signal in prior command, quit
         */
        CHECK_FOR_INTERRUPTS();

        if (IsA(stmt, PlannedStmt) &&
            ((PlannedStmt *) stmt)->utilityStmt == NULL)
        {
            /*
             * process a plannable query.
             */
            PlannedStmt *pstmt = (PlannedStmt *) stmt;

            TRACE_POSTGRESQL_QUERY_EXECUTE_START();

            if (log_executor_stats)
                ResetUsage();

            /*
             * Must always have a snapshot for plannable queries.  First time
             * through, take a new snapshot; for subsequent queries in the
             * same portal, just update the snapshot's copy of the command
             * counter.
             */
            if (!active_snapshot_set)
            {
                PushActiveSnapshot(GetTransactionSnapshot());
                active_snapshot_set = true;
            }
            else
                UpdateActiveSnapshotCommandId();

            if (pstmt->canSetTag)
            {
                /* statement can set tag string */
                ProcessQuery(pstmt,
                             portal->sourceText,
                             portal->portalParams,
                             dest, completionTag);
            }
            else
            {
                /* stmt added by rewrite cannot set tag */
                ProcessQuery(pstmt,
                             portal->sourceText,
                             portal->portalParams,
                             altdest, NULL);
            }

            if (log_executor_stats)
                ShowUsage("EXECUTOR STATISTICS");

            TRACE_POSTGRESQL_QUERY_EXECUTE_DONE();
        }
        else
        {
            /*
             * process utility functions (create, destroy, etc..)
             *
             * These are assumed canSetTag if they're the only stmt in the
             * portal.
             *
             * We must not set a snapshot here for utility commands (if one is
             * needed, PortalRunUtility will do it).  If a utility command is
             * alone in a portal then everything's fine.  The only case where
             * a utility command can be part of a longer list is that rules
             * are allowed to include NotifyStmt.  NotifyStmt doesn't care
             * whether it has a snapshot or not, so we just leave the current
             * snapshot alone if we have one.
             */
            if (list_length(portal->stmts) == 1)
            {
                Assert(!active_snapshot_set);
                /* statement can set tag string */
                PortalRunUtility(portal, stmt, isTopLevel,
                                 dest, completionTag);
            }
            else
            {
                Assert(IsA(stmt, NotifyStmt));
                /* stmt added by rewrite cannot set tag */
                PortalRunUtility(portal, stmt, isTopLevel,
                                 altdest, NULL);
            }
        }

        /*
         * Increment command counter between queries, but not after the last
         * one.
         */
        if (lnext(stmtlist_item) != NULL)
            CommandCounterIncrement();

        /*
         * Clear subsidiary contexts to recover temporary memory.
         */
        Assert(PortalGetHeapMemory(portal) == CurrentMemoryContext);

        MemoryContextDeleteChildren(PortalGetHeapMemory(portal));
    }

    /* Pop the snapshot if we pushed one. */
    if (active_snapshot_set)
        PopActiveSnapshot();

    /*
     * If a command completion tag was supplied, use it.  Otherwise use the
     * portal's commandTag as the default completion tag.
     *
     * Exception: Clients expect INSERT/UPDATE/DELETE tags to have counts, so
     * fake them with zeros.  This can happen with DO INSTEAD rules if there
     * is no replacement query of the same type as the original.  We print "0
     * 0" here because technically there is no query of the matching tag type,
     * and printing a non-zero count for a different query type seems wrong,
     * e.g.  an INSERT that does an UPDATE instead should not print "0 1" if
     * one row was updated.  See QueryRewrite(), step 3, for details.
     */
    if (completionTag && completionTag[0] == '\0')
    {
        if (portal->commandTag)
            strcpy(completionTag, portal->commandTag);
        if (strcmp(completionTag, "SELECT") == 0)
            sprintf(completionTag, "SELECT 0 0");
        else if (strcmp(completionTag, "INSERT") == 0)
            strcpy(completionTag, "INSERT 0 0");
        else if (strcmp(completionTag, "UPDATE") == 0)
            strcpy(completionTag, "UPDATE 0");
        else if (strcmp(completionTag, "DELETE") == 0)
            strcpy(completionTag, "DELETE 0");
    }
}

static long PortalRunSelect ( Portal  portal,
bool  forward,
long  count,
DestReceiver dest 
) [static]

Definition at line 890 of file pquery.c.

References Assert, PortalData::atEnd, PortalData::atStart, CURSOR_OPT_NO_SCROLL, PortalData::cursorOptions, QueryDesc::dest, ereport, errcode(), errhint(), errmsg(), ERROR, EState::es_processed, QueryDesc::estate, ExecutorRun(), FETCH_ALL, PortalData::holdStore, PopActiveSnapshot(), PortalGetQueryDesc, PortalData::portalPos, PortalData::posOverflow, PushActiveSnapshot(), RunFromStore(), ScanDirectionIsNoMovement, and QueryDesc::snapshot.

Referenced by DoPortalRunFetch(), and PortalRun().

{
    QueryDesc  *queryDesc;
    ScanDirection direction;
    uint32      nprocessed;

    /*
     * NB: queryDesc will be NULL if we are fetching from a held cursor or a
     * completed utility query; can't use it in that path.
     */
    queryDesc = PortalGetQueryDesc(portal);

    /* Caller messed up if we have neither a ready query nor held data. */
    Assert(queryDesc || portal->holdStore);

    /*
     * Force the queryDesc destination to the right thing.  This supports
     * MOVE, for example, which will pass in dest = DestNone.  This is okay to
     * change as long as we do it on every fetch.  (The Executor must not
     * assume that dest never changes.)
     */
    if (queryDesc)
        queryDesc->dest = dest;

    /*
     * Determine which direction to go in, and check to see if we're already
     * at the end of the available tuples in that direction.  If so, set the
     * direction to NoMovement to avoid trying to fetch any tuples.  (This
     * check exists because not all plan node types are robust about being
     * called again if they've already returned NULL once.)  Then call the
     * executor (we must not skip this, because the destination needs to see a
     * setup and shutdown even if no tuples are available).  Finally, update
     * the portal position state depending on the number of tuples that were
     * retrieved.
     */
    if (forward)
    {
        if (portal->atEnd || count <= 0)
            direction = NoMovementScanDirection;
        else
            direction = ForwardScanDirection;

        /* In the executor, zero count processes all rows */
        if (count == FETCH_ALL)
            count = 0;

        if (portal->holdStore)
            nprocessed = RunFromStore(portal, direction, count, dest);
        else
        {
            PushActiveSnapshot(queryDesc->snapshot);
            ExecutorRun(queryDesc, direction, count);
            nprocessed = queryDesc->estate->es_processed;
            PopActiveSnapshot();
        }

        if (!ScanDirectionIsNoMovement(direction))
        {
            long        oldPos;

            if (nprocessed > 0)
                portal->atStart = false;        /* OK to go backward now */
            if (count == 0 ||
                (unsigned long) nprocessed < (unsigned long) count)
                portal->atEnd = true;   /* we retrieved 'em all */
            oldPos = portal->portalPos;
            portal->portalPos += nprocessed;
            /* portalPos doesn't advance when we fall off the end */
            if (portal->portalPos < oldPos)
                portal->posOverflow = true;
        }
    }
    else
    {
        if (portal->cursorOptions & CURSOR_OPT_NO_SCROLL)
            ereport(ERROR,
                    (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
                     errmsg("cursor can only scan forward"),
                     errhint("Declare it with SCROLL option to enable backward scan.")));

        if (portal->atStart || count <= 0)
            direction = NoMovementScanDirection;
        else
            direction = BackwardScanDirection;

        /* In the executor, zero count processes all rows */
        if (count == FETCH_ALL)
            count = 0;

        if (portal->holdStore)
            nprocessed = RunFromStore(portal, direction, count, dest);
        else
        {
            PushActiveSnapshot(queryDesc->snapshot);
            ExecutorRun(queryDesc, direction, count);
            nprocessed = queryDesc->estate->es_processed;
            PopActiveSnapshot();
        }

        if (!ScanDirectionIsNoMovement(direction))
        {
            if (nprocessed > 0 && portal->atEnd)
            {
                portal->atEnd = false;  /* OK to go forward now */
                portal->portalPos++;    /* adjust for endpoint case */
            }
            if (count == 0 ||
                (unsigned long) nprocessed < (unsigned long) count)
            {
                portal->atStart = true; /* we retrieved 'em all */
                portal->portalPos = 0;
                portal->posOverflow = false;
            }
            else
            {
                long        oldPos;

                oldPos = portal->portalPos;
                portal->portalPos -= nprocessed;
                if (portal->portalPos > oldPos ||
                    portal->portalPos <= 0)
                    portal->posOverflow = true;
            }
        }
    }

    return nprocessed;
}

static void PortalRunUtility ( Portal  portal,
Node utilityStmt,
bool  isTopLevel,
DestReceiver dest,
char *  completionTag 
) [static]

Definition at line 1149 of file pquery.c.

References ActiveSnapshotSet(), DEBUG3, elog, GetTransactionSnapshot(), IsA, MemoryContextSwitchTo(), PopActiveSnapshot(), PortalGetHeapMemory, PortalData::portalParams, PROCESS_UTILITY_QUERY, PROCESS_UTILITY_TOPLEVEL, ProcessUtility(), PushActiveSnapshot(), and PortalData::sourceText.

Referenced by FillPortalStore(), and PortalRunMulti().

{
    bool        active_snapshot_set;

    elog(DEBUG3, "ProcessUtility");

    /*
     * Set snapshot if utility stmt needs one.  Most reliable way to do this
     * seems to be to enumerate those that do not need one; this is a short
     * list.  Transaction control, LOCK, and SET must *not* set a snapshot
     * since they need to be executable at the start of a transaction-snapshot
     * mode transaction without freezing a snapshot.  By extension we allow
     * SHOW not to set a snapshot.  The other stmts listed are just efficiency
     * hacks.  Beware of listing anything that can modify the database --- if,
     * say, it has to update an index with expressions that invoke
     * user-defined functions, then it had better have a snapshot.
     */
    if (!(IsA(utilityStmt, TransactionStmt) ||
          IsA(utilityStmt, LockStmt) ||
          IsA(utilityStmt, VariableSetStmt) ||
          IsA(utilityStmt, VariableShowStmt) ||
          IsA(utilityStmt, ConstraintsSetStmt) ||
    /* efficiency hacks from here down */
          IsA(utilityStmt, FetchStmt) ||
          IsA(utilityStmt, ListenStmt) ||
          IsA(utilityStmt, NotifyStmt) ||
          IsA(utilityStmt, UnlistenStmt) ||
          IsA(utilityStmt, CheckPointStmt)))
    {
        PushActiveSnapshot(GetTransactionSnapshot());
        active_snapshot_set = true;
    }
    else
        active_snapshot_set = false;

    ProcessUtility(utilityStmt,
                   portal->sourceText,
                   isTopLevel ? PROCESS_UTILITY_TOPLEVEL : PROCESS_UTILITY_QUERY,
                   portal->portalParams,
                   dest,
                   completionTag);

    /* Some utility statements may change context on us */
    MemoryContextSwitchTo(PortalGetHeapMemory(portal));

    /*
     * Some utility commands may pop the ActiveSnapshot stack from under us,
     * so we only pop the stack if we actually see a snapshot set.  Note that
     * the set of utility commands that do this must be the same set
     * disallowed to run inside a transaction; otherwise, we could be popping
     * a snapshot that belongs to some other operation.
     */
    if (active_snapshot_set && ActiveSnapshotSet())
        PopActiveSnapshot();
}

void PortalSetResultFormat ( Portal  portal,
int  nFormats,
int16 formats 
)

Definition at line 643 of file pquery.c.

References ereport, errcode(), errmsg(), ERROR, PortalData::formats, i, MemoryContextAlloc(), tupleDesc::natts, NULL, PortalGetHeapMemory, and PortalData::tupDesc.

Referenced by exec_bind_message(), and exec_simple_query().

{
    int         natts;
    int         i;

    /* Do nothing if portal won't return tuples */
    if (portal->tupDesc == NULL)
        return;
    natts = portal->tupDesc->natts;
    portal->formats = (int16 *)
        MemoryContextAlloc(PortalGetHeapMemory(portal),
                           natts * sizeof(int16));
    if (nFormats > 1)
    {
        /* format specified for each column */
        if (nFormats != natts)
            ereport(ERROR,
                    (errcode(ERRCODE_PROTOCOL_VIOLATION),
                     errmsg("bind message has %d result formats but query has %d columns",
                            nFormats, natts)));
        memcpy(portal->formats, formats, natts * sizeof(int16));
    }
    else if (nFormats > 0)
    {
        /* single format specified, use for all columns */
        int16       format1 = formats[0];

        for (i = 0; i < natts; i++)
            portal->formats[i] = format1;
    }
    else
    {
        /* use default format for all columns */
        for (i = 0; i < natts; i++)
            portal->formats[i] = 0;
    }
}

void PortalStart ( Portal  portal,
ParamListInfo  params,
int  eflags,
Snapshot  snapshot 
)

Definition at line 459 of file pquery.c.

References Assert, AssertArg, AssertState, PortalData::atEnd, PortalData::atStart, ChoosePortalStrategy(), CreateQueryDesc(), CurrentResourceOwner, CURSOR_OPT_SCROLL, PortalData::cursorOptions, EXEC_FLAG_REWIND, ExecCleanTypeFromTL(), ExecutorStart(), GetActiveSnapshot(), GetTransactionSnapshot(), InvalidSnapshot, IsA, linitial, MarkPortalFailed(), MemoryContextSwitchTo(), None_Receiver, PG_CATCH, PG_END_TRY, PG_RE_THROW, PG_TRY, PlannedStmt::planTree, PopActiveSnapshot(), PORTAL_DEFINED, PORTAL_MULTI_QUERY, PORTAL_ONE_MOD_WITH, PORTAL_ONE_RETURNING, PORTAL_ONE_SELECT, PORTAL_UTIL_SELECT, PortalContext, PortalGetHeapMemory, PortalGetPrimaryStmt, PortalIsValid, PortalData::portalParams, PortalData::portalPos, PortalData::posOverflow, PushActiveSnapshot(), PortalData::queryDesc, PortalData::resowner, PortalData::sourceText, PortalData::status, PortalData::stmts, PortalData::strategy, Plan::targetlist, QueryDesc::tupDesc, PortalData::tupDesc, and UtilityTupleDescriptor().

Referenced by exec_bind_message(), exec_simple_query(), ExecuteQuery(), PerformCursorOpen(), and SPI_cursor_open_internal().

{
    Portal      saveActivePortal;
    ResourceOwner saveResourceOwner;
    MemoryContext savePortalContext;
    MemoryContext oldContext;
    QueryDesc  *queryDesc;
    int         myeflags;

    AssertArg(PortalIsValid(portal));
    AssertState(portal->status == PORTAL_DEFINED);

    /*
     * Set up global portal context pointers.
     */
    saveActivePortal = ActivePortal;
    saveResourceOwner = CurrentResourceOwner;
    savePortalContext = PortalContext;
    PG_TRY();
    {
        ActivePortal = portal;
        CurrentResourceOwner = portal->resowner;
        PortalContext = PortalGetHeapMemory(portal);

        oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));

        /* Must remember portal param list, if any */
        portal->portalParams = params;

        /*
         * Determine the portal execution strategy
         */
        portal->strategy = ChoosePortalStrategy(portal->stmts);

        /*
         * Fire her up according to the strategy
         */
        switch (portal->strategy)
        {
            case PORTAL_ONE_SELECT:

                /* Must set snapshot before starting executor. */
                if (snapshot)
                    PushActiveSnapshot(snapshot);
                else
                    PushActiveSnapshot(GetTransactionSnapshot());

                /*
                 * Create QueryDesc in portal's context; for the moment, set
                 * the destination to DestNone.
                 */
                queryDesc = CreateQueryDesc((PlannedStmt *) linitial(portal->stmts),
                                            portal->sourceText,
                                            GetActiveSnapshot(),
                                            InvalidSnapshot,
                                            None_Receiver,
                                            params,
                                            0);

                /*
                 * If it's a scrollable cursor, executor needs to support
                 * REWIND and backwards scan, as well as whatever the caller
                 * might've asked for.
                 */
                if (portal->cursorOptions & CURSOR_OPT_SCROLL)
                    myeflags = eflags | EXEC_FLAG_REWIND | EXEC_FLAG_BACKWARD;
                else
                    myeflags = eflags;

                /*
                 * Call ExecutorStart to prepare the plan for execution
                 */
                ExecutorStart(queryDesc, myeflags);

                /*
                 * This tells PortalCleanup to shut down the executor
                 */
                portal->queryDesc = queryDesc;

                /*
                 * Remember tuple descriptor (computed by ExecutorStart)
                 */
                portal->tupDesc = queryDesc->tupDesc;

                /*
                 * Reset cursor position data to "start of query"
                 */
                portal->atStart = true;
                portal->atEnd = false;  /* allow fetches */
                portal->portalPos = 0;
                portal->posOverflow = false;

                PopActiveSnapshot();
                break;

            case PORTAL_ONE_RETURNING:
            case PORTAL_ONE_MOD_WITH:

                /*
                 * We don't start the executor until we are told to run the
                 * portal.  We do need to set up the result tupdesc.
                 */
                {
                    PlannedStmt *pstmt;

                    pstmt = (PlannedStmt *) PortalGetPrimaryStmt(portal);
                    Assert(IsA(pstmt, PlannedStmt));
                    portal->tupDesc =
                        ExecCleanTypeFromTL(pstmt->planTree->targetlist,
                                            false);
                }

                /*
                 * Reset cursor position data to "start of query"
                 */
                portal->atStart = true;
                portal->atEnd = false;  /* allow fetches */
                portal->portalPos = 0;
                portal->posOverflow = false;
                break;

            case PORTAL_UTIL_SELECT:

                /*
                 * We don't set snapshot here, because PortalRunUtility will
                 * take care of it if needed.
                 */
                {
                    Node       *ustmt = PortalGetPrimaryStmt(portal);

                    Assert(!IsA(ustmt, PlannedStmt));
                    portal->tupDesc = UtilityTupleDescriptor(ustmt);
                }

                /*
                 * Reset cursor position data to "start of query"
                 */
                portal->atStart = true;
                portal->atEnd = false;  /* allow fetches */
                portal->portalPos = 0;
                portal->posOverflow = false;
                break;

            case PORTAL_MULTI_QUERY:
                /* Need do nothing now */
                portal->tupDesc = NULL;
                break;
        }
    }
    PG_CATCH();
    {
        /* Uncaught error while executing portal: mark it dead */
        MarkPortalFailed(portal);

        /* Restore global vars and propagate error */
        ActivePortal = saveActivePortal;
        CurrentResourceOwner = saveResourceOwner;
        PortalContext = savePortalContext;

        PG_RE_THROW();
    }
    PG_END_TRY();

    MemoryContextSwitchTo(oldContext);

    ActivePortal = saveActivePortal;
    CurrentResourceOwner = saveResourceOwner;
    PortalContext = savePortalContext;

    portal->status = PORTAL_READY;
}

static void ProcessQuery ( PlannedStmt plan,
const char *  sourceText,
ParamListInfo  params,
DestReceiver dest,
char *  completionTag 
) [static]

Definition at line 160 of file pquery.c.

References CMD_DELETE, CMD_INSERT, CMD_SELECT, CMD_UPDATE, COMPLETION_TAG_BUFSIZE, CreateQueryDesc(), DEBUG3, elog, EState::es_lastoid, EState::es_processed, QueryDesc::estate, ExecutorEnd(), ExecutorFinish(), ExecutorRun(), ExecutorStart(), ForwardScanDirection, FreeQueryDesc(), GetActiveSnapshot(), InvalidSnapshot, QueryDesc::operation, and snprintf().

Referenced by PortalRunMulti().

{
    QueryDesc  *queryDesc;

    elog(DEBUG3, "ProcessQuery");

    /*
     * Create the QueryDesc object
     */
    queryDesc = CreateQueryDesc(plan, sourceText,
                                GetActiveSnapshot(), InvalidSnapshot,
                                dest, params, 0);

    /*
     * Call ExecutorStart to prepare the plan for execution
     */
    ExecutorStart(queryDesc, 0);

    /*
     * Run the plan to completion.
     */
    ExecutorRun(queryDesc, ForwardScanDirection, 0L);

    /*
     * Build command completion status string, if caller wants one.
     */
    if (completionTag)
    {
        Oid         lastOid;

        switch (queryDesc->operation)
        {
            case CMD_SELECT:
                snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
                         "SELECT %u", queryDesc->estate->es_processed);
                break;
            case CMD_INSERT:
                if (queryDesc->estate->es_processed == 1)
                    lastOid = queryDesc->estate->es_lastoid;
                else
                    lastOid = InvalidOid;
                snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
                   "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
                break;
            case CMD_UPDATE:
                snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
                         "UPDATE %u", queryDesc->estate->es_processed);
                break;
            case CMD_DELETE:
                snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
                         "DELETE %u", queryDesc->estate->es_processed);
                break;
            default:
                strcpy(completionTag, "???");
                break;
        }
    }

    /*
     * Now, we close down all the scans and free allocated resources.
     */
    ExecutorFinish(queryDesc);
    ExecutorEnd(queryDesc);

    FreeQueryDesc(queryDesc);
}

static uint32 RunFromStore ( Portal  portal,
ScanDirection  direction,
long  count,
DestReceiver dest 
) [static]

Definition at line 1089 of file pquery.c.

References CMD_SELECT, ExecClearTuple(), ExecDropSingleTupleTableSlot(), PortalData::holdContext, PortalData::holdStore, MakeSingleTupleTableSlot(), MemoryContextSwitchTo(), _DestReceiver::receiveSlot, _DestReceiver::rShutdown, _DestReceiver::rStartup, ScanDirectionIsForward, ScanDirectionIsNoMovement, PortalData::tupDesc, and tuplestore_gettupleslot().

Referenced by PortalRunSelect().

{
    long        current_tuple_count = 0;
    TupleTableSlot *slot;

    slot = MakeSingleTupleTableSlot(portal->tupDesc);

    (*dest->rStartup) (dest, CMD_SELECT, portal->tupDesc);

    if (ScanDirectionIsNoMovement(direction))
    {
        /* do nothing except start/stop the destination */
    }
    else
    {
        bool        forward = ScanDirectionIsForward(direction);

        for (;;)
        {
            MemoryContext oldcontext;
            bool        ok;

            oldcontext = MemoryContextSwitchTo(portal->holdContext);

            ok = tuplestore_gettupleslot(portal->holdStore, forward, false,
                                         slot);

            MemoryContextSwitchTo(oldcontext);

            if (!ok)
                break;

            (*dest->receiveSlot) (slot, dest);

            ExecClearTuple(slot);

            /*
             * check our tuple count.. if we've processed the proper number
             * then quit, else loop again and process more tuples. Zero count
             * means no limit.
             */
            current_tuple_count++;
            if (count && count == current_tuple_count)
                break;
        }
    }

    (*dest->rShutdown) (dest);

    ExecDropSingleTupleTableSlot(slot);

    return (uint32) current_tuple_count;
}


Variable Documentation

Definition at line 33 of file pquery.c.

Referenced by function_parse_error_transpose(), and PersistHoldablePortal().