summaryrefslogtreecommitdiffstats
path: root/Bugzilla/DB.pm
diff options
context:
space:
mode:
authormkanat%bugzilla.org <>2007-03-11 01:21:19 +0100
committermkanat%bugzilla.org <>2007-03-11 01:21:19 +0100
commit40a199771b751ebf7378efe32a68584ad7570ee7 (patch)
treefd2dbdbdbb782cd3cb5fa3bd4e09dd5be9fa3c09 /Bugzilla/DB.pm
parent2884cd8606668e3174617cecf159e9e2bd128edd (diff)
downloadbugzilla-40a199771b751ebf7378efe32a68584ad7570ee7.tar.gz
bugzilla-40a199771b751ebf7378efe32a68584ad7570ee7.tar.xz
Bug 373442: Add referential integrity against the profiles table in some more simple places
Patch By Max Kanat-Alexander <mkanat@bugzilla.org> (module owner) a=mkanat
Diffstat (limited to 'Bugzilla/DB.pm')
-rw-r--r--Bugzilla/DB.pm92
1 files changed, 86 insertions, 6 deletions
diff --git a/Bugzilla/DB.pm b/Bugzilla/DB.pm
index e4e30a8d3..22c6bbafa 100644
--- a/Bugzilla/DB.pm
+++ b/Bugzilla/DB.pm
@@ -43,6 +43,7 @@ use Bugzilla::Error;
use Bugzilla::DB::Schema;
use List::Util qw(max);
+use Storable qw(dclone);
#####################################################################
# Constants
@@ -428,6 +429,23 @@ sub bz_populate_enum_tables {
}
}
+sub bz_setup_foreign_keys {
+ my ($self) = @_;
+
+ # We use _bz_schema because bz_add_table has removed all REFERENCES
+ # items from _bz_real_schema.
+ my @tables = $self->_bz_schema->get_table_list();
+ foreach my $table (@tables) {
+ my @columns = $self->_bz_schema->get_table_columns($table);
+ foreach my $column (@columns) {
+ my $def = $self->_bz_schema->get_column_abstract($table, $column);
+ if ($def->{REFERENCES}) {
+ $self->bz_add_fk($table, $column, $def->{REFERENCES});
+ }
+ }
+ }
+}
+
#####################################################################
# Schema Modification Methods
#####################################################################
@@ -463,6 +481,24 @@ sub bz_add_column {
}
}
+sub bz_add_fk {
+ my ($self, $table, $column, $def) = @_;
+
+ my $col_def = $self->bz_column_info($table, $column);
+ if (!$col_def->{REFERENCES}) {
+ $self->_check_references($table, $column, $def->{TABLE},
+ $def->{COLUMN});
+ print get_text('install_fk_add',
+ { table => $table, column => $column, fk => $def })
+ . "\n" if Bugzilla->usage_mode == USAGE_MODE_CMDLINE;
+ my @sql = $self->_bz_real_schema->get_add_fk_sql($table, $column, $def);
+ $self->do($_) foreach @sql;
+ $col_def->{REFERENCES} = $def;
+ $self->_bz_real_schema->set_column($table, $column, $col_def);
+ $self->_bz_store_real_schema;
+ }
+}
+
sub bz_alter_column {
my ($self, $table, $name, $new_def, $set_nulls_to) = @_;
@@ -515,11 +551,10 @@ sub bz_alter_column_raw {
my @statements = $self->_bz_real_schema->get_alter_column_ddl(
$table, $name, $new_def,
defined $set_nulls_to ? $self->quote($set_nulls_to) : undef);
- my $new_ddl = $self->_bz_schema->get_display_ddl($table, $name, $new_def);
+ my $new_ddl = $self->_bz_schema->get_type_ddl($new_def);
print "Updating column $name in table $table ...\n";
if (defined $current_def) {
- my $old_ddl = $self->_bz_schema->get_display_ddl($table, $name,
- $current_def);
+ my $old_ddl = $self->_bz_schema->get_type_ddl($current_def);
print "Old: $old_ddl\n";
}
print "New: $new_ddl\n";
@@ -569,8 +604,17 @@ sub bz_add_table {
if (!$table_exists) {
$self->_bz_add_table_raw($name);
- $self->_bz_real_schema->add_table($name,
- $self->_bz_schema->get_table_abstract($name));
+ my $table_def = dclone($self->_bz_schema->get_table_abstract($name));
+
+ my %fields = @{$table_def->{FIELDS}};
+ foreach my $col (keys %fields) {
+ # Foreign Key references have to be added by Install::DB after
+ # initial table creation, because column names have changed
+ # over history and it's impossible to keep track of that info
+ # in ABSTRACT_SCHEMA.
+ delete $fields{$col}->{REFERENCES};
+ }
+ $self->_bz_real_schema->add_table($name, $table_def);
$self->_bz_store_real_schema;
}
}
@@ -751,7 +795,10 @@ sub _bz_get_initial_schema {
sub bz_column_info {
my ($self, $table, $column) = @_;
- return $self->_bz_real_schema->get_column_abstract($table, $column);
+ my $def = $self->_bz_real_schema->get_column_abstract($table, $column);
+ # We dclone it so callers can't modify the Schema.
+ $def = dclone($def) if defined $def;
+ return $def;
}
sub bz_index_info {
@@ -1050,6 +1097,39 @@ sub _bz_populate_enum_table {
}
}
+# This is used before adding a foreign key to a column, to make sure
+# that the database won't fail adding the key.
+sub _check_references {
+ my ($self, $table, $column, $foreign_table, $foreign_column) = @_;
+
+ my $bad_values = $self->selectcol_arrayref(
+ "SELECT DISTINCT $table.$column
+ FROM $table LEFT JOIN $foreign_table
+ ON $table.$column = $foreign_table.$foreign_column
+ WHERE $foreign_table.$foreign_column IS NULL
+ AND $table.$column IS NOT NULL");
+
+ if (@$bad_values) {
+ my $values = join(', ', @$bad_values);
+ print <<EOT;
+
+ERROR: There are invalid values for the $column column in the $table
+table. (These values do not exist in the $foreign_table table, in the
+$foreign_column column.)
+
+Before continuing with checksetup, you will need to fix these values,
+either by deleting these rows from the database, or changing the values
+of $column in $table to point to valid values in $foreign_table.$foreign_column.
+
+The bad values from the $table.$column column are:
+$values
+
+EOT
+ # I just picked a number above 2, to be considered "abnormal exit."
+ exit 3;
+ }
+}
+
1;
__END__