Add pg_get_table_ddl() to reconstruct CREATE TABLE statements - #8
Open
akshay-joshi wants to merge 1 commit into
Open
Add pg_get_table_ddl() to reconstruct CREATE TABLE statements#8akshay-joshi wants to merge 1 commit into
akshay-joshi wants to merge 1 commit into
Conversation
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
7 times, most recently
from
June 9, 2026 08:52
6fe8fc4 to
4d1e585
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
4 times, most recently
from
June 15, 2026 08:51
9f4de53 to
98856d7
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
7 times, most recently
from
June 24, 2026 09:02
07d3079 to
b291ba0
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
9 times, most recently
from
July 3, 2026 08:19
c300172 to
bc6baad
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
3 times, most recently
from
July 8, 2026 11:05
3299af6 to
3718fdb
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
5 times, most recently
from
July 16, 2026 06:21
b31f2e1 to
77109fd
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
from
July 16, 2026 08:53
77109fd to
295c7f2
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
2 times, most recently
from
July 27, 2026 10:07
5630a33 to
991c622
Compare
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
from
August 5, 2026 07:04
991c622 to
d3cdc41
Compare
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 (including named NOT NULL constraints), 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 (including partial and functional) via
pg_get_indexdef_ddl; constraints (PRIMARY KEY with WITHOUT OVERLAPS for
temporal keys, UNIQUE with NULLS NOT DISTINCT and INCLUDE columns,
FOREIGN KEY with ON DELETE/UPDATE referential actions and MATCH clause,
NOT ENFORCED foreign keys, EXCLUDE, named NOT NULL) via
pg_get_constraintdef_body; rules via pg_get_ruledef_ddl; extended
statistics via pg_get_statisticsobjdef_ddl; 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.
The function signature follows the named-parameter convention
established by pg_get_role_ddl(), pg_get_tablespace_ddl(), and
pg_get_database_ddl():
pg_get_table_ddl(relation regclass,
pretty boolean DEFAULT false,
owner boolean DEFAULT true,
tablespace boolean DEFAULT true,
schema_qualified boolean DEFAULT true,
only_kinds text[] DEFAULT NULL,
except_kinds text[] DEFAULT NULL)
pretty controls pretty-printed output. owner controls emission of the
ALTER TABLE ... OWNER TO statement. tablespace controls the TABLESPACE
clause on CREATE TABLE. schema_qualified controls whether object names
are emitted with their schema prefix: when true (the default) the
active search_path is temporarily narrowed to pg_catalog so every
deparse helper produces fully-qualified names; when false it is narrowed
to the target table's own schema so same-schema references come out
unqualified while cross-schema references remain qualified for
correctness. Temporary tables are never schema-qualified regardless of
this setting: the TEMPORARY keyword already places them in pg_temp, and
emitting pg_temp_NN.relname would produce non-replayable DDL.
Object-class filtering uses two mutually-exclusive text-array
parameters, only_kinds and except_kinds. When only_kinds is set, only
the listed kinds are emitted; when except_kinds is set, every kind
except the listed ones is emitted; when neither is set every kind is
emitted. Each array element is matched case-insensitively with
leading/trailing whitespace trimmed; an unrecognized name raises an
error. The kind vocabulary is:
table, index, primary_key, unique, check, foreign_key, exclusion,
rule, statistics, rls, replica_identity, partition
trigger and policy are accepted in the vocabulary but currently produce
no output; they are reserved for when standalone pg_get_trigger_ddl()
and pg_get_policy_ddl() helpers become available.
NOT NULL is not part of the vocabulary: it is always emitted to prevent
producing schemas that silently accept NULLs the source would reject.
When replica_identity is in the active filter and the table's REPLICA
IDENTITY USING INDEX references an index that the filter would suppress,
the function raises an error before emitting any output, so the
generated DDL never references an index it did not produce.
Default omission convention: every optional clause is omitted when its
value matches what the server 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>
Reviewed-by: Rui Zhao <zhaorui126@gmail.com>
akshay-joshi
force-pushed
the
pg_get_table_ddl
branch
from
August 5, 2026 07:38
d3cdc41 to
e0b51b4
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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