📄 pquery.c
字号:
/*------------------------------------------------------------------------- * * pquery.c * POSTGRES process query command code * * Portions Copyright (c) 1996-2005, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * * * IDENTIFICATION * $PostgreSQL: pgsql/src/backend/tcop/pquery.c,v 1.97.2.1 2005/11/22 18:23:20 momjian Exp $ * *------------------------------------------------------------------------- */#include "postgres.h"#include "commands/prepare.h"#include "commands/trigger.h"#include "executor/executor.h"#include "miscadmin.h"#include "tcop/tcopprot.h"#include "tcop/pquery.h"#include "tcop/utility.h"#include "utils/guc.h"#include "utils/memutils.h"/* * ActivePortal is the currently executing Portal (the most closely nested, * if there are several). */Portal ActivePortal = NULL;static void ProcessQuery(Query *parsetree, Plan *plan, ParamListInfo params, DestReceiver *dest, char *completionTag);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, DestReceiver *dest, char *completionTag);static void PortalRunMulti(Portal portal, DestReceiver *dest, DestReceiver *altdest, char *completionTag);static long DoPortalRunFetch(Portal portal, FetchDirection fdirection, long count, DestReceiver *dest);static void DoPortalRewind(Portal portal);/* * CreateQueryDesc */QueryDesc *CreateQueryDesc(Query *parsetree, Plan *plantree, Snapshot snapshot, Snapshot crosscheck_snapshot, DestReceiver *dest, ParamListInfo params, bool doInstrument){ 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->crosscheck_snapshot = crosscheck_snapshot; /* RI check snapshot */ qd->dest = dest; /* output dest */ qd->params = params; /* parameter values passed into query */ qd->doInstrument = doInstrument; /* instrumentation wanted? */ /* null these fields until set by ExecutorStart */ qd->tupDesc = NULL; qd->estate = NULL; qd->planstate = NULL; return qd;}/* * FreeQueryDesc */voidFreeQueryDesc(QueryDesc *qdesc){ /* Can't be a live query */ Assert(qdesc->estate == NULL); /* Only the QueryDesc itself need be freed */ pfree(qdesc);}/* * ProcessQuery * Execute a single plannable query within a PORTAL_MULTI_QUERY portal * * parsetree: the query tree * plan: the plan tree for the query * params: any parameters needed * dest: where to send results * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE * in which to store a command completion status string. * * completionTag may be NULL if caller doesn't want a status string. * * Must be called in a memory context that will be reset or deleted on * error; otherwise the executor's memory usage will be leaked. */static voidProcessQuery(Query *parsetree, Plan *plan, ParamListInfo params, DestReceiver *dest, char *completionTag){ int operation = parsetree->commandType; QueryDesc *queryDesc; ereport(DEBUG3, (errmsg_internal("ProcessQuery"))); /* * Check for special-case destinations */ if (operation == CMD_SELECT) { if (parsetree->into != NULL) { /* * SELECT INTO table (a/k/a CREATE AS ... SELECT). * * Override the normal communication destination; execMain.c * special-cases this case. (Perhaps would be cleaner to have an * additional destination type?) */ dest = None_Receiver; } } /* * Must always set snapshot for plannable queries. Note we assume that * caller will take care of restoring ActiveSnapshot on exit/error. */ ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); /* * Create the QueryDesc object */ queryDesc = CreateQueryDesc(parsetree, plan, ActiveSnapshot, InvalidSnapshot, dest, params, false); /* * Set up to collect AFTER triggers */ AfterTriggerBeginQuery(); /* * Call ExecStart to prepare the plan for execution */ ExecutorStart(queryDesc, false); /* * Run the plan to completion. */ ExecutorRun(queryDesc, ForwardScanDirection, 0L); /* * Build command completion status string, if caller wants one. */ if (completionTag) { Oid lastOid; switch (operation) { case CMD_SELECT: strcpy(completionTag, "SELECT"); 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 take care of any queued AFTER triggers */ AfterTriggerEndQuery(queryDesc->estate); /* * Now, we close down all the scans and free allocated resources. */ ExecutorEnd(queryDesc); FreeQueryDesc(queryDesc); FreeSnapshot(ActiveSnapshot); ActiveSnapshot = NULL;}/* * ChoosePortalStrategy * Select portal execution strategy given the intended query list. * * See the comments in portal.h. */PortalStrategyChoosePortalStrategy(List *parseTrees){ PortalStrategy strategy; strategy = PORTAL_MULTI_QUERY; /* default assumption */ if (list_length(parseTrees) == 1) { Query *query = (Query *) linitial(parseTrees); if (query->commandType == CMD_SELECT && query->canSetTag && query->into == NULL) strategy = PORTAL_ONE_SELECT; else if (query->commandType == CMD_UTILITY && query->canSetTag && query->utilityStmt != NULL) { if (UtilityReturnsTuples(query->utilityStmt)) strategy = PORTAL_UTIL_SELECT; } } return strategy;}/* * FetchPortalTargetList * Given a portal that returns tuples, extract the query targetlist. * 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_UTIL_SELECT) { Node *utilityStmt; utilityStmt = ((Query *) linitial(portal->parseTrees))->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;}/* * PortalStart * Prepare a portal for execution. * * Caller must already have created the portal, done PortalDefineQuery(), * and adjusted portal options if needed. If parameters are needed by * the query, they must be passed in here (caller is responsible for * giving them appropriate lifetime). * * The caller can optionally pass a snapshot to be used; pass InvalidSnapshot * for the normal behavior of setting a new snapshot. This parameter is * presently ignored for non-PORTAL_ONE_SELECT portals (it's only intended * to be used for cursors). * * On return, portal is ready to accept PortalRun() calls, and the result * tupdesc (if any) is known. */voidPortalStart(Portal portal, ParamListInfo params, Snapshot snapshot){ Portal saveActivePortal; Snapshot saveActiveSnapshot; ResourceOwner saveResourceOwner; MemoryContext savePortalContext; MemoryContext oldContext; QueryDesc *queryDesc; AssertArg(PortalIsValid(portal)); AssertState(portal->queryContext != NULL); /* query defined? */ AssertState(portal->status == PORTAL_NEW); /* else extra PortalStart */ /* * Set up global portal context pointers. (Should we set QueryContext?) */ saveActivePortal = ActivePortal; saveActiveSnapshot = ActiveSnapshot; saveResourceOwner = CurrentResourceOwner; savePortalContext = PortalContext; PG_TRY(); { ActivePortal = portal; ActiveSnapshot = NULL; /* will be set later */ 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->parseTrees); /* * Fire her up according to the strategy */ switch (portal->strategy) { case PORTAL_ONE_SELECT: /* * Must set snapshot before starting executor. Be sure to * copy it into the portal's context. */ if (snapshot) ActiveSnapshot = CopySnapshot(snapshot); else ActiveSnapshot = CopySnapshot(GetTransactionSnapshot()); /* * Create QueryDesc in portal's context; for the moment, set * the destination to DestNone. */ queryDesc = CreateQueryDesc((Query *) linitial(portal->parseTrees), (Plan *) linitial(portal->planTrees), ActiveSnapshot, InvalidSnapshot, None_Receiver, params, false); /* * We do *not* call AfterTriggerBeginQuery() here. We assume * that a SELECT cannot queue any triggers. It would be messy * to support triggers since the execution of the portal may * be interleaved with other queries. */ /* * Call ExecStart to prepare the plan for execution */ ExecutorStart(queryDesc, false); /* * 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; break; case PORTAL_UTIL_SELECT: /* * We don't set snapshot here, because PortalRunUtility will * take care of it if needed. */ portal->tupDesc = UtilityTupleDescriptor(((Query *) linitial(portal->parseTrees))->utilityStmt); /* * 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 */ portal->status = PORTAL_FAILED; /* Restore global vars and propagate error */ ActivePortal = saveActivePortal; ActiveSnapshot = saveActiveSnapshot; CurrentResourceOwner = saveResourceOwner; PortalContext = savePortalContext; PG_RE_THROW(); } PG_END_TRY(); MemoryContextSwitchTo(oldContext); ActivePortal = saveActivePortal; ActiveSnapshot = saveActiveSnapshot; CurrentResourceOwner = saveResourceOwner; PortalContext = savePortalContext; portal->status = PORTAL_READY;}/* * PortalSetResultFormat * Select the format codes for a portal's output. * * This must be run after PortalStart for a portal that will be read by * a DestRemote or DestRemoteExecute destination. It is not presently needed * for other destination types. * * formats[] is the client format request, as per Bind message conventions. */void
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -