Module: Exwiw::DdlPostprocessor

Defined in:
lib/exwiw/ddl_postprocessor.rb

Overview

Rewrites raw CREATE statements emitted by mysqldump / pg_dump / sqlite_master.sql into idempotent forms so the generated ‘insert-000-schema.sql` file can be re-applied without error.

Constant Summary collapse

ADD_CONSTRAINT_RE =

‘ALTER TABLE … ADD CONSTRAINT …;` is not idempotent on its own. PostgreSQL’s PL/pgSQL has no IF-NOT-EXISTS clause for ADD CONSTRAINT, so wrap each statement in a DO block that swallows ‘duplicate_object`. Matches only statements whose ALTER TABLE clause leads directly into ADD CONSTRAINT (no intervening ALTER COLUMN / DROP / etc) so that unrelated ALTER TABLE statements in the same dump are not absorbed.

/^[ \t]*ALTER\s+TABLE\s+(?:ONLY\s+)?[^\s;,]+\s+(?:\n[ \t]*)?ADD\s+CONSTRAINT\b[^;]*;/m.freeze

Class Method Summary collapse

Class Method Details

.add_if_not_exists_to_create_index(sql) ⇒ Object

‘CREATE [UNIQUE] INDEX [name]` → `CREATE [UNIQUE] INDEX IF NOT EXISTS [name]`. Use only for databases that support it (PostgreSQL, SQLite). MySQL does NOT support `CREATE INDEX IF NOT EXISTS` — do not call from the MySQL adapter.



21
22
23
24
25
26
# File 'lib/exwiw/ddl_postprocessor.rb', line 21

def add_if_not_exists_to_create_index(sql)
  sql.gsub(/\bCREATE(\s+UNIQUE)?\s+INDEX\b(?!\s+IF\s+NOT\s+EXISTS)/i) do
    unique = Regexp.last_match(1) || ""
    "CREATE#{unique} INDEX IF NOT EXISTS"
  end
end

.add_if_not_exists_to_create_schema(sql) ⇒ Object

‘CREATE SCHEMA [name]` → `CREATE SCHEMA IF NOT EXISTS [name]`.



29
30
31
32
33
# File 'lib/exwiw/ddl_postprocessor.rb', line 29

def add_if_not_exists_to_create_schema(sql)
  sql.gsub(/\bCREATE\s+SCHEMA\b(?!\s+IF\s+NOT\s+EXISTS)/i) do |m|
    "#{m} IF NOT EXISTS"
  end
end

.add_if_not_exists_to_create_sequence(sql) ⇒ Object

‘CREATE SEQUENCE [name]` → `CREATE SEQUENCE IF NOT EXISTS [name]`.



36
37
38
39
40
# File 'lib/exwiw/ddl_postprocessor.rb', line 36

def add_if_not_exists_to_create_sequence(sql)
  sql.gsub(/\bCREATE\s+SEQUENCE\b(?!\s+IF\s+NOT\s+EXISTS)/i) do |m|
    "#{m} IF NOT EXISTS"
  end
end

.add_if_not_exists_to_create_table(sql) ⇒ Object

‘CREATE TABLE [name]` → `CREATE TABLE IF NOT EXISTS [name]`. `TEMP` / `TEMPORARY` variants and already-IF-NOT-EXISTS lines are skipped.



12
13
14
15
16
# File 'lib/exwiw/ddl_postprocessor.rb', line 12

def add_if_not_exists_to_create_table(sql)
  sql.gsub(/\bCREATE\s+TABLE\b(?!\s+IF\s+NOT\s+EXISTS)/i) do |m|
    "#{m} IF NOT EXISTS"
  end
end

.wrap_add_constraint_in_do_block(sql) ⇒ Object



50
51
52
53
54
55
56
57
58
59
# File 'lib/exwiw/ddl_postprocessor.rb', line 50

def wrap_add_constraint_in_do_block(sql)
  sql.gsub(ADD_CONSTRAINT_RE) do |stmt|
    <<~SQL.chomp
      DO $exwiw$ BEGIN
        #{stmt.strip}
      EXCEPTION WHEN duplicate_object THEN NULL;
      END $exwiw$;
    SQL
  end
end