Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Column types

Every Postgres type family with pgevolve's support status. The IR's ColumnType enum is the source of truth; entries below mirror its variants and document the gaps.

See ../README.md for the status legend.

Numeric

Tests (whole section): tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests (variant parse + display); tier-2: crates/pgevolve-core/tests/fixtures/parser/equivalent_pairs/0001-int-aliases, 0004-timestamp-tz; tier-C: objects/columns/alter-column-type-widening, alter-column-type-narrowing.

TypeStatusNotes
boolean✅ Implementedchange_kinds: [add, change_type]
smallint (int2)✅ Implementedchange_kinds: [add, change_type]
integer (int, int4)✅ Implementedchange_kinds: [add, change_type]
bigint (int8)✅ Implementedchange_kinds: [add, change_type]
real (float4)✅ Implementedchange_kinds: [add, change_type]
double precision (float8)✅ Implementedchange_kinds: [add, change_type]
numeric (decimal)✅ ImplementedIncluding precision and scale (numeric(p), numeric(p, s)). Unbounded numeric round-trips. change_kinds: [add, change_type]
smallserial / serial / bigserial✅ ImplementedDesugared at parse time into the underlying integer column + owned sequence; round-trips through introspection by detecting the nextval(...) default.
Tests: tier-1: crates/pgevolve-core/src/parse/builder/desugar_serial.rs::tests; tier-2: fixture parser/equivalent_pairs/0002-serial-desugar
money⛔ Not plannedLocale-dependent representation; discouraged by Postgres docs. Use numeric instead.

Character

Tests (whole section): tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests; tier-2: crates/pgevolve-core/tests/fixtures/parser/equivalent_pairs/0003-varchar-aliases.

TypeStatusNotes
text✅ Implementedchange_kinds: [add, change_type]
varchar(n) / character varying(n)✅ Implementedchange_kinds: [add, change_type]
varchar (unbounded)✅ Implementedchange_kinds: [add, change_type]
char(n) / character(n)✅ Implementedchange_kinds: [add, change_type]
char (unbounded; single-char)✅ Implementedchange_kinds: [add, change_type]
name⛔ Not plannedInternal PG type; you should not be using this in application schemas.
"char" (single-byte; quoted)⛔ Not plannedInternal PG type.

Binary

Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests; tier-3: crates/pgevolve-core/tests/catalog_round_trip.rs.

TypeStatusNotes
bytea✅ Implementedchange_kinds: [add, change_type]

Date / time

Tests (whole section): tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests; tier-2: crates/pgevolve-core/tests/fixtures/parser/equivalent_pairs/0004-timestamp-tz.

TypeStatusNotes
date✅ Implementedchange_kinds: [add, change_type]
time✅ ImplementedSub-second precision (time(p)); no time zone. change_kinds: [add, change_type]
time with time zone (timetz)✅ ImplementedIncluding time(p) with time zone. change_kinds: [add, change_type]
timestamp✅ ImplementedWith sub-second precision. change_kinds: [add, change_type]
timestamp with time zone (timestamptz)✅ ImplementedThe recommended type for most workflows. change_kinds: [add, change_type]
interval✅ ImplementedIncluding field constraints (interval year, interval day to hour, etc.) and sub-second precision (interval(N)). pg_query encodes the SQL field qualifier as an INTERVAL_MASK bitmask in the first typmod argument; pgevolve decodes it to the canonical form so the source and catalog paths converge (no spurious ALTER COLUMN TYPE). change_kinds: [add, change_type]

Networking

Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests; tier-3: crates/pgevolve-core/tests/catalog_round_trip.rs.

TypeStatusNotes
inet✅ Implementedchange_kinds: [add, change_type]
cidr✅ Implementedchange_kinds: [add, change_type]
macaddr✅ Implementedchange_kinds: [add, change_type]
macaddr8✅ Implementedchange_kinds: [add, change_type]

UUID, JSON, XML

Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests; tier-3: crates/pgevolve-core/tests/catalog_round_trip.rs.

TypeStatusNotes
uuid✅ Implementedchange_kinds: [add, change_type]
json✅ ImplementedLacks a default btree opclass, so the IR generator deliberately avoids indexing json columns. change_kinds: [add, change_type]
jsonb✅ Implementedchange_kinds: [add, change_type]
jsonpath🔮 FutureRarely used as a column type; mostly an expression-level value.
xml🔮 FutureRequires --with-libxml Postgres build; less common in modern stacks.

Bit strings

Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests.

TypeStatusNotes
bit(n)✅ ImplementedFixed-length. change_kinds: [add, change_type]
bit varying(n) (varbit)✅ ImplementedVariable-length. change_kinds: [add, change_type]

Arrays

Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests.

TypeStatusNotes
<element>[] (single-dimension)✅ ImplementedElement type and dimension count modeled in IR. change_kinds: [add, change_type]
Multi-dimensional arrays (int[][])🟡 PartialThe IR carries dims: u8 so multi-dimensional declarations parse, but the differ treats all dimensions ≥ 1 identically (Postgres itself does not enforce dimension counts). change_kinds: [add, change_type]
Array element constraints🔮 FutureE.g., CHECK (array_length(col, 1) = 3). Modeled as a CHECK constraint, not as an array attribute.

Range and multirange types

