From 921388813f46afb14f9c053c613cdeb3f37fdfeb Mon Sep 17 00:00:00 2001 From: Vitaliy Filippov Date: Mon, 27 Oct 2014 20:08:52 +0300 Subject: [PATCH] Make contrib/bzdbcopy.pl actually work with anything other than Pg, independent of current localconfig. Never use Bugzilla->dbh in Bugzilla::DB::Schema, store and use $self->{dbh} instead. --- Bugzilla/DB.pm | 2 +- Bugzilla/DB/Schema.pm | 35 ++++++++++++++++------------------- Bugzilla/DB/Schema/Mysql.pm | 18 ++++++------------ Bugzilla/DB/Schema/Oracle.pm | 9 +++------ Bugzilla/DB/Schema/Sqlite.pm | 5 ++--- 5 files changed, 28 insertions(+), 41 deletions(-) diff --git a/Bugzilla/DB.pm b/Bugzilla/DB.pm index 9e380c0fe..7ba9725b4 100644 --- a/Bugzilla/DB.pm +++ b/Bugzilla/DB.pm @@ -1057,7 +1057,7 @@ sub _bz_schema { return $self->{private_bz_schema} if exists $self->{private_bz_schema}; my @module_parts = split('::', ref $self); my $module_name = pop @module_parts; - $self->{private_bz_schema} = Bugzilla::DB::Schema->new($module_name); + $self->{private_bz_schema} = Bugzilla::DB::Schema->new($self); return $self->{private_bz_schema}; } diff --git a/Bugzilla/DB/Schema.pm b/Bugzilla/DB/Schema.pm index 540cbadf9..7ddf86a2e 100644 --- a/Bugzilla/DB/Schema.pm +++ b/Bugzilla/DB/Schema.pm @@ -41,6 +41,7 @@ use Bugzilla::Constants; use Carp qw(confess); use Digest::MD5 qw(md5_hex); +use Scalar::Util; use Safe; # Historical, needed for SCHEMA_VERSION = '1.00' use Storable qw(dclone freeze thaw); @@ -1340,15 +1341,15 @@ sub new { =over -=item C +=item C Description: Public constructor method used to instantiate objects of this class. However, it also can be used as a factory method to instantiate database-specific subclasses when an optional driver argument is supplied. - Parameters: $driver (optional) - Used to specify the type of database. - This routine Cs if no subclass is found for the specified - driver. + Parameters: $dbh - Database handle this schema object is used for. + The Schema subclass is also determined from the type of this object. + Stored as a weak reference inside $self to prevent memory leaks. $schema (optional) - A reference to a hash. Callers external to this package should never use this parameter. Returns: new instance of the Schema class or a database-specific subclass @@ -1356,24 +1357,20 @@ sub new { =cut my $this = shift; - my $class = ref($this) || $this; - my $driver = shift; + my $dbh = shift; + my ($driver) = ref($dbh) =~ /^Bugzilla::DB::(.*)$/so; + die "$dbh is not an instance of Bugzilla::DB subclass" unless $driver; - if ($driver) { - (my $subclass = $driver) =~ s/^(\S)/\U$1/; - $class .= '::' . $subclass; - eval "require $class;"; - die "The $class class could not be found ($subclass " . - "not supported?): $@" if ($@); - } - die "$class is an abstract base class. Instantiate a subclass instead." - if ($class eq __PACKAGE__); + my $class = 'Bugzilla::DB::Schema::'.$driver; + eval "require $class;"; + die "The $class class could not be found ($driver not supported?): $@" if $@; - my $self = {}; + my $self = { dbh => $dbh }; + Scalar::Util::weaken($self->{dbh}); bless $self, $class; $self = $self->_initialize(@_); - return($self); + return $self; } #eosub--new #-------------------------------------------------------------------------- @@ -2452,7 +2449,7 @@ sub serialize_abstract { =cut sub deserialize_abstract { - my ($class, $serialized, $version) = @_; + my ($self, $serialized, $version) = @_; my $thawed_hash; if (int($version) < 2) { @@ -2465,7 +2462,7 @@ sub deserialize_abstract { $thawed_hash = ${$cpt->varglob('VAR1')}; } - return $class->new(undef, $thawed_hash); + return $self->new($self->{dbh}, $thawed_hash); } ##################################################################### diff --git a/Bugzilla/DB/Schema/Mysql.pm b/Bugzilla/DB/Schema/Mysql.pm index 24b044fb9..39833732b 100644 --- a/Bugzilla/DB/Schema/Mysql.pm +++ b/Bugzilla/DB/Schema/Mysql.pm @@ -133,7 +133,7 @@ sub _get_create_table_ddl { my($self, $table) = @_; - my $charset = Bugzilla->dbh->bz_db_is_utf8 ? "CHARACTER SET utf8" : ''; + my $charset = $self->{dbh}->bz_db_is_utf8 ? "CHARACTER SET utf8" : ''; my $type = grep($_ eq $table, MYISAM_TABLES) ? 'MYISAM' : 'InnoDB'; return($self->SUPER::_get_create_table_ddl($table) . " ENGINE = $type $charset"); @@ -219,12 +219,11 @@ sub get_drop_fk_sql { my ($self, $table, $column, $references) = @_; my $fk_name = $self->_get_fk_name($table, $column, $references); my @sql = ("ALTER TABLE $table DROP FOREIGN KEY $fk_name"); - my $dbh = Bugzilla->dbh; # MySQL requires, and will create, an index on any column with # an FK. It will name it after the fk, which we never do. # So if there's an index named after the fk, we also have to delete it. - if ($dbh->bz_index_info_real($table, $fk_name)) { + if ($self->{dbh}->bz_index_info_real($table, $fk_name)) { push(@sql, $self->get_drop_index_ddl($table, $fk_name)); } @@ -275,10 +274,6 @@ sub get_set_serial_sql { sub column_info_to_column { my ($self, $column_info) = @_; - # Unfortunately, we have to break Schema's normal "no database" - # barrier a few times in this function. - my $dbh = Bugzilla->dbh; - my $table = $column_info->{TABLE_NAME}; my $col_name = $column_info->{COLUMN_NAME}; @@ -293,7 +288,7 @@ sub column_info_to_column { # Unfortunately, the only way to definitely solve this is # to break Schema's standard of not touching the live database # and check if the index called PRIMARY is on that field. - my $pri_index = $dbh->bz_index_info_real($table, 'PRIMARY'); + my $pri_index = $self->{dbh}->bz_index_info_real($table, 'PRIMARY'); if ( $pri_index && grep($_ eq $col_name, @{$pri_index->{FIELDS}}) ) { $column->{PRIMARYKEY} = 1; } @@ -324,9 +319,8 @@ sub column_info_to_column { my $default = $column_info->{COLUMN_DEF}; # Schema uses '0' for the defaults for decimal fields. $default = 0 if $default =~ /^0\.0+$/; - # If we're not a number, we're a string and need to be - # quoted. - $default = $dbh->quote($default) if !($default =~ /^(-)?(\d+)(.\d+)?$/); + # If we're not a number, we're a string and need to be quoted. + $default = $self->{dbh}->quote($default) if !($default =~ /^(-)?(\d+)(.\d+)?$/); $column->{DEFAULT} = $default; } } @@ -354,7 +348,7 @@ sub column_info_to_column { # Unfortunately, the only way to do this in DBI is to query the # database, so we have to break the rule here that Schema normally # doesn't touch the live DB. - my $ref_sth = $dbh->prepare( + my $ref_sth = $self->{dbh}->prepare( "SELECT $col_name FROM $table LIMIT 1"); $ref_sth->execute; if ($ref_sth->{mysql_is_auto_increment}->[0]) { diff --git a/Bugzilla/DB/Schema/Oracle.pm b/Bugzilla/DB/Schema/Oracle.pm index 079172b47..e84d095c1 100644 --- a/Bugzilla/DB/Schema/Oracle.pm +++ b/Bugzilla/DB/Schema/Oracle.pm @@ -169,8 +169,7 @@ sub get_fk_ddl . " SET $column = :NEW.$to_column" . " WHERE $column = :OLD.$to_column;" . " END ${fk_name}_UC;"; - my $dbh = Bugzilla->dbh; - $dbh->do($tr_str); + $self->{dbh}->do($tr_str); } return $fk_string; @@ -295,8 +294,7 @@ sub _get_alter_type_sql { # LONG to VARCHAR or VARCHAR to LONG is not allowed in Oracle, just a way to work around. # Determine whether column_temp is already exist. - my $dbh = Bugzilla->dbh; - my $column_exist = $dbh->selectcol_arrayref( + my $column_exist = $self->{dbh}->selectcol_arrayref( "SELECT CNAME FROM COL WHERE TNAME = UPPER(?) AND CNAME = UPPER(?)", undef, $table, $column . "_temp" ); @@ -432,9 +430,8 @@ sub get_drop_column_ddl my ($table, $column) = @_; my @sql; push @sql, $self->SUPER::get_drop_column_ddl(@_); - my $dbh = Bugzilla->dbh; my $trigger_name = uc($table . "_" . $column); - my $exist_trigger = $dbh->selectcol_arrayref( + my $exist_trigger = $self->{dbh}->selectcol_arrayref( "SELECT OBJECT_NAME FROM USER_OBJECTS". " WHERE OBJECT_NAME = ?", undef, $trigger_name ); diff --git a/Bugzilla/DB/Schema/Sqlite.pm b/Bugzilla/DB/Schema/Sqlite.pm index f731451ae..9fa2bf50d 100644 --- a/Bugzilla/DB/Schema/Sqlite.pm +++ b/Bugzilla/DB/Schema/Sqlite.pm @@ -57,7 +57,7 @@ sub _initialize sub _sqlite_create_table { my ($self, $table) = @_; - return scalar Bugzilla->dbh->selectrow_array( + return scalar $self->{dbh}->selectrow_array( "SELECT sql FROM sqlite_master WHERE name = ? AND type = 'table'", undef, $table ); @@ -93,7 +93,7 @@ sub _sqlite_alter_schema $create_table = join(',', @$create_table) . "\n)"; } - my $dbh = Bugzilla->dbh; + my $dbh = $self->{dbh}; my $random = generate_random_password(5); my $rename_to = "${table}_$random"; @@ -236,7 +236,6 @@ sub get_alter_column_ddl { my $self = shift; my ($table, $column, $new_def, $set_nulls_to) = @_; - my $dbh = Bugzilla->dbh; my $table_sql = $self->_sqlite_create_table($table); my $new_ddl = $self->get_type_ddl($new_def); # When we do ADD COLUMN, columns can show up all on one line separated