PostgreSQL Engine

db9 PostgreSQL Engine Reference

Data types, SQL compatibility, transaction semantics, built-in functions, extensions, and limits for the db9 PostgreSQL-compatible engine running on TiKV.

Section 01

Architecture Overview

db9 is a PostgreSQL-compatible distributed SQL database. Your data is stored in a distributed TiKV cluster, and each database (tenant) gets its own isolated keyspace.

Query Execution Pipeline

When you send a SQL query to db9, it follows this pipeline:

  1. Parse — SQL text is parsed into an abstract syntax tree
  2. Route — The statement is classified as DDL, DML, SELECT, transaction control, or settings
  3. Expand Views — View references are recursively inlined (up to 64 levels deep)
  4. Analyze — Semantic analysis resolves column names, infers types, and checks scope rules
  5. Optimize — Cost-based optimizer chooses join order, access methods (table scan vs. index scan), and physical operators
  6. Execute — A pull-based (Volcano) operator tree streams results one row at a time
  7. Return — Results are sent back over the PostgreSQL wire protocol

Wire Protocol Compatibility

db9 implements the PostgreSQL wire protocol (v3). You can connect with any PostgreSQL client:

  • psql
  • Any PostgreSQL ORM or driver (psycopg2, node-postgres, JDBC, etc.)
  • Standard connection tools and GUIs

Both Simple Query and Extended Query (Parse/Bind/Describe/Execute) protocols are supported.

Query Optimization

The query optimizer uses table statistics from ANALYZE for cardinality estimation, cost-based join reordering (DPccp algorithm), predicate pushdown, subquery decorrelation, and index scan selection when beneficial.

Section 02

Data Types

db9 supports 23 data types. All data is stored in UTF-8 encoding.

SQL TypeAliasesDescription
BOOLEANBOOLTrue/false values
INTEGERINT, INT44-byte signed integer
BIGINTINT88-byte signed integer
DOUBLE PRECISIONFLOAT88-byte IEEE 754 floating point
NUMERICNUMERIC(p,s), DECIMALArbitrary-precision number (up to 28-29 significant digits)
TEXTVariable-length UTF-8 string
VARCHAR(n)CHARACTER VARYING(n)Length-limited text (max n characters)
BYTEARaw byte array
TIMESTAMPTIMESTAMP WITHOUT TIME ZONETimestamp (millisecond precision)
TIMESTAMPTZTIMESTAMP WITH TIME ZONETimestamp with timezone (millisecond precision)
DATECalendar date (days)
TIMETIME WITHOUT TIME ZONETime of day (microsecond precision)
INTERVALTime interval (months + milliseconds)
UUID128-bit UUID
JSONJSON data (original text preserved)
JSONBJSON data in canonical binary form
SERIALAuto-incrementing 4-byte integer
BIGSERIALAuto-incrementing 8-byte integer
type[]Array of any supported type
vector(N)Dense float vector of N dimensions (pgvector-compatible)
TSVECTORFull-text search document representation
TSQUERYFull-text search query
NAME63-byte identifier (PostgreSQL system type)
Not supported: SMALLINT / INT2, REAL / FLOAT4, CHAR(n) (fixed-length). Use INTEGER, DOUBLE PRECISION, and VARCHAR(n) instead.
Timestamp precision: Timestamps are stored at millisecond precision, not microsecond as in standard PostgreSQL. Precision parameters 0–6 are accepted in syntax, but sub-millisecond precision cannot be represented.

Interval Representation

Intervals store months and sub-month components separately, enabling calendar-aware arithmetic (e.g., adding 1 month to January 31 gives February 28/29). The sub-month component is stored in milliseconds.

Type Coercion

The type system uses two coercion strategies matching PostgreSQL behavior:

UNION / CASE / COALESCE / VALUES ("Text wins")

When mixing Text with a typed value, the result is Text. Example: SELECT 1 UNION SELECT 'a' resolves to TEXT.

Comparisons ("Non-Text wins")

When comparing Text with a typed value, the text literal is coerced to the typed side. Example: WHERE col = '42' coerces '42' to the column's type.

Numeric Promotion Hierarchy

Int32Int64Float64Numeric. When two numeric types are mixed, the higher-precedence type wins.

Temporal Promotion

  • Date + Timestamp = Timestamp
  • Timestamp + TimestampTz = TimestampTz
  • Date + TimestampTz = TimestampTz

CAST Contexts

ContextWhen UsedBehavior
ExplicitCAST(x AS type) or x::typeMost permissive. Allows rounding (Float to Int), Bool↔Int, VARCHAR truncation
AssignmentINSERT/UPDATE column coercionMedium. Rejects fractional Float→Int, rejects Bool↔Int, errors on VARCHAR overflow
ImplicitComparison coercionStrictest. Similar to Assignment
CastExplicitAssignment
2.7::INTEGERRounds to 3Rejects (fraction)
TRUE::INTEGERReturns 1Rejects
42::BOOLEANReturns trueRejects
'hello'::VARCHAR(3)Truncates to "hel"Errors if > 3 chars
NULL to any typeAlways succeedsAlways succeeds
Section 03

SQL Reference: DDL

Data Definition Language statements for creating and managing database objects.

CREATE TABLE

sql
CREATE TABLE [IF NOT EXISTS] table_name (
    column_name type [constraints],
    ...
    [table_constraints]
);

-- Create from query result
CREATE TABLE new_table AS SELECT ... FROM source;
SELECT ... INTO new_table FROM source;

Column constraints: NOT NULL, DEFAULT, PRIMARY KEY, UNIQUE, REFERENCES (foreign key), CHECK

Table constraints: PRIMARY KEY (col, ...), UNIQUE (col, ...), FOREIGN KEY (col) REFERENCES table(col) with ON DELETE/ON UPDATE actions, CHECK (expr)

SERIAL and BIGSERIAL columns are supported for auto-incrementing IDs. Self-referential foreign keys are supported.

CREATE INDEX

sql
-- B-tree index (default)
CREATE INDEX idx_name ON table (column);

-- Unique index
CREATE UNIQUE INDEX idx_name ON table (column);

-- GIN index (for JSONB, full-text search, arrays)
CREATE INDEX idx_name ON table USING GIN (column);

-- GiST index
CREATE INDEX idx_name ON table USING GIST (column);

-- Expression index
CREATE INDEX idx_name ON table (lower(column));

-- Partial index
CREATE INDEX idx_name ON table (column) WHERE active = true;

-- Non-blocking index creation
CREATE INDEX CONCURRENTLY idx_name ON table (column);

Index methods: btree (default), GIN, GiST. IF NOT EXISTS is supported.

CREATE VIEW

sql
CREATE VIEW view_name AS SELECT ...;
CREATE OR REPLACE VIEW view_name AS SELECT ...;

CREATE OR REPLACE VIEW cannot drop or rename existing columns; only appending new columns is allowed.

CREATE MATERIALIZED VIEW

sql
CREATE MATERIALIZED VIEW mv_name AS SELECT ...;
REFRESH MATERIALIZED VIEW mv_name;

ALTER TABLE

OperationSyntax
Add columnALTER TABLE t ADD COLUMN col type
Drop columnALTER TABLE t DROP COLUMN col
Rename columnALTER TABLE t RENAME COLUMN old TO new
Rename tableALTER TABLE t RENAME TO new_name
Set defaultALTER TABLE t ALTER COLUMN col SET DEFAULT val
Drop defaultALTER TABLE t ALTER COLUMN col DROP DEFAULT
Set not nullALTER TABLE t ALTER COLUMN col SET NOT NULL
Drop not nullALTER TABLE t ALTER COLUMN col DROP NOT NULL
Change typeALTER TABLE t ALTER COLUMN col SET DATA TYPE type [USING expr]
Add constraintALTER TABLE t ADD CONSTRAINT name ...
Drop constraintALTER TABLE t DROP CONSTRAINT name
Rename constraintALTER TABLE t RENAME CONSTRAINT old TO new

DROP Statements

sql
DROP TABLE [IF EXISTS] table_name [CASCADE];
DROP INDEX [IF EXISTS] index_name;
DROP VIEW [IF EXISTS] view_name [CASCADE];
DROP MATERIALIZED VIEW [IF EXISTS] mv_name [CASCADE];
TRUNCATE TABLE table_name;

CASCADE transitively resolves and drops all dependent views and materialized views.

Other DDL

StatementSupported
CREATE SCHEMAYes
CREATE SEQUENCE / DROP SEQUENCEYes
CREATE TYPE (enum, composite) / ALTER TYPE / DROP TYPEYes
CREATE FUNCTION / DROP FUNCTIONYes
CREATE TRIGGER / DROP TRIGGERYes
CREATE COLLATION / DROP COLLATIONYes
CREATE DATABASE / DROP DATABASE / ALTER DATABASEYes
CREATE EXTENSION / DROP EXTENSIONYes
Section 03.1

SQL Reference: DML

Data Manipulation Language statements for inserting, updating, and deleting data.

INSERT

sql
-- Single row
INSERT INTO users (name, email) VALUES ('Alice', 'alice@example.com');

-- Multi-row
INSERT INTO users (name, email) VALUES
    ('Alice', 'alice@example.com'),
    ('Bob', 'bob@example.com');

-- INSERT ... SELECT
INSERT INTO archive SELECT * FROM users WHERE active = false;

-- With RETURNING
INSERT INTO users (name) VALUES ('Alice') RETURNING id, name;

INSERT ON CONFLICT (Upsert)

sql
-- Skip conflicting rows
INSERT INTO users (email, name) VALUES ('alice@example.com', 'Alice')
ON CONFLICT (email) DO NOTHING;

-- Upsert by column
INSERT INTO users (email, name) VALUES ('alice@example.com', 'Alice Updated')
ON CONFLICT (email) DO UPDATE SET name = excluded.name;

-- Upsert by constraint name
INSERT INTO users (email, name) VALUES ('alice@example.com', 'Alice')
ON CONFLICT ON CONSTRAINT users_email_key DO UPDATE SET name = excluded.name;

The excluded pseudo-table is available in DO UPDATE SET clauses, referencing the row that was proposed for insertion.

UPDATE

sql
UPDATE users SET name = 'Bob' WHERE id = 1;
UPDATE users SET name = 'Bob' WHERE id = 1 RETURNING *;

DELETE

sql
DELETE FROM users WHERE id = 1;
DELETE FROM users WHERE id = 1 RETURNING *;

Foreign Key Referential Actions

Supported actions for ON DELETE and ON UPDATE: CASCADE, SET NULL, SET DEFAULT, RESTRICT, NO ACTION. Recursive cascade operations include cycle detection. MATCH SIMPLE semantics (PostgreSQL default): if any referencing column is NULL, the FK check is skipped.

Section 03.2

SQL Reference: Queries

SELECT query features, JOINs, window functions, CTEs, subqueries, and set operations.

JOINs

Join TypeSupported
INNER JOINYes
LEFT [OUTER] JOINYes
RIGHT [OUTER] JOINYes
FULL [OUTER] JOINYes
CROSS JOINYes
Semi join (via EXISTS)Yes
Anti join (via NOT EXISTS)Yes

Both hash join and nested-loop join implementations are available. The optimizer uses cost-based join reordering (DPccp algorithm).

Aggregation

  • GROUP BY with hash-based aggregation
  • HAVING clause
  • DISTINCT aggregates: COUNT(DISTINCT col)
  • FILTER clause: COUNT(*) FILTER (WHERE x > 0)
  • GROUPING() function

Window Functions

sql
SELECT
    name,
    department,
    salary,
    ROW_NUMBER() OVER (PARTITION BY department ORDER BY salary DESC) AS rank
FROM employees;

Supported ranking functions: ROW_NUMBER, RANK, DENSE_RANK, NTILE, PERCENT_RANK, CUME_DIST

Supported access functions: LAG, LEAD, FIRST_VALUE, LAST_VALUE, NTH_VALUE

All standard aggregate functions can also be used as window functions.

Common Table Expressions (CTEs)

sql
-- Standard CTE
WITH active_users AS (
    SELECT * FROM users WHERE active = true
)
SELECT * FROM active_users;

-- Recursive CTE
WITH RECURSIVE tree AS (
    SELECT id, parent_id, name, 1 AS depth
    FROM categories WHERE parent_id IS NULL
    UNION ALL
    SELECT c.id, c.parent_id, c.name, t.depth + 1
    FROM categories c JOIN tree t ON c.parent_id = t.id
)
SELECT * FROM tree;

Subqueries

  • Scalar subqueries
  • EXISTS / NOT EXISTS
  • IN / NOT IN with subquery
  • ANY / ALL with subquery
  • Array subqueries
  • Correlated subqueries (with subquery decorrelation optimization)

Set Operations

OperationSupported
UNION / UNION ALLYes
INTERSECT / INTERSECT ALLYes
EXCEPT / EXCEPT ALLYes

Other Query Features

  • SELECT DISTINCT and SELECT DISTINCT ON (expr)
  • ORDER BY with ASC/DESC and NULLS FIRST/NULLS LAST
  • LIMIT and OFFSET
  • EXPLAIN and EXPLAIN ANALYZE for query plans
  • PREPARE name AS ... / EXECUTE name (params) / DEALLOCATE name
  • generate_series() table function
  • SHOW TABLES
Section 03.3

SQL Reference: Transactions

Transaction control, savepoints, isolation semantics, and autocommit behavior.

Transaction Control

sql
BEGIN;
-- ... your SQL statements ...
COMMIT;     -- persist all changes atomically
ROLLBACK;   -- discard all changes

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

sql
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 state
COMMIT;  -- only Alice is committed

Savepoint 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

Default transaction mode is pessimistic with Snapshot Isolation provided by TiKV. Each transaction sees a consistent snapshot of the database at its start time.

Sequence Behavior

Sequence advances (nextval) are non-transactional — they survive transaction rollbacks, matching PostgreSQL behavior.

Failed Transaction State

When an error occurs in a transaction, it enters a failed state. Only ROLLBACK, COMMIT, and END are accepted. All other statements return an error. This matches PostgreSQL behavior.

Section 03.4

SQL Reference: COPY

Bulk data import and export.

sql
-- Import from file (via client)
COPY table_name FROM STDIN;

-- Import from Parquet (with parquet extension)
COPY table_name FROM '/data/file.parquet' FORMAT parquet;

Text, CSV, and Parquet formats are supported for COPY FROM.

Section 04

Built-in Functions

Comprehensive reference of all built-in functions, organized by category.

String Functions
UPPER, LOWER, LENGTH, CONCAT, CONCAT_WS, LEFT, RIGHT, TRIM, BTRIM, LTRIM, RTRIM, LPAD, RPAD, REPEAT, REPLACE, REVERSE, INITCAP, ASCII, CHR, STRPOS, SPLIT_PART, TRANSLATE, QUOTE_IDENT, QUOTE_LITERAL, QUOTE_NULLABLE, SUBSTRING, OVERLAY, POSITION, FORMAT
Mathematical Functions
ABS, CEIL/CEILING, FLOOR, ROUND, TRUNC, SQRT, CBRT, POWER, EXP, LN, LOG, MOD, SIGN, PI, DEGREES, RADIANS, SIN, COS, TAN, ASIN, ACOS, ATAN, ATAN2, DIV, WIDTH_BUCKET, HASHTEXT
Date/Time Functions
DATE_PART / EXTRACT, DATE_TRUNC, DATE, AGE, TO_CHAR, NOW, CURRENT_TIMESTAMP, CURRENT_DATE, CURRENT_TIME, CLOCK_TIMESTAMP, TO_TIMESTAMP, MAKE_DATE, MAKE_TIME, MAKE_TIMESTAMP, TIMEZONE
Aggregate Functions
COUNT, SUM, AVG, MIN, MAX, STRING_AGG, ARRAY_AGG, BOOL_AND, BOOL_OR, EVERY, JSON_AGG, JSONB_AGG
Window Functions
ROW_NUMBER, RANK, DENSE_RANK, NTILE, PERCENT_RANK, CUME_DIST, LAG, LEAD, FIRST_VALUE, LAST_VALUE, NTH_VALUE

