| 1 | #!/usr/bin/perl |
|---|
| 2 | |
|---|
| 3 | use strict; |
|---|
| 4 | use warnings; |
|---|
| 5 | |
|---|
| 6 | open FILE, "< $ARGV[0]" or die "Usage: $0 <file>\nFailed: $!"; |
|---|
| 7 | |
|---|
| 8 | my %table_pk; |
|---|
| 9 | my %table_fk; |
|---|
| 10 | my %table_unique; |
|---|
| 11 | |
|---|
| 12 | while (my $line = <FILE>) |
|---|
| 13 | { |
|---|
| 14 | next unless $line =~ /ALTER TABLE ONLY (\S+)/; |
|---|
| 15 | my $table = $1; |
|---|
| 16 | |
|---|
| 17 | my $constraint = <FILE>; # read next line |
|---|
| 18 | |
|---|
| 19 | if ($constraint =~ /^ {4}ADD CONSTRAINT (\S+) (.*);$/) |
|---|
| 20 | { |
|---|
| 21 | my $name = $1; |
|---|
| 22 | my $body = $2; |
|---|
| 23 | |
|---|
| 24 | if ($body =~ /^UNIQUE \((.*)\)$/) |
|---|
| 25 | { |
|---|
| 26 | my @unique_fields = split m{, }, $1; |
|---|
| 27 | $table_unique{$table}{$name} = \@unique_fields; |
|---|
| 28 | } |
|---|
| 29 | elsif ($body =~ /PRIMARY KEY \((.*)\)$/) |
|---|
| 30 | { |
|---|
| 31 | my @pk_fields = split m{, }, $1; |
|---|
| 32 | $table_pk{$table} and die "duplicate pk for table $table"; |
|---|
| 33 | $table_pk{$table} = { map {$_ => 1} @pk_fields }; |
|---|
| 34 | } |
|---|
| 35 | elsif ($body =~ /FOREIGN KEY \(([^)]+)\) REFERENCES (.+)\(([^)]+)\)/) |
|---|
| 36 | { |
|---|
| 37 | # ON UPDATE RESTRICT ON DELETE RESTRICT; |
|---|
| 38 | $table_fk{$table}{$name} = [$1,$2,$3]; |
|---|
| 39 | } |
|---|
| 40 | else |
|---|
| 41 | { |
|---|
| 42 | warn "Ignored unknown constraint on $table: $body"; |
|---|
| 43 | } |
|---|
| 44 | } |
|---|
| 45 | else |
|---|
| 46 | { |
|---|
| 47 | warn "Ignored unknown ALTER TABLE on $table: $constraint"; |
|---|
| 48 | } |
|---|
| 49 | } |
|---|
| 50 | |
|---|
| 51 | close FILE; |
|---|
| 52 | open FILE, "< $ARGV[0]" or die; |
|---|
| 53 | |
|---|
| 54 | sub create_index ($$$) |
|---|
| 55 | { |
|---|
| 56 | my ($index_name, $table, $fields) = @_; |
|---|
| 57 | return "addIndex(uniqueIndex(\"$index_name\", \"$table\", ". |
|---|
| 58 | join(",", map {"\"$_\""} @$fields) . |
|---|
| 59 | "));\n"; |
|---|
| 60 | } |
|---|
| 61 | |
|---|
| 62 | my ($table, $pk, $fk, $unique, $first_column); |
|---|
| 63 | |
|---|
| 64 | while (<FILE>) |
|---|
| 65 | { |
|---|
| 66 | if (/CREATE TABLE (.*) \(/) |
|---|
| 67 | { |
|---|
| 68 | $table = $1; |
|---|
| 69 | print "createTable(table(\"$table\",\n"; |
|---|
| 70 | $pk = $table_pk{$table}; |
|---|
| 71 | $fk = $table_fk{$table}; |
|---|
| 72 | $unique = $table_unique{$table}; |
|---|
| 73 | $first_column = 1; |
|---|
| 74 | } |
|---|
| 75 | elsif (/CREATE UNIQUE INDEX (\S+) ON (\S+) .* \((.*)\);/) |
|---|
| 76 | { |
|---|
| 77 | my $name = $1; |
|---|
| 78 | my $table = $2; |
|---|
| 79 | my @unique_fields = split m{, }, $3; |
|---|
| 80 | print create_index($name, $table, \@unique_fields); |
|---|
| 81 | } |
|---|
| 82 | elsif (m{ # extended regular expression, whitespace and comments ignored |
|---|
| 83 | ^ # start of line |
|---|
| 84 | \s{4} # four space indent |
|---|
| 85 | (\S+) # one word, column name, group 1 |
|---|
| 86 | \s # space |
|---|
| 87 | ( # start of group 2 (the entire type) |
|---|
| 88 | [^ ,(]+ # a word without a comma (not "SMALLINT,") or an open parenthesis |
|---|
| 89 | | # or |
|---|
| 90 | ( # start of group 3 (the entire type if it contains parentheses) |
|---|
| 91 | ([^(]+) # anything that doesn't contain parentheses (type name), group 4 |
|---|
| 92 | \( # followed by an open para |
|---|
| 93 | (\d+) # followed by a number, group 5 (length or precision) |
|---|
| 94 | ( # optionally followed by, group 6 |
|---|
| 95 | , # a comma |
|---|
| 96 | (\d+) # and another number, group 7 (scale) |
|---|
| 97 | )? # group 6 is optional |
|---|
| 98 | \) # end parenthesis |
|---|
| 99 | ) # end group 3 (the entire type if it contains parentheses) |
|---|
| 100 | | # or |
|---|
| 101 | timestamp \s without \s time \s zone # exactly "timestamp without time zone" |
|---|
| 102 | ) # end of group 2 |
|---|
| 103 | (\s DEFAULT \s # group 8, optional DEFAULT clause |
|---|
| 104 | (\S+) # group 9, default value |
|---|
| 105 | )? # end of optional group 8 |
|---|
| 106 | (\s NOT \s NULL)? # group 10, optional "NOT NULL" option |
|---|
| 107 | (,)? # optional comma at end of line (not present for last column), group 11 |
|---|
| 108 | $ # end of line/newline |
|---|
| 109 | }x) |
|---|
| 110 | { |
|---|
| 111 | # start a column, include the quoted name |
|---|
| 112 | $_ = "\tcolumn(\"$1\", "; |
|---|
| 113 | |
|---|
| 114 | # convert type |
|---|
| 115 | if ($4 and lc($4) eq "character varying") |
|---|
| 116 | { |
|---|
| 117 | $_ .= "VARCHAR"; |
|---|
| 118 | } |
|---|
| 119 | elsif ($4 and lc($4) eq "text") |
|---|
| 120 | { |
|---|
| 121 | $_ .= "CLOB"; |
|---|
| 122 | } |
|---|
| 123 | elsif ($4 and lc($4) eq "character") |
|---|
| 124 | { |
|---|
| 125 | $_ .= "CHAR"; |
|---|
| 126 | } |
|---|
| 127 | elsif (lc($2) eq "timestamp without time zone") |
|---|
| 128 | { |
|---|
| 129 | $_ .= "TIMESTAMP"; |
|---|
| 130 | } |
|---|
| 131 | elsif ($4) |
|---|
| 132 | { |
|---|
| 133 | $_ .= uc($4); # wild guess |
|---|
| 134 | } |
|---|
| 135 | else |
|---|
| 136 | { |
|---|
| 137 | $_ .= uc($2); # wild guess |
|---|
| 138 | } |
|---|
| 139 | |
|---|
| 140 | # length/precision |
|---|
| 141 | if ($4 and ($4 eq "decimal" or $4 eq "numeric")) # only types that have precision? |
|---|
| 142 | { |
|---|
| 143 | $_ .= ", precision($5)"; |
|---|
| 144 | } |
|---|
| 145 | elsif ($5) |
|---|
| 146 | { |
|---|
| 147 | $_ .= ", length($5)"; |
|---|
| 148 | } |
|---|
| 149 | |
|---|
| 150 | # scale, optional |
|---|
| 151 | if ($7) |
|---|
| 152 | { |
|---|
| 153 | $_ .= ", scale($7)"; |
|---|
| 154 | } |
|---|
| 155 | |
|---|
| 156 | # default option |
|---|
| 157 | if ($8) |
|---|
| 158 | { |
|---|
| 159 | $_ .= ", defaultValue($9)"; |
|---|
| 160 | } |
|---|
| 161 | |
|---|
| 162 | # notnull option |
|---|
| 163 | if ($10) |
|---|
| 164 | { |
|---|
| 165 | $_ .= ", notnull()"; |
|---|
| 166 | } |
|---|
| 167 | |
|---|
| 168 | if ($pk and $pk->{$1}) |
|---|
| 169 | { |
|---|
| 170 | $_ .= ", primarykey()"; |
|---|
| 171 | } |
|---|
| 172 | |
|---|
| 173 | # end of line and column definition |
|---|
| 174 | $_ .= ")"; |
|---|
| 175 | |
|---|
| 176 | if ($first_column) |
|---|
| 177 | { |
|---|
| 178 | $first_column = 0; |
|---|
| 179 | } |
|---|
| 180 | else |
|---|
| 181 | { |
|---|
| 182 | print ",\n"; |
|---|
| 183 | } |
|---|
| 184 | |
|---|
| 185 | print $_; |
|---|
| 186 | } |
|---|
| 187 | elsif (/^ {4}CONSTRAINT /) |
|---|
| 188 | { |
|---|
| 189 | # migrate4j doesn't support this, ignore it |
|---|
| 190 | } |
|---|
| 191 | elsif (/^ {4}ADD CONSTRAINT /) |
|---|
| 192 | { |
|---|
| 193 | # already parsed and processed |
|---|
| 194 | } |
|---|
| 195 | elsif (/^ {4}/) # looks like a column |
|---|
| 196 | { |
|---|
| 197 | warn "Ignored line: $_"; |
|---|
| 198 | } |
|---|
| 199 | elsif (/^\);$/) |
|---|
| 200 | { |
|---|
| 201 | print "\n\t));\n"; |
|---|
| 202 | |
|---|
| 203 | if ($unique) |
|---|
| 204 | { |
|---|
| 205 | foreach my $index_name (keys %$unique) |
|---|
| 206 | { |
|---|
| 207 | my $fields = $unique->{$index_name}; |
|---|
| 208 | print create_index($index_name, $table, $fields); |
|---|
| 209 | } |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | if ($fk) |
|---|
| 213 | { |
|---|
| 214 | foreach my $fk_name (keys %$fk) |
|---|
| 215 | { |
|---|
| 216 | my $fk_info = $fk->{$fk_name}; |
|---|
| 217 | my ($parent_field, $child_table, $child_field) = @$fk_info; |
|---|
| 218 | my @parent_fields = split ', *', $parent_field; |
|---|
| 219 | my @child_fields = split ', *', $child_field; |
|---|
| 220 | |
|---|
| 221 | if (@parent_fields > 1 or @child_fields > 1) |
|---|
| 222 | { |
|---|
| 223 | print "addForeignKey(new ForeignKey(\"$fk_name\",". |
|---|
| 224 | "\n\t\"$table\", ". |
|---|
| 225 | "\n\tnew String[]{".join(',', map {"\"$_\""} @parent_fields)."}, ". |
|---|
| 226 | "\n\t\"$child_table\", ". |
|---|
| 227 | "\n\tnew String[]{".join(',', map {"\"$_\""} @child_fields)."}". |
|---|
| 228 | "));\n"; |
|---|
| 229 | } |
|---|
| 230 | else |
|---|
| 231 | { |
|---|
| 232 | print "addForeignKey(new ForeignKey(\"$fk_name\", ". |
|---|
| 233 | "\n\t\"$table\", \"$parent_field\"," . |
|---|
| 234 | "\n\t\"$child_table\", \"$child_field\"));\n"; |
|---|
| 235 | } |
|---|
| 236 | } |
|---|
| 237 | } |
|---|
| 238 | |
|---|
| 239 | print "\n"; |
|---|
| 240 | } |
|---|
| 241 | } |
|---|
| 242 | |
|---|
| 243 | exit 0; |
|---|