Skip to content

pgplex/pgddl

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

22 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

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"
)

func main() {
	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)
	if err != 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"
)

func main() {
	// Load existing schema.
	base, err := pgddl.LoadSQL(`CREATE TABLE users (id integer PRIMARY KEY, name text);`)
	if err != 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 := range results {
		if r.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

Category Statements
Tables CREATE TABLE, ALTER TABLE (~30 sub-commands), DROP TABLE, TRUNCATE
Views CREATE VIEW, CREATE OR REPLACE VIEW, DROP VIEW
Indexes CREATE INDEX, CREATE UNIQUE INDEX, DROP INDEX
Sequences CREATE SEQUENCE, ALTER SEQUENCE, DROP SEQUENCE
Schemas CREATE SCHEMA, DROP SCHEMA
Types CREATE TYPE (enum, domain, composite, range), ALTER TYPE, DROP TYPE
Functions CREATE FUNCTION, CREATE PROCEDURE, ALTER FUNCTION, DROP FUNCTION
Triggers CREATE TRIGGER, DROP TRIGGER
Policies CREATE POLICY, ALTER POLICY, DROP POLICY
Privileges GRANT, REVOKE
Materialized Views CREATE MATERIALIZED VIEW, REFRESH MATERIALIZED VIEW
Comments COMMENT 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

License

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •  

Languages