TypeStatusNotes
Built-in range types (int4range, int8range, numrange, tsrange, tstzrange, daterange)🔮 FutureLands with user-defined range types.
Built-in multirange types (int4multirange, etc.)🔮 FutureLands with range types.
User-defined range types🔮 FutureDepends on CREATE TYPE ... AS RANGE (see objects.md).

Geometric

TypeStatusNotes
point, line, lseg, box, path, polygon, circle🔮 FutureNiche; lands when there is concrete user demand.
TypeStatusNotes
tsvector🔮 FutureUseful as a STORED generated column; lands with the broader text-search story.
tsquery🔮 FutureMostly an expression-level type.

Object identifier types

TypeStatusNotes
oid, regclass, regtype, regnamespace, etc.⛔ Not plannedThese are catalog-internal types; user schemas should not depend on them. Catalogs returning regclass are converted to qualified-name strings at introspection time.

User-defined types

Tests: tier-1: crates/pgevolve-core/src/ir/user_type.rs::tests; tier-C: objects/enums/, objects/domains/, objects/composites/ (see objects.md for fixture list).

TypeStatusNotes
Enum (CREATE TYPE ... AS ENUM)📋 Planned, v0.2A column typed as an enum is modeled as ColumnType::UserDefined(qname) today; v0.2 adds first-class enum diff (including ALTER TYPE ... ADD VALUE).
Composite (CREATE TYPE ... AS (...))📋 Planned, v0.2Same as enum: typed columns work today as UserDefined; v0.2 adds first-class composite diff.
Domain (CREATE DOMAIN)📋 Planned, v0.2First-class diff including NOT NULL, CHECK, default.
Range (CREATE TYPE ... AS RANGE)🔮 FutureLands with range columns.
Base type (CREATE TYPE ... ( INPUT = c_func, OUTPUT = c_func ))⛔ Not plannedRequires C-language functions.

Catch-all fallback

VariantStatusNotes
ColumnType::Other { raw: String }✅ ImplementedAny type pgevolve doesn't recognize is preserved as a raw string. Two Other types compare equal iff their strings match — pgevolve makes no claim about semantic equivalence. Lets the system parse unknown types without aborting, which is essential for adopting an existing DB. PostGIS: parameterized geometry(Point,4326) / geography(...) are preserved with their typmod, the subtype is normalized to lowercase so the source and format_type catalog forms compare equal, and the schema-qualified form (public.geometry(Point,4326)) is handled too.
Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests
ColumnType::UserDefined(QualifiedName)✅ ImplementedSchema-qualified reference to a user-defined type. The IR doesn't introspect the type's structure in v0.1 — that lands with first-class custom types in v0.2.
Tests: tier-1: crates/pgevolve-core/src/ir/column_type.rs::tests, user_type.rs::tests

Type-level attributes

AttributeStatusNotes
NOT NULL✅ ImplementedColumn-level; not a constraint. The SET NOT NULL via CHECK pattern rewrite avoids long locks (see pipeline.md).
Tests: tier-1: crates/pgevolve-core/src/plan/rewrite/tests::set_not_null_on_existing_column_emits_four_steps, crates/pgevolve-core/src/diff/columns.rs::tests; tier-2: parser/equivalent_pairs/0007-not-null-via-pk
DEFAULT <literal>✅ ImplementedBooleans, integers, floats, text, bytea, NULL.
Tests: tier-1: crates/pgevolve-core/src/ir/default_expr.rs::tests; tier-C: objects/columns/set-default, drop-default
DEFAULT <sequence>✅ Implementednextval('seq') recognized; canonicalized at parse + introspect time.
Tests: tier-1: crates/pgevolve-core/src/ir/default_expr.rs::tests; tier-C: objects/columns/add-column-with-default
DEFAULT <expression>✅ ImplementedAny other expression preserved as canonical text (lowercased keywords, sorted commutative operands, paren-folded).
Tests: tier-1: crates/pgevolve-core/src/parse/normalize_expr.rs::tests; tier-2: parser/equivalent_pairs/0005-default-cast-strip
COLLATE <collation>✅ ImplementedPer-column collation. pg_catalog.default is treated as "no collation" so it doesn't appear as drift.
Tests: tier-1: crates/pgevolve-core/src/ir/canon/filter_pg_defaults.rs::tests
GENERATED ALWAYS AS IDENTITY / GENERATED BY DEFAULT AS IDENTITY✅ ImplementedIncluding sequence option overrides (START, INCREMENT, MINVALUE, MAXVALUE, CACHE, CYCLE).
Tests: tier-1: crates/pgevolve-core/src/ir/sequence.rs::tests, parse/builder/create_stmt.rs::tests
GENERATED ALWAYS AS (expr) STORED (computed columns)✅ ImplementedStored generated columns.
Tests: tier-1: crates/pgevolve-core/src/ir/column.rs::tests; tier-C: objects/columns/add-generated-column
GENERATED ALWAYS AS (expr) VIRTUAL⛔ Not plannedPostgres only supports STORED through at least PG 17; this row will move to ✅ Implemented if/when Postgres adds it.
Per-column comments✅ ImplementedTests: tier-1: crates/pgevolve-core/src/parse/builder/comment_stmt.rs::tests; tier-C: objects/tables/comment-on-column