Transactions & COPY
SQL Reference: Transactions
Section titled “SQL Reference: Transactions”Transaction control, savepoints, isolation semantics, and autocommit behavior.
Transaction Control
Section titled “Transaction Control”BEGIN;-- ... your SQL statements ...COMMIT; -- persist all changes atomicallyROLLBACK; -- discard all changesAutocommit
Section titled “Autocommit”Single statements outside an explicit BEGIN block run in implicit autocommit mode. The system begins a transaction, executes the statement, and commits (or rolls back on error). Retryable TiKV errors trigger automatic retry with backoff.
Savepoints
Section titled “Savepoints”BEGIN;INSERT INTO users (name) VALUES ('Alice');
SAVEPOINT sp1;INSERT INTO users (name) VALUES ('Bob');ROLLBACK TO SAVEPOINT sp1; -- Bob's insert is undone
RELEASE SAVEPOINT sp1; -- destroys savepoint, merges stateCOMMIT; -- only Alice is committedSavepoint behavior matches PostgreSQL: duplicate names are allowed (most recent is targeted), RELEASE destroys the named savepoint and all later ones, ROLLBACK TO re-establishes the savepoint for reuse.
Isolation Level
Section titled “Isolation Level”Transactions are pessimistic, and the default isolation level is READ COMMITTED.
| Level | Behavior |
|---|---|
READ COMMITTED (default) | Statement-level snapshots, as in PostgreSQL — each statement sees rows committed before it started |
READ UNCOMMITTED | Behaves as READ COMMITTED, as in PostgreSQL |
REPEATABLE READ | One snapshot held for the transaction’s lifetime, taken when the transaction starts (PostgreSQL takes it at the transaction’s first query) |
SERIALIZABLE | Not implemented — downgraded to REPEATABLE READ |
Under READ COMMITTED, a statement later in the transaction sees another session’s committed writes:
-- Session A -- Session BBEGIN; -- default: READ COMMITTEDSELECT count(*) FROM t; -- 1 INSERT INTO t VALUES (2); -- commitsSELECT count(*) FROM t; -- 2COMMIT;Under REPEATABLE READ the same sequence returns 1 both times.
Read-Only Transactions
Section titled “Read-Only Transactions”BEGIN READ ONLY, SET TRANSACTION READ ONLY, and SET default_transaction_read_only = on all
enable read-only transaction enforcement. DML and DDL writes are rejected with SQLSTATE 25006:
BEGIN READ ONLY;INSERT INTO t VALUES (1);-- ERROR: cannot execute INSERT in a read-only transaction-- SQLSTATE: 25006ROLLBACK;For credential-level write restrictions that apply across sessions, issue a token with a read-only
scope (db9 token create --scope mydb:ro) — see CLI reference.
Row Locks
Section titled “Row Locks”SELECT ... FOR UPDATE, FOR NO KEY UPDATE, FOR SHARE and FOR KEY SHARE, with or without
NOWAIT or SKIP LOCKED, need a primary key on the table they lock. On a table without one they
fail as soon as the query returns a row, where PostgreSQL locks the rows. A query that matches
nothing returns no rows without an error, so test against data:
CREATE TABLE notes (id INT, body TEXT); -- no primary keyINSERT INTO notes VALUES (1, 'draft');SELECT * FROM notes FOR UPDATE;-- ERROR: FOR UPDATE/SHARE requires primary key-- SQLSTATE: 0A000A RANGE-partitioned table is the exception: locking through the parent works with or without a
primary key, and another session’s NOWAIT and SKIP LOCKED see those locks. A partition without
a primary key, queried directly, fails as above.
Sequence Behavior
Section titled “Sequence Behavior”Failed Transaction State
Section titled “Failed Transaction State”When a statement fails inside a transaction block, the transaction enters a failed state, and every
later statement returns 25P02 (current transaction is aborted, commands ignored until end of transaction block). Only ROLLBACK (or ABORT), ROLLBACK TO SAVEPOINT, COMMIT and END are
accepted. COMMIT and END roll the transaction back and report ROLLBACK. ROLLBACK TO SAVEPOINT
undoes the work done after the savepoint and makes the transaction usable again. This matches
PostgreSQL behavior, including after a serialization failure (40001) or deadlock (40P01) raised
by a statement.
SQL Reference: COPY
Section titled “SQL Reference: COPY”Bulk data import and export.
-- Import from file (via client)COPY table_name FROM STDIN;
-- Import from Parquet (requires CREATE EXTENSION parquet)COPY table_name FROM 'fs9:///data/file.parquet' WITH (FORMAT parquet);
-- Export a table (PostgreSQL wire protocol only)COPY table_name TO STDOUT WITH (FORMAT csv, HEADER);Text, CSV, and Parquet formats are supported for COPY FROM; FORMAT binary is rejected with
0A000. A Parquet source must be an http://, https:// or fs9:// URL — a bare path such as
'/data/file.parquet' fails with unsupported Parquet URL scheme. See
Parquet Import.
COPY ... TO writes only to STDOUT, only in the table form (COPY table [(columns)] TO STDOUT),
and only over the PostgreSQL wire protocol: COPY (SELECT ...) TO STDOUT is rejected, a file
target fails, and the HTTP SQL API cannot carry the stream. See
Migrate from PostgreSQL.