[Rt-commit] r5694 - in rt/branches/3.7-EXPERIMENTAL: .
ruz at bestpractical.com
ruz at bestpractical.com
Sun Aug 6 23:00:04 EDT 2006
Author: ruz
Date: Sun Aug 6 23:00:03 2006
New Revision: 5694
Modified:
rt/branches/3.7-EXPERIMENTAL/ (props changed)
rt/branches/3.7-EXPERIMENTAL/sbin/rt-setup-database.in
Log:
r3590 at cubic-pc: cubic | 2006-08-05 02:31:57 +0400
* forward port 'rt-setup-database' changes from 3.5-EXP-MYSQL-UPDATES
Modified: rt/branches/3.7-EXPERIMENTAL/sbin/rt-setup-database.in
==============================================================================
--- rt/branches/3.7-EXPERIMENTAL/sbin/rt-setup-database.in (original)
+++ rt/branches/3.7-EXPERIMENTAL/sbin/rt-setup-database.in Sun Aug 6 23:00:03 2006
@@ -45,7 +45,7 @@
#
# END BPS TAGGED BLOCK }}}
use strict;
-use vars qw($PROMPT $VERSION $Handle $Nobody $SystemUser $item);
+use vars qw($PROMPT $VERSION $Nobody $SystemUser $item);
use vars qw(@Groups @Users @ACL @Queues @ScripActions @ScripConditions
@Templates @CustomFields @Scrips @Attributes @Initial @Final);
@@ -66,9 +66,10 @@
my %args;
GetOptions(
\%args,
- 'prompt-for-dba-password', 'force', 'debug',
- 'action=s', 'dba=s', 'dba-password=s', 'datafile=s',
- 'datadir=s'
+ 'action=s',
+ 'force', 'debug',
+ 'dba=s', 'dba-password=s', 'prompt-for-dba-password',
+ 'datafile=s', 'datadir=s'
);
unless ( $args{'action'} ) {
@@ -100,32 +101,15 @@
my $dbh;
if ( $args{'action'} eq 'init' ) {
- $dbh = DBI->connect( get_system_dsn(), $args{'dba'}, $args{'dba-password'} )
- || die "Failed to connect to " . get_system_dsn() . " as $args{'dba'}: $DBI::errstr";
+ $dbh = get_system_dbh();
print "Now creating a database for RT.\n";
if ( $db_type ne 'Oracle' || $args{'dba'} ne $db_user ) {
create_db();
} else {
- print "...skipped as ".$args{'dba'} ." is not " . $db_user . " or we're working with Oracle.\n";
+ print "...skipped as ".$args{'dba'} ." is not " . $db_user ." or we're working with Oracle.\n";
}
- if ( $db_type eq "mysql" ) {
- # Check which version we're running
- my ($version) = $dbh->selectrow_hashref("show variables like 'version'")->{Value} =~ /^(\d\.\d+)/;
- print "*** Warning: RT is unsupported on MySQL versions before 4.0.x\n" if $version < 4;
-
- # MySQL must have InnoDB support
- my $innodb = $dbh->selectrow_hashref("show variables like 'have_innodb'")->{Value};
- if ( $innodb eq "NO" ) {
- die "RT requires that MySQL be compiled with InnoDB table support.\n".
- "See http://dev.mysql.com/doc/mysql/en/InnoDB.html\n";
- } elsif ( $innodb eq "DISABLED" ) {
- die "RT requires that MySQL InnoDB table support be enabled.\n".
- ($version < 4
- ? "Add 'innodb_data_file_path=ibdata1:10M:autoextend' to the [mysqld] section of my.cnf\n"
- : "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n");
- }
- }
+ check_db_compatibility();
# SQLite can't deal with the disconnect/reconnect
unless ( $db_type eq 'SQLite' ) {
@@ -133,10 +117,9 @@
$dbh->disconnect;
if ( $db_type eq "Oracle" ) {
- $dbh = DBI->connect( $Handle->DSN, $db_user, $db_pass ) || die $DBI::errstr;
- }
- else {
- $dbh = DBI->connect( $Handle->DSN, $args{'dba'}, $args{'dba-password'} ) || die $DBI::errstr;
+ $dbh = get_rt_dbh();
+ } else {
+ $dbh = get_rt_dbh( $args{'dba'}, $args{'dba-password'} );
}
}
print "Now populating database schema.\n";
@@ -149,26 +132,21 @@
insert_data( $RT::EtcPath . "/initialdata" );
}
elsif ( $args{'action'} eq 'drop' ) {
- unless ( $dbh =
- DBI->connect( get_system_dsn(), $args{'dba'}, $args{'dba-password'} ) )
- {
- warn $DBI::errstr;
- warn "Database doesn't appear to exist. Aborting database drop.";
- exit;
- }
+ $dbh = get_system_dbh();
drop_db();
}
elsif ( $args{'action'} eq 'insert' ) {
+ $dbh = get_rt_dbh();
+ check_db_compatibility();
insert_data( $args{'datafile'} || ($args{'datadir'}."/content") );
}
elsif ( $args{'action'} eq 'acl' ) {
- $dbh = DBI->connect( $Handle->DSN, $args{'dba'}, $args{'dba-password'} )
- || die "Failed to connect to " . get_system_dsn() . " as $args{'dba'}: $DBI::errstr";
+ $dbh = get_rt_dbh( $args{'dba'}, $args{'dba-password'} );
insert_acl($args{'datadir'});
}
elsif ( $args{'action'} eq 'schema' ) {
- $dbh = DBI->connect( $Handle->DSN, $args{'dba'}, $args{'dba-password'} )
- || die "Failed to connect to " . get_system_dsn() . " as $args{'dba'}: $DBI::errstr";
+ $dbh = get_rt_dbh( $args{'dba'}, $args{'dba-password'} );
+ check_db_compatibility();
insert_schema($args{'datadir'});
}
else {
@@ -176,55 +154,29 @@
exit(-1);
}
-# {{{ sub insert_schema
-sub insert_schema {
- my $base_path = (shift || $RT::EtcPath);
- my (@schema);
- print "Creating database schema.\n";
-
- if ( -f $base_path . "/schema." . $db_type ) {
- no warnings 'unopened';
-
- open( SCHEMA, "<" . $base_path . "/schema." . $db_type );
-
- my $has_local = 0;
- open( SCHEMA_LOCAL, "<" . $RT::LocalEtcPath . "/schema." . $db_type ) and $has_local = 1;
-
- my $statement = "";
- foreach my $line (<SCHEMA>, ($_ = ';;'), ($has_local? <SCHEMA_LOCAL>: ()) ) {
- $line =~ s/\#.*//g;
- $line =~ s/--.*//g;
- $statement .= $line;
- if ( $line =~ /;(\s*)$/ ) {
- $statement =~ s/;(\s*)$//g;
- push @schema, $statement;
- $statement = "";
- }
- }
-
- local $SIG{__WARN__} = sub {};
- my $is_local = 0; # local/etc/schema needs to be nonfatal.
- $dbh->begin_work or die $dbh->errstr;
- foreach my $statement (@schema) {
- if ( $statement =~ /^\s*;$/ ) { $is_local = 1; next; }
-
- print STDERR "SQL: $statement\n" if defined $args{'debug'};
- my $sth = $dbh->prepare($statement) or die $dbh->errstr;
- unless ( $sth->execute or $is_local ) {
- die "Problem with statement:\n $statement\n" . $sth->errstr;
- }
+sub create_db {
+ print "Creating $db_type database $db_name.\n";
+ if ( $db_type eq 'SQLite' ) {
+ return;
+ }
+ elsif ( $db_type eq 'Pg' ) {
+ $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE'");
+ if ( $DBI::errstr ) {
+ $dbh->do("CREATE DATABASE $db_name") || die $DBI::errstr;
}
- $dbh->commit or die $dbh->errstr;
+ }
+ elsif ( $db_type eq 'Oracle' ) {
+ insert_acl();
+ }
+ elsif ( $db_type eq 'Informix' ) {
+ $ENV{'DB_LOCALE'} = 'en_us.utf8';
+ $dbh->do("CREATE DATABASE $db_name WITH BUFFERED LOG");
}
else {
- die "Couldn't find schema file for " . $db_type . "\n";
+ $dbh->do("CREATE DATABASE $db_name") or die $DBI::errstr;
}
- print "Done setting up database schema.\n";
}
-# }}}
-
-# {{{ sub drop_db
sub drop_db {
if ( $db_type eq 'Oracle' ) {
print <<END;
@@ -256,89 +208,17 @@
$dbh->do("DROP DATABASE ". $db_name) or warn $DBI::errstr;
}
-# }}}
-# {{{ sub create_db
-sub create_db {
- print "Creating $db_type database $db_name.\n";
- if ( $db_type eq 'SQLite' ) {
- return;
- }
- elsif ( $db_type eq 'Pg' ) {
- $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE'");
- if ( $DBI::errstr ) {
- $dbh->do("CREATE DATABASE $db_name") || die $DBI::errstr;
- }
- }
- elsif ( $db_type eq 'Oracle' ) {
- insert_acl();
- }
- elsif ( $db_type eq 'Informix' ) {
- $ENV{DB_LOCALE} = 'en_us.utf8';
- $dbh->do("CREATE DATABASE $db_name WITH BUFFERED LOG");
- }
- else {
- $dbh->do("CREATE DATABASE $db_name") or die $DBI::errstr;
- }
-}
-
-# }}}
-
-sub get_dba_password {
- print "In order to create or update your RT database,";
- print "this script needs to connect to your "
- . $db_type
- . " instance on "
- . $db_host . " as "
- . $args{'dba'} . ".\n";
- print "Please specify that user's database password below. If the user has no database\n";
- print "password, just press return.\n\n";
- print "Password: ";
- ReadMode('noecho');
- my $password = ReadLine(0);
- ReadMode('normal');
- print "\n";
- return ($password);
-}
-# {{{ sub _yesno
-sub _yesno {
- print "Proceed [y/N]:";
- my $x = scalar(<STDIN>);
- $x =~ /^y/i;
-}
-
-# }}}
-
-# {{{ insert_acls
sub insert_acl {
my $base_path = (shift || $RT::EtcPath);
my $db_type = $db_type;
- if ( $db_type =~ /^oracle$/i ) {
- do $base_path . "/acl.Oracle"
- || die "Couldn't find ACLS for Oracle\n" . $@;
- }
- elsif ( $db_type =~ /^pg$/i ) {
- do $base_path . "/acl.Pg" || die "Couldn't find ACLS for Pg\n" . $@;
- }
- elsif ( $db_type =~ /^mysql$/i ) {
- do $base_path . "/acl.mysql"
- || die "Couldn't find ACLS for mysql in $base_path\n" . $@;
- }
- elsif ( $db_type =~ /^Sybase$/i ) {
- do $base_path . "/acl.Sybase"
- || die "Couldn't find ACLS for Sybase in $base_path\n" . $@;
- }
- elsif ( $db_type =~ /^informix$/i ) {
- do $base_path . "/acl.Informix"
- || die "Couldn't find ACLS for Informix in $base_path\n" . $@;
- }
- elsif ( $db_type =~ /^SQLite$/i ) {
+ if ( $db_type eq 'SQLite' ) {
return;
- }
- else {
- die "Unknown RT database type";
+ } else {
+ do $base_path ."/acl.". $db_type
+ || die "Couldn't find ACLs for ". $db_type .": " . $@;
}
my @acl = acl($dbh);
@@ -352,42 +232,62 @@
print "Done setting up database ACLs.\n";
}
-# }}}
-
-=head2 get_system_dsn
-
-Returns a dsn suitable for database creates and drops
-and user creates and drops
+sub insert_schema {
+ my $base_path = (shift || $RT::EtcPath);
+ my $file = get_version_file( $base_path . "/schema." . $db_type );
+ unless ( $file ) {
+ die "Couldn't find schema file in '$base_path' dir";
+ }
+ unless ( -f $file || -r $file ) {
+ die "File '$file' doesn't exist or couldn't be read";
+ }
-=cut
+ my (@schema);
+ print "Creating database schema.\n";
-sub get_system_dsn {
+ open my $fh_schema, "<$file";
- my $dsn = $Handle->DSN;
+ my $has_local = 0;
+ open my $fh_schema_local, "<" . get_version_file( $RT::LocalEtcPath . "/schema." . $db_type )
+ and $has_local = 1;
+
+ my $statement = "";
+ foreach my $line ( <$fh_schema>, ($_ = ';;'), $has_local? <$fh_schema_local>: () ) {
+ $line =~ s/\#.*//g;
+ $line =~ s/--.*//g;
+ $statement .= $line;
+ if ( $line =~ /;(\s*)$/ ) {
+ $statement =~ s/;(\s*)$//g;
+ push @schema, $statement;
+ $statement = "";
+ }
+ }
+ close $fh_schema; close $fh_schema_local;
+
+ local $SIG{__WARN__} = sub {};
+ my $is_local = 0; # local/etc/schema needs to be nonfatal.
+ $dbh->begin_work or die $dbh->errstr;
+ foreach my $statement (@schema) {
+ if ( $statement =~ /^\s*;$/ ) { $is_local = 1; next; }
- #with mysql, you want to connect sans database to funge things
- if ( $db_type eq 'mysql' ) {
- $dsn =~ s/dbname=\Q$db_name//;
- }
- elsif ( $db_type eq 'Pg' ) {
- # with postgres, you want to connect to database1
- $dsn =~ s/dbname=\Q$db_name/dbname=template1/;
- }
- elsif ( $db_type eq 'Informix' ) {
- # with Informix, you want to connect sans database:
- $dsn =~ s/Informix:\Q$db_name/Informix:/;
+ print "Executing SQL:\n$statement\n" if defined $args{'debug'};
+ my $sth = $dbh->prepare($statement) or die $dbh->errstr;
+ unless ( $sth->execute or $is_local ) {
+ die "Problem with statement:\n$statement\n" . $sth->errstr;
+ }
}
- return $dsn;
+ $dbh->commit or die $dbh->errstr;
+
+ print "Done setting up database schema.\n";
}
+
sub insert_initial_data {
RT::InitLogging();
#connect to the db, for actual RT work
- require RT::Handle;
- $RT::Handle = RT::Handle->new();
- $RT::Handle->Connect();
+ connect_rt_handle();
#Put together a current user object so we can create a User object
my $CurrentUser = new RT::CurrentUser();
@@ -406,14 +306,14 @@
}
print "Creating system user...";
- my $RT_System = new RT::User($CurrentUser);
+ my $RT_System = RT::User->new($CurrentUser);
my ( $val, $msg ) = $RT_System->_BootstrapCreate(
Name => 'RT_System',
RealName => 'The RT System itself',
- Comments =>
-'Do not delete or modify this user. It is integral to RT\'s internal database structures',
- Creator => '1',
+ Comments => 'Do not delete or modify this user. '
+ . 'It is integral to RT\'s internal database structures',
+ Creator => '1',
LastUpdatedBy => '1',
);
@@ -423,7 +323,6 @@
}
print "done.\n";
$RT::Handle->Disconnect() unless $db_type eq 'SQLite';
-
}
# load some sort of data into the database
@@ -691,6 +590,193 @@
print "Done setting up database content.\n";
}
+sub check_db_compatibility {
+ if ( $db_type eq "mysql" ) {
+ # Check which version we're running
+ my ($version) = $dbh->selectrow_hashref("show variables like 'version'")->{Value} =~ /^(\d\.\d+)/;
+ if ( $version < 4 ) {
+ print STDERR "*** WARNING: RT is unsupported on MySQL versions before 4.0.x\n";
+ }
+
+ # MySQL must have InnoDB support
+ if ( $args{'action'} =~ /^(init|insert|schema)$/ ) {
+ print "Checking that mysql has spport for InnoDB.\n" if $args{'debug'};
+ my $innodb = $dbh->selectrow_hashref("show variables like 'have_innodb'")->{Value};
+ if ( $innodb eq "NO" ) {
+ print STDERR "RT requires that MySQL be compiled with InnoDB table support.\n".
+ "See http://dev.mysql.com/doc/mysql/en/InnoDB.html\n";
+ exit -1;
+ } elsif ( $innodb eq "DISABLED" ) {
+ print STDERR "RT requires that MySQL InnoDB table support be enabled.\n".
+ ($version < 4
+ ? "Add 'innodb_data_file_path=ibdata1:10M:autoextend' to the [mysqld] section of my.cnf\n"
+ : "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n");
+ exit -1;
+ }
+ }
+ if ( $args{'action'} =~ /^(insert|schema)$/ ) {
+ print "Checking that Tickets table is of InnoDB type.\n" if $args{'debug'};
+ my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Tickets")->[1];
+ unless ( $create_table =~ /ENGINE=InnoDB/ ) {
+ print STDERR 'RT requires that all its tables be of InnoDB type.\n'.
+ "Upgrade RT tables.\n";
+ exit -1;
+ }
+ }
+ if ( $version >= 4.1 && $args{'action'} =~ /^(insert|schema)$/ ) {
+ print "MySQL >= 4.1, checking that user upgraded.\n" if $args{'debug'};
+ my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1];
+ unless ( $create_table =~ /\bContent\b[^,]*BLOB/i ) {
+ print STDERR "*** WARNING: RT since version 3.6 has new schema for MySQL versions after 4.1.0\n"
+ ."Follow instructions in the UPGRADING.mysql file.\n";
+ sleep 3;
+ }
+ }
+ }
+}
+
+sub get_dba_password {
+ print "In order to create or update your RT database,";
+ print "this script needs to connect to your "
+ . $db_type
+ . " instance on "
+ . $db_host . " as "
+ . $args{'dba'} . ".\n";
+ print "Please specify that user's database password below. If the user has no database\n";
+ print "password, just press return.\n\n";
+ print "Password: ";
+ ReadMode('noecho');
+ my $password = ReadLine(0);
+ ReadMode('normal');
+ print "\n";
+ return ($password);
+}
+
+sub _yesno {
+ print "Proceed [y/N]:";
+ my $x = scalar(<STDIN>);
+ $x =~ /^y/i;
+}
+
+=head2 get_system_dsn
+
+Returns a dsn suitable for database creates and drops
+and user creates and drops.
+
+=cut
+
+sub get_system_dsn {
+
+ my $dsn = get_rt_dsn();
+
+ if ( $db_type eq 'mysql' ) {
+ # with mysql, you want to connect sans database to funge things
+ $dsn =~ s/dbname=\Q$db_name//;
+ }
+ elsif ( $db_type eq 'Pg' ) {
+ # with postgres, you want to connect to template1 database
+ $dsn =~ s/dbname=\Q$db_name/dbname=template1/;
+ }
+ elsif ( $db_type eq 'Informix' ) {
+ # with Informix, you want to connect sans database:
+ $dsn =~ s/Informix:\Q$db_name/Informix:/;
+ }
+ return $dsn;
+}
+
+sub get_rt_dsn {
+ require RT::Handle;
+ $RT::Handle ||= RT::Handle->new;
+ $RT::Handle->BuildDSN;
+ return $RT::Handle->DSN;
+}
+
+sub _get_dbh {
+ my ($dsn, $user, $pass) = @_;
+ my $dbh = DBI->connect(
+ $dsn, $user, $pass,
+ { RaiseError => 0, PrintError => 0 },
+ );
+ unless ( $dbh ) {
+ my $msg = "Failed to connect to $dsn as user '$user': ". $DBI::errstr;
+ if ( $args{'debug'} ) {
+ require Carp; Carp::confess( $msg );
+ } else {
+ print STDERR $msg; exit -1;
+ }
+ }
+ return $dbh;
+}
+
+sub get_system_dbh {
+ return _get_dbh( get_system_dsn(), $args{'dba'}, $args{'dba-password'} );
+}
+
+sub get_rt_dbh {
+ my ($user, $pass) = @_;
+ unless ( @_ ) {
+ ($user, $pass) = ($db_user, $db_pass);
+ }
+ return _get_dbh( get_rt_dsn, $user, $pass );
+}
+
+=head2 connect_rt_handle
+
+Returns connected C<$RT::Handle>, connect with credentials from RT config.
+
+=cut
+
+sub connect_rt_handle {
+
+ require RT::Handle;
+
+ $RT::Handle ||= RT::Handle->new;
+ $RT::Handle->Connect;
+
+ return $RT::Handle;
+}
+
+=head1 get_version_file
+
+Takes base name of the file as argument, scans for <base name>-<version> named
+files and returns file name with closest version to the version of the RT DB.
+
+=cut
+
+sub get_version_file {
+ my $base_name = shift;
+
+ require File::Glob;
+ my @files = File::Glob::bsd_glob("$base_name*");
+ return '' unless @files;
+
+ my %version = map { $_ =~ /\.\w+-([-\w\.]+)$/; ($1||0) => $_ } @files;
+ my $db_version = connect_rt_handle()->DatabaseVersion;
+ print "Server version $db_version\n";
+ my $version;
+ foreach ( reverse sort cmp_version keys %version ) {
+ print "version $_\n"; print "comparision ". cmp_version( $db_version, $_ ) ."\n";
+ if ( cmp_version( $db_version, $_ ) >= 0 ) {
+ $version = $_;
+ last;
+ }
+ }
+
+ return defined $version? $version{ $version } : undef;
+}
+
+sub cmp_version($$) {
+ my ($a, $b) = (@_);
+ my @a = split /[^0-9]+/, $a;
+ my @b = split /[^0-9]+/, $b;
+ for ( my $i = 0; $i < @a; $i++ ) {
+ return 1 unless defined $b[$i];
+ return $a[$i] <=> $b[$i] if $a[$i] <=> $b[$i];
+ }
+ return 0 if @a == @b;
+ return -1;
+}
+
=head2 ACLEquivGroupId
Given a userid, return that user's acl equivalence group
More information about the Rt-commit
mailing list