SQL DDL Generation
Diagram2Code generates SQL DDL for four database dialects: PostgreSQL, MySQL, SQLite, and Oracle 19c+. All dialects share the same normalisation and validation pipeline — only the final rendering differs.
Generation Pipeline
- Parse the diagram into the intermediate Schema model.
- Normalise — add synthetic
idPKs where no PK is defined, deduplicate columns, set FK column names from relationship endpoints. - Validate — check that FK targets exist, composite PKs are consistent, enum directives are present for
enum-typed columns. - Emit
- Enum type definitions (PostgreSQL:
CREATE TYPE … AS ENUM) CREATE TABLEstatements with column definitions and inline constraintsALTER TABLE … ADD CONSTRAINT … FOREIGN KEYstatementsCREATE [UNIQUE] INDEXstatementsCOMMENT ONstatements (PostgreSQL & Oracle)
- Enum type definitions (PostgreSQL:
Primary Keys
| Dialect | Single-column PK syntax |
|---|---|
| PostgreSQL | "id" SERIAL PRIMARY KEY |
| MySQL | `id` INT AUTO_INCREMENT PRIMARY KEY |
| SQLite | "id" INTEGER PRIMARY KEY AUTOINCREMENT |
| Oracle 19c+ | "id" NUMBER(10) GENERATED ALWAYS AS IDENTITY PRIMARY KEY |
For composite primary keys (multiple PK markers), the individual columns have no inline constraint; instead a table-level PRIMARY KEY (col1, col2) clause is appended.
Foreign Keys
Every relationship line in the diagram generates an ALTER TABLE foreign key constraint after all tables are created. FK columns are identified by matching the FK marker on a column with a relationship that references the same table.
erDiagram
USER { int id PK }
ORDER {
int id PK
int user_id FK
}
USER ||--o{ ORDER : placesALTER TABLE "order"
ADD CONSTRAINT "fk_order_user_id"
FOREIGN KEY ("user_id")
REFERENCES "user"("id");Cascade Actions
Use the %% ::RELATIONSHIP[onDelete: X, onUpdate: Y] directive before the relationship line (Mermaid) or ' ::RELATIONSHIP[…] (PlantUML). Supported values:
CASCADE— delete/update child rows automaticallySET NULL— set FK column to NULLRESTRICT— prevent parent deletion if children existNO ACTION— same as RESTRICT, checked at end of statementSET DEFAULT— set FK to its DEFAULT value
Constraints
| Constraint | Diagram syntax | SQL generated |
|---|---|---|
| NOT NULL | %% ::NN / PlantUML * | NOT NULL |
| UNIQUE (column) | UK marker | UNIQUE inline |
| UNIQUE (named) | %% @col::UK(name: "…") | CONSTRAINT "…" UNIQUE ("col") |
| CHECK | %% ::CHECK(expr) | CHECK (expr) inline |
| DEFAULT | %% ::DEFAULT(val) | DEFAULT val |
Indexes
Indexes are emitted after all CREATE TABLE statements and foreign keys.
| Directive | SQL generated |
|---|---|
%% ::INDEX([col]) | CREATE INDEX "idx_table_col" ON "table" ("col"); |
%% ::INDEX([col], name: "my_idx") | CREATE INDEX "my_idx" ON "table" ("col"); |
%% ::INDEX([c1, c2]) | CREATE INDEX "idx_table_c1_c2" ON "table" ("c1", "c2"); |
%% ::UNIQUE([c1, c2]) | CREATE UNIQUE INDEX "uq_table_c1_c2" ON "table" ("c1", "c2"); |
The INDEX marker on a column (without a directive) generates a single-column index with an auto-generated name.
Enums
ORDER {
int id PK
%% ::ENUM(pending,shipped,delivered)
enum status
}CREATE TYPE "order_status_enum"
AS ENUM('pending','shipped','delivered');
CREATE TABLE "order" (
"id" SERIAL PRIMARY KEY,
"status" "order_status_enum"
);MySQL: Generates inline ENUM('pending','shipped','delivered') on the column.
SQLite & Oracle: Generates TEXT / VARCHAR2 with a CHECK (status IN (…)) constraint.
Column Comments
Quoted strings at the end of a column definition become comments.
string email UK "Login email"
COMMENT ON COLUMN "user"."email" IS 'Login email';
MySQL generates inline COMMENT 'text' on the column definition. SQLite ignores comments.
Dialect Differences
| Feature | PostgreSQL | MySQL | SQLite | Oracle |
|---|---|---|---|---|
| Identifier quoting | "double" | `backtick` | "double" | "double" |
| String type | TEXT | VARCHAR(255) | TEXT | VARCHAR2(255) |
| Enum support | CREATE TYPE … AS ENUM | Inline ENUM | TEXT + CHECK | VARCHAR2 + CHECK |
| JSON type | JSONB | JSON | TEXT | CLOB |
| UUID type | UUID | CHAR(36) | TEXT | CHAR(36) |
| Column comments | COMMENT ON COLUMN | Inline COMMENT | — | COMMENT ON COLUMN |
| Table comments | COMMENT ON TABLE | TABLE option | — | COMMENT ON TABLE |
| IF NOT EXISTS | ✓ | ✓ | ✓ | — |