Catalog
information_schema
Both views are synthesized from the live schema on every query, so a column added a moment ago is already there. There is one schema, public.
information_schema.tables — table_catalog, table_schema, table_name, table_type (BASE TABLE).
information_schema.columns — table_schema, table_name, column_name, ordinal_position, data_type, is_nullable (YES/NO), column_default, character_maximum_length, datetime_precision.
SELECT column_name, data_type, character_maximum_length, datetime_precision, is_nullable
FROM information_schema.columns
WHERE table_name = 'orders'
ORDER BY ordinal_position; column_name | data_type | character_maximum_length | datetime_precision | is_nullable
-------------+--------------------------+--------------------------+--------------------+-------------
id | bigint | | | NO
customer_id | bigint | | | NO
note | text | 64 | | YES
total | numeric | | | NO
placed_at | timestamp with time zone | | 3 | NO
payload | jsonb | | | YESdata_type uses Postgres names: bigint, integer (only for the 32-bit int storage type), smallint, real, double precision, numeric, text, boolean, timestamp with time zone, date, bytea, jsonb (for JSON and JSONB alike), uuid. A column declared INTEGER reports bigint because that is how it is stored (Data types → Integers). Arrays, structs and vectors report text.
Filtering on table_name and on a single column_name = '…' equality is honoured; the projection you ask for is the projection you get, so SELECT column_name FROM … returns one column, as psql’s \d expects.
Only these two views are served. information_schema.table_constraints, key_column_usage, referential_constraints and the rest are not intercepted and fail as an undefined table (42P01), so foreign keys, enforced as they are, are never reported back (Constraints).
pg_catalog
The adapter intercepts the catalog queries real drivers send and answers them from a fixed model. It is an emulation with a known edge, not a real catalog.
| Query | Status | Answer |
|---|---|---|
SELECT version() | Supported | PostgreSQL 16.0 (Dodil Tables adapterd) on x86_64, compiled by rustc, 64-bit |
current_database(), current_schema(), current_user, session_user | Supported | The bucket name; public; the login user. Call these probes alone: SELECT version(), x returns only the version column. |
current_setting('name'), set_config('name', 'v', false) | Supported | Read and (no-op) write of session settings; used by Django’s connect sequence. |
pg_is_in_recovery() | Supported | false, when it is the only expression. clock_timestamp() does not exist (42P01); use now(). |
pg_type | Partial | The 14 types the wire uses: bool, bytea, int8, int2, int4, text, json, float4, float8, date, timestamptz, numeric, uuid, jsonb, each with its array OID. psycopg’s and pgx’s type-resolution probes are answered from this list. |
pg_namespace | Partial | One row, public. |
pg_database | Partial | One row, the connected bucket. |
pg_class joined with pg_namespace (existence probes) | Partial | Answers “does table x exist” for SQLAlchemy create_all, Prisma and Alembic. Column-level pg_attribute detail is not served; use information_schema.columns. |
| Prisma’s introspection battery (extensions, views, enums, sequences, functions, check constraints, foreign keys) | Partial | Each query is answered with its exact projected columns and zero rows, so prisma db push sees an empty database and emits CREATE TABLE. |
SELECT 1, SELECT <int> liveness pings | Supported | Answered locally. |
Any other pg_catalog.* or pg_* table (pg_stat_activity, pg_indexes, pg_views, pg_constraint, pg_attrdef, pg_proc, …) | Refused42P01 | Falls through to the planner and fails as an undefined table. |
Because of that last row, an administrative tool that reads pg_stat_* or pg_locks will not work here, and an ORM feature that needs pg_indexes (index reflection) sees no indexes. Table and column reflection, which is what migrations and model discovery need, works.
Session settings
SHOW <name> answers a fixed list; every other name is refused.
SHOW | Value |
|---|---|
server_version | 16.0 (Dodil Tables adapterd) |
client_encoding | UTF8 |
standard_conforming_strings | on |
DateStyle | ISO, MDY |
TimeZone | UTC |
integer_datetimes | on |
search_path | "$user", public |
SET of these has no effect. SET statement_timeout and the vector knobs do work; SHOW statement_timeout reports the session value (5s, 250ms, 0) since 0.1.44. Anything not in the list above is refused the same way (Statements → Session).
DESCRIBE, SHOW, EXPLAIN
These are the engine’s native catalog statements, and they are the fastest way to see exactly what was stored.
DESCRIBE orders; column | type | nullable | pk | default
-------------+-----------------+----------+-------+----------------------------
id | long | false | true |
customer_id | long | false | false |
note | string(64) | true | false |
status | string | false | false | 'open'
total | decimal(18,2) | false | false |
placed_at | timestamp(3) | false | false | CURRENT_TIMESTAMP
ref | uuid | true | false |
payload | json | true | false |type is the storage type with its declared width or precision: string(n) for VARCHAR(n)/CHAR(n), decimal(p,s), timestamp(p), vector<n>, array<long>, struct<…>. since 0.1.43 for the width and precision suffixes.
| Statement | Returns |
|---|---|
SHOW TABLES | one row per table: table, pk_columns |
SHOW DATABASES / SHOW SCHEMAS | the databases visible to the connection |
SHOW VECTOR INDEXES | table, column, kind (hnsw/ivfflat), state (building/ready), parameters |
SHOW GRAPHS | graph name and its node and edge tables |
DESCRIBE DATABASE d | storage location and table count |
EXPLAIN <statement> | one row, columns explain_key / explain_value: the physical plan the engine chose. Executes nothing. |
A table created without a primary key has a hidden key column, _rowid. DESCRIBE shows it; information_schema and the pg_catalog emulation hide it so ORM model discovery does not pick up a phantom column.
psql
\dt lists the tables (as table_catalog, table_schema, table_name, table_type). \d <table> shows Column / Type / Nullable / Default and the primary-key index line; its Type column is the Postgres name without widths (text, numeric), so read widths from information_schema.columns or DESCRIBE. \di and \dv fail because pg_indexes and pg_views are not served; use SHOW VECTOR INDEXES and DESCRIBE.