# LogicTest: !3node-tenant-default-configs !local-mixed-24.3

query T
SHOW max_prepared_transactions
----
2147483647

query TTTTTTT
SELECT * FROM system.prepared_transactions
----

query ITTTT
SELECT * FROM pg_catalog.pg_prepared_xacts
----

statement ok
CREATE TABLE t (a INT)

statement ok
GRANT ALL on t TO testuser


# Prepare a read-only transaction.
statement ok
BEGIN

query I
SELECT * FROM t
----

statement ok
PREPARE TRANSACTION 'read-only'

# Verify the prepared transaction was added to the system table.
query TTT
SELECT global_id, owner, database FROM system.prepared_transactions
----
read-only  root  test

# Verify the prepared transaction is visible in the pg_catalog.pg_prepared_xacts
# table.
query ITTT
SELECT transaction, gid, owner, database FROM pg_catalog.pg_prepared_xacts
----
0  read-only  root  test

# Commit the read-only prepared transaction.
statement ok
COMMIT PREPARED 'read-only'

# Verify the prepared transaction is gone.
query T
SELECT global_id FROM system.prepared_transactions
----


# Prepare another read-only transaction for abort.
statement ok
BEGIN

query I
SELECT * FROM t
----

statement ok
PREPARE TRANSACTION 'read-only'

# Commit the read-only prepared transaction.
statement ok
ROLLBACK PREPARED 'read-only'


# Prepare a read-write transaction.
statement ok
BEGIN

statement ok
INSERT INTO t(a) VALUES (1)

statement ok
PREPARE TRANSACTION 'read-write'

# Verify the prepared transaction is visible in the system table.
query T
SELECT global_id FROM system.prepared_transactions
----
read-write

# Commit the prepared transaction
statement ok
COMMIT PREPARED 'read-write'

# Verify prepared insert is visible.
query I
SELECT * FROM t
----
1


# Prepare a read-write transaction for rollback.
statement ok
BEGIN

statement ok
INSERT INTO t(a) VALUES (2)

statement ok
PREPARE TRANSACTION 'read-write'

statement ok
ROLLBACK PREPARED 'read-write'

query I
SELECT * FROM t
----
1

query T
SELECT global_id FROM system.prepared_transactions
----


# Verify a transaction cannot be prepared with a duplicate global id.
statement ok
BEGIN

statement ok
INSERT INTO t(a) VALUES (2)

statement ok
PREPARE TRANSACTION 'duplicate'

statement ok
BEGIN

statement ok
INSERT INTO t(a) VALUES (3)

statement error pgcode 42710 transaction identifier "duplicate" is already in use
PREPARE TRANSACTION 'duplicate'

query T
SHOW transaction_status
----
NoTxn

# Commit concurrent prepared transaction.
statement ok
COMMIT PREPARED 'duplicate'

# Verify the intent for a=2 has been commited and the intent for a=3 has been
# rolled back.
query I
SELECT * FROM t ORDER BY a
----
1
2


# Verify the global id has a maximum length of 200 characters.
statement ok
BEGIN

statement error pgcode 22023 transaction identifier "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" is too long
PREPARE TRANSACTION 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

query T
SHOW transaction_status
----
NoTxn

# Prepare a transaction with one fewer character.
statement ok
BEGIN

statement ok
PREPARE TRANSACTION 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';

query T
SELECT global_id FROM system.prepared_transactions
----
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa

statement ok
ROLLBACK PREPARED 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa';


# Prepare in an aborted transaction rolls the transaction back without inserting
# into the system table.
statement error pgcode 22012 division by zero
BEGIN; SELECT 1/0

statement ok
PREPARE TRANSACTION 'aborted-txn'

query T
SHOW transaction_status
----
NoTxn

query TTT
SELECT global_id, owner, database FROM system.prepared_transactions
----


# Verify prepare must be executed inside a transaction block.
statement error pgcode 25P01 there is no transaction in progress
PREPARE TRANSACTION 'implicit-txn'


# Verify commit/rollback cannot be executed inside a transaction block.
statement ok
BEGIN

statement error pgcode 25001 COMMIT PREPARED cannot run inside a transaction block
COMMIT PREPARED 'txn'

statement ok
ROLLBACK; BEGIN

statement error pgcode 25001 ROLLBACK PREPARED cannot run inside a transaction block
ROLLBACK PREPARED 'txn'

statement ok
ROLLBACK


# Verify an error is throw for unknown prepared transactions.
statement error pgcode 42704 prepared transaction with identifier "unknown" does not exist
COMMIT PREPARED 'unknown'

statement error pgcode 42704 prepared transaction with identifier "unknown" does not exist
ROLLBACK PREPARED 'unknown'


# Verify permissions.
statement ok
BEGIN

statement ok
INSERT INTO t(a) VALUES (3)

statement ok
PREPARE TRANSACTION 'read-write-root'

query TTT
SELECT global_id, owner, database FROM system.prepared_transactions
----
read-write-root  root  test

user testuser

statement error pgcode 42501 permission denied to finish prepared transaction
COMMIT PREPARED 'read-write-root'

# Prepare a transaction as testuser and verify that root can roll it back.
statement ok
BEGIN

statement ok
INSERT INTO t(a) VALUES (4)

statement ok
PREPARE TRANSACTION 'read-write-testuser'

# Before we switch back, verify that non-root/admin users cannot read from
# or write to system.prepared_transactions.
statement error pgcode 42501 user testuser does not have SELECT privilege on relation prepared_transactions
SELECT global_id, owner, database FROM system.prepared_transactions

statement error pgcode 42501 user testuser does not have DELETE privilege on relation prepared_transactions
DELETE FROM system.prepared_transactions

user root

query TTT rowsort
SELECT global_id, owner, database FROM system.prepared_transactions
----
read-write-root      root      test
read-write-testuser  testuser  test

query ITTT rowsort
SELECT transaction, gid, owner, database FROM pg_catalog.pg_prepared_xacts
----
0  read-write-root      root      test
0  read-write-testuser  testuser  test

statement ok
ROLLBACK PREPARED 'read-write-root'

statement ok
ROLLBACK PREPARED 'read-write-testuser'

query TTT
SELECT global_id, owner, database FROM system.prepared_transactions
----
