You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This is the canonical, feature-by-feature record of what PostgreSQL functionality
Duckgres supports and which tests prove it. It exists so that "is feature X
supported?" and "where's the test / where's the gap?" have one answer instead of
being smeared across the README and test docs.
Duckgres speaks the PostgreSQL wire protocol but executes on DuckDB, an OLAP
engine. So the compatibility target is "PostgreSQL semantics for analytical
workloads," not full OLTP parity. Many gaps below are deliberate (DuckDB has no
SAVEPOINT, no triggers, no sequences) rather than unfinished.
Status legend
Symbol
Meaning
✅ Covered
Works, and a differential test asserts it (same query run against real PostgreSQL 16 and Duckgres, results compared) — tests/integration/.
🟡 Partial
Works, but only unit/transpiler-tested (no differential assertion), or differential-covered with notable cases skipped.
⚠️Implemented, thin/untested
Code path exists and is reachable by clients, but no real test exercises the happy path. These are the real test gaps.
❌ Unsupported
Not implemented and/or not tested; behavior undefined for clients that rely on it.
⛔ Out of scope
Intentionally unsupported (DuckDB limitation or OLTP feature). Often has a skipped test documenting the reason.
Test citations use file.go::TestName. Integration (differential) tests live in
tests/integration/; unit tests in server/ and transpiler/; real-driver tests
in scripts/client-compat/ and tests/integration/clients/.
Maintenance contract
Per CLAUDE.md, every behavior change ships with a test. When that
change adds, removes, or changes a PostgreSQL-visible feature, update the matching
row here in the same PR — flip the status, fix the test citation, or add the row.
A row that points at a real test name rots slower than prose; keep the citations
honest. If you mark something ⛔ Out of scope, link the skipped test that documents
why.
1. Queries (DQL)
Feature
Status
Test(s)
Notes
SELECT, projections, aliases, arithmetic, ||
✅
dql_test.go::TestDQLBasicSelect
WHERE: comparisons, IS [NOT] DISTINCT FROM, AND/OR/NOT
Emulated in server/conn_cursor.go. Forward-only: backward fetch → 0A000 (PostgreSQL uses 55000 for non-SCROLL cursors, same message). Re-DECLARE of an open cursor replaces it (PostgreSQL raises 42P03). Cursors close at transaction end, before COMMIT/ROLLBACK executes (also a liveness requirement: an open cursor rowset pins the session's single DuckDB connection — server/conn_cursor_test.go::TestCloseCursorsAtTxEnd)
Cursor CLOSE
✅
cursor_test.go::TestCursorSimpleQuery/lifecycle_fetch_close + parity, ::TestCursorExtendedQuery/declare_fetch_close; server conn_test.go (CLOSE detection)
FETCH after CLOSE → clean 34000 missing-cursor error
Auth: cleartext password
✅
server worker_auth_test.go; integration via connection params
Auth: MD5
❌
—
Current startup path requests cleartext password auth over TLS
Not PostgreSQL features, but exercised because clients may send them and Duckgres
must route them to native DuckDB execution rather than the PG transpiler.
🟡 Stale skipIfKnown skips. Differential RETURNING
(TestDML{Insert,Update,Delete}Returning) and COPY TO STDOUT
(TestCopyToStdout) are skipped in tests/integration/ though the behavior is
covered at unit/client level. Re-enable or document why they must stay skipped.
🟡 Transpiler-only, no differential assertion: generated columns, SELECT FOR UPDATE/SHARE (stripped). Add differential cases if these matter to clients.
❌ Unsupported or untested but plausibly reachable — undefined behavior today: MD5/SCRAM auth,
enum/domain/composite/xml types, advisory locks, LOCK TABLE,
GRANT/REVOKE/roles, information_schema.{key_column_usage,table_constraints, referential_constraints} (ORM FK discovery), TABLESAMPLE. Asserting these
(even as "errors cleanly") would pin the compatibility boundary.
⛔ Out of scope by design (correctly skipped): SAVEPOINT, MERGE,
sequences/SERIAL, materialized views, partitioning/inheritance,
triggers/PL-pgSQL/rules/LISTEN-NOTIFY, RLS, and the network/geometric/range/
text-search/money types. These are DuckDB or OLTP limitations.
Appendix A — Catalog object, function & startup-parameter reference
This is the emulation-internals view that previously lived in the README: which
pg_catalog/information_schema objects and compatibility macros Duckgres
provides, and what each returns. "Implemented" = Duckgres-provided wrapper;
"Native (DuckDB)" = works through DuckDB's own pg_catalog with no Duckgres
wrapper; "Stub" = present but intentionally empty/constant; "Missing" = neither
wrapper nor native support. Behavior values (returns NULL / 0 / always true) are
deliberate stubs sized to satisfy client introspection, not real implementations.
pg_catalog views
View
Status
Notes
pg_class
Implemented
pg_class_full wrapper adding relforcerowsecurity; DuckLake variant sources from duckdb_tables()/duckdb_views()
pg_namespace
Implemented
Maps main → public; DuckLake variant derives from duckdb_tables()/duckdb_views()
pg_attribute
Implemented
Maps DuckDB internal type OIDs to PG OIDs via duckdb_columns() JOIN; fixes atttypmod for NUMERIC
Uses reltuples from pg_class; zeros for scan/tuple stats
pg_roles
Minimal view
Single hardcoded superuser row (not empty)
pg_settings
Native (DuckDB)
pg_catalog.pg_settings is queryable via DuckDB; the current_setting() macro only special-cases server_version/server_encoding
pg_stat_activity
Stub (empty)
Static view is empty; intercepted at query time for live data
pg_constraint
Stub (empty)
pg_enum
Stub (empty)
pg_collation
Stub (empty)
pg_policy
Stub (empty)
pg_inherits
Stub (empty)
pg_statistic_ext
Stub (empty)
pg_publication
Stub (empty)
pg_publication_rel
Stub (empty)
pg_publication_tables
Stub (empty)
pg_rules
Stub (empty)
pg_matviews
Stub (empty)
pg_partitioned_table
Stub (empty)
pg_statio_user_tables
Stub (empty)
pg_stat_statements
Stub (empty)
pg_indexes
Stub (empty)
pg_proc
Native (DuckDB)
DuckDB has native pg_catalog.pg_proc; no Duckgres wrapper
pg_description
Missing
Handled via obj_description()/col_description() macros returning NULL
pg_depend
Missing
pg_am
Missing
pg_attrdef
Missing
pg_tablespace
Missing
information_schema views
View
Status
Notes
tables
Implemented
Filters internal views, normalizes main → public
columns
Implemented
DuckDB → PG type name normalization, optional metadata overlay
schemata
Implemented
Adds synthetic entries for pg_catalog, information_schema, pg_toast
views
Implemented
Filters internal views
key_column_usage
Missing
Used by ORMs for relationship discovery
table_constraints
Missing
Used by ORMs for relationship discovery
referential_constraints
Missing
Used by ORMs for FK introspection
Functions & macros
Function
Status
Notes
format_type(oid, int)
Implemented
Comprehensive OID → name mapping
pg_get_expr(text, oid)
Implemented
Returns NULL
pg_get_indexdef(oid)
Implemented
Returns empty string
pg_get_constraintdef(oid)
Implemented
Returns empty string
pg_get_serial_sequence(text, text)
Implemented
Returns NULL (no sequence support)
pg_table_is_visible(oid)
Implemented
Always true
pg_get_userbyid(oid)
Implemented
Maps OID 10 → postgres, 6171 → pg_database_owner
obj_description(oid, text)
Implemented
Returns NULL
col_description(oid, int)
Implemented
Returns NULL
shobj_description(oid, text)
Implemented
Returns NULL
has_table_privilege(text, text)
Implemented
Always true
has_schema_privilege(text, text)
Implemented
Always true
pg_encoding_to_char(int)
Implemented
Always UTF8
version()
Implemented
Returns PostgreSQL 15.0 … (Duckgres/DuckDB)
current_setting(text)
Implemented
Special-cases server_version, server_encoding
current_schema()
Native (DuckDB)
Works via DuckDB; no Duckgres wrapper
current_schemas(bool)
Missing
pg_is_in_recovery()
Implemented
Always false
pg_backend_pid()
Implemented
Returns 0
pg_size_pretty(bigint)
Implemented
Full human-readable formatting
pg_total_relation_size(oid)
Implemented
Returns 0
pg_relation_size(oid)
Implemented
Returns 0
pg_table_size(oid)
Implemented
Returns 0
pg_indexes_size(oid)
Implemented
Returns 0
pg_database_size(text)
Implemented
Returns 0
quote_ident(text)
Implemented
quote_literal(text)
Implemented
quote_nullable(text)
Implemented
txid_current()
Implemented
Epoch-based pseudo ID
Startup parameters
Parameter
Value
server_version
15.0 (Duckgres)
server_encoding
UTF8
client_encoding
UTF8
DateStyle
ISO, MDY
TimeZone
UTC
integer_datetimes
on
standard_conforming_strings
on
IntervalStyle
Missing
Duckgres advertises PostgreSQL 15.0 on the wire (server/catalog.go,
server/conn.go). The differential test suite compares results against a real
PostgreSQL 16 server, but the emulated version string is intentionally 15.0.
Related docs
README.md → "SQL Client Compatibility" — short user-facing summary that links here.