All aggregate functions can also be used as window functions.

JSON/JSONB Functions
JSONB_BUILD_OBJECT, JSONB_BUILD_ARRAY, JSONB_TYPEOF, JSONB_ARRAY_LENGTH, JSONB_EXISTS, JSONB_EXISTS_ANY, JSONB_EXISTS_ALL, JSONB_OBJECT_KEYS, JSONB_EXTRACT_PATH, JSONB_EXTRACT_PATH_TEXT, JSONB_PRETTY, JSONB_SET, JSONB_ARRAY_ELEMENTS, JSONB_ARRAY_ELEMENTS_TEXT, JSONB_EACH, JSONB_EACH_TEXT, TO_JSON, TO_JSONB, ROW_TO_JSON, JSON_BUILD_OBJECT, JSON_BUILD_ARRAY
JSON Operators
OperatorDescriptionExample
->Get JSON element by key/indexdata->'name'
->>Get JSON element as textdata->>'name'
#>Get element by pathdata#>'{addr,city}'
#>>Get element by path as textdata#>>'{addr,city}'
#-Delete key/pathdata #- '{addr}'
@>Containsdata @> '{"a":1}'
<@Contained by'{"a":1}' <@ data
?Key existsdata ? 'email'
?|Any key existsdata ?| array['a','b']
?&All keys existdata ?& array['a','b']
Array Functions
ARRAY_LENGTH, ARRAY_UPPER, ARRAY_LOWER, CARDINALITY, ARRAY_POSITION, ARRAY_CAT, ARRAY_APPEND, ARRAY_PREPEND, ARRAY_REMOVE, ARRAY_TO_STRING, STRING_TO_ARRAY, UNNEST
Regular Expression Functions
REGEXP_REPLACE, REGEXP_MATCHES, REGEXP_MATCH, REGEXP_SPLIT_TO_ARRAY, REGEXP_SPLIT_TO_TABLE, REGEXP_COUNT, REGEXP_LIKE, REGEXP_SUBSTR, REGEXP_INSTR
Regular Expression Operators
OperatorDescription
~Matches regex (case-sensitive)
~*Matches regex (case-insensitive)
!~Does not match (case-sensitive)
!~*Does not match (case-insensitive)
Full-Text Search
TO_TSVECTOR, TO_TSQUERY, PLAINTO_TSQUERY

Operator: @@ (text search match)

UUID Functions
GEN_RANDOM_UUID, UUID_GENERATE_V4, UUIDV7
Encoding & Hashing
ENCODE, DECODE, MD5, SHA256, DIGEST
Vector Functions (pgvector-compatible)
L2_DISTANCE, INNER_PRODUCT, COSINE_DISTANCE, VECTOR_DIMS, VECTOR_NORM

Operators: <-> (L2 distance), <=> (cosine distance), <#> (negative inner product)

Sequence Functions
NEXTVAL, CURRVAL, SETVAL
Conditional Expressions
COALESCE, NULLIF, GREATEST, LEAST, CASE WHEN ... THEN ... ELSE ... END
System / Compatibility Functions
PG_TYPEOF, VERSION, CURRENT_USER, CURRENT_DATABASE, CURRENT_SCHEMA, FORMAT_TYPE, PG_GET_EXPR, HAS_TABLE_PRIVILEGE, HAS_SCHEMA_PRIVILEGE, HAS_DATABASE_PRIVILEGE, PG_TOTAL_RELATION_SIZE, PG_RELATION_SIZE, PG_TABLE_SIZE, PG_SIZE_PRETTY, PG_ENCODING_TO_CHAR, PG_COLUMN_SIZE, OBJ_DESCRIPTION, COL_DESCRIPTION, PG_BACKEND_PID, GENERATE_SERIES
Background SQL
PG_BACKGROUND_LAUNCH, PG_BACKGROUND_RESULT

Launch SQL statements asynchronously in background sessions.

Section 05

Extensions

Available extensions that add capabilities to your database. Install with CREATE EXTENSION name;

ExtensionDescription
httpHTTP client functions for making web requests from SQL. Provides http_get(), http_post(), http_put(), http_delete(), http_head(), http_patch(). Returns status, content_type, headers (JSONB), and content. SSRF protection built in. Requires superuser.
fs9Embedded filesystem stored in the database. Read, write, and manage files via SQL. Supports CSV, TSV, JSONL, Parquet, and plain text. Table functions and scalar functions (fs9_read, fs9_write, fs9_exists, fs9_size, fs9_mtime, fs9_remove).
pg_cronpg_cron-compatible scheduled job management. Schedule recurring SQL with cron expressions. Exposes cron.job, cron.job_run_details, and cron.running_jobs virtual tables.
parquetParquet file import. Read Parquet files from HTTP URLs or the embedded filesystem via read_parquet() and COPY FROM ... FORMAT parquet.
uuid-osspUUID generation functions. uuid_generate_v4() is also available built-in without the extension.
hstoreKey-value type. Metadata-only for client compatibility.

See the SDK Docs for detailed usage examples of the HTTP, fs9, and vector search extensions.

Section 06

System Catalog

System views for introspecting database objects.

Coming Soon
Detailed documentation for pg_catalog and information_schema views is in progress.
Section 07

Authentication & Roles

Connection format, TLS, and role-based access control.

Connecting

Connect using the standard PostgreSQL connection string format:

bash
psql "postgresql://<db_id>.<user>:<password>@pg.staging.db9.ai:5433/postgres"

All connections use TLS (sslmode=require).

RBAC

  • CREATE ROLE / ALTER ROLE
  • GRANT / REVOKE privileges on tables and schemas
  • SET ROLE for session role switching
  • Privilege checks enforced on every table access
Coming Soon
Detailed RBAC documentation with permission matrices and examples is in progress.
Section 08

Advanced SQL

PL/pgSQL, sequences, triggers, and other advanced features.

Coming Soon
Documentation for PL/pgSQL functions, sequences, triggers, custom types, and collations is in progress.
Section 09

Session Parameters

Session-level configuration with SET/SHOW.

sql
SET variable = value;           -- session-scoped
SET LOCAL variable = value;     -- transaction-scoped
SHOW variable;
RESET variable;

-- Functions
SELECT current_setting('variable_name');
SELECT set_config('variable_name', 'value', false);

Statement timeout enforcement is supported.

Coming Soon
Complete list of supported GUC (Grand Unified Configuration) parameters is in progress.
Section 10

Limits & Constraints

Resource limits and constraints across the db9 engine and extensions.

Engine Limits

ResourceLimit
Statement timeout60s (default)
Idle transaction timeout60s (default)
View nesting depth64 levels
Pending portals per connection32
Timestamp precisionMilliseconds (not microseconds)
EncodingUTF-8 only

HTTP Extension Limits

ResourceLimit
Connect timeout1s
Total timeout5s
Max request body256 KiB
Max response body1 MiB
Max calls per statement100
Max concurrent per tenant20

fs9 Extension Limits

ResourceLimit
Max file size10 MB
Max glob total size100 MB
Max file traversal10,000 files
Max directory recursion10 levels

pg_cron Limits

ResourceLimit
Job execution timeout30 minutes (default)

Unsupported PostgreSQL Features

Not supported:
  • SMALLINT / INT2 type — use INTEGER
  • REAL / FLOAT4 type — use DOUBLE PRECISION
  • CHAR(n) fixed-length type — use VARCHAR(n)
  • LISTEN / NOTIFY async notifications
  • Microsecond timestamp precision (millisecond only)