I recently updated a script that checks Apache httpd process sizes and saves the information to an SQLite database file. As part of some new functionality in the script, I needed to modify the SQLite database to add an additional column and some indexes. When creating new tables, you can use create table if not exists $table (); for example, but the same “if not exists” condition is not available when adding columns or creating indexes.
There are several solutions available to create a similar “if not exists” test for columns and indexes, but all of them (or at least the ones I found) are based on long SQL statements and/or stored procedures. I wanted something more flexible and perl-based, so wrote the following to set hash elements (%dbcol_exists and %dbidx_exists) using column and index names as references. The section that retrieves table / index names from the database and sets the hash elements, has been highlighted in the following snippet of code.
After setting the hash elements, perl can quickly loop through the column and index definition arrays (@dbcol and @dbidx) to create the missing columns and indexes. This snippet of code was written for SQLite, and assumes you’ve already connected to the database using $dbh = DBI->connect();.
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
# Use an array instead of a hash to keep the column order. Always add new # columns to the end of the array. my @dbcol = ( { 'name' => 'DateTimeAdded', 'definition' => 'DATE', }, { 'name' => 'HttpdRealAvg', 'definition' => 'INTEGER', }, { 'name' => 'HttpdSharedAvg', 'definition' => 'INTEGER', }, { 'name' => 'HttpdRealTot', 'definition' => 'INTEGER', }, { 'name' => 'HttpdRunning', 'definition' => 'INTEGER', }, ); my @dbidx = ( { 'name' => 'HttpdRealAvgIdx', 'table' => 'HttpdRealAvg', }, { 'name' => 'HttpdRunningIdx', 'table' => 'HttpdRunning', }, ); # Use hashes to quickly define (and lookup) which tables/indexes already exist. my %dbcol_exists = (); my %dbidx_exists = (); # Get the table and index information as a two-dimensional array, loop through # each first-dimension array (the array elements are another array describing a # table or index), and set a hash string using the table / index name (second # element of second dimension). for ( @{ $dbh->selectall_arrayref( "PRAGMA TABLE_INFO($dbtable)") } ) { $dbcol_exists{$_->[1]} = 1; }; for ( @{ $dbh->selectall_arrayref( "PRAGMA INDEX_LIST($dbtable)") } ) { $dbidx_exists{$_->[1]} = 1; }; # Create missing columns by looping through the @dbcol array and checking for # missing %dbcol_exists hash elements (using the column name as the hash # reference). for my $col ( @dbcol ) { $dbh->do("ALTER TABLE $dbtable ADD COLUMN $col->{'name'} $col->{'definition'}") unless ( $dbcol_exists{$col->{'name'}} ); } # Create missing indexes by looping through the @dbidx array and checking for # missing %dbidx_exists hash elements (using the index name as the hash # reference). for my $idx ( @dbidx ) { $dbh->do("CREATE INDEX $idx->{'name'} ON $dbtable ($idx->{'table'})") unless ( $dbidx_exists{$idx->{'name'}} ); } |
Did you find this post useful? Share it with your circles / friends, or leave a quick note bellow.
Thank you,
js.

SHOW COLUMNS FROM {table}with MySQL might return a very similar array. And if you need additional information on the table, besides just the column names, MySQL::TableInfo on CPAN could be a good alternative. js.