您的位置:首页 > 数据库

PostgreSQL在何处处理 sql查询之二

2013-05-22 08:16 417 查看
在exec_simple_query中,代码如下:

/*
* exec_simple_query
*
* Execute a "simple Query" protocol message.
*/
static void
exec_simple_query(const char *query_string)
{
CommandDest dest = whereToSendOutput;
MemoryContext oldcontext;
List       *parsetree_list;
ListCell   *parsetree_item;

bool        save_log_statement_stats = log_statement_stats;
bool        was_logged = false;
bool        isTopLevel;
char        msec_str[32];

/*
* Report query to various monitoring facilities.
*/
debug_query_string = query_string;

pgstat_report_activity(STATE_RUNNING, query_string);

TRACE_POSTGRESQL_QUERY_START(query_string);

/*
* We use save_log_statement_stats so ShowUsage doesn't report incorrect
* results because ResetUsage wasn't called.
*/
if (save_log_statement_stats)
ResetUsage();

/*
* Start up a transaction command.    All queries generated by the
* query_string will be in this same command block, *unless* we find a
* BEGIN/COMMIT/ABORT statement; we have to force a new xact command after
* one of those, else bad things will happen in xact.c. (Note that this
* will normally change current memory context.)
*/
start_xact_command();

/*
* Zap any pre-existing unnamed statement.    (While not strictly necessary,
* it seems best to define simple-Query mode as if it used the unnamed
* statement and portal; this ensures we recover any storage used by prior
* unnamed operations.)
*/
drop_unnamed_stmt();

/*
* Switch to appropriate context for constructing parsetrees.
*/
oldcontext = MemoryContextSwitchTo(MessageContext);

/*
* Do basic parsing of the query or queries (this should be safe even if
* we are in aborted transaction state!)
*/
parsetree_list = pg_parse_query(query_string);

/* Log immediately if dictated by log_statement */
if (check_log_statement(parsetree_list))
{
ereport(LOG,
(errmsg("statement: %s", query_string),
errhidestmt(true),
errdetail_execute(parsetree_list)));
was_logged = true;
}

/*
* Switch back to transaction context to enter the loop.
*/
MemoryContextSwitchTo(oldcontext);

/*
* We'll tell PortalRun it's a top-level command iff there's exactly one
* raw parsetree.  If more than one, it's effectively a transaction block
* and we want PreventTransactionChain to reject unsafe commands. (Note:
* we're assuming that query rewrite cannot add commands that are
* significant to PreventTransactionChain.)
*/
isTopLevel = (list_length(parsetree_list) == 1);

/*
* Run through the raw parsetree(s) and process each one.
*/
foreach(parsetree_item, parsetree_list)
{
Node       *parsetree = (Node *) lfirst(parsetree_item);

bool        snapshot_set = false;
const char *commandTag;
char        completionTag[COMPLETION_TAG_BUFSIZE];
List       *querytree_list,
*plantree_list;
Portal        portal;
DestReceiver *receiver;
int16        format;

/*
* Get the command name for use in status display (it also becomes the
* default completion tag, down inside PortalRun).    Set ps_status and
* do any special start-of-SQL-command processing needed by the
* destination.
*/
commandTag = CreateCommandTag(parsetree);

//fprintf(stderr,"commandTag is :%s\n",commandTag);

set_ps_display(commandTag, false);

BeginCommand(commandTag, dest);

//fprintf(stderr,"BeginCommand finished.\n");

/*
* If we are in an aborted transaction, reject all commands except
* COMMIT/ABORT.  It is important that this test occur before we try
* to do parse analysis, rewrite, or planning, since all those phases
* try to do database accesses, which may fail in abort state. (It
* might be safe to allow some additional utility commands in this
* state, but not many...)
*/
if (IsAbortedTransactionBlockState() &&
!IsTransactionExitStmt(parsetree))
ereport(ERROR,
(errcode(ERRCODE_IN_FAILED_SQL_TRANSACTION),
errmsg("current transaction is aborted, "
"commands ignored until end of transaction block"),
errdetail_abort()));

/* Make sure we are in a transaction command */
start_xact_command();

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

/*
* Set up a snapshot if parse analysis/planning will need one.
*/
if (analyze_requires_snapshot(parsetree))
{
PushActiveSnapshot(GetTransactionSnapshot());
snapshot_set = true;
}

/*
* OK to analyze, rewrite, and plan this query.
*
* Switch to appropriate context for constructing querytrees (again,
* these must outlive the execution context).
*/
oldcontext = MemoryContextSwitchTo(MessageContext);

querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
NULL, 0);

plantree_list = pg_plan_queries(querytree_list, 0, NULL);

/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();

/*
* Create unnamed portal to run the query or queries in. If there
* already is one, silently drop it.
*/
portal = CreatePortal("", true, true);
/* Don't display the portal in pg_cursors */
portal->visible = false;

/*
* We don't have to copy anything into the portal, because everything
* we are passing here is in MessageContext, which will outlive the
* portal anyway.
*/
PortalDefineQuery(portal,
NULL,
query_string,
commandTag,
plantree_list,
NULL);

/*
* Start the portal.
*
* If we took a snapshot for parsing/planning, the portal may be able
* to reuse it for the execution phase.  Currently, this will only
* happen in PORTAL_ONE_SELECT mode.  But even if PortalStart doesn't
* end up being able to do this, keeping the parse/plan snapshot
* around until after we start the portal doesn't cost much.
*/
PortalStart(portal, NULL, 0, snapshot_set);

/* Done with the snapshot used for parsing/planning */
if (snapshot_set)
PopActiveSnapshot();

/*
* Select the appropriate output format: text unless we are doing a
* FETCH from a binary cursor.    (Pretty grotty to have to do this here
* --- but it avoids grottiness in other places.  Ah, the joys of
* backward compatibility...)
*/
format = 0;                /* TEXT is default */
if (IsA(parsetree, FetchStmt))
{
FetchStmt  *stmt = (FetchStmt *) parsetree;

if (!stmt->ismove)
{
Portal        fportal = GetPortalByName(stmt->portalname);

if (PortalIsValid(fportal) &&
(fportal->cursorOptions & CURSOR_OPT_BINARY))
format = 1; /* BINARY */
}
}
PortalSetResultFormat(portal, 1, &format);

/*
* Now we can create the destination receiver object.
*/
receiver = CreateDestReceiver(dest);
if (dest == DestRemote)
SetRemoteDestReceiverParams(receiver, portal);

/*
* Switch back to transaction context for execution.
*/
MemoryContextSwitchTo(oldcontext);

/*
* Run the portal to completion, and then drop it (and the receiver).
*/
(void) PortalRun(portal,
FETCH_ALL,
isTopLevel,
receiver,
receiver,
completionTag);

(*receiver->rDestroy) (receiver);

PortalDrop(portal, false);

if (IsA(parsetree, TransactionStmt))
{
/*
* If this was a transaction control statement, commit it. We will
* start a new xact command for the next command (if any).
*/
finish_xact_command();
}
else if (lnext(parsetree_item) == NULL)
{
/*
* If this is the last parsetree of the query string, close down
* transaction statement before reporting command-complete.  This
* is so that any end-of-transaction errors are reported before
* the command-complete message is issued, to avoid confusing
* clients who will expect either a command-complete message or an
* error, not one and then the other.  But for compatibility with
* historical Postgres behavior, we do not force a transaction
* boundary between queries appearing in a single query string.
*/
finish_xact_command();
}
else
{
/*
* We need a CommandCounterIncrement after every query, except
* those that start or end a transaction block.
*/
CommandCounterIncrement();
}

/*
* Tell client that we're done with this query.  Note we emit exactly
* one EndCommand report for each raw parsetree, thus one for each SQL
* command the client sent, regardless of rewriting. (But a command
* aborted by error will not send an EndCommand report at all.)
*/
EndCommand(completionTag, dest);
}                            /* end loop over parsetrees */

/*
* Close down transaction statement, if one is open.
*/
finish_xact_command();

/*
* If there were no parsetrees, return EmptyQueryResponse message.
*/
if (!parsetree_list)
NullCommand(dest);

/*
* Emit duration logging if appropriate.
*/
switch (check_log_duration(msec_str, was_logged))
{
case 1:
ereport(LOG,
(errmsg("duration: %s ms", msec_str),
errhidestmt(true)));
break;
case 2:
ereport(LOG,
(errmsg("duration: %s ms  statement: %s",
msec_str, query_string),
errhidestmt(true),
errdetail_execute(parsetree_list)));
break;
}

if (save_log_statement_stats)
ShowUsage("QUERY STATISTICS");

TRACE_POSTGRESQL_QUERY_DONE(query_string);

debug_query_string = NULL;

}


其中,从 portal = CreatePortal("", true, true); 这一句开始,就是准备要执行了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: