############################################################################# sub wish_to_adjust_options_for_table_columns { my ($options) = @_; $options -> {key} = ['name']; } ############################################################################# sub wish_to_clarify_demands_for_table_columns { my ($i, $options) = @_; $i -> {REMARKS} ||= delete $i -> {label}; exists $i -> {NULLABLE} or $i -> {NULLABLE} = $i -> {name} eq 'id' ? 0 : 1; exists $i -> {COLUMN_DEF} or $i -> {COLUMN_DEF} = undef; $i -> {TYPE_NAME} = uc $i -> {TYPE_NAME}; if ($i -> {TYPE_NAME} eq 'NUMERIC') { $i -> {TYPE_NAME} = 'DECIMAL'; } if ($i -> {TYPE_NAME} eq 'MEDIUMINT') { $i -> {TYPE_NAME} = 'BIGINT'; } if ($i -> {TYPE_NAME} =~ /TEXT$/) { $i -> {TYPE_NAME} = 'TEXT'; } if ($i -> {TYPE_NAME} eq 'DECIMAL') { $i -> {COLUMN_SIZE} ||= 10; $i -> {DECIMAL_DIGITS} ||= 0; } if ($i -> {TYPE_NAME} =~ /VARCHAR$/) { $i -> {COLUMN_SIZE} ||= 255; } if ($i -> {TYPE_NAME} eq 'TIMESTAMP') { $i -> {TYPE_NAME} = 'DATETIME'; $i -> {COLUMN_DEF} = 'GETDATE()'; } if ($i -> {TYPE_NAME} eq 'DATE') { $i -> {TYPE_NAME} = 'DATETIME'; } if (!$i -> {NULLABLE} && !defined $i -> {COLUMN_DEF} && $i -> {name} ne 'id') { $i -> {COLUMN_DEF} = $i -> {TYPE_NAME} =~ /INT$/ ? 0 : $i -> {TYPE_NAME} eq 'DECIMAL' ? 0 : $i -> {TYPE_NAME} eq 'DATETIME' ? '1970-01-01' : '' } if (defined $i -> {COLUMN_DEF}) { $i -> {COLUMN_DEF} .= ''; } } ################################################################################ sub wish_to_explore_existing_table_columns { my ($options) = @_; my $existing = {}; sql_select_loop ( q { SELECT column_name , data_type , column_default , is_nullable , numeric_precision , numeric_scale , character_maximum_length FROM information_schema.columns WHERE table_catalog = db_name() AND table_name = ? }, sub { my $name = $i -> {column_name}; $existing -> {$name} = my $def = { name => $name, TYPE_NAME => uc $i -> {data_type}, COLUMN_DEF => $i -> {column_default}, NULLABLE => ($i -> {is_nullable} =~ /^No/i ? 0 : 1), }; if ($def -> {COLUMN_DEF} =~ /^\(\'(.*)\'\)$/) { $def -> {COLUMN_DEF} = $1; } if ($def -> {TYPE_NAME} eq 'NUMERIC') { $def -> {TYPE_NAME} = 'DECIMAL'; } if ($def -> {TYPE_NAME} eq 'DECIMAL') { $def -> {COLUMN_SIZE} = $i -> {numeric_precision}; $def -> {DECIMAL_DIGITS} = $i -> {numeric_scale}; } elsif ($def -> {TYPE_NAME} =~ /CHAR$/) { $def -> {COLUMN_SIZE} = $i -> {character_maximum_length}; } }, $options -> {table} ); sql_select_loop ("EXEC sp_helpindex '$options->{table}'", sub { foreach my $col (split /\,/, $i -> {index_keys}) { $col =~ /^\w+/ or next; push @{$options -> {col2key} -> {lc $1}}, $i -> {index_name}; } }); return $existing; } ############################################################################# sub __genereate_sql_fragment_for_column { my ($i) = @_; return if $i -> {SQL}; $i -> {SQL} = $i -> {TYPE_NAME} . ( $i -> {TYPE_NAME} eq 'DECIMAL' ? " ($i->{COLUMN_SIZE}, $i->{DECIMAL_DIGITS})" : $i -> {TYPE_NAME} =~ /CHAR$/ ? " ($i->{COLUMN_SIZE})" : ''); $i -> {SQL} .= $i -> {NULLABLE} ? ' NULL' : ' NOT NULL'; $i -> {SQL_DEF} = $i -> {SQL}; if (defined $i -> {COLUMN_DEF}) { $i -> {COLUMN_DEF} =~ s{'}{''}g; #'; $i -> {SQL_DEF} .= " DEFAULT '$i->{COLUMN_DEF}'"; } %$i = map {$_ => $i -> {$_}} qw (name SQL SQL_DEF NULLABLE TYPE_NAME COLUMN_DEF); } ############################################################################# sub wish_to_update_demands_for_table_columns { my ($old, $new, $options) = @_; if ($old -> {TYPE_NAME} =~ /^N.*CHAR$/ and $new -> {TYPE_NAME} !~ /^N/ and $new -> {TYPE_NAME} =~ /(CHAR|TEXT)$/) { $new -> {TYPE_NAME} = 'N' . $new -> {TYPE_NAME}; } __adjust_column_dimensions ($old, $new, { char => qr {CHAR$}, decimal => 'DECIMAL', }); __genereate_sql_fragment_for_column ($_) foreach ($old, $new); } ############################################################################# sub wish_to_schedule_modifications_for_table_columns { my ($old, $new, $todo, $options) = @_; unless ($old -> {TYPE_NAME} eq $new -> {TYPE_NAME} and $new -> {TYPE_NAME} =~ /VARCHAR$/) { sql_do ("DROP INDEX [$_]") foreach @{$options -> {col2key} -> {$new -> {name}}}; } push @{$todo -> {$old -> {COLUMN_DEF} eq $new -> {COLUMN_DEF} ? 'alter' : 'recreate'}}, $new; } ############################################################################# sub wish_to_actually_alter_table_columns { my ($items, $options) = @_; sql_do ("ALTER TABLE [$options->{table}] ALTER COLUMN [$_->{name}] $_->{SQL}") foreach @$items; } ############################################################################# sub wish_to_actually_create_table_columns { my ($items, $options) = @_; __genereate_sql_fragment_for_column ($_) foreach @$items; sql_do ("ALTER TABLE [$options->{table}] ADD " . (join ', ', map {"[$_->{name}] $_->{SQL_DEF}"} @$items)); } ############################################################################# sub wish_to_actually_recreate_table_columns { my ($items, $options) = @_; foreach my $i (@$items) { foreach ( "ALTER TABLE $options->{table} ADD mssuxx $i->{SQL_DEF} ", "UPDATE $options->{table} SET mssuxx = $i->{name}", "ALTER TABLE $options->{table} DROP COLUMN $i->{name}", "EXEC sp_rename '$options->{table}.mssuxx', '$i->{name}', 'COLUMN'" ) { sql_do ($_) } } } 1;