1#!/usr/bin/env perl 2 3use strict; 4use warnings; 5 6use Carp; 7use DBI; 8use Getopt::Long::Descriptive; 9use Try::Tiny; 10 11my @supported_dbs = qw/ 12 db2 13 default 14 mysql 15 oracle 16 pg 17/; 18 19my ( $opt, $usage ) = describe_options( 20 "$0 %o", 21 [ 'db_version|b=s', 'Database version (mainly for a local DB2 v8 instance) -- optional' ], 22 [ 'dsn|d=s', 'Database source name (dsn) to connect to -- required' ], 23 [ 'execute|e', 'Execute the database update -- otherwise will just rollback' ], 24 [ 'schema|s=s', 'Database schema -- optional' ], 25 [ 'pass|p=s', 'Database password -- optional' ], 26 [ 'trace|t', 'Enable DBI_TRACE -- optional' ], 27 [ 'user|u=s', 'Database username -- optional' ], 28 [], 29 [ 'help|h', 'Print usage message and exit' ], 30); 31 32print( $usage->text ), exit if $opt->help or !$opt->dsn; 33 34my $schema_attributes = { 35 AutoCommit => 0, 36 RaiseError => 1, 37}; 38if ( $opt->dsn =~ m/db2/i ) { 39 $schema_attributes->{db2_set_schema} = $opt->schema 40 or croak "***** Must supply a schema for db2."; 41} 42 43my $dbh 44 = DBI->connect( $opt->dsn, $opt->user, $opt->pass, $schema_attributes ) 45 or croak "***** Error connecting to db:\n" . $DBI::errstr; 46 47DBI->trace(1) if $opt->trace; 48 49try { 50 my %update = map { $_ => \&$_ } @supported_dbs; 51 my $code_ref = $update{ lc($dbh->{Driver}{Name}) } || $update{'default'}; 52 if ( $code_ref ) { 53 $code_ref->($dbh); 54 if ( $opt->execute ) { 55 $dbh->commit; 56 } 57 else { 58 print "***** Rolling back changes as the 'execute' parameter was not passed.\n"; 59 $dbh->rollback; 60 } 61 } 62 else { 63 print "***** Database '" . lc($dbh->{Driver}{Name}) . "' not supported.\n"; 64 } 65} 66catch { 67 carp "***** Database definition update aborted: $_"; 68 $dbh->rollback; 69} 70finally { 71 $dbh->disconnect; 72}; 73 74sub default { 75 my $dbh = shift; 76 print "Executing 'default' database update.\n"; 77 my @sql = ( 78 79 # audit_log_changeset 80 'ALTER TABLE audit_log_changeset RENAME COLUMN "USER" TO "USER_ID"', 81 'ALTER TABLE audit_log_changeset RENAME COLUMN "TIMESTAMP" TO "CREATED_ON"', 82 83 # audit_log_action 84 'ALTER TABLE audit_log_action RENAME COLUMN "CHANGESET" TO "CHANGESET_ID"', 85 'ALTER TABLE audit_log_action RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 86 'ALTER TABLE audit_log_action RENAME COLUMN "TYPE" TO "ACTION_TYPE"', 87 88 # audit_log_change 89 'ALTER TABLE audit_log_change RENAME COLUMN "ACTION" TO "ACTION_ID"', 90 'ALTER TABLE audit_log_change RENAME COLUMN "FIELD" TO "FIELD_ID"', 91 92 # audit_log_field 93 'ALTER TABLE audit_log_field RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 94 ); 95 96 $dbh->do($_) for @sql; 97} 98 99sub db2 { 100 my $dbh = shift; 101 print "Executing 'db2' database update.\n"; 102 my @sql; 103 if ( $opt->db_version && $opt->db_version =~ /8\.?/ ) { 104 @sql = ( 105 ### DROP ALL FOREIGN KEY INDEXES 106 107 'DROP INDEX "' . ($opt->schema) . '"."AL_CS_IDX_U"', 108 'DROP INDEX "' . ($opt->schema) . '"."AL_A_IDX_AT"', 109 'DROP INDEX "' . ($opt->schema) . '"."AL_A_IDX_CS"', 110 'DROP INDEX "' . ($opt->schema) . '"."AL_C_IDX_A"', 111 'DROP INDEX "' . ($opt->schema) . '"."AL_C_IDX_F"', 112 'DROP INDEX "' . ($opt->schema) . '"."AL_F_IDX_AT"', 113 114 ### DROP ALL FOREIGN KEYS 115 116 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" DROP FOREIGN KEY "AL_CS_FK_U"', 117 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" DROP FOREIGN KEY "AL_A_FK_AT"', 118 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" DROP FOREIGN KEY "AL_A_FK_CS"', 119 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" DROP FOREIGN KEY "AL_C_FK_A"', 120 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" DROP FOREIGN KEY "AL_C_FK_F"', 121 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" DROP FOREIGN KEY "AL_F_FK_AT"', 122 123 ### ALTER TABLE STRUCTURE 124 125 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" RENAME COLUMN "USER" TO "USER_ID"', 126 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" RENAME COLUMN "TIMESTAMP" TO "CREATED_ON"', 127 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" RENAME COLUMN "CHANGESET" TO "CHANGESET_ID"', 128 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 129 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" RENAME COLUMN "TYPE" TO "ACTION_TYPE"', 130 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" RENAME COLUMN "ACTION" TO "ACTION_ID"', 131 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" RENAME COLUMN "FIELD" TO "FIELD_ID"', 132 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 133 134 #### RE-ADD THE INDEXES AND CONSTRAINTS 135 136 # add the foreign key indexes 137 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET_IDX_USER" ON "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" ( "USER_ID" )', 138 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_FIELD_IDX_AUDITED_TABLE" ON "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" ( "AUDITED_TABLE_ID" )', 139 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_ACTION_IDX_AUDITED_TABLE" ON "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ( "AUDITED_TABLE_ID" )', 140 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_ACTION_IDX_CHANGESET" ON "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ( "CHANGESET_ID" )', 141 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE_IDX_ACTION" ON "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ( "ACTION_ID" )', 142 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE_IDX_FIELD" ON "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ( "FIELD_ID" )', 143 144 # add the foreign keys 145 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" ADD CONSTRAINT AUDIT_LOG_CHANGESET_FK_USER FOREIGN KEY ("USER_ID") REFERENCES AUDIT_LOG_USER("ID") ON DELETE CASCADE', 146 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" ADD CONSTRAINT AUDIT_LOG_FIELD_FK_AUDITED_TABLE FOREIGN KEY ("AUDITED_TABLE_ID") REFERENCES AUDIT_LOG_TABLE("ID") ON DELETE CASCADE', 147 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ADD CONSTRAINT AUDIT_LOG_ACTION_FK_AUDITED_TABLE FOREIGN KEY ("AUDITED_TABLE_ID") REFERENCES AUDIT_LOG_TABLE("ID") ON DELETE CASCADE', 148 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ADD CONSTRAINT AUDIT_LOG_ACTION_FK_CHANGESET FOREIGN KEY ("CHANGESET_ID") REFERENCES AUDIT_LOG_CHANGESET("ID") ON DELETE CASCADE', 149 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ADD CONSTRAINT AUDIT_LOG_CHANGE_FK_ACTION FOREIGN KEY ("ACTION_ID") REFERENCES AUDIT_LOG_ACTION("ID") ON DELETE CASCADE', 150 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ADD CONSTRAINT AUDIT_LOG_CHANGE_FK_FIELD FOREIGN KEY ("FIELD_ID") REFERENCES AUDIT_LOG_FIELD("ID") ON DELETE CASCADE', 151 ); 152 } 153 else { 154 @sql = ( 155 ### DROP ALL FOREIGN KEY INDEXES 156 157 'DROP INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET_IDX_USER"', 158 'DROP INDEX "' . ($opt->schema) . '"."AUDIT_LOG_ACTION_IDX_AUDITED_TABLE"', 159 'DROP INDEX "' . ($opt->schema) . '"."AUDIT_LOG_ACTION_IDX_CHANGESET"', 160 'DROP INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE_IDX_ACTION"', 161 'DROP INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE_IDX_FIELD"', 162 'DROP INDEX "' . ($opt->schema) . '"."AUDIT_LOG_FIELD_IDX_AUDITED_TABLE"', 163 164 ### DROP ALL FOREIGN KEYS 165 166 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" DROP FOREIGN KEY "AUDIT_LOG_CHANGESET_FK_USER"', 167 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" DROP FOREIGN KEY "AUDIT_LOG_ACTION_FK_AUDITED_TABLE"', 168 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" DROP FOREIGN KEY "AUDIT_LOG_ACTION_FK_CHANGESET"', 169 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" DROP FOREIGN KEY "AUDIT_LOG_CHANGE_FK_ACTION"', 170 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" DROP FOREIGN KEY "AUDIT_LOG_CHANGE_FK_FIELD"', 171 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" DROP FOREIGN KEY "AUDIT_LOG_FIELD_FK_AUDITED_TABLE"', 172 173 ### ALTER TABLE STRUCTURE 174 175 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" RENAME COLUMN "USER" TO "USER_ID"', 176 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" RENAME COLUMN "TIMESTAMP" TO "CREATED_ON"', 177 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" RENAME COLUMN "CHANGESET" TO "CHANGESET_ID"', 178 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 179 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" RENAME COLUMN "TYPE" TO "ACTION_TYPE"', 180 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" RENAME COLUMN "ACTION" TO "ACTION_ID"', 181 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" RENAME COLUMN "FIELD" TO "FIELD_ID"', 182 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 183 184 #### RE-ADD THE INDEXES AND CONSTRAINTS 185 186 # add the foreign key indexes 187 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET_IDX_USER" ON "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" ( "USER_ID" )', 188 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_FIELD_IDX_AUDITED_TABLE" ON "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" ( "AUDITED_TABLE_ID" )', 189 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_ACTION_IDX_AUDITED_TABLE" ON "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ( "AUDITED_TABLE_ID" )', 190 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_ACTION_IDX_CHANGESET" ON "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ( "CHANGESET_ID" )', 191 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE_IDX_ACTION" ON "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ( "ACTION_ID" )', 192 'CREATE INDEX "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE_IDX_FIELD" ON "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ( "FIELD_ID" )', 193 194 # add the foreign keys 195 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGESET" ADD CONSTRAINT AUDIT_LOG_CHANGESET_FK_USER FOREIGN KEY ("USER_ID") REFERENCES ' . ($opt->schema) . '.AUDIT_LOG_USER("ID") ON DELETE CASCADE', 196 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_FIELD" ADD CONSTRAINT AUDIT_LOG_FIELD_FK_AUDITED_TABLE FOREIGN KEY ("AUDITED_TABLE_ID") REFERENCES ' . ($opt->schema) . '.AUDIT_LOG_TABLE("ID") ON DELETE CASCADE', 197 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ADD CONSTRAINT AUDIT_LOG_ACTION_FK_AUDITED_TABLE FOREIGN KEY ("AUDITED_TABLE_ID") REFERENCES ' . ($opt->schema) . '.AUDIT_LOG_TABLE("ID") ON DELETE CASCADE', 198 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_ACTION" ADD CONSTRAINT AUDIT_LOG_ACTION_FK_CHANGESET FOREIGN KEY ("CHANGESET_ID") REFERENCES ' . ($opt->schema) . '.AUDIT_LOG_CHANGESET("ID") ON DELETE CASCADE', 199 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ADD CONSTRAINT AUDIT_LOG_CHANGE_FK_ACTION FOREIGN KEY ("ACTION_ID") REFERENCES ' . ($opt->schema) . '.AUDIT_LOG_ACTION("ID") ON DELETE CASCADE', 200 'ALTER TABLE "' . ($opt->schema) . '"."AUDIT_LOG_CHANGE" ADD CONSTRAINT AUDIT_LOG_CHANGE_FK_FIELD FOREIGN KEY ("FIELD_ID") REFERENCES ' . ($opt->schema) . '.AUDIT_LOG_FIELD("ID") ON DELETE CASCADE', 201 ); 202 } 203 204 $dbh->do($_) for @sql; 205} 206 207sub mysql { 208 my $dbh = shift; 209 print "Executing 'mysql' database update.\n"; 210 my @sql = ( 211 212 # audit_log_changeset 213 'ALTER TABLE `audit_log_changeset` DROP FOREIGN KEY `audit_log_changeset_fk_user`', 214 'ALTER TABLE `audit_log_changeset` CHANGE `timestamp` `created_on` TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, 215 CHANGE `user` `user_id` INTEGER DEFAULT NULL, 216 DROP INDEX `audit_log_changeset_idx_user`, 217 ADD INDEX `audit_log_changeset_idx_user` USING BTREE(`user_id`), 218 ADD CONSTRAINT `audit_log_changeset_fk_user` FOREIGN KEY `audit_log_changeset_fk_user` (`user_id`) 219 REFERENCES `audit_log_user` (`id`) 220 ON DELETE CASCADE 221 ON UPDATE CASCADE', 222 223 # audit_log_action 224 'ALTER TABLE `audit_log_action` DROP FOREIGN KEY `audit_log_action_fk_audited_table`', 225 'ALTER TABLE `audit_log_action` DROP FOREIGN KEY `audit_log_action_fk_changeset`', 226 'ALTER TABLE `audit_log_action` CHANGE `changeset` `changeset_id` INTEGER NOT NULL, 227 CHANGE `audited_table` `audited_table_id` INTEGER NOT NULL, 228 DROP INDEX `audit_log_action_idx_audited_table`, 229 ADD INDEX `audit_log_action_idx_audited_table` USING BTREE(`audited_table_id`), 230 DROP INDEX `audit_log_action_idx_changeset`, 231 ADD INDEX `audit_log_action_idx_changeset` USING BTREE(`changeset_id`), 232 ADD CONSTRAINT `audit_log_action_fk_audited_table` FOREIGN KEY `audit_log_action_fk_audited_table` (`audited_table_id`) 233 REFERENCES `audit_log_table` (`id`) 234 ON DELETE CASCADE 235 ON UPDATE CASCADE, 236 ADD CONSTRAINT `audit_log_action_fk_canngeset` FOREIGN KEY `audit_log_action_fk_canngeset` (`changeset_id`) 237 REFERENCES `audit_log_changeset` (`id`) 238 ON DELETE CASCADE 239 ON UPDATE CASCADE', 240 'ALTER TABLE `audit_log_action CHANGE `type` `action_type` VARCHAR(10) NOT NULL', 241 242 # audit_log_change 243 'ALTER TABLE `audit_log_change` DROP FOREIGN KEY `audit_log_change_fk_action`', 244 'ALTER TABLE `audit_log_change` DROP FOREIGN KEY `audit_log_change_fk_field`', 245 246 'ALTER TABLE `audit_log_change` CHANGE `action` `action_id` INTEGER NOT NULL, 247 CHANGE `field` `field_id` INTEGER NOT NULL, 248 DROP INDEX `audit_log_change_idx_action`, 249 ADD INDEX `audit_log_change_idx_action` USING BTREE(`action_id`), 250 DROP INDEX `audit_log_change_idx_field`, 251 ADD INDEX `audit_log_change_idx_field` USING BTREE(`field_id`), 252 ADD CONSTRAINT `audit_log_change_fk_action` FOREIGN KEY `audit_log_change_fk_action` (`action_id`) 253 REFERENCES `audit_log_action` (`id`) 254 ON DELETE CASCADE 255 ON UPDATE CASCADE, 256 ADD CONSTRAINT `audit_log_change_fk_field` FOREIGN KEY `audit_log_change_fk_field` (`field_id`) 257 REFERENCES `audit_log_field` (`id`) 258 ON DELETE CASCADE 259 ON UPDATE CASCADE', 260 261 # audit_log_field 262 'ALTER TABLE `audit_log_field` DROP FOREIGN KEY `audit_log_field_fk_audited_table`', 263 264 'ALTER TABLE `audit_log_field` CHANGE `audited_table` `audited_table_id` INTEGER NOT NULL, 265 DROP INDEX `audit_log_field_idx_audited_table`, 266 ADD INDEX `audit_log_field_idx_audited_table` USING BTREE(`audited_table_id`), 267 ADD CONSTRAINT `audit_log_field_fk_audited_table` FOREIGN KEY `audit_log_field_fk_audited_table` (`audited_table_id`) 268 REFERENCES `audit_log_table` (`id`) 269 ON DELETE CASCADE 270 ON UPDATE CASCADE', 271 ); 272 273 $dbh->do($_) for @sql; 274} 275 276sub oracle { 277 my $dbh = shift; 278 print "Executing 'oracle' database update.\n"; 279 my @sql = ( 280 281 # audit_log_changeset 282 'ALTER TABLE audit_log_changeset RENAME COLUMN "USER" TO "USER_ID"', 283 'ALTER TABLE audit_log_changeset RENAME COLUMN "TIMESTAMP" TO "CREATED_ON"', 284 285 # audit_log_action 286 'ALTER TABLE audit_log_action RENAME COLUMN "CHANGESET" TO "CHANGESET_ID"', 287 'ALTER TABLE audit_log_action RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 288 'ALTER TABLE audit_log_action RENAME COLUMN "TYPE" TO "ACTION_TYPE"', 289 290 # audit_log_change 291 'ALTER TABLE audit_log_change RENAME COLUMN "ACTION" TO "ACTION_ID"', 292 'ALTER TABLE audit_log_change RENAME COLUMN "FIELD" TO "FIELD_ID"', 293 294 # audit_log_field 295 'ALTER TABLE audit_log_field RENAME COLUMN "AUDITED_TABLE" TO "AUDITED_TABLE_ID"', 296 ); 297 298 $dbh->do($_) for @sql; 299} 300 301sub pg { 302 my $dbh = shift; 303 print "Executing 'pg' database update.\n"; 304 my @sql = ( 305 306 # audit_log_changeset 307 'ALTER TABLE audit_log_changeset RENAME COLUMN "user" TO "user_id"', 308 'ALTER TABLE audit_log_changeset RENAME COLUMN "timestamp" TO "created_on"', 309 310 # audit_log_action 311 'ALTER TABLE audit_log_action RENAME COLUMN "changeset" TO "changeset_id"', 312 'ALTER TABLE audit_log_action RENAME COLUMN "audited_table" TO "audited_table_id"', 313 'ALTER TABLE audit_log_action RENAME COLUMN "type" TO "action_type"', 314 315 # audit_log_change 316 'ALTER TABLE audit_log_change RENAME COLUMN "action" TO "action_id"', 317 'ALTER TABLE audit_log_change RENAME COLUMN "field" TO "field_id"', 318 319 # audit_log_field 320 'ALTER TABLE audit_log_field RENAME COLUMN "audited_table" TO "audited_table_id"', 321 ); 322 323 $dbh->do($_) for @sql; 324} 325