BeginImplicitTransactionBlock函数启动一个隐含事务块,和BeginTransactionBlock不一样,BeginImplicitTransactionBlock是从postgres.c的main loop直接调用的而不是通过Portal。所以我们仅改变事务状态块,也不期望调用者调用CommitTransactionCommand/StartTransactionCommand。
void BeginImplicitTransactionBlock(void) { TransactionState s = CurrentTransactionState; /* If we are in STARTED state (that is, no transaction block is open), * switch to IMPLICIT_INPROGRESS state, creating an implicit transaction * block. * For caller convenience, we consider all other transaction states as * legal here; otherwise the caller would need its own state check, which * seems rather pointless. */ if (s->blockState == TBLOCK_STARTED) s->blockState = TBLOCK_IMPLICIT_INPROGRESS; } static void start_xact_command(void) { if (!xact_started) { StartTransactionCommand(); xact_started = true; } /* Start statement timeout if necessary. Note that this'll intentionally not reset the clock on an already started timeout, to avoid the timing overhead when start_xact_command() is invoked repeatedly, without an interceding finish_xact_command() (e.g. parse/bind/execute). If that's not desired, the timeout has to be disabled explicitly. */ enable_statement_timeout(); }
调用处在于exec_simple_query函数:
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 use_implicit_block; 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); /* For historical reasons, if multiple SQL statements are given in a * single "simple Query" message, we execute them as a single transaction, * unless explicit transaction control commands are included to make * portions of the list be separate transactions. To represent this * behavior properly in the transaction machinery, we use an "implicit" * transaction block. */ use_implicit_block = (list_length(parsetree_list) > 1); /* Run through the raw parsetree(s) and process each one. */ foreach(parsetree_item, parsetree_list) { RawStmt *parsetree = lfirst_node(RawStmt, 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->stmt); set_ps_display(commandTag, false); BeginCommand(commandTag, dest); /* 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->stmt)) 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 using an implicit transaction block, and we're not already in a * transaction block, start an implicit block to force this statement * to be grouped together with any following ones. (We must do this * each time through the loop; otherwise, a COMMIT/ROLLBACK in the * list would cause later statements to not be grouped.) */ if (use_implicit_block) BeginImplicitTransactionBlock();