Skip to content

Add pg_get_table_ddl() to reconstruct CREATE TABLE statements#8

Open
akshay-joshi wants to merge 1 commit into
masterfrom
pg_get_table_ddl
Open

Add pg_get_table_ddl() to reconstruct CREATE TABLE statements#8
akshay-joshi wants to merge 1 commit into
masterfrom
pg_get_table_ddl

Conversation

@akshay-joshi

Copy link
Copy Markdown
Owner

The function reconstructs the CREATE TABLE statement for an ordinary or partitioned table, followed by the ALTER TABLE / CREATE INDEX / CREATE RULE / CREATE STATISTICS statements needed to restore its full definition. Each statement is returned as a separate row.

Supported per-column features: data type with type modifiers, COLLATE, STORAGE, COMPRESSION (pglz / lz4), GENERATED ALWAYS AS (expr) STORED/VIRTUAL, GENERATED ALWAYS|BY DEFAULT AS IDENTITY (with sequence options), DEFAULT, NOT NULL, and per-column attoptions emitted as ALTER COLUMN SET (...).

Supported table-level features: UNLOGGED, INHERITS, PARTITION BY (RANGE / LIST / HASH parents), PARTITION OF parent FOR VALUES (FROM/TO, WITH modulus/remainder, DEFAULT), USING table access method, WITH (reloptions), TABLESPACE, and inline CHECK constraints in the CREATE TABLE body.

Supported sub-objects (re-using existing deparse helpers from ruleutils.c): indexes via pg_get_indexdef_string, constraints (PRIMARY KEY, UNIQUE, FOREIGN KEY, EXCLUDE, named NOT NULL) via pg_get_constraintdef_command, rules via pg_get_ruledef, extended statistics via pg_get_statisticsobjdef_string, REPLICA IDENTITY NOTHING/FULL/USING INDEX, ALTER TABLE ENABLE/FORCE ROW LEVEL SECURITY, and child-local DEFAULT overrides on inheritance/partition children.

Default omission convention: every optional clause is dropped when its value equals what the system would reapply on round-trip, including type-default COLLATE, per-type STORAGE, the auto-generated identity sequence name and parameter defaults, heap access method, default REPLICA IDENTITY, disabled RLS toggles, empty reloptions, and the default tablespace.

A regression test under src/test/regress covers ordinary tables, identity (default and custom sequence options), generated columns, STORAGE/COMPRESSION, constraints (CHECK/UNIQUE/FK with deferrable), functional and partial indexes, inheritance and partitioning, partition children with FOR VALUES FROM/TO, WITH modulus/remainder, and DEFAULT, rules, extended statistics, RLS toggles, REPLICA IDENTITY, UNLOGGED with reloptions, per-column attoptions, child DEFAULT overrides, pretty mode, owner=false, and the error paths for views, sequences, NULL, unknown options, and odd-variadic argument counts.

Author: Akshay Joshi akshay.joshi@enterprisedb.com

@akshay-joshi akshay-joshi force-pushed the pg_get_table_ddl branch 7 times, most recently from 6fe8fc4 to 4d1e585 Compare June 9, 2026 08:52
@akshay-joshi akshay-joshi force-pushed the pg_get_table_ddl branch 4 times, most recently from 9f4de53 to 98856d7 Compare June 15, 2026 08:51
@akshay-joshi akshay-joshi force-pushed the pg_get_table_ddl branch 6 times, most recently from 6052f0e to 07d3079 Compare June 23, 2026 13:30
The function reconstructs the CREATE TABLE statement for an ordinary or
partitioned table, followed by the ALTER TABLE / CREATE INDEX /
CREATE RULE / CREATE STATISTICS statements needed to restore its full
definition.  Each statement is returned as a separate row.

Supported per-column features: data type with type modifiers, COLLATE,
STORAGE, COMPRESSION (pglz / lz4), GENERATED ALWAYS AS (expr)
STORED/VIRTUAL, GENERATED ALWAYS|BY DEFAULT AS IDENTITY (with sequence
options), DEFAULT, NOT NULL, and per-column attoptions emitted as
ALTER COLUMN SET (...).

Supported table-level features: UNLOGGED, INHERITS, PARTITION BY (RANGE
/ LIST / HASH parents), PARTITION OF parent FOR VALUES (FROM/TO, WITH
modulus/remainder, DEFAULT), USING table access method, WITH
(reloptions), TABLESPACE, and inline CHECK constraints in the
CREATE TABLE body.

Supported sub-objects (re-using existing deparse helpers from
ruleutils.c): indexes via pg_get_indexdef_string, constraints
(PRIMARY KEY, UNIQUE, FOREIGN KEY, EXCLUDE, named NOT NULL) via
pg_get_constraintdef_command, rules via pg_get_ruledef, extended
statistics via pg_get_statisticsobjdef_string, REPLICA IDENTITY
NOTHING/FULL/USING INDEX, ALTER TABLE ENABLE/FORCE ROW LEVEL SECURITY,
and child-local DEFAULT overrides on inheritance/partition children.
DDL for partition children of a partitioned-table parent is appended
after the parent by default.

Options are passed as variadic name/value pairs.  Formatting options
are pretty (boolean), owner (boolean, controls the
ALTER TABLE ... OWNER TO line), tablespace (boolean, controls the
TABLESPACE clause), and schema_qualified (boolean, controls whether
the target table and same-schema sibling references are emitted with
their schema prefix).  Object-class filtering is expressed through two
mutually-exclusive options, include and exclude, each taking a
comma-separated list drawn from the kind vocabulary
{table, indexes, primary_key, unique, check, foreign_keys, exclusion,
rules, statistics, triggers, policies, rls, replica_identity,
partitions}.  When include is set, only the listed kinds are emitted;
when exclude is set, every kind except the listed ones is emitted;
when neither is set, every kind is emitted.  Unknown kind names raise
an error at parse time.  NOT NULL is deliberately not part of the
vocabulary - it is always emitted to prevent producing schemas that
silently accept NULLs the source would have rejected.  Excluding
primary_key on a table whose REPLICA IDENTITY is USING INDEX of the
primary key is rejected unless replica_identity is also excluded, so
the emitted DDL never references an index it just dropped.

Default omission convention: every optional clause is dropped when its
value equals what the system would reapply on round-trip, including
type-default COLLATE, per-type STORAGE, the auto-generated identity
sequence name and parameter defaults, heap access method, default
REPLICA IDENTITY, disabled RLS toggles, empty reloptions, and the
default tablespace.

Author: Akshay Joshi <akshay.joshi@enterprisedb.com>
Reviewed-by: Marcos Pegoraro <marcos@f10.com.br>
Reviewed-by: Zsolt Parragi <zsolt.parragi@percona.com>
Reviewed-by: Kyotaro Horiguchi <horikyota.ntt@gmail.com>
Reviewed-by: Chao Li <li.evan.chao@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant