Skip to content

Repository files navigation

pgddl - PostgreSQL DDL Semantic Layer

pgddl is an in-memory PostgreSQL DDL semantic layer implemented in pure Go. It takes parsed ASTs from pgparser and maintains a catalog that tracks schema state, validates DDL operations, resolves types, and deparses view definitions — all without requiring a running PostgreSQL instance.

Target PostgreSQL Version: 17 (translated from PG 17 source code)

Features

  • 100% Native Go: No CGO, no external C dependencies.
  • Faithful Translation: Every function is a 1:1 translation of the PostgreSQL C source — same control flow, same error codes, same error messages.
  • Full DDL Coverage: CREATE/ALTER/DROP for tables, views, indexes, sequences, schemas, types (enum, domain, composite, range), functions, procedures, triggers, policies, and more.
  • Type System: Complete type resolution and coercion with all 193 built-in types, 229 casts, 799 operators, and 3,314 functions loaded from PG catalog data.
  • View Deparse: pg_get_viewdef equivalent that produces character-for-character identical output to PostgreSQL (141/141 PG compat tests pass).
  • pg_catalog Queries: 14 system catalog tables exposed via Query* methods (pg_class, pg_attribute, pg_type, pg_constraint, etc.).
  • Dry-Run Validation: Execute DDL statements against an in-memory catalog to catch semantic errors before hitting a real database.

Installation

Library

go get github.com/pgplex/pgddl

CLI

go install github.com/pgplex/pgddl/cmd/pgddl@latest

Quick Start

Load and validate SQL

package main
import (
"fmt""log""github.com/pgplex/pgddl"
)
funcmain() {
sql:=` CREATE TABLE users ( id integer PRIMARY KEY, name text NOT NULL, email text UNIQUE ); CREATE INDEX users_name_idx ON users (name); CREATE VIEW active_users AS SELECT id, name FROM users WHERE id > 0;	`cat, err:=pgddl.LoadSQL(sql)
iferr!=nil {
log.Fatalf("DDL error: %v", err)
}
// Query catalog state.rel:=cat.GetRelation("", "users")
fmt.Printf("Table: %s (%d columns)\n", rel.Name, len(rel.Columns))
// Get view definition (pg_get_viewdef equivalent).def, _:=cat.GetViewDefinition("", "active_users")
fmt.Printf("View: %s\n", def)
}

Dry-run migrations

package main
import (
"fmt""log""github.com/pgplex/pgddl""github.com/pgplex/pgddl/catalog"
)
funcmain() {
// Load existing schema.base, err:=pgddl.LoadSQL(`CREATE TABLE users (id integer PRIMARY KEY, name text);`)
iferr!=nil {
log.Fatal(err)
}
// Dry-run a migration against the existing catalog.migration:=` ALTER TABLE users ADD COLUMN email text; CREATE INDEX users_email_idx ON users (email); ALTER TABLE users ADD COLUMN name text; -- duplicate column!	`stmts, _:=pgddl.ParseStatements(migration)
results:=base.Clone().DryRunStatements(stmts, &catalog.DryRunOptions{ContinueOnError: true})
for_, r:=rangeresults {
ifr.Error!=nil {
fmt.Printf("ERROR line %d: %v\n", r.Line, r.Error)
}
}
}

CLI

The pgddl CLI validates SQL files, dry-runs migrations, and inspects schema state — all without a running database. It reads from files or stdin, and supports structured JSON output for CI integration.

validate

Validate SQL files for syntax and semantic correctness:

pgddl validate schema.sql
# schema.sql: 42 statements OK
pgddl validate -continue schema.sql
# continues past errors, reporting all issues
pgddl validate -warnings schema.sql
# also shows notices (e.g., IF NOT EXISTS skips)
cat schema.sql | pgddl validate
# reads from stdin

dry-run

Load a base schema, then dry-run migration SQL against a clone of that catalog:

pgddl dry-run -base schema.sql migration.sql
# base: 42 statements loaded# migration.sql: 5 statements, 1 error# multiple base files
pgddl dry-run -base schema.sql -base extensions.sql migration.sql

inspect

Load SQL and print a catalog summary (schemas, tables, views, indexes, sequences):

pgddl inspect schema.sql
# Schemas:# public 3 tables, 1 view, 2 indexes## Tables:# public.users id integer, name text, email text# public.orders id integer, user_id integer, total numeric# ...

JSON output

All commands support -json for structured output, useful in CI pipelines:

pgddl validate -json schema.sql
pgddl dry-run -json -base schema.sql migration.sql
pgddl inspect -json schema.sql

Errors include PostgreSQL-compatible SQLSTATE codes:

{
"files": [{
"file": "migration.sql",
"total": 5,
"errors": 1,
"results": [{
"index": 2,
"line": 4,
"sql": "ALTER TABLE users ADD COLUMN name text",
"error": { "code": "42701", "message": "column \"name\" of relation \"users\" already exists" }
}]
}]
}

Supported DDL Statements

CategoryStatements
TablesCREATE TABLE, ALTER TABLE (~30 sub-commands), DROP TABLE, TRUNCATE
ViewsCREATE VIEW, CREATE OR REPLACE VIEW, DROP VIEW
IndexesCREATE INDEX, CREATE UNIQUE INDEX, DROP INDEX
SequencesCREATE SEQUENCE, ALTER SEQUENCE, DROP SEQUENCE
SchemasCREATE SCHEMA, DROP SCHEMA
TypesCREATE TYPE (enum, domain, composite, range), ALTER TYPE, DROP TYPE
FunctionsCREATE FUNCTION, CREATE PROCEDURE, ALTER FUNCTION, DROP FUNCTION
TriggersCREATE TRIGGER, DROP TRIGGER
PoliciesCREATE POLICY, ALTER POLICY, DROP POLICY
PrivilegesGRANT, REVOKE
Materialized ViewsCREATE MATERIALIZED VIEW, REFRESH MATERIALIZED VIEW
CommentsCOMMENT ON (table, column, index, type, function, etc.)

Related Projects

  • pgparser - Pure Go PostgreSQL parser (provides AST input for pgddl)
  • pgschema - PostgreSQL schema management tool

Star History

Star History Chart

License

PostgreSQL License - see LICENSE for details.

About

No description, website, or topics provided.

Resources

Stars

4 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages