Commit 62b2ec34 authored by mkanat%kerio.com's avatar mkanat%kerio.com

Bug 237862: New database layer for cross-database compatibility

Patch By Tomas Kopal <Tomas.Kopal@altap.cz> r=mkanat, a=myk
parent fc3aa3e7
......@@ -71,7 +71,7 @@ our $webdotdir = "$datadir/webdot";
%Bugzilla::Config::EXPORT_TAGS =
(
admin => [qw(GetParamList UpdateParams SetParam WriteParams)],
db => [qw($db_host $db_port $db_name $db_user $db_pass $db_sock)],
db => [qw($db_driver $db_host $db_port $db_name $db_user $db_pass $db_sock)],
locations => [qw($libpath $localconfig $datadir $templatedir $webdotdir)],
);
Exporter::export_ok_tags('admin', 'db', 'locations');
......
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dave Miller <davem00@aol.com>
# Gayathri Swaminath <gayathrik00@aol.com>
# Jeroen Ruigrok van der Werven <asmodai@wxs.nl>
# Dave Lawrence <dkl@redhat.com>
# Tomas Kopal <Tomas.Kopal@altap.cz>
=head1 NAME
Bugzilla::DB::Mysql - Bugzilla database compatibility layer for MySQL
=head1 DESCRIPTION
This module overrides methods of the Bugzilla::DB module with MySQL specific
implementation. It is instantiated by the Bugzilla::DB module and should never
be used directly.
For interface details see L<Bugzilla::DB> and L<DBI>.
=cut
package Bugzilla::DB::Mysql;
use strict;
use Bugzilla::Error;
use Carp;
# This module extends the DB interface via inheritance
use base qw(Bugzilla::DB);
sub new {
my ($class, $user, $pass, $host, $dbname, $port, $sock) = @_;
# construct the DSN from the parameters we got
my $dsn = "DBI:mysql:host=$host;database=$dbname;port=$port";
$dsn .= ";mysql_socket=$sock" if $sock;
my $self = $class->db_new($dsn, $user, $pass);
# all class local variables stored in DBI derived class needs to have
# a prefix 'private_'. See DBI documentation.
$self->{private_bz_tables_locked} = 0;
bless ($self, $class);
return $self;
}
# when last_insert_id() is supported on MySQL by lowest DBI/DBD version
# required by Bugzilla, this implementation can be removed.
sub bz_last_key {
my ($self) = @_;
my ($last_insert_id) = $self->selectrow_array('SELECT LAST_INSERT_ID()');
return $last_insert_id;
}
sub sql_regexp {
return "REGEXP";
}
sub sql_not_regexp {
return "NOT REGEXP";
}
sub sql_limit {
my ($self, $limit,$offset) = @_;
if (defined($offset)) {
return "LIMIT $offset, $limit";
} else {
return "LIMIT $limit";
}
}
sub sql_to_days {
my ($self, $date) = @_;
return "TO_DAYS($date)";
}
sub sql_date_format {
my ($self, $date, $format) = @_;
$format = "%Y.%m.%d %H:%i:%s" if !$format;
return "DATE_FORMAT($date, " . $self->quote($format) . ")";
}
sub sql_interval {
my ($self, $interval) = @_;
return "INTERVAL $interval";
}
sub bz_lock_tables {
my ($self, @tables) = @_;
# Check first if there was no lock before
if ($self->{private_bz_tables_locked}) {
carp("Tables already locked");
ThrowCodeError("already_locked");
} else {
$self->do('LOCK TABLE ' . join(', ', @tables));
$self->{private_bz_tables_locked} = 1;
}
}
sub bz_unlock_tables {
my ($self, $abort) = @_;
# Check first if there was previous matching lock
if (!$self->{private_bz_tables_locked}) {
# Abort is allowed even without previous lock for error handling
return if $abort;
carp("No matching lock");
ThrowCodeError("no_matching_lock");
} else {
$self->do("UNLOCK TABLES");
$self->{private_bz_tables_locked} = 0;
}
}
# As Bugzilla currently runs on MyISAM storage, which does not supprt
# transactions, these functions die when called.
# Maybe we should just ignore these calls for now, but as we are not
# using transactions in MySQL yet, this just hints the developers.
sub bz_start_transaction {
die("Attempt to start transaction on DB without transaction support");
}
sub bz_commit_transaction {
die("Attempt to commit transaction on DB without transaction support");
}
sub bz_rollback_transaction {
die("Attempt to rollback transaction on DB without transaction support");
}
1;
# -*- Mode: perl; indent-tabs-mode: nil -*-
#
# The contents of this file are subject to the Mozilla Public
# License Version 1.1 (the "License"); you may not use this file
# except in compliance with the License. You may obtain a copy of
# the License at http://www.mozilla.org/MPL/
#
# Software distributed under the License is distributed on an "AS
# IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
# implied. See the License for the specific language governing
# rights and limitations under the License.
#
# The Original Code is the Bugzilla Bug Tracking System.
#
# The Initial Developer of the Original Code is Netscape Communications
# Corporation. Portions created by Netscape are
# Copyright (C) 1998 Netscape Communications Corporation. All
# Rights Reserved.
#
# Contributor(s): Dave Miller <davem00@aol.com>
# Gayathri Swaminath <gayathrik00@aol.com>
# Jeroen Ruigrok van der Werven <asmodai@wxs.nl>
# Dave Lawrence <dkl@redhat.com>
# Tomas Kopal <Tomas.Kopal@altap.cz>
=head1 NAME
Bugzilla::DB::Pg - Bugzilla database compatibility layer for PostgreSQL
=head1 DESCRIPTION
This module overrides methods of the Bugzilla::DB module with PostgreSQL
specific implementation. It is instantiated by the Bugzilla::DB module
and should never be used directly.
For interface details see L<Bugzilla::DB> and L<DBI>.
=cut
package Bugzilla::DB::Pg;
use strict;
use Bugzilla::Error;
use Carp;
# This module extends the DB interface via inheritance
use base qw(Bugzilla::DB);
sub new {
my ($class, $user, $pass, $host, $dbname, $port) = @_;
# construct the DSN from the parameters we got
my $dsn = "DBI:Pg:host=$host;dbname=$dbname;port=$port";
my $self = $class->db_new($dsn, $user, $pass);
# all class local variables stored in DBI derived class needs to have
# a prefix 'private_'. See DBI documentation.
$self->{private_bz_tables_locked} = 0;
bless ($self, $class);
return $self;
}
# if last_insert_id is supported on PostgreSQL by lowest DBI/DBD version
# supported by Bugzilla, this implementation can be removed.
sub bz_last_key {
my ($self, $table, $column) = @_;
my $seq = $table . "_" . $column . "_seq";
my ($last_insert_id) = $self->selectrow_array("SELECT CURRVAL('$seq')");
return $last_insert_id;
}
sub sql_regexp {
return "~";
}
sub sql_not_regexp {
return "!~"
}
sub sql_limit {
my ($self, $limit,$offset) = @_;
if (defined($offset)) {
return "LIMIT $limit OFFSET $offset";
} else {
return "LIMIT $limit";
}
}
sub sql_to_days {
my ($self, $date) = @_;
return "TO_CHAR($date, 'J')::int";
}
sub sql_date_format {
my ($self, $date, $format) = @_;
$format = "%Y.%m.%d %H:%i:%s" if !$format;
$format =~ s/\%Y/YYYY/g;
$format =~ s/\%y/YY/g;
$format =~ s/\%m/MM/g;
$format =~ s/\%d/DD/g;
$format =~ s/\%a/Dy/g;
$format =~ s/\%H/HH24/g;
$format =~ s/\%i/MI/g;
$format =~ s/\%s/SS/g;
return "TO_CHAR($date, " . $self->quote($format) . ")";
}
sub sql_interval {
my ($self, $interval) = @_;
return "INTERVAL '$interval'";
}
sub bz_lock_tables {
my ($self, @tables) = @_;
# Check first if there was no lock before
if ($self->{private_bz_tables_locked}) {
carp("Tables already locked");
ThrowCodeError("already_locked");
} else {
my %read_tables;
my %write_tables;
foreach my $table (@tables) {
$table =~ /^([\d\w]+)([\s]+AS[\s]+[\d\w]+)?[\s]+(WRITE|READ)$/i;
my $table_name = $1;
if ($3 =~ /READ/i) {
if (!exists $read_tables{$table_name}) {
$read_tables{$table_name} = undef;
}
}
else {
if (!exists $write_tables{$table_name}) {
$write_tables{$table_name} = undef;
}
}
}
# Begin Transaction
$self->bz_start_transaction();
Bugzilla->dbh->do('LOCK TABLE ' . join(', ', keys %read_tables) .
' IN ROW SHARE MODE') if keys %read_tables;
Bugzilla->dbh->do('LOCK TABLE ' . join(', ', keys %write_tables) .
' IN ROW EXCLUSIVE MODE') if keys %write_tables;
}
}
sub bz_unlock_tables {
my ($self, $abort) = @_;
# Check first if there was previous matching lock
if (!$self->{private_bz_tables_locked}) {
# Abort is allowed even without previous lock for error handling
return if $abort;
carp("No matching lock");
ThrowCodeError("no_matching_lock");
} else {
# End transaction, tables will be unlocked automatically
if ($abort) {
$self->bz_rollback_transaction();
} else {
$self->bz_commit_transaction();
}
}
}
1;
......@@ -101,6 +101,7 @@
# The format of that file is....
#
# $answer{'db_host'} = '$db_host = "localhost";
# $db_driver = "mydbdriver";
# $db_port = 3306;
# $db_name = "mydbname";
# $db_user = "mydbuser";';
......@@ -644,6 +645,14 @@ END
LocalVar('db_driver', '
#
# What SQL database to use. Default is mysql. List of supported databases
# can be obtained by listing Bugzilla/DB directory - every module corresponds
# to one supported database and the name corresponds to a driver name.
#
$db_driver = "mysql";
');
LocalVar('db_host', '
#
# How to access the SQL database:
......@@ -793,6 +802,7 @@ if ($newstuff ne "") {
# Note that we won't need to do this in globals.pl because globals.pl couldn't
# care less whether they were defined ahead of time or not.
my $my_db_check = ${*{$main::{'db_check'}}{SCALAR}};
my $my_db_driver = ${*{$main::{'db_driver'}}{SCALAR}};
my $my_db_host = ${*{$main::{'db_host'}}{SCALAR}};
my $my_db_port = ${*{$main::{'db_port'}}{SCALAR}};
my $my_db_name = ${*{$main::{'db_name'}}{SCALAR}};
......@@ -1505,11 +1515,6 @@ $::ENV{'PATH'} = $origPath;
# Check if we have access to --MYSQL--
#
# This settings are not yet changeable, because other code depends on
# the fact that we use MySQL and not, say, PostgreSQL.
my $db_base = 'mysql';
# No need to "use" this here. It should already be loaded from the
# version-checking routines above, and this file won't even compile if
# DBI isn't installed so the user gets nasty errors instead of our
......@@ -1522,15 +1527,15 @@ if ($my_db_check) {
my $sql_want = "3.23.41"; # minimum version of MySQL
# original DSN line was:
# my $dsn = "DBI:$db_base:$my_db_name;$my_db_host;$my_db_port";
# my $dsn = "DBI:$my_db_driver:$my_db_name;$my_db_host;$my_db_port";
# removed the $db_name because we don't know it exists yet, and this will fail
# if we request it here and it doesn't. - justdave@syndicomm.com 2000/09/16
my $dsn = "DBI:$db_base:;$my_db_host;$my_db_port";
my $dsn = "DBI:$my_db_driver:;$my_db_host;$my_db_port";
if ($my_db_sock ne "") {
$dsn .= ";mysql_socket=$my_db_sock";
}
my $dbh = DBI->connect($dsn, $my_db_user, $my_db_pass)
or die "Can't connect to the $db_base database. Is the database " .
or die "Can't connect to the $my_db_driver database. Is the database " .
"installed and\nup and running? Do you have the correct username " .
"and password selected in\nlocalconfig?\n\n";
printf("Checking for %15s %-9s ", "MySQL Server", "(v$sql_want)") unless $silent;
......@@ -1581,14 +1586,14 @@ EOF
}
# now get a handle to the database:
my $connectstring = "dbi:$db_base:$my_db_name:host=$my_db_host:port=$my_db_port";
my $connectstring = "dbi:$my_db_driver:$my_db_name:host=$my_db_host:port=$my_db_port";
if ($my_db_sock ne "") {
$connectstring .= ";mysql_socket=$my_db_sock";
}
my $dbh = DBI->connect($connectstring, $my_db_user, $my_db_pass)
or die "Can't connect to the table '$connectstring'.\n",
"Have you read the Bugzilla Guide in the doc directory? Have you read the doc of '$db_base'?\n";
"Have you read the Bugzilla Guide in the doc directory? Have you read the doc of '$my_db_driver'?\n";
END { $dbh->disconnect if $dbh }
......@@ -2191,7 +2196,7 @@ while (my ($tabname, $fielddef) = each %table) {
$fielddef =~ s/\$my_platforms/$my_platforms/;
$dbh->do("CREATE TABLE $tabname (\n$fielddef\n) TYPE = MYISAM")
or die "Could not create table '$tabname'. Please check your '$db_base' access.\n";
or die "Could not create table '$tabname'. Please check your '$my_db_driver' access.\n";
}
###########################################################################
......
......@@ -83,7 +83,7 @@ $vars->{'open_status'} = \@open_status;
$vars->{'closed_status'} = \@closed_status;
# Generate a list of fields that can be queried.
$vars->{'field'} = [Bugzilla::DB::GetFieldDefs()];
$vars->{'field'} = [Bugzilla->dbh->bz_get_field_defs()];
# Determine how the user would like to receive the output;
# default is JavaScript.
......
......@@ -351,7 +351,7 @@ $vars->{'bug_severity'} = \@::legal_severity;
# Boolean charts
my @fields;
push(@fields, { name => "noop", description => "---" });
push(@fields, Bugzilla::DB::GetFieldDefs());
push(@fields, Bugzilla->dbh->bz_get_field_defs());
$vars->{'fields'} = \@fields;
# Creating new charts - if the cmd-add value is there, we define the field
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment