package Bugzilla::DB;
use 5.10.1;
-use strict;
-use warnings;
+use Moo;
use DBI;
-# Inherit the DB class from DBI::db.
-use base qw(DBI::db);
+has 'dbh' => (
+ is => 'lazy',
+ handles => [qw[
+ begin_work column_info commit disconnect do errstr get_info last_insert_id ping prepare
+ primary_key quote_identifier rollback selectall_arrayref selectall_hashref
+ selectcol_arrayref selectrow_array selectrow_arrayref selectrow_hashref table_info
+ ]],
+);
use Bugzilla::Constants;
use Bugzilla::Mailer;
use List::Util qw(max);
use Storable qw(dclone);
+has [qw(dsn user pass attrs)] => (is => 'ro', required => 1,);
+
#####################################################################
# Constants
#####################################################################
sub quote {
my $self = shift;
- my $retval = $self->SUPER::quote(@_);
+ my $retval = $self->dbh->quote(@_);
trick_taint($retval) if defined $retval;
return $retval;
}
# Subclass Helpers
#####################################################################
-sub db_new {
- my ($class, $params) = @_;
- my ($dsn, $user, $pass, $override_attrs) = @$params{qw(dsn user pass attrs)};
+sub _build_dbh {
+ my ($self) = @_;
+ my ($dsn, $user, $pass, $override_attrs)
+ = map { $self->$_ } qw(dsn user pass attrs);
# set up default attributes used to connect to the database
# (may be overridden by DB driver implementations)
$attributes->{$key} = $override_attrs->{$key};
}
}
+ my $class = ref $self;
+ if ($class->can('on_dbi_connected')) {
+ $attributes->{Callbacks}
+ = {connected => sub { $class->on_dbi_connected(@_); return },};
+ }
# connect using our known info to the specified db
- my $self = DBI->connect($dsn, $user, $pass, $attributes)
+ my $dbh = DBI->connect($dsn, $user, $pass, $attributes)
or die "\nCan't connect to the database.\nError: $DBI::errstr\n"
. " Is your database installed and up and running?\n Do you have"
. " the correct username and password selected in localconfig?\n\n";
# RaiseError was only set to 0 so that we could catch the
# above "die" condition.
- $self->{RaiseError} = 1;
+ $dbh->{RaiseError} = 1;
- bless($self, $class);
-
- return $self;
+ return $dbh;
}
#####################################################################
package Bugzilla::DB::Mysql;
use 5.10.1;
-use strict;
-use warnings;
+use Moo;
-use base qw(Bugzilla::DB);
+extends qw(Bugzilla::DB);
use Bugzilla::Constants;
use Bugzilla::Install::Util qw(install_string);
use constant FULLTEXT_OR => '|';
-sub new {
+sub BUILDARGS {
my ($class, $params) = @_;
my ($user, $pass, $host, $dbname, $port, $sock)
= @$params{qw(db_user db_pass db_host db_name db_port db_sock)};
$dsn .= ";port=$port" if $port;
$dsn .= ";mysql_socket=$sock" if $sock;
- my %attrs = (
- mysql_enable_utf8 => Bugzilla->params->{'utf8'},
-
- # Needs to be explicitly specified for command-line processes.
- mysql_auto_reconnect => 1,
- );
+ my %attrs = (mysql_enable_utf8 => Bugzilla->params->{'utf8'},);
# MySQL SSL options
my ($ssl_ca_file, $ssl_ca_path, $ssl_cert, $ssl_key) = @$params{
$attrs{'mysql_ssl_client_key'} = $ssl_key if $ssl_key;
}
- my $self = $class->db_new(
- {dsn => $dsn, user => $user, pass => $pass, attrs => \%attrs});
+ return {dsn => $dsn, user => $user, pass => $pass, attrs => \%attrs};
+}
+
+sub on_dbi_connected {
+ my ($class, $dbh) = @_;
# This makes sure that if the tables are encoded as UTF-8, we
# return their data correctly.
- $self->do("SET NAMES utf8") if Bugzilla->params->{'utf8'};
-
- # all class local variables stored in DBI derived class needs to have
- # a prefix 'private_'. See DBI documentation.
- $self->{private_bz_tables_locked} = "";
-
- # Needed by TheSchwartz
- $self->{private_bz_dsn} = $dsn;
-
- bless($self, $class);
+ $dbh->do("SET NAMES utf8") if Bugzilla->params->{'utf8'};
# Check for MySQL modes.
my ($var, $sql_mode)
- = $self->selectrow_array("SHOW VARIABLES LIKE 'sql\\_mode'");
+ = $dbh->selectrow_array("SHOW VARIABLES LIKE 'sql\\_mode'");
# Disable ANSI and strict modes, else Bugzilla will crash.
if ($sql_mode) {
split(/,/, $sql_mode));
if ($sql_mode ne $new_sql_mode) {
- $self->do("SET SESSION sql_mode = ?", undef, $new_sql_mode);
+ $dbh->do("SET SESSION sql_mode = ?", undef, $new_sql_mode);
}
}
# Allow large GROUP_CONCATs (largely for inserting comments
# into bugs_fulltext).
- $self->do('SET SESSION group_concat_max_len = 128000000');
+ $dbh->do('SET SESSION group_concat_max_len = 128000000');
# MySQL 5.5.2 and older have this variable set to true, which causes
# trouble, see bug 870369.
- $self->do('SET SESSION sql_auto_is_null = 0');
-
- return $self;
+ $dbh->do('SET SESSION sql_auto_is_null = 0');
}
# when last_insert_id() is supported on MySQL by lowest DBI/DBD version
package Bugzilla::DB::Oracle;
use 5.10.1;
-use strict;
-use warnings;
+use Moo;
-use base qw(Bugzilla::DB);
+extends qw(Bugzilla::DB);
use DBD::Oracle;
use DBD::Oracle qw(:ora_types);
use constant MIN_LONG_READ_LEN => 32 * 1024;
use constant FULLTEXT_OR => ' OR ';
-sub new {
+sub BUILDARGS {
my ($class, $params) = @_;
my ($user, $pass, $host, $dbname, $port)
= @$params{qw(db_user db_pass db_host db_name db_port)};
LongReadLen =>
max(Bugzilla->params->{'maxattachmentsize'} || 0, MIN_LONG_READ_LEN) * 1024,
};
- my $self = $class->db_new(
- {dsn => $dsn, user => $user, pass => $pass, attrs => $attrs});
-
- # Needed by TheSchwartz
- $self->{private_bz_dsn} = $dsn;
+ return {dsn => $dsn, user => $user, pass => $pass, attrs => $attrs};
+}
- bless($self, $class);
+sub on_dbi_connected {
+ my ($class, $dbh) = @_;
# Set the session's default date format to match MySQL
- $self->do("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
- $self->do("ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS'");
- $self->do("ALTER SESSION SET NLS_LENGTH_SEMANTICS='CHAR'")
+ $dbh->do("ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'");
+ $dbh->do("ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SS'");
+ $dbh->do("ALTER SESSION SET NLS_LENGTH_SEMANTICS='CHAR'")
if Bugzilla->params->{'utf8'};
# To allow case insensitive query.
- $self->do("ALTER SESSION SET NLS_COMP='ANSI'");
- $self->do("ALTER SESSION SET NLS_SORT='BINARY_AI'");
- return $self;
+ $dbh->do("ALTER SESSION SET NLS_COMP='ANSI'");
+ $dbh->do("ALTER SESSION SET NLS_SORT='BINARY_AI'");
}
sub bz_last_key {
package Bugzilla::DB::Pg;
use 5.10.1;
-use strict;
-use warnings;
+use Moo;
use Bugzilla::Error;
use Bugzilla::Version;
use DBD::Pg;
# This module extends the DB interface via inheritance
-use base qw(Bugzilla::DB);
+extends qw(Bugzilla::DB);
use constant BLOB_TYPE => {pg_type => DBD::Pg::PG_BYTEA};
-sub new {
+sub BUILDARGS {
my ($class, $params) = @_;
my ($user, $pass, $host, $dbname, $port)
= @$params{qw(db_user db_pass db_host db_name db_port)};
my $attrs = {pg_enable_utf8 => Bugzilla->params->{'utf8'}};
- my $self = $class->db_new(
- {dsn => $dsn, user => $user, pass => $pass, attrs => $attrs});
-
- # all class local variables stored in DBI derived class needs to have
- # a prefix 'private_'. See DBI documentation.
- $self->{private_bz_tables_locked} = "";
-
- # Needed by TheSchwartz
- $self->{private_bz_dsn} = $dsn;
-
- bless($self, $class);
-
- return $self;
+ return {dsn => $dsn, user => $user, pass => $pass, attrs => $attrs};
}
# if last_insert_id is supported on PostgreSQL by lowest DBI/DBD version
package Bugzilla::DB::Sqlite;
use 5.10.1;
-use strict;
-use warnings;
+use Moo;
-use base qw(Bugzilla::DB);
+extends qw(Bugzilla::DB);
use Bugzilla::Constants;
use Bugzilla::Error;
# Constructor #
###############
-sub new {
+sub BUILDARGS {
my ($class, $params) = @_;
my $db_name = $params->{db_name};
sqlite_unicode => Bugzilla->params->{'utf8'},
};
- my $self
- = $class->db_new({dsn => $dsn, user => '', pass => '', attrs => $attrs});
+ return {dsn => $dsn, user => '', pass => '', attrs => $attrs};
+}
- # Needed by TheSchwartz
- $self->{private_bz_dsn} = $dsn;
+sub on_dbi_connected {
+ my ($class, $dbh) = @_;
my %pragmas = (
);
while (my ($name, $value) = each %pragmas) {
- $self->do("PRAGMA $name = $value");
+ $dbh->do("PRAGMA $name = $value");
}
- $self->sqlite_create_collation('bugzilla', \&_sqlite_collate_ci);
- $self->sqlite_create_function('position', 2, \&_sqlite_position);
- $self->sqlite_create_function('iposition', 2, \&_sqlite_position_ci);
+ $dbh->sqlite_create_collation('bugzilla', \&_sqlite_collate_ci);
+ $dbh->sqlite_create_function('position', 2, \&_sqlite_position);
+ $dbh->sqlite_create_function('iposition', 2, \&_sqlite_position_ci);
# SQLite has a "substr" function, but other DBs call it "SUBSTRING"
# so that's what we use, and I don't know of any way in SQLite to
# to write to it.
my $self = $class->SUPER::new(
databases => [{
- dsn => Bugzilla->dbh_main->{private_bz_dsn},
+ dsn => Bugzilla->dbh_main->dsn,
user => $lc->{db_user},
pass => $lc->{db_pass},
prefix => 'ts_',