From 1e08b93a108dba06e4b24a726b94b2a71ea46676 Mon Sep 17 00:00:00 2001 From: luozihao <1165977584@qq.com> Date: Wed, 30 Nov 2022 14:56:14 +0800 Subject: [PATCH] =?UTF-8?q?=E5=85=81=E8=AE=B8=E5=9C=A8B=E5=85=BC=E5=AE=B9?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E4=B8=8B=E5=B0=86autocommit=E8=AE=BE?= =?UTF-8?q?=E7=BD=AE=E4=B8=BAfalse=E5=B9=B6=E4=B8=BA=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=8F=90=E4=BA=A4=E5=85=B3=E9=97=AD=E6=8F=90=E4=BE=9B=E7=9B=B8?= =?UTF-8?q?=E5=BA=94=E7=9A=84=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../backend/utils/misc/guc/guc_storage.cpp | 22 +- src/gausskernel/process/tcop/postgres.cpp | 9 + .../storage/access/transam/xact.cpp | 20 ++ src/include/access/xact.h | 3 + src/test/regress/expected/autocommit_test.out | 243 ++++++++++++++++++ src/test/regress/parallel_schedule0 | 2 +- src/test/regress/sql/autocommit_test.sql | 121 +++++++++ 7 files changed, 415 insertions(+), 5 deletions(-) create mode 100644 src/test/regress/expected/autocommit_test.out create mode 100644 src/test/regress/sql/autocommit_test.sql diff --git a/src/common/backend/utils/misc/guc/guc_storage.cpp b/src/common/backend/utils/misc/guc/guc_storage.cpp index 027976653..521a9523f 100755 --- a/src/common/backend/utils/misc/guc/guc_storage.cpp +++ b/src/common/backend/utils/misc/guc/guc_storage.cpp @@ -170,6 +170,7 @@ static bool check_and_assign_catalog_oids(List* elemlist); static const char* show_archive_command(void); bool check_enable_gtm_free(bool* newval, void** extra, GucSource source); static bool check_phony_autocommit(bool* newval, void** extra, GucSource source); +static void assign_phony_autocommit(bool newval, void* extra); static bool check_enable_data_replicate(bool* newval, void** extra, GucSource source); static bool check_adio_debug_guc(bool* newval, void** extra, GucSource source); static bool check_adio_function_guc(bool* newval, void** extra, GucSource source); @@ -521,13 +522,14 @@ static void InitStorageConfigureNamesBool() PGC_USERSET, NODE_ALL, CLIENT_CONN_STATEMENT, - gettext_noop("This parameter doesn't do anything."), - gettext_noop("It's just here so that we won't choke on SET AUTOCOMMIT TO ON from 7.3-vintage clients."), + gettext_noop("This parameter is only used in B compatibility."), + gettext_noop("Otherwise, it's just here so that we won't choke on SET AUTOCOMMIT TO ON from 7.3-vintage clients.\n" + "This parameter is used to control whether the transactions are committed automatically in B compatibility."), GUC_NO_SHOW_ALL | GUC_NOT_IN_SAMPLE}, &u_sess->attr.attr_storage.phony_autocommit, true, check_phony_autocommit, - NULL, + assign_phony_autocommit, NULL}, /* * security requirements: system/ordinary users can not set current transaction to read-only, @@ -4656,7 +4658,7 @@ void InitializeNumLwLockPartitions(void) static bool check_phony_autocommit(bool* newval, void** extra, GucSource source) { - if (!*newval) { + if (!*newval && (!OidIsValid(u_sess->proc_cxt.MyDatabaseId) || !DB_IS_CMPT(B_FORMAT))) { GUC_check_errcode(ERRCODE_FEATURE_NOT_SUPPORTED); GUC_check_errmsg("SET AUTOCOMMIT TO OFF is no longer supported"); return false; @@ -4665,6 +4667,18 @@ static bool check_phony_autocommit(bool* newval, void** extra, GucSource source) return true; } + +static void assign_phony_autocommit(bool newval, void* extra) +{ + /* change autocommit from false to on */ + if (newval && u_sess->attr.attr_storage.phony_autocommit != newval) { + if (!IsTransactionDefaultState() && !EndTransactionBlock()) { + ereport(ERROR, (errmsg("end transaction failed"))); + } + } + return; +} + static bool check_enable_data_replicate(bool* newval, void** extra, GucSource source) { /* Always disable data replication in multi standbys mode */ diff --git a/src/gausskernel/process/tcop/postgres.cpp b/src/gausskernel/process/tcop/postgres.cpp index 37e5a8c4c..b957604cf 100755 --- a/src/gausskernel/process/tcop/postgres.cpp +++ b/src/gausskernel/process/tcop/postgres.cpp @@ -2713,6 +2713,9 @@ static void exec_simple_query(const char* query_string, MessageType messageType, ((ReindexStmt*)parsetree)->kind == OBJECT_DATABASE && IsPostmasterEnvironment) SetForceXidFromGTM(true); #endif + if (!u_sess->attr.attr_storage.phony_autocommit) { + BeginTxnForAutoCommitOff(); + } /* SQL bypass */ if (runOpfusionCheck) { (void)MemoryContextSwitchTo(oldcontext); @@ -9304,6 +9307,9 @@ int PostgresMain(int argc, char* argv[], const char* dbname, const char* usernam } } bool isQueryCompleted = false; + if (!u_sess->attr.attr_storage.phony_autocommit) { + BeginTxnForAutoCommitOff(); + } if (OpFusion::process(FUSION_EXECUTE, &input_message, completionTag, true, &isQueryCompleted)) { if(isQueryCompleted) { CommandCounterIncrement(); @@ -11222,6 +11228,9 @@ static void exec_batch_bind_execute(StringInfo input_message) * we are already in one. */ start_xact_command(); + if (!u_sess->attr.attr_storage.phony_autocommit) { + BeginTxnForAutoCommitOff(); + } if (ENABLE_WORKLOAD_CONTROL && SqlIsValid(t_thrd.postgres_cxt.debug_query_string) && (IS_PGXC_COORDINATOR || IS_SINGLE_NODE) && diff --git a/src/gausskernel/storage/access/transam/xact.cpp b/src/gausskernel/storage/access/transam/xact.cpp index 0773e66fb..6fdb04a52 100755 --- a/src/gausskernel/storage/access/transam/xact.cpp +++ b/src/gausskernel/storage/access/transam/xact.cpp @@ -8484,3 +8484,23 @@ static void AtEOXact_Proceed_PatchSeq() u_sess->opt_cxt.xact_modify_sql_patch = false; } } + +bool IsTransactionDefaultState() +{ + TransactionState s = CurrentTransactionState; + return s->blockState == TBLOCK_DEFAULT; +} + +bool IsTransactionInProgressState() +{ + TransactionState s = CurrentTransactionState; + return s->blockState == TBLOCK_INPROGRESS; +} + +void BeginTxnForAutoCommitOff() +{ + TransactionState s = CurrentTransactionState; + if (s->blockState == TBLOCK_STARTED) { + s->blockState = TBLOCK_INPROGRESS; + } +} diff --git a/src/include/access/xact.h b/src/include/access/xact.h index d98f8749d..0ff8a562d 100644 --- a/src/include/access/xact.h +++ b/src/include/access/xact.h @@ -464,4 +464,7 @@ extern void push_unlink_rel_to_hashtbl(ColFileNode *xnodes, int nrels); extern void XactCleanExceptionSubTransaction(SubTransactionId head); extern char* GetCurrentTransactionName(); extern List* GetTransactionList(List *head); +extern void BeginTxnForAutoCommitOff(); +extern bool IsTransactionInProgressState(); +extern bool IsTransactionDefaultState(); #endif /* XACT_H */ diff --git a/src/test/regress/expected/autocommit_test.out b/src/test/regress/expected/autocommit_test.out new file mode 100644 index 000000000..05ac4ec7f --- /dev/null +++ b/src/test/regress/expected/autocommit_test.out @@ -0,0 +1,243 @@ +CREATE DATABASE test_db DBCOMPATIBILITY 'B'; +\c test_db +SET autocommit = 1; +CREATE TABLE test_table (a text); +CREATE DATABASE test_drop; +INSERT INTO test_table values('aaaaa'); +SELECT * FROM test_table; + a +------- + aaaaa +(1 row) + +ROLLBACK; +NOTICE: there is no transaction in progress +SELECT * FROM test_table; + a +------- + aaaaa +(1 row) + +SET autocommit = 0; +-- DML +-- rollback the insert statement +INSERT INTO test_table values('bbbbb'); +SELECT * FROM test_table; + a +------- + aaaaa + bbbbb +(2 rows) + +ROLLBACK; +SELECT * FROM test_table; + a +------- + aaaaa +(1 row) + +-- commit the insert statement +INSERT INTO test_table values('ccccc'); +SELECT * FROM test_table; + a +------- + aaaaa + ccccc +(2 rows) + +COMMIT; +SELECT * FROM test_table; + a +------- + aaaaa + ccccc +(2 rows) + +-- commit the insert statement auto +INSERT INTO test_table values('ddddd'); +SELECT * FROM test_table; + a +------- + aaaaa + ccccc + ddddd +(3 rows) + +SET autocommit = 1; +SELECT * FROM test_table; + a +------- + aaaaa + ccccc + ddddd +(3 rows) + +SET autocommit = 0; +-- DDL +-- rollback the create table statement +CREATE TABLE test_a (a text); +INSERT INTO test_a values('aaaaa'); +SELECT * FROM test_a; + a +------- + aaaaa +(1 row) + +ROLLBACK; +SELECT * FROM test_a; +ERROR: relation "test_a" does not exist on datanode1 +LINE 1: SELECT * FROM test_a; + ^ +COMMIT; +-- commit the create table statement +CREATE TABLE test_b (a text); +INSERT INTO test_b values('aaaaa'); +SELECT * FROM test_b; + a +------- + aaaaa +(1 row) + +COMMIT; +SELECT * FROM test_b; + a +------- + aaaaa +(1 row) + +-- commit the create table statement auto +CREATE TABLE test_c (a text); +INSERT INTO test_c values('aaaaa'); +SELECT * FROM test_c; + a +------- + aaaaa +(1 row) + +SET autocommit = 1; +SELECT * FROM test_c; + a +------- + aaaaa +(1 row) + +-- prepare test +SET autocommit = 0; +INSERT INTO test_table values('eeeee'); +PREPARE TRANSACTION 'test_id'; +SET autocommit = 1; +SELECT * FROM test_table; + a +------- + aaaaa + ccccc + ddddd +(3 rows) + +COMMIT PREPARED 'test_id'; +SELECT * FROM test_table; + a +------- + aaaaa + ccccc + ddddd + eeeee +(4 rows) + +-- truncate the table test_table +TRUNCATE test_table; +SELECT * FROM test_table; + a +--- +(0 rows) + +ROLLBACK; +NOTICE: there is no transaction in progress +TRUNCATE test_table; +SELECT * FROM test_table; + a +--- +(0 rows) + +COMMIT; +WARNING: there is no transaction in progress +SELECT * FROM test_table; + a +--- +(0 rows) + +-- something statement could not execute in the transaction block +SET autocommit = 0; +START TRANSACTION; +WARNING: there is already a transaction in progress +BEGIN; +WARNING: there is already a transaction in progress +CREATE DATABASE test_error; +ERROR: CREATE DATABASE cannot run inside a transaction block +ROLLBACK; +VACUUM; +ERROR: VACUUM cannot run inside a transaction block +ROLLBACK; +DROP DATABASE test_drop; +ERROR: DROP DATABASE cannot run inside a transaction block +ROLLBACK; +CLUSTER test_table; +ERROR: CLUSTER cannot run inside a transaction block +ROLLBACK; +CREATE TABLESPACE gs_basebackup_tablespace relative LOCATION 'gs_basebackup_tablespace'; +ERROR: CREATE TABLESPACE cannot run inside a transaction block +ROLLBACK; +CREATE INDEX CONCURRENTLY ON test_table(a); +ERROR: CREATE INDEX CONCURRENTLY cannot run inside a transaction block +ROLLBACK; +REINDEX DATABASE test_db; +ERROR: REINDEX DATABASE cannot run inside a transaction block +ROLLBACK; +DROP DATABASE test_error; +ERROR: DROP DATABASE cannot run inside a transaction block +ROLLBACK; +DROP TABLESPACE test_space; +ERROR: DROP TABLESPACE cannot run inside a transaction block +ROLLBACK; +DROP INDEX test_index; +ERROR: index "test_index" does not exist +ROLLBACK; +REINDEX TABLE CONCURRENTLY test_table; +ERROR: REINDEX CONCURRENTLY cannot run inside a transaction block +-- test about set autocommit = 1 when the transaction is aborted +SET autocommit = 1; +ERROR: current transaction is aborted, commands ignored until end of transaction block, firstChar[Q] +ROLLBACK; +-- set autocommit = 0 in a transaction block +SET autocommit = 1; +TRUNCATE test_table; +BEGIN; +INSERT INTO test_table values('aaaaa'); +SET autocommit = 0; +SET autocommit = 1; +SHOW autocommit; + autocommit +------------ + on +(1 row) + +SELECT * FROM test_table; + a +------- + aaaaa +(1 row) + +-- only set autocommit = 1 cannot commit transaction +BEGIN; +INSERT INTO test_table values('bbbbb'); +SET autocommit = 1; +ROLLBACK; +SELECT * FROM test_table; + a +------- + aaaaa +(1 row) + +\c regression +DROP DATABASE test_db; +DROP DATABASE test_drop; diff --git a/src/test/regress/parallel_schedule0 b/src/test/regress/parallel_schedule0 index 2b348de77..22aa63edd 100644 --- a/src/test/regress/parallel_schedule0 +++ b/src/test/regress/parallel_schedule0 @@ -189,7 +189,7 @@ test: single_node_select_implicit single_node_select_having test: single_node_union #test: single_node_case single_node_join single_node_aggregates #test: single_node_transactions -test: single_node_random transactions_test +test: single_node_random transactions_test autocommit_test #test: single_node_portals #test: single_node_arrays #test: single_node_btree_index single_node_hash_index single_node_update diff --git a/src/test/regress/sql/autocommit_test.sql b/src/test/regress/sql/autocommit_test.sql new file mode 100644 index 000000000..1d4d6e172 --- /dev/null +++ b/src/test/regress/sql/autocommit_test.sql @@ -0,0 +1,121 @@ +CREATE DATABASE test_db DBCOMPATIBILITY 'B'; +\c test_db +SET autocommit = 1; +CREATE TABLE test_table (a text); +CREATE DATABASE test_drop; +INSERT INTO test_table values('aaaaa'); +SELECT * FROM test_table; +ROLLBACK; +SELECT * FROM test_table; + +SET autocommit = 0; +-- DML +-- rollback the insert statement +INSERT INTO test_table values('bbbbb'); +SELECT * FROM test_table; +ROLLBACK; +SELECT * FROM test_table; + +-- commit the insert statement +INSERT INTO test_table values('ccccc'); +SELECT * FROM test_table; +COMMIT; +SELECT * FROM test_table; + +-- commit the insert statement auto +INSERT INTO test_table values('ddddd'); +SELECT * FROM test_table; +SET autocommit = 1; +SELECT * FROM test_table; + +SET autocommit = 0; +-- DDL +-- rollback the create table statement +CREATE TABLE test_a (a text); +INSERT INTO test_a values('aaaaa'); +SELECT * FROM test_a; +ROLLBACK; +SELECT * FROM test_a; +COMMIT; + +-- commit the create table statement +CREATE TABLE test_b (a text); +INSERT INTO test_b values('aaaaa'); +SELECT * FROM test_b; +COMMIT; +SELECT * FROM test_b; + +-- commit the create table statement auto +CREATE TABLE test_c (a text); +INSERT INTO test_c values('aaaaa'); +SELECT * FROM test_c; +SET autocommit = 1; +SELECT * FROM test_c; + +-- prepare test +SET autocommit = 0; +INSERT INTO test_table values('eeeee'); +PREPARE TRANSACTION 'test_id'; +SET autocommit = 1; +SELECT * FROM test_table; +COMMIT PREPARED 'test_id'; +SELECT * FROM test_table; + +-- truncate the table test_table +TRUNCATE test_table; +SELECT * FROM test_table; +ROLLBACK; +TRUNCATE test_table; +SELECT * FROM test_table; +COMMIT; +SELECT * FROM test_table; + +-- something statement could not execute in the transaction block +SET autocommit = 0; +START TRANSACTION; +BEGIN; +CREATE DATABASE test_error; +ROLLBACK; +VACUUM; +ROLLBACK; +DROP DATABASE test_drop; +ROLLBACK; +CLUSTER test_table; +ROLLBACK; +CREATE TABLESPACE gs_basebackup_tablespace relative LOCATION 'gs_basebackup_tablespace'; +ROLLBACK; +CREATE INDEX CONCURRENTLY ON test_table(a); +ROLLBACK; +REINDEX DATABASE test_db; +ROLLBACK; +DROP DATABASE test_error; +ROLLBACK; +DROP TABLESPACE test_space; +ROLLBACK; +DROP INDEX test_index; +ROLLBACK; +REINDEX TABLE CONCURRENTLY test_table; +-- test about set autocommit = 1 when the transaction is aborted +SET autocommit = 1; +ROLLBACK; + +-- set autocommit = 0 in a transaction block +SET autocommit = 1; +TRUNCATE test_table; +BEGIN; +INSERT INTO test_table values('aaaaa'); +SET autocommit = 0; +SET autocommit = 1; +SHOW autocommit; +SELECT * FROM test_table; + +-- only set autocommit = 1 cannot commit transaction +BEGIN; +INSERT INTO test_table values('bbbbb'); +SET autocommit = 1; +ROLLBACK; +SELECT * FROM test_table; + +\c regression +DROP DATABASE test_db; +DROP DATABASE test_drop;