Skip to main content

Guide: Generate DDL Scripts

After the comparison engine produces the TDDLCommand list, you can either execute commands immediately or collect the SQL text for review.

Automatic execution

Set CommandsAutoExecute := True before calling BuildDatabase. The engine will:

  1. Open a transaction on the target connection.
  2. Call BuildCommand on each TDDLCommand, passing the dialect's IDDLGeneratorCommand.
  3. Feed each non-empty SQL string to IDBConnection.AddScript.
  4. Call ExecuteScripts then Commit.
  5. On any exception, call Rollback and re-raise with context (command warning + SQL string).
LCompare.CommandsAutoExecute := True;
LCompare.BuildDatabase; // executes DDL in a single transaction

Manual / dry-run mode

Leave CommandsAutoExecute := False (default). After BuildDatabase you can iterate:

LCompare.CommandsAutoExecute := False;
LCompare.BuildDatabase;

var
LSL: TStringList;
LCmd: TDDLCommand;
LSQL: string;
begin
LSL := TStringList.Create;
try
for LCmd in LCompare.GetCommandList do
begin
LSQL := LCmd.BuildCommand(LCompare.GeneratorCommand);
if Length(LSQL) > 0 then
LSL.Add(LSQL);
end;
LSL.SaveToFile('migration.sql');
finally
LSL.Free;
end;
end;

The DDL command hierarchy

Every command descends from TDDLCommand and overrides BuildCommand(ASQLGeneratorCommand: IDDLGeneratorCommand): String.

ClassDDL verb
TDDLCommandCreateTableCREATE TABLE (with columns, PK, indexes, FKs, checks)
TDDLCommandDropTableDROP TABLE
TDDLCommandCreateColumnALTER TABLE ... ADD COLUMN
TDDLCommandDropColumnALTER TABLE ... DROP COLUMN
TDDLCommandAlterColumnALTER TABLE ... ALTER COLUMN (type/size/nullability change)
TDDLCommandAlterColumnPositionReorder column (dialect-dependent)
TDDLCommandAlterDefaultValueSet column default value
TDDLCommandDropDefaultValueDrop column default value
TDDLCommandCreatePrimaryKeyALTER TABLE ... ADD CONSTRAINT PK_...
TDDLCommandDropPrimaryKeyALTER TABLE ... DROP CONSTRAINT PK_...
TDDLCommandCreateForeignKeyALTER TABLE ... ADD CONSTRAINT FK_...
TDDLCommandDropForeignKeyALTER TABLE ... DROP CONSTRAINT FK_...
TDDLCommandCreateIndexeCREATE [UNIQUE] INDEX ...
TDDLCommandDropIndexeDROP INDEX ...
TDDLCommandCreateSequenceCREATE SEQUENCE / GENERATOR ...
TDDLCommandDropSequenceDROP SEQUENCE / GENERATOR ...
TDDLCommandCreateViewCREATE OR REPLACE VIEW ...
TDDLCommandDropViewDROP VIEW ...
TDDLCommandCreateTriggerCREATE TRIGGER ...
TDDLCommandDropTriggerDROP TRIGGER ...
TDDLCommandCreateCheckALTER TABLE ... ADD CONSTRAINT CHK_...
TDDLCommandDropCheckALTER TABLE ... DROP CONSTRAINT CHK_...
TDDLCommandAlterCheckDrop + recreate a CHECK constraint
TDDLCommandEnableForeignKeysEnable/disable all FKs (dialect-specific syntax)
TDDLCommandEnableTriggersEnable/disable all triggers (dialect-specific syntax)

Supported dialects and driver units

DialectDriver unit
Firebird 2.xMetaDbDiff.DDL.Generator.Firebird
Firebird 3MetaDbDiff.DDL.Generator.Firebird3
InterbaseMetaDbDiff.DDL.Generator.Interbase
PostgreSQLMetaDbDiff.DDL.Generator.PostgreSQL
MySQLMetaDbDiff.DDL.Generator.MySQL
MSSQL (SQL Server)MetaDbDiff.DDL.Generator.MSSQL
OracleMetaDbDiff.DDL.Generator.Oracle
SQLiteMetaDbDiff.DDL.Generator.SQLite
AbsoluteDBMetaDbDiff.DDL.Generator.AbsoluteDB

The correct generator is selected automatically from DataEngine's TDriverName enum based on the connection's declared driver. No manual wiring is needed.

Example: Firebird table creation

For a TCustomer entity with a NAME VARCHAR(100) column, MetaDbDiff generates:

CREATE TABLE CUSTOMERS (
ID INTEGER NOT NULL,
NAME VARCHAR(100) NOT NULL,
EMAIL VARCHAR(200),
CONSTRAINT PK_CUSTOMERS PRIMARY KEY (ID)
);

The exact syntax (keyword casing, quoting, sequence/generator naming) is handled by TDDLSQLGeneratorFirebird.

Saving generated SQL to a file

var
LScript: TStringList;
LCmd: TDDLCommand;
LSQL: string;
begin
LScript := TStringList.Create;
try
for LCmd in LMapping.GetCommandList do
begin
LSQL := LCmd.BuildCommand(LMapping.GeneratorCommand);
if Length(LSQL) > 0 then
begin
LScript.Add('-- ' + LCmd.Warning);
LScript.Add(LSQL);
LScript.Add('');
end;
end;
LScript.SaveToFile('migration_' + FormatDateTime('yyyymmdd_hhnnss', Now) + '.sql');
finally
LScript.Free;
end;
end;

TDDLCommand.Warning contains a human-readable description (e.g., "Create Table: CUSTOMERS", "Alter Column: NAME").