T_TransactionStmt在PortalRunMulti -> PortalRunUtility -> ProcessUtility --> standard_ProcessUtility中处理,主要调用的是事务系统中上层系统中涉及到的函数,如下所示:
begin的处理流程比较特殊,我们以这个命令为列。需要从stmt->options取出transaction_isolation、transaction_read_only、transaction_deferrable,通过SetPGVariable函数设置相应的GUC参数。
BEGIN [ WORK | TRANSACTION ] [ transaction_mode [, ...] ]
where transaction_mode is one of:
ISOLATION LEVEL { SERIALIZABLE | REPEATABLE READ | READ COMMITTED | READ UNCOMMITTED }
READ WRITE | READ ONLY
[ NOT ] DEFERRABLE
BEGIN 启动一个事务块,即BEGIN 命令之后的所有语句都将在单个事务中执行,直到给出明确的 COMMIT 或 ROLLBACK。 默认情况下(没有BEGIN),PostgreSQL以“自动提交”模式执行事务,即每条语句都在自己的事务中执行,并在语句末尾隐式执行一次提交(如果执行成功,否则进行回滚)。
语句在事务块中执行得更快,因为事务启动/提交需要大量的 CPU 和磁盘活动。 在事务中执行多个语句也有助于确保在进行多个相关更改时的一致性:其他会话将无法看到并非所有相关更新都已完成的中间状态。
如果指定了隔离级别、读/写模式或延迟模式,则新事务具有这些特征,就好像执行了 SET TRANSACTION。
[ WORK | TRANSACTION ] Optional key words. They have no effect.
START TRANSACTION 具有与 BEGIN 相同的功能。使用 COMMIT 或 ROLLBACK 终止事务块。当已经在事务块内时发出 BEGIN 将引发警告消息。 事务状态不受影响。 要将事务嵌套在事务块中,请使用保存点。出于向后兼容性的原因,可以省略连续 transaction_modes 之间的逗号。
BEGIN 是 PostgreSQL 语言扩展。 它等效于 SQL 标准命令 START TRANSACTION,其参考页包含其他兼容性信息。DEFERRABLE transaction_mode 是 PostgreSQL 语言扩展。顺便说一下,BEGIN 关键字在嵌入式 SQL 中用于不同的目的。 建议您在移植数据库应用程序时注意事务语义。
case T_TransactionStmt: {
TransactionStmt *stmt = (TransactionStmt *) parsetree;
switch (stmt->kind) {
case TRANS_STMT_BEGIN: /* START TRANSACTION, as defined by SQL99: Identical to BEGIN. Same code for both. */
case TRANS_STMT_START:
ListCell *lc;
BeginTransactionBlock();
foreach(lc, stmt->options) {
DefElem *item = (DefElem *) lfirst(lc);
if (strcmp(item->defname, "transaction_isolation") == 0) SetPGVariable("transaction_isolation",list_make1(item->arg),true);
else if (strcmp(item->defname, "transaction_read_only") == 0) SetPGVariable("transaction_read_only",list_make1(item->arg), true);
else if (strcmp(item->defname, "transaction_deferrable") == 0) SetPGVariable("transaction_deferrable", list_make1(item->arg), true);
}
break;
case TRANS_STMT_COMMIT:
if (!EndTransactionBlock(stmt->chain)) {
if (completionTag) strcpy(completionTag, "ROLLBACK"); /* report unsuccessful commit in completionTag */
}
break;
case TRANS_STMT_PREPARE:
PreventCommandDuringRecovery("PREPARE TRANSACTION");
if (!PrepareTransactionBlock(stmt->gid)) {
if (completionTag) strcpy(completionTag, "ROLLBACK"); /* report unsuccessful commit in completionTag */
}
break;
case TRANS_STMT_COMMIT_PREPARED:
PreventInTransactionBlock(isTopLevel, "COMMIT PREPARED");
PreventCommandDuringRecovery("COMMIT PREPARED");
FinishPreparedTransaction(stmt->gid, true);
break;
case TRANS_STMT_ROLLBACK_PREPARED:
PreventInTransactionBlock(isTopLevel, "ROLLBACK PREPARED");
PreventCommandDuringRecovery("ROLLBACK PREPARED");
FinishPreparedTransaction(stmt->gid, false);
break;
case TRANS_STMT_ROLLBACK:
UserAbortTransactionBlock(stmt->chain);
break;
case TRANS_STMT_SAVEPOINT:
RequireTransactionBlock(isTopLevel, "SAVEPOINT");
DefineSavepoint(stmt->savepoint_name);
break;
case TRANS_STMT_RELEASE:
RequireTransactionBlock(isTopLevel, "RELEASE SAVEPOINT");
ReleaseSavepoint(stmt->savepoint_name);
break;
case TRANS_STMT_ROLLBACK_TO:
RequireTransactionBlock(isTopLevel, "ROLLBACK TO SAVEPOINT");
RollbackToSavepoint(stmt->savepoint_name);
/* CommitTransactionCommand is in charge of re-defining the savepoint again */
break;
}
}
break;
参考:https://www.postgresql.org/docs/12/sql-set-transaction.html