允许在B兼容模式下将autocommit设置为false并为自动提交关闭提供相应的功能
This commit is contained in:
@ -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 */
|
||||
|
||||
@ -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) &&
|
||||
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -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 */
|
||||
|
||||
243
src/test/regress/expected/autocommit_test.out
Normal file
243
src/test/regress/expected/autocommit_test.out
Normal file
@ -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;
|
||||
@ -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
|
||||
|
||||
121
src/test/regress/sql/autocommit_test.sql
Normal file
121
src/test/regress/sql/autocommit_test.sql
Normal file
@ -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;
|
||||
Reference in New Issue
Block a user