# Transaction involving schema changes.
statement ok
BEGIN TRANSACTION

statement ok
CREATE TABLE kv (
  k VARCHAR PRIMARY KEY,
  v VARCHAR
)

statement ok
INSERT INTO kv (k,v) VALUES ('a', 'b')

query TT
SELECT * FROM kv
----
a b

statement ok
COMMIT TRANSACTION

# A transaction to update kv.

statement ok
BEGIN TRANSACTION

statement ok
UPDATE kv SET v = 'c' WHERE k in ('a')

query TT
SELECT * FROM kv
----
a c

statement ok
COMMIT TRANSACTION

query TT
SELECT * FROM kv
----
a c

# Rollback a transaction before committing.

statement ok
BEGIN TRANSACTION

statement ok
UPDATE kv SET v = 'b' WHERE k in ('a')

query TT
SELECT * FROM kv
----
a b

statement ok
ROLLBACK TRANSACTION

query TT
SELECT * FROM kv
----
a c

# Statement execution should not depend on request boundaries.

statement ok
BEGIN TRANSACTION; UPDATE kv SET v = 'b' WHERE k in ('a')

query TT
SELECT * FROM kv
----
a b

query TT
SELECT * FROM kv; COMMIT; BEGIN; UPDATE kv SET v = 'd' WHERE k in ('a')
----
a b

query TT
SELECT * FROM kv; UPDATE kv SET v = 'c' WHERE k in ('a'); COMMIT
----
a d

query TT
SELECT * FROM kv
----
a c

# Abort transaction with a syntax error, and ignore statements until the end of the transaction block

statement ok
BEGIN

query error at or near ",": syntax error
SELECT count(*, 1) FROM kv

statement error pgcode 25P02 current transaction is aborted, commands ignored until end of transaction block
UPDATE kv SET v = 'b' WHERE k in ('a')

statement ok
ROLLBACK

query TT
SELECT * FROM kv
----
a c

# Abort transaction with a problematic statement, and ignore statements until
# the end of the transaction block (a COMMIT/ROLLBACK statement as the first
# statement in a batch).

statement ok
BEGIN

statement error duplicate key value violates unique constraint "kv_pkey"\nDETAIL: Key \(k\)=\('a'\) already exists\.
INSERT INTO kv VALUES('unique_key', 'some value');
INSERT INTO kv VALUES('a', 'c');
INSERT INTO kv VALUES('unique_key2', 'some value');
COMMIT

# Txn is still aborted.
statement error current transaction is aborted, commands ignored until end of transaction block
UPDATE kv SET v = 'b' WHERE k in ('a')

# Txn is still aborted.
statement error current transaction is aborted, commands ignored until end of transaction block
UPDATE kv SET v = 'b' WHERE k in ('a')

# Now the transaction will be ended. After that, statements execute.
statement ok
COMMIT;
INSERT INTO kv VALUES('x', 'y')

query TT rowsort
SELECT * FROM kv
----
a c
x y

# Two BEGINs in a row.

statement ok
BEGIN TRANSACTION

statement error pgcode 25001 there is already a transaction in progress
BEGIN TRANSACTION

statement ok
ROLLBACK TRANSACTION

# BEGIN in the middle of a transaction is an error.

statement ok
BEGIN TRANSACTION

statement ok
UPDATE kv SET v = 'b' WHERE k in ('a')

statement error pgcode 25001 there is already a transaction in progress
BEGIN TRANSACTION

statement error pgcode 25P02 current transaction is aborted, commands ignored until end of transaction block
SELECT * FROM kv

statement ok
ROLLBACK TRANSACTION

# An empty transaction is allowed.

statement ok
BEGIN; COMMIT

# END is same as commit
statement ok
BEGIN; END

# COMMIT/ROLLBACK without a transaction are errors.

statement error pgcode 25P01 there is no transaction in progress
COMMIT TRANSACTION

statement error pgcode 25P01 there is no transaction in progress
ROLLBACK TRANSACTION

# Set isolation level without a transaction is an error.

statement error pgcode 25P01 there is no transaction in progress
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

statement ok
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ; COMMIT

onlyif config enterprise-configs
query T noticetrace
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED
----

skipif config enterprise-configs
query T noticetrace
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED
----
NOTICE: READ COMMITTED isolation level is not allowed without an enterprise license; upgrading to SERIALIZABLE

statement ok
COMMIT

statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE; COMMIT

statement ok
BEGIN TRANSACTION; SET TRANSACTION ISOLATION LEVEL REPEATABLE READ; COMMIT

statement ok
BEGIN TRANSACTION; SET TRANSACTION ISOLATION LEVEL SERIALIZABLE; COMMIT

statement ok
BEGIN TRANSACTION

onlyif config enterprise-configs
query T noticetrace
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
----

skipif config enterprise-configs
query T noticetrace
SET TRANSACTION ISOLATION LEVEL READ COMMITTED
----
NOTICE: READ COMMITTED isolation level is not allowed without an enterprise license; upgrading to SERIALIZABLE

statement ok
COMMIT

# It is an error to change the isolation level of a running transaction.

statement ok
BEGIN TRANSACTION

statement ok
UPDATE kv SET v = 'b' WHERE k in ('a')

onlyif config enterprise-configs
skipif config weak-iso-level-configs
statement error pgcode 25001 cannot change the isolation level of a running transaction
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

onlyif config weak-iso-level-configs
statement error pgcode 25001 cannot change the isolation level of a running transaction
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

statement ok
ROLLBACK

statement ok
BEGIN TRANSACTION

statement ok
SELECT * FROM kv LIMIT 1

onlyif config enterprise-configs
skipif config weak-iso-level-configs
statement error pgcode 25001 cannot change the isolation level of a running transaction
SET transaction_isolation = 'READ COMMITTED'

onlyif config weak-iso-level-configs
statement error pgcode 25001 cannot change the isolation level of a running transaction
SET transaction_isolation = 'SERIALIZABLE'

statement ok
ROLLBACK

statement ok
SET CLUSTER SETTING sql.txn.read_committed_isolation.enabled = false

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = false

# Transactions default to serializable when the read_committed and
# repeatable_read cluster settings are off.

statement ok
BEGIN TRANSACTION

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW transaction_isolation
----
serializable

# READ COMMITTED is mapped to serializable by default.
statement ok
SET TRANSACTION ISOLATION LEVEL READ COMMITTED

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

# REPEATABLE READ is now mapped to serializable
statement ok
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW transaction_isolation
----
serializable

statement ok
COMMIT

statement ok
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
COMMIT

# Since read_committed_isolation.enabled and repeatable_read_isolation.enabled
# are both false, setting isolation level to READ COMMITTED should map to
# SERIALIZABLE.
statement ok
SET default_transaction_isolation = 'read committed'

query T
SHOW default_transaction_isolation
----
serializable

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED

query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = true

# Since read_committed_isolation.enabled is false but repeatable_read_isolation.enabled
# is true, setting isolation level to READ COMMITTED should map to REPEATABLE READ.
statement ok
SET default_transaction_isolation = 'read committed'

onlyif config enterprise-configs
query T
SHOW default_transaction_isolation
----
repeatable read

skipif config enterprise-configs
query T
SHOW default_transaction_isolation
----
serializable

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED

onlyif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
repeatable read

skipif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

# Since repeatable_read_isolation.enabled is true, REPEATABLE READ can be used.
statement ok
BEGIN

statement ok
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
repeatable read

onlyif config enterprise-configs
query T
SHOW transaction_isolation
----
repeatable read

skipif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

skipif config enterprise-configs
query T
SHOW transaction_isolation
----
serializable

statement ok
COMMIT

# We can't set isolation level to an unsupported one.
statement error invalid value for parameter "transaction_isolation": "this is made up"\n.*Available values: serializable,repeatable read
SET transaction_isolation = 'this is made up'

# We can explicitly start a transaction with isolation level specified.

statement ok
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ

onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
repeatable read

skipif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
COMMIT

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = false

statement ok
SET CLUSTER SETTING sql.txn.read_committed_isolation.enabled = true

statement ok
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED

onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
read committed

skipif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

# The isolation level of a transaction can be changed with the session variable too.
statement ok
SET transaction_isolation = 'READ COMMITTED'

onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
read committed

skipif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

onlyif config enterprise-configs
query T
SHOW transaction_isolation
----
read committed

skipif config enterprise-configs
query T
SHOW transaction_isolation
----
serializable

statement ok
COMMIT

# User priority.

statement error pgcode 25P01 there is no transaction in progress
SET TRANSACTION PRIORITY LOW

statement ok
BEGIN TRANSACTION PRIORITY LOW; COMMIT

statement ok
BEGIN TRANSACTION PRIORITY NORMAL; COMMIT

statement ok
BEGIN TRANSACTION PRIORITY HIGH; COMMIT

statement ok
BEGIN TRANSACTION; SET TRANSACTION PRIORITY LOW; COMMIT

statement ok
BEGIN TRANSACTION; SET TRANSACTION PRIORITY NORMAL; COMMIT

statement ok
BEGIN TRANSACTION; SET TRANSACTION PRIORITY HIGH; COMMIT

# It is an error to change the user priority of a running transaction.

statement ok
BEGIN TRANSACTION

statement ok
UPDATE kv SET v = 'b' WHERE k in ('a')

statement error cannot change the user priority of a running transaction
SET TRANSACTION PRIORITY HIGH

statement ok
ROLLBACK

statement ok
BEGIN TRANSACTION

statement ok
UPDATE kv SET v = 'b' WHERE k in ('a')

statement error cannot change the user priority of a running transaction
SET TRANSACTION PRIORITY HIGH

statement ok
ROLLBACK

# User priority default to normal

statement ok
BEGIN TRANSACTION

query T
SHOW TRANSACTION PRIORITY
----
normal

statement ok
SET TRANSACTION PRIORITY HIGH

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
COMMIT

# We can explicitly start a transaction in low user priority.

statement ok
BEGIN TRANSACTION PRIORITY LOW

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
SET TRANSACTION PRIORITY NORMAL

query T
SHOW TRANSACTION PRIORITY
----
normal

statement ok
COMMIT

# Transaction priority can be assigned a default value.

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
normal

query T
SHOW TRANSACTION PRIORITY
----
normal

statement ok
SET DEFAULT_TRANSACTION_PRIORITY TO 'LOW'

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
low

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
SET DEFAULT_TRANSACTION_PRIORITY TO 'NORMAL'

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
normal

query T
SHOW TRANSACTION PRIORITY
----
normal

statement ok
SET DEFAULT_TRANSACTION_PRIORITY TO 'HIGH'

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
high

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION PRIORITY LOW

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
low

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION PRIORITY NORMAL

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
normal

query T
SHOW TRANSACTION PRIORITY
----
normal

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION PRIORITY HIGH

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
high

query T
SHOW TRANSACTION PRIORITY
----
high

# Without the priority specified, BEGIN should use the default

statement ok
BEGIN

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
COMMIT

# With the priority specified, BEGIN PRIORITY overrides the default

statement ok
BEGIN TRANSACTION PRIORITY LOW

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
COMMIT

# Even after starting a transaction, the default priority can be overridden

statement ok
BEGIN

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
SET TRANSACTION PRIORITY LOW

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
COMMIT

statement ok
RESET DEFAULT_TRANSACTION_PRIORITY

query T
SHOW DEFAULT_TRANSACTION_PRIORITY
----
normal

# We can specify both isolation level and user priority.

statement ok
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ, PRIORITY LOW; COMMIT

statement ok
BEGIN TRANSACTION PRIORITY LOW, ISOLATION LEVEL REPEATABLE READ; COMMIT

# We can explicitly start a transaction with specified isolation level and low user priority.

statement ok
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ, PRIORITY LOW

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, PRIORITY HIGH

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
SET TRANSACTION PRIORITY NORMAL, ISOLATION LEVEL REPEATABLE READ

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW TRANSACTION PRIORITY
----
normal

statement ok
COMMIT

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = true

statement ok
BEGIN TRANSACTION ISOLATION LEVEL REPEATABLE READ, PRIORITY LOW

onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
repeatable read

query T
SHOW TRANSACTION PRIORITY
----
low

statement ok
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE, PRIORITY HIGH

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
COMMIT

# With the repeatable_read_isolation.enabled cluster setting set to true,
# REPEATABLE READ can be used if there is a valid license.
onlyif config enterprise-configs
query T noticetrace
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ
----

skipif config enterprise-configs
query T noticetrace
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ
----
NOTICE: REPEATABLE READ isolation level is not allowed without an enterprise license; upgrading to SERIALIZABLE

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ

onlyif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
repeatable read

skipif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = false

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ UNCOMMITTED

onlyif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
read committed

skipif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL REPEATABLE READ

query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SNAPSHOT

query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

# SHOW without a transaction should create an auto-transaction with the default level
query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL READ COMMITTED

onlyif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
read committed

# SHOW without a transaction should create an auto-transaction with the new default level
onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
read committed

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL SERIALIZABLE

query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

statement ok
SET default_transaction_isolation = 'read uncommitted'

onlyif config enterprise-configs
query T
SHOW default_transaction_isolation
----
read committed

skipif config enterprise-configs
query T
SHOW default_transaction_isolation
----
serializable

onlyif config enterprise-configs
query T noticetrace
SET default_transaction_isolation = 'read committed'
----

skipif config enterprise-configs
query T noticetrace
SET default_transaction_isolation = 'read committed'
----
NOTICE: READ COMMITTED isolation level is not allowed without an enterprise license; upgrading to SERIALIZABLE

onlyif config enterprise-configs
query T
SHOW default_transaction_isolation
----
read committed

skipif config enterprise-configs
query T
SHOW default_transaction_isolation
----
serializable

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = true

# Since repeatable_read_isolation.enabled is true, setting isolation level to
# SNAPSHOT should map to REPEATABLE READ.
statement ok
SET default_transaction_isolation = 'snapshot'

onlyif config enterprise-configs
query T
SHOW default_transaction_isolation
----
repeatable read

skipif config enterprise-configs
query T
SHOW default_transaction_isolation
----
serializable

statement ok
SET DEFAULT_TRANSACTION_ISOLATION TO 'REPEATABLE READ'

onlyif config enterprise-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
repeatable read

skipif config enterprise-configs
query T
SHOW default_transaction_isolation
----
serializable

statement ok
SET CLUSTER SETTING sql.txn.repeatable_read_isolation.enabled = false

# Since repeatable_read_isolation.enabled is false, setting isolation level to
# REPEATABLE READ should map to SERIALIZABLE.
statement ok
SET default_transaction_isolation = 'repeatable read'

query T
SHOW default_transaction_isolation
----
serializable

statement ok
SET DEFAULT_TRANSACTION_ISOLATION TO 'REPEATABLE READ'

query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

# Without the isolation level specified, BEGIN should use the default

statement ok
BEGIN

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
COMMIT

# With the isolation level specified, BEGIN ISOLATION LEVEL overrides the default.

statement ok
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED

onlyif config enterprise-configs
query T
SHOW TRANSACTION ISOLATION LEVEL
----
read committed

statement ok
COMMIT

# Setting user priority without isolation level should not change isolation level

statement ok
BEGIN TRANSACTION

statement ok
SET TRANSACTION ISOLATION LEVEL REPEATABLE READ

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
SET TRANSACTION PRIORITY HIGH

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

statement ok
COMMIT

statement ok
RESET DEFAULT_TRANSACTION_ISOLATION

skipif config weak-iso-level-configs
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
serializable

onlyif config local-read-committed
query T
SHOW DEFAULT_TRANSACTION_ISOLATION
----
read committed

# SHOW TRANSACTION STATUS

query T
SHOW TRANSACTION STATUS
----
NoTxn

statement ok
BEGIN

query T
SHOW TRANSACTION STATUS
----
Open

statement ok
COMMIT

query T
SHOW TRANSACTION STATUS
----
NoTxn

statement ok
BEGIN

query error pq: relation "t\.b" does not exist
SELECT a FROM t.b

query T
SHOW TRANSACTION STATUS
----
Aborted

statement ok
ROLLBACK

query T
SHOW TRANSACTION STATUS
----
NoTxn

# CommitWait state
statement ok
BEGIN;SAVEPOINT cockroach_restart

statement ok
RELEASE SAVEPOINT cockroach_restart

query T
SHOW TRANSACTION STATUS
----
CommitWait

statement ok
COMMIT

# Aborted state
# The SELECT 1 is necessary to move the txn out of the AutoRetry state,
# otherwise the next statement is automatically retried on the server.
statement ok
BEGIN TRANSACTION; SAVEPOINT cockroach_restart; SELECT 1

skipif config local-read-committed
query error pgcode 40001 restart transaction: crdb_internal.force_retry\(\): TransactionRetryWithProtoRefreshError: forced by crdb_internal.force_retry\(\).*\nHINT:.*transaction-retry-error-reference.html
SELECT crdb_internal.force_retry('1h':::INTERVAL)

onlyif config local-read-committed
query error pgcode 40001 pq: restart transaction: read committed retry limit exceeded; set by max_retries_for_read_committed=10: crdb_internal.force_retry\(\): TransactionRetryWithProtoRefreshError: forced by crdb_internal.force_retry\(\)
SELECT crdb_internal.force_retry('1h':::INTERVAL)

query T
SHOW TRANSACTION STATUS
----
Aborted

statement ok
ROLLBACK TO SAVEPOINT cockroach_restart

query T
SHOW TRANSACTION STATUS
----
Open

statement ok
COMMIT


# Automatic retries for the first batch.
# We use a sequence to avoid busy-looping the test.
statement ok
CREATE SEQUENCE s;

statement ok
BEGIN TRANSACTION;
SELECT IF(nextval('s')<3, crdb_internal.force_retry('1h':::INTERVAL), 0)

# Demonstrate that the txn was indeed retried.
query I
SELECT currval('s')
----
3

statement ok
ROLLBACK;

statement ok
DROP SEQUENCE s

# Automatic retries for the first batch even when that first batch comes after
# the BEGIN.
statement ok
CREATE SEQUENCE s;

statement ok
BEGIN TRANSACTION;

statement ok
SELECT 1;
  SELECT IF(nextval('s')<3, crdb_internal.force_retry('1h':::INTERVAL), 0)

# Demonstrate that the txn was indeed retried.
query I
SELECT currval('s')
----
3

statement ok
ROLLBACK;

statement ok
DROP SEQUENCE s

# Automatic retries for the first batch even when that first batch comes after
# the BEGIN and the BEGIN also has special statements that don't move the txn
# state out of the "AutoRetry" state.
statement ok
CREATE SEQUENCE s;

statement ok
BEGIN TRANSACTION;
  SAVEPOINT cockroach_restart;
  SET TRANSACTION PRIORITY HIGH;
  SET TRANSACTION ISOLATION LEVEL REPEATABLE READ;

statement ok
SELECT IF(nextval('s')<3, crdb_internal.force_retry('1h':::INTERVAL), 0)

# Demonstrate that the txn was indeed retried.
query I
SELECT currval('s')
----
3

query T
SHOW TRANSACTION ISOLATION LEVEL
----
serializable

query T
SHOW TRANSACTION PRIORITY
----
high

statement ok
ROLLBACK;

statement ok
DROP SEQUENCE s

# Like above, but the SAVEPOINT is its own batch.
statement ok
CREATE SEQUENCE s;

statement ok
BEGIN TRANSACTION

statement ok
SAVEPOINT cockroach_restart;

statement ok
SELECT IF(nextval('s')<3, crdb_internal.force_retry('1h':::INTERVAL), 0)

# Demonstrate that the txn was indeed retried.
query I
SELECT currval('s')
----
3

statement ok
ROLLBACK;

statement ok
DROP SEQUENCE s


# Automatic retries for the first batch after an explicit restart.
statement ok
CREATE SEQUENCE s;

statement ok
BEGIN TRANSACTION;
  SAVEPOINT cockroach_restart;
  SELECT 1;

skipif config local-read-committed
query error pgcode 40001 restart transaction: crdb_internal.force_retry\(\): TransactionRetryWithProtoRefreshError: forced by crdb_internal.force_retry\(\)
SELECT crdb_internal.force_retry('1h':::INTERVAL)

onlyif config local-read-committed
query error pgcode 40001 pq: restart transaction: read committed retry limit exceeded; set by max_retries_for_read_committed=10: crdb_internal.force_retry\(\): TransactionRetryWithProtoRefreshError: forced by crdb_internal.force_retry\(\)
SELECT crdb_internal.force_retry('1h':::INTERVAL)

statement ok
ROLLBACK TO SAVEPOINT COCKROACH_RESTART;

# This is the automatic retry we care about.
statement ok
SELECT IF(nextval('s')<3, crdb_internal.force_retry('1h':::INTERVAL), 0)

# Demonstrate that the txn was indeed retried.
query I
SELECT currval('s')
----
3

statement ok
ROLLBACK;

statement ok
DROP SEQUENCE s


# Test READ ONLY/WRITE syntax.

statement ok
BEGIN

query T
SHOW transaction_read_only
----
off

statement ok
SET TRANSACTION READ ONLY

query T
SHOW transaction_read_only
----
on

statement ok
SET TRANSACTION READ WRITE

query T
SHOW transaction_read_only
----
off

statement ok
SET transaction_read_only = true

query T
SHOW transaction_read_only
----
on

statement ok
SET transaction_read_only = false

query T
SHOW transaction_read_only
----
off

statement error read mode specified multiple times
SET TRANSACTION READ ONLY, READ WRITE

statement ok
ROLLBACK

statement ok
BEGIN READ WRITE

query T
SHOW transaction_read_only
----
off

statement ok
COMMIT

statement ok
BEGIN READ ONLY

query T
SHOW transaction_read_only
----
on

statement ok
COMMIT

# Test default read-only status.
query T
SHOW default_transaction_read_only
----
off

statement ok
SET default_transaction_read_only = true

query T
SHOW default_transaction_read_only
----
on

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION READ WRITE

query T
SHOW default_transaction_read_only
----
off

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION READ ONLY

query T
SHOW default_transaction_read_only
----
on

statement ok
BEGIN

statement ok
SAVEPOINT cockroach_restart

query T
SHOW transaction_read_only
----
on

# Can override setting.
statement ok
SET TRANSACTION READ WRITE

query T
SHOW transaction_read_only
----
off

# Rolling back to savepoint doesn't reset to default.
# TODO(jordan) fix this if necessary.
statement ok
ROLLBACK TO SAVEPOINT cockroach_restart

query T
SHOW transaction_read_only
----
off

statement ok
COMMIT

# BEGIN READ WRITE overrides READ ONLY default
statement ok
BEGIN READ WRITE

statement ok
CREATE SEQUENCE a

statement ok
COMMIT

statement error cannot execute CREATE TABLE in a read-only transaction
CREATE TABLE tab (a int)

statement error cannot execute INSERT in a read-only transaction
INSERT INTO kv VALUES('foo')

statement error cannot execute UPDATE in a read-only transaction
UPDATE kv SET v = 'foo'

statement error cannot execute UPSERT in a read-only transaction
UPSERT INTO kv VALUES('foo')

statement error cannot execute DELETE in a read-only transaction
DELETE FROM kv

statement error cannot execute SELECT FOR UPDATE in a read-only transaction
SELECT * FROM kv FOR UPDATE

statement error cannot execute SELECT FOR SHARE in a read-only transaction
SELECT * FROM kv FOR SHARE

statement error cannot execute nextval\(\) in a read-only transaction
SELECT nextval('a')

statement error cannot execute setval\(\) in a read-only transaction
SELECT setval('a', 2)

statement error cannot execute CREATE ROLE in a read-only transaction
CREATE ROLE my_user

statement error cannot execute ALTER ROLE in a read-only transaction
ALTER ROLE testuser SET default_int_size = 4

statement error cannot execute DROP ROLE in a read-only transaction
DROP ROLE testuser

statement error cannot execute SET CLUSTER SETTING in a read-only transaction
SET CLUSTER SETTING sql.auth.change_own_password.enabled = true

statement error cannot execute GRANT in a read-only transaction
GRANT admin TO testuser

statement error cannot execute REVOKE in a read-only transaction
REVOKE admin FROM testuser

statement error cannot execute GRANT in a read-only transaction
GRANT CONNECT ON DATABASE test TO testuser

statement error cannot execute create_tenant\(\) in a read-only transaction
SELECT crdb_internal.create_tenant(3)

# SET session variable should work in a read-only txn.
statement ok
SET intervalstyle = 'postgres'

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION PRIORITY NORMAL

statement ok
SET SESSION AUTHORIZATION DEFAULT

statement ok
BEGIN

# DECLARE, FETCH, and CLOSE CURSOR should work in a read-only txn.
statement ok
DECLARE foo CURSOR FOR SELECT 1

statement ok
FETCH 1 foo

statement ok
CLOSE foo

statement ok
COMMIT

query T
SHOW TRANSACTION STATUS
----
NoTxn

statement error read mode specified multiple times
BEGIN READ WRITE, READ ONLY

statement error user priority specified multiple times
BEGIN PRIORITY LOW, PRIORITY HIGH

statement error isolation level specified multiple times
BEGIN ISOLATION LEVEL SERIALIZABLE, ISOLATION LEVEL SERIALIZABLE

# Retryable error in a txn that hasn't performed any KV operations. It used to
# not work.
# The SELECT 1 is necessary to take the session out of the AutoRetry state,
# otherwise the statement below would be retries automatically.
statement ok
BEGIN; SELECT 1

skipif config local-read-committed
query error pgcode 40001 restart transaction: crdb_internal.force_retry\(\): TransactionRetryWithProtoRefreshError: forced by crdb_internal.force_retry\(\)
SELECT crdb_internal.force_retry('1h':::INTERVAL)

onlyif config local-read-committed
query error pgcode 40001 pq: restart transaction: read committed retry limit exceeded; set by max_retries_for_read_committed=10: crdb_internal.force_retry\(\): TransactionRetryWithProtoRefreshError: forced by crdb_internal.force_retry\(\)
SELECT crdb_internal.force_retry('1h':::INTERVAL)

statement ok
ROLLBACK

# restore the default
statement ok
SET default_transaction_read_only = false

# Test that we cannot change to READ WRITE during AS OF SYSTEM TIME transactions.

statement ok
BEGIN AS OF SYSTEM TIME '-1us'

statement error AS OF SYSTEM TIME specified with READ WRITE mode
SET transaction_read_only = false

statement ok
ROLLBACK

statement ok
BEGIN AS OF SYSTEM TIME '-1us'

statement error AS OF SYSTEM TIME specified with READ WRITE mode
SET TRANSACTION READ WRITE

statement ok
ROLLBACK

# Transaction AS OF SYSTEM TIME clauses can be assigned a default value.

query T
SHOW DEFAULT_TRANSACTION_USE_FOLLOWER_READS
----
off

statement ok
SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO TRUE

# NOTE: run SHOW statement at different AS OF SYSTEM TIME time to avoid schema
# resolution complications.
query T
BEGIN AS OF SYSTEM TIME '-1us'; SHOW DEFAULT_TRANSACTION_USE_FOLLOWER_READS; COMMIT
----
on

statement ok
SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO FALSE

query T
SHOW DEFAULT_TRANSACTION_USE_FOLLOWER_READS
----
off

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION AS OF SYSTEM TIME follower_read_timestamp()

# NOTE: run SHOW statement at different AS OF SYSTEM TIME time to avoid schema
# resolution complications.
query T
BEGIN AS OF SYSTEM TIME '-1us'; SHOW DEFAULT_TRANSACTION_USE_FOLLOWER_READS; COMMIT
----
on

statement error pgcode 22023 unsupported default as of system time expression, only follower_read_timestamp\(\) allowed
SET SESSION CHARACTERISTICS AS TRANSACTION AS OF SYSTEM TIME now()

statement error pgcode 22023 unsupported default as of system time expression, only follower_read_timestamp\(\) allowed
SET SESSION CHARACTERISTICS AS TRANSACTION AS OF SYSTEM TIME '-1m'

statement ok
SET DEFAULT_TRANSACTION_USE_FOLLOWER_READS TO FALSE

query T
SHOW DEFAULT_TRANSACTION_USE_FOLLOWER_READS
----
off

# Transaction deferrability can be assigned a default value.

statement ok
SET SESSION CHARACTERISTICS AS TRANSACTION NOT DEFERRABLE

statement error pq: unimplemented: DEFERRABLE transactions
SET SESSION CHARACTERISTICS AS TRANSACTION DEFERRABLE

# Test retry rewinds correctly.

statement ok
SET intervalstyle = 'postgres'

statement ok
CREATE TABLE rewind_session_test (s string primary key);

statement ok
BEGIN;
INSERT INTO rewind_session_test VALUES ('1 day 01:02:03'::interval::string);
SET intervalstyle = 'iso_8601';
INSERT INTO rewind_session_test VALUES ('1 day 01:02:04'::interval::string);
SELECT crdb_internal.force_retry('10ms');
COMMIT

query T
SELECT s FROM rewind_session_test ORDER BY s
----
1 day 01:02:03
P1DT1H2M4S

query T
SHOW intervalstyle
----
iso_8601

statement ok
TRUNCATE rewind_session_test

statement ok
SET intervalstyle = 'postgres'

statement ok
BEGIN;
INSERT INTO rewind_session_test VALUES ('1 day 01:02:03'::interval::string);
SET LOCAL intervalstyle = 'iso_8601';
INSERT INTO rewind_session_test VALUES ('1 day 01:02:04'::interval::string);
SELECT crdb_internal.force_retry('10ms');
COMMIT

query T
SELECT s FROM rewind_session_test ORDER BY s
----
1 day 01:02:03
P1DT1H2M4S

query T
SHOW intervalstyle
----
postgres

query T
SHOW default_transaction_quality_of_service
----
regular

statement ok
SET default_transaction_quality_of_service=critical

query T
SHOW default_transaction_quality_of_service
----
critical

statement ok
SET default_transaction_quality_of_service=background

query T
SHOW default_transaction_quality_of_service
----
background

statement ok
RESET default_transaction_quality_of_service

query T
SHOW default_transaction_quality_of_service
----
regular

statement error pq: invalid value for parameter "default_transaction_quality_of_service": "ttl_low"
SET default_transaction_quality_of_service=ttl_low

statement ok
BEGIN

statement ok
SET LOCAL default_transaction_quality_of_service=background

query T
SHOW default_transaction_quality_of_service
----
background

statement ok
END

query T
SHOW default_transaction_quality_of_service
----
regular

# Sanity: Implicit txns with multiple statements can't have SET CLUSTER
# SETTING.
statement error pq: SET CLUSTER SETTING cannot be used inside a multi-statement transaction
SET CLUSTER SETTING sql.defaults.use_declarative_schema_changer = 'on';
SET CLUSTER SETTING sql.defaults.use_declarative_schema_changer = 'off';

statement ok
BEGIN TRANSACTION ISOLATION LEVEL SERIALIZABLE;
SELECT cluster_logical_timestamp();

statement ok
ROLLBACK

statement ok
BEGIN TRANSACTION ISOLATION LEVEL READ COMMITTED;

onlyif config enterprise-configs
statement error pq: cluster_logical_timestamp\(\): unsupported in READ COMMITTED isolation
SELECT cluster_logical_timestamp();

statement ok
ROLLBACK
