#
# COPYRIGHT:
#
-# This software is Copyright (c) 1996-2011 Best Practical Solutions, LLC
+# This software is Copyright (c) 1996-2015 Best Practical Solutions, LLC
# <sales@bestpractical.com>
#
# (Except where explicitly superseded by other copyright notices)
use strict;
use warnings;
-use vars qw/@ISA/;
+
+use File::Spec;
=head1 METHODS
sub Connect {
my $self = shift;
+ my %args = (@_);
my $db_type = RT->Config->Get('DatabaseType');
if ( $db_type eq 'Oracle' ) {
$self->SUPER::Connect(
User => RT->Config->Get('DatabaseUser'),
Password => RT->Config->Get('DatabasePassword'),
+ DisconnectHandleOnDestroy => 1,
+ %args,
);
if ( $db_type eq 'mysql' ) {
if ( $db_type eq 'Pg' ) {
my $version = $self->DatabaseVersion;
($version) = $version =~ /^(\d+\.\d+)/;
+ $self->dbh->{pg_server_prepare} = 0 if $version > 9.1; #and we're using a deb-7 version DBD::Pg?
$self->dbh->do("SET bytea_output = 'escape'") if $version >= 9.0;
}
=cut
-require File::Spec;
sub BuildDSN {
my $self = shift;
Port => $db_port,
Driver => $db_type,
RequireSSL => RT->Config->Get('DatabaseRequireSSL'),
- DisconnectHandleOnDestroy => 1,
);
if ( $db_type eq 'Oracle' && $db_host ) {
$args{'SID'} = delete $args{'Database'};
# 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 CheckIntegrity {
my $self = shift;
-
- my $dsn = $self->DSN;
- my $user = RT->Config->Get('DatabaseUser');
- my $pass = RT->Config->Get('DatabasePassword');
+ $self = new $self unless ref $self;
- my $dbh = DBI->connect(
- $dsn, $user, $pass,
- { RaiseError => 0, PrintError => 0 },
- );
- unless ( $dbh ) {
- return (0, 'no connection', "Failed to connect to $dsn as user '$user': ". $DBI::errstr);
+ unless ($RT::Handle and $RT::Handle->dbh) {
+ local $@;
+ unless ( eval { RT::ConnectToDatabase(); 1 } ) {
+ return (0, 'no connection', "$@");
+ }
}
- RT::ConnectToDatabase();
- RT::InitLogging();
-
require RT::CurrentUser;
- my $test_user = new RT::CurrentUser;
+ my $test_user = RT::CurrentUser->new;
$test_user->Load('RT_System');
unless ( $test_user->id ) {
- return (0, 'no system user', "Couldn't find RT_System user in the DB '$dsn'");
+ return (0, 'no system user', "Couldn't find RT_System user in the DB '". $self->DSN ."'");
}
- $test_user = new RT::CurrentUser;
+ $test_user = RT::CurrentUser->new;
$test_user->Load('Nobody');
unless ( $test_user->id ) {
- return (0, 'no nobody user', "Couldn't find Nobody user in the DB '$dsn'");
+ return (0, 'no nobody user', "Couldn't find Nobody user in the DB '". $self->DSN ."'");
}
- return $dbh;
+ return 1;
}
sub CheckCompatibility {
unless $version;
($version) = $version =~ /^(\d+\.\d+)/;
- return (0, "RT is unsupported on MySQL versions before 4.0.x, it's $version")
- if $version < 4;
+ return (0, "RT is unsupported on MySQL versions before 4.1. Your version is $version.")
+ if $version < 4.1;
# MySQL must have InnoDB support
- my $innodb = ($dbh->selectrow_array("show variables like 'have_innodb'"))[1];
- if ( lc $innodb eq "no" ) {
+ local $dbh->{FetchHashKeyName} = 'NAME_lc';
+ my $innodb = lc($dbh->selectall_hashref("SHOW ENGINES", "engine")->{InnoDB}{support} || "no");
+ if ( $innodb eq "no" ) {
return (0, "RT requires that MySQL be compiled with InnoDB table support.\n".
- "See http://dev.mysql.com/doc/mysql/en/InnoDB.html");
- } elsif ( lc $innodb eq "disabled" ) {
+ "See <http://dev.mysql.com/doc/mysql/en/innodb-storage-engine.html>\n".
+ "and check that there are no 'skip-innodb' lines in your my.cnf.");
+ } elsif ( $innodb eq "disabled" ) {
return (0, "RT requires that MySQL InnoDB table support be enabled.\n".
- "Remove the 'skip-innodb' line from your my.cnf file, restart MySQL, and try again.\n");
+ "Remove the 'skip-innodb' or 'innodb = OFF' line from your my.cnf file, restart MySQL, and try again.\n");
}
if ( $state eq 'post' ) {
unless ( $create_table =~ /(?:ENGINE|TYPE)\s*=\s*InnoDB/i ) {
return (0, "RT requires that all its tables be of InnoDB type. Upgrade RT tables.");
}
- }
- if ( $version >= 4.1 && $state eq 'post' ) {
- my $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1];
+
+ $create_table = $dbh->selectrow_arrayref("SHOW CREATE TABLE Attachments")->[1];
unless ( $create_table =~ /\bContent\b[^,]*BLOB/i ) {
return (0, "RT since version 3.8 has new schema for MySQL versions after 4.1.0\n"
."Follow instructions in the UPGRADING.mysql file.");
}
}
+
+ my $max_packet = ($dbh->selectrow_array("show variables like 'max_allowed_packet'"))[1];
+ if ($state =~ /^(create|post)$/ and $max_packet <= (1024 * 1024)) {
+ my $max_packet = sprintf("%.1fM", $max_packet/1024/1024);
+ warn "max_allowed_packet is set to $max_packet, which limits the maximum attachment or email size that RT can process. Consider adjusting MySQL's max_allowed_packet setting.\n";
+ }
}
return (1)
}
+sub CheckSphinxSE {
+ my $self = shift;
+
+ my $dbh = $RT::Handle->dbh;
+ local $dbh->{'RaiseError'} = 0;
+ local $dbh->{'PrintError'} = 0;
+ my $has = ($dbh->selectrow_array("show variables like 'have_sphinx'"))[1];
+ $has ||= ($dbh->selectrow_array(
+ "select 'yes' from INFORMATION_SCHEMA.PLUGINS where PLUGIN_NAME = 'sphinx' AND PLUGIN_STATUS='active'"
+ ))[0];
+
+ return 0 unless lc($has||'') eq "yes";
+ return 1;
+}
+
=head2 Database maintanance
=head3 CreateDatabase $DBH
return (1, "Created user $db_user. All RT's objects should be in his schema.");
}
elsif ( $db_type eq 'Pg' ) {
- # XXX: as we get external DBH we don't know if RaiseError or PrintError
- # are enabled, so we have to setup it here and restore them back
- $status = $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE' TEMPLATE template0")
- || $dbh->do("CREATE DATABASE $db_name TEMPLATE template0");
+ $status = $dbh->do("CREATE DATABASE $db_name WITH ENCODING='UNICODE' TEMPLATE template0");
}
- elsif ( $db_type eq 'Informix' ) {
- local $ENV{'DB_LOCALE'} = 'en_us.utf8';
- $status = $dbh->do("CREATE DATABASE $db_name WITH BUFFERED LOG");
+ elsif ( $db_type eq 'mysql' ) {
+ $status = $dbh->do("CREATE DATABASE $db_name DEFAULT CHARACTER SET utf8");
}
else {
$status = $dbh->do("CREATE DATABASE $db_name");
return ($status, $DBI::errstr);
}
-=head3 DropDatabase $DBH [Force => 0]
+=head3 DropDatabase $DBH
Drops RT's database. This method can be used as class method.
Takes DBI handle as first argument. Many database systems require
-special handle to allow you to create a new database, so you have
-to use L<SystemDSN> method during connection.
+a special handle to allow you to drop a database, so you may have
+to use L<SystemDSN> when acquiring the DBI handle.
-Fetches type and name of the DB from the config.
+Fetches the type and name of the database from the config.
=cut
my $db_type = RT->Config->Get('DatabaseType');
my $db_name = RT->Config->Get('DatabaseName');
- if ( $db_type eq 'Oracle' || $db_type eq 'Informix' ) {
+ if ( $db_type eq 'Oracle' ) {
my $db_user = RT->Config->Get('DatabaseUser');
my $status = $dbh->do( "DROP USER $db_user CASCADE" );
unless ( $status ) {
open( my $fh_schema, '<', $file ) or die $!;
my $has_local = 0;
- open( my $fh_schema_local, "<", $self->GetVersionFile( $dbh, $RT::LocalEtcPath . "/schema." . $db_type ))
+ open( my $fh_schema_local, "<" . $self->GetVersionFile( $dbh, $RT::LocalEtcPath . "/schema." . $db_type ))
and $has_local = 1;
my $statement = "";
return defined $version? $version{ $version } : undef;
}
+{ my %word = (
+ a => -4,
+ alpha => -4,
+ b => -3,
+ beta => -3,
+ pre => -2,
+ rc => -1,
+ head => 9999,
+);
sub cmp_version($$) {
my ($a, $b) = (@_);
- $b =~ s/HEAD$/9999/;
- my @a = split /[^0-9]+/, $a;
- my @b = split /[^0-9]+/, $b;
+ my @a = grep defined, map { /^[0-9]+$/? $_ : /^[a-zA-Z]+$/? $word{$_}|| -10 : undef }
+ split /([^0-9]+)/, $a;
+ my @b = grep defined, map { /^[0-9]+$/? $_ : /^[a-zA-Z]+$/? $word{$_}|| -10 : undef }
+ split /([^0-9]+)/, $b;
+ @a > @b
+ ? push @b, (0) x (@a-@b)
+ : push @a, (0) x (@b-@a);
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;
+ return 0;
+}
+
+sub version_words {
+ return keys %word;
+}
+
}
{
require RT::CurrentUser;
- my $test_user = RT::User->new( new RT::CurrentUser );
+ my $test_user = RT::User->new( RT::CurrentUser->new() );
$test_user->Load('RT_System');
if ( $test_user->id ) {
push @warns, "Found system user in the DB.";
}
else {
- my $user = RT::User->new( new RT::CurrentUser );
+ my $user = RT::User->new( RT::CurrentUser->new() );
my ( $val, $msg ) = $user->_BootstrapCreate(
Name => 'RT_System',
RealName => 'The RT System itself',
# init RT::SystemUser and RT::System objects
RT::InitSystemObjects();
- unless ( $RT::SystemUser->id ) {
+ unless ( RT->SystemUser->id ) {
return (0, "Couldn't load system user");
}
# grant SuperUser right to system user
{
- my $test_ace = RT::ACE->new( $RT::SystemUser );
+ my $test_ace = RT::ACE->new( RT->SystemUser );
$test_ace->LoadByCols(
- PrincipalId => ACLEquivGroupId( $RT::SystemUser->Id ),
+ PrincipalId => ACLEquivGroupId( RT->SystemUser->Id ),
PrincipalType => 'Group',
RightName => 'SuperUser',
ObjectType => 'RT::System',
if ( $test_ace->id ) {
push @warns, "System user has global SuperUser right.";
} else {
- my $ace = RT::ACE->new( $RT::SystemUser );
+ my $ace = RT::ACE->new( RT->SystemUser );
my ( $val, $msg ) = $ace->_BootstrapCreate(
- PrincipalId => ACLEquivGroupId( $RT::SystemUser->Id ),
+ PrincipalId => ACLEquivGroupId( RT->SystemUser->Id ),
PrincipalType => 'Group',
RightName => 'SuperUser',
ObjectType => 'RT::System',
# $self->loc('Privileged'); # For the string extractor to get a string to localize
# $self->loc('Unprivileged'); # For the string extractor to get a string to localize
foreach my $name (qw(Everyone Privileged Unprivileged)) {
- my $group = RT::Group->new( $RT::SystemUser );
+ my $group = RT::Group->new( RT->SystemUser );
$group->LoadSystemInternalGroup( $name );
if ( $group->id ) {
push @warns, "System group '$name' already exists.";
next;
}
- $group = RT::Group->new( $RT::SystemUser );
+ $group = RT::Group->new( RT->SystemUser );
my ( $val, $msg ) = $group->_Create(
Type => $name,
Domain => 'SystemInternal',
# nobody
{
- my $user = RT::User->new( $RT::SystemUser );
+ my $user = RT::User->new( RT->SystemUser );
$user->Load('Nobody');
if ( $user->id ) {
push @warns, "Found 'Nobody' user in the DB.";
# system role groups
foreach my $name (qw(Owner Requestor Cc AdminCc)) {
- my $group = RT::Group->new( $RT::SystemUser );
+ my $group = RT::Group->new( RT->SystemUser );
$group->LoadSystemRoleGroup( $name );
if ( $group->id ) {
push @warns, "System role '$name' already exists.";
next;
}
- $group = RT::Group->new( $RT::SystemUser );
+ $group = RT::Group->new( RT->SystemUser );
my ( $val, $msg ) = $group->_Create(
Type => $name,
Domain => 'RT::System-Role',
sub InsertData {
my $self = shift;
my $datafile = shift;
+ my $root_password = shift;
+ my %args = (
+ disconnect_after => 1,
+ @_
+ );
# Slurp in stuff to insert from the datafile. Possible things to go in here:-
- our (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions,
+ our (@Groups, @Users, @Members, @ACL, @Queues, @ScripActions, @ScripConditions,
@Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final);
- local (@Groups, @Users, @ACL, @Queues, @ScripActions, @ScripConditions,
+ local (@Groups, @Users, @Members, @ACL, @Queues, @ScripActions, @ScripConditions,
@Templates, @CustomFields, @Scrips, @Attributes, @Initial, @Final);
local $@;
if ( @Groups ) {
$RT::Logger->debug("Creating groups...");
foreach my $item (@Groups) {
- my $new_entry = RT::Group->new( $RT::SystemUser );
+ my $new_entry = RT::Group->new( RT->SystemUser );
+ $item->{Domain} ||= 'UserDefined';
my $member_of = delete $item->{'MemberOf'};
+ my $members = delete $item->{'Members'};
my ( $return, $msg ) = $new_entry->_Create(%$item);
unless ( $return ) {
$RT::Logger->error( $msg );
if ( $member_of ) {
$member_of = [ $member_of ] unless ref $member_of eq 'ARRAY';
foreach( @$member_of ) {
- my $parent = RT::Group->new($RT::SystemUser);
+ my $parent = RT::Group->new(RT->SystemUser);
if ( ref $_ eq 'HASH' ) {
$parent->LoadByCols( %$_ );
}
}
}
}
+ push @Members, map { +{Group => $new_entry->id,
+ Class => "RT::User", Name => $_} }
+ @{ $members->{Users} || [] };
+ push @Members, map { +{Group => $new_entry->id,
+ Class => "RT::Group", Name => $_} }
+ @{ $members->{Groups} || [] };
}
$RT::Logger->debug("done.");
}
if ( @Users ) {
$RT::Logger->debug("Creating users...");
foreach my $item (@Users) {
- my $new_entry = new RT::User( $RT::SystemUser );
+ if ( $item->{'Name'} eq 'root' && $root_password ) {
+ $item->{'Password'} = $root_password;
+ }
+ my $new_entry = RT::User->new( RT->SystemUser );
my ( $return, $msg ) = $new_entry->Create(%$item);
unless ( $return ) {
$RT::Logger->error( $msg );
}
$RT::Logger->debug("done.");
}
+ if ( @Members ) {
+ $RT::Logger->debug("Adding users and groups to groups...");
+ for my $item (@Members) {
+ my $group = RT::Group->new(RT->SystemUser);
+ $group->LoadUserDefinedGroup( delete $item->{Group} );
+ unless ($group->Id) {
+ RT->Logger->error("Unable to find group '$group' to add members to");
+ next;
+ }
+
+ my $class = delete $item->{Class} || 'RT::User';
+ my $member = $class->new( RT->SystemUser );
+ $item->{Domain} = 'UserDefined' if $member->isa("RT::Group");
+ $member->LoadByCols( %$item );
+ unless ($member->Id) {
+ RT->Logger->error("Unable to find $class '".($item->{id} || $item->{Name})."' to add to ".$group->Name);
+ next;
+ }
+
+ my ( $return, $msg) = $group->AddMember( $member->PrincipalObj->Id );
+ unless ( $return ) {
+ $RT::Logger->error( $msg );
+ } else {
+ $RT::Logger->debug( $return ."." );
+ }
+ }
+ }
if ( @Queues ) {
$RT::Logger->debug("Creating queues...");
for my $item (@Queues) {
- my $new_entry = new RT::Queue($RT::SystemUser);
+ my $new_entry = RT::Queue->new(RT->SystemUser);
my ( $return, $msg ) = $new_entry->Create(%$item);
unless ( $return ) {
$RT::Logger->error( $msg );
if ( @CustomFields ) {
$RT::Logger->debug("Creating custom fields...");
for my $item ( @CustomFields ) {
- my $new_entry = new RT::CustomField( $RT::SystemUser );
+ my $new_entry = RT::CustomField->new( RT->SystemUser );
my $values = delete $item->{'Values'};
my @queues;
@queues = @{ delete $item->{'Queue'} };
}
- my ( $return, $msg ) = $new_entry->Create(%$item);
- unless( $return ) {
- $RT::Logger->error( $msg );
- next;
- }
-
if ( $item->{'BasedOn'} ) {
- my $basedon = RT::CustomField->new($RT::SystemUser);
- my ($ok, $msg ) = $basedon->LoadByCols( Name => $item->{'BasedOn'},
- LookupType => $new_entry->LookupType );
- if ($ok) {
- ($ok, $msg) = $new_entry->SetBasedOn( $basedon );
+ if ( $item->{'BasedOn'} =~ /^\d+$/) {
+ # Already have an ID -- should be fine
+ } elsif ( $item->{'LookupType'} ) {
+ my $basedon = RT::CustomField->new($RT::SystemUser);
+ my ($ok, $msg ) = $basedon->LoadByCols( Name => $item->{'BasedOn'},
+ LookupType => $item->{'LookupType'} );
if ($ok) {
- $RT::Logger->debug("Added BasedOn $item->{BasedOn}: $msg");
+ $item->{'BasedOn'} = $basedon->Id;
} else {
- $RT::Logger->error("Failed to add basedOn $item->{BasedOn}: $msg");
+ $RT::Logger->error("Unable to load $item->{BasedOn} as a $item->{LookupType} CF. Skipping BasedOn: $msg");
+ delete $item->{'BasedOn'};
}
} else {
- $RT::Logger->error("Unable to load $item->{BasedOn} as a $item->{LookupType} CF. Skipping BasedOn");
+ $RT::Logger->error("Unable to load CF $item->{BasedOn} because no LookupType was specified. Skipping BasedOn");
+ delete $item->{'BasedOn'};
}
+
+ }
+
+ my ( $return, $msg ) = $new_entry->Create(%$item);
+ unless( $return ) {
+ $RT::Logger->error( $msg );
+ next;
}
foreach my $value ( @{$values} ) {
# apply by default
if ( !@queues && !exists $item->{'Queue'} && $item->{LookupType} ) {
- my $ocf = RT::ObjectCustomField->new($RT::SystemUser);
+ my $ocf = RT::ObjectCustomField->new(RT->SystemUser);
$ocf->Create( CustomField => $new_entry->Id );
}
for my $q (@queues) {
- my $q_obj = RT::Queue->new($RT::SystemUser);
+ my $q_obj = RT::Queue->new(RT->SystemUser);
$q_obj->Load($q);
unless ( $q_obj->Id ) {
$RT::Logger->error("Could not find queue ". $q );
next;
}
- my $OCF = RT::ObjectCustomField->new($RT::SystemUser);
+ my $OCF = RT::ObjectCustomField->new(RT->SystemUser);
( $return, $msg ) = $OCF->Create(
CustomField => $new_entry->Id,
ObjectId => $q_obj->Id,
# Global rights or Queue rights?
if ( $item->{'CF'} ) {
- $object = RT::CustomField->new( $RT::SystemUser );
+ $object = RT::CustomField->new( RT->SystemUser );
my @columns = ( Name => $item->{'CF'} );
push @columns, Queue => $item->{'Queue'} if $item->{'Queue'} and not ref $item->{'Queue'};
$object->LoadByName( @columns );
} elsif ( $item->{'Queue'} ) {
- $object = RT::Queue->new($RT::SystemUser);
+ $object = RT::Queue->new(RT->SystemUser);
$object->Load( $item->{'Queue'} );
} else {
$object = $RT::System;
# Group rights or user rights?
if ( $item->{'GroupDomain'} ) {
- $princ = RT::Group->new($RT::SystemUser);
+ $princ = RT::Group->new(RT->SystemUser);
if ( $item->{'GroupDomain'} eq 'UserDefined' ) {
$princ->LoadUserDefinedGroup( $item->{'GroupId'} );
} elsif ( $item->{'GroupDomain'} eq 'SystemInternal' ) {
} else {
$princ->Load( $item->{'GroupId'} );
}
+ unless ( $princ->Id ) {
+ RT->Logger->error("Unable to load Group: GroupDomain => $item->{GroupDomain}, GroupId => $item->{GroupId}, Queue => $item->{Queue}");
+ next;
+ }
} else {
- $princ = RT::User->new($RT::SystemUser);
- $princ->Load( $item->{'UserId'} );
+ $princ = RT::User->new(RT->SystemUser);
+ my ($ok, $msg) = $princ->Load( $item->{'UserId'} );
+ unless ( $ok ) {
+ RT->Logger->error("Unable to load user: $item->{UserId} : $msg");
+ next;
+ }
}
# Grant it
$RT::Logger->debug("Creating ScripActions...");
for my $item (@ScripActions) {
- my $new_entry = RT::ScripAction->new($RT::SystemUser);
+ my $new_entry = RT::ScripAction->new(RT->SystemUser);
my ( $return, $msg ) = $new_entry->Create(%$item);
unless ( $return ) {
$RT::Logger->error( $msg );
$RT::Logger->debug("Creating ScripConditions...");
for my $item (@ScripConditions) {
- my $new_entry = RT::ScripCondition->new($RT::SystemUser);
+ my $new_entry = RT::ScripCondition->new(RT->SystemUser);
my ( $return, $msg ) = $new_entry->Create(%$item);
unless ( $return ) {
$RT::Logger->error( $msg );
$RT::Logger->debug("Creating templates...");
for my $item (@Templates) {
- my $new_entry = new RT::Template($RT::SystemUser);
+ my $new_entry = RT::Template->new(RT->SystemUser);
my ( $return, $msg ) = $new_entry->Create(%$item);
unless ( $return ) {
$RT::Logger->error( $msg );
$RT::Logger->debug("Creating scrips...");
for my $item (@Scrips) {
- my $new_entry = new RT::Scrip($RT::SystemUser);
+ my $new_entry = RT::Scrip->new(RT->SystemUser);
my @queues = ref $item->{'Queue'} eq 'ARRAY'? @{ $item->{'Queue'} }: $item->{'Queue'} || 0;
push @queues, 0 unless @queues; # add global queue at least
$RT::Logger->debug("done.");
}
if ( @Attributes ) {
- $RT::Logger->debug("Creating predefined searches...");
- my $sys = RT::System->new($RT::SystemUser);
+ $RT::Logger->debug("Creating attributes...");
+ my $sys = RT::System->new(RT->SystemUser);
for my $item (@Attributes) {
my $obj = delete $item->{Object}; # XXX: make this something loadable
$RT::Logger->debug("done.");
}
- my $db_type = RT->Config->Get('DatabaseType');
- $RT::Handle->Disconnect() unless $db_type eq 'SQLite';
+ # XXX: This disconnect doesn't really belong here; it's a relict from when
+ # this method was extracted from rt-setup-database. However, too much
+ # depends on it to change without significant testing. At the very least,
+ # we can provide a way to skip the side-effect.
+ if ( $args{disconnect_after} ) {
+ my $db_type = RT->Config->Get('DatabaseType');
+ $RT::Handle->Disconnect() unless $db_type eq 'SQLite';
+ }
$RT::Logger->debug("Done setting up database content.");
sub ACLEquivGroupId {
my $id = shift;
- my $cu = $RT::SystemUser;
+ my $cu = RT->SystemUser;
unless ( $cu ) {
require RT::CurrentUser;
- $cu = new RT::CurrentUser;
+ $cu = RT::CurrentUser->new;
$cu->LoadByName('RT_System');
warn "Couldn't load RT_System user" unless $cu->id;
}
return $equiv_group->Id;
}
+=head2 QueryHistory
+
+Returns the SQL query history associated with this handle. The top level array
+represents a lists of request. Each request is a hash with metadata about the
+request (such as the URL) and a list of queries. You'll probably not be using this.
+
+=cut
+
+sub QueryHistory {
+ my $self = shift;
+
+ return $self->{QueryHistory};
+}
+
+=head2 AddRequestToHistory
+
+Adds a web request to the query history. It must be a hash with keys Path (a
+string) and Queries (an array reference of arrays, where elements are time,
+sql, bind parameters, and duration).
+
+=cut
+
+sub AddRequestToHistory {
+ my $self = shift;
+ my $request = shift;
+
+ push @{ $self->{QueryHistory} }, $request;
+}
+
+=head2 Quote
+
+Returns the parameter quoted by DBI. B<You almost certainly do not need this.>
+Use bind parameters (C<?>) instead. This is used only outside the scope of interacting
+with the database.
+
+=cut
+
+sub Quote {
+ my $self = shift;
+ my $value = shift;
+
+ return $self->dbh->quote($value);
+}
+
+=head2 FillIn
+
+Takes a SQL query and an array reference of bind parameters and fills in the
+query's C<?> parameters.
+
+=cut
+
+sub FillIn {
+ my $self = shift;
+ my $sql = shift;
+ my $bind = shift;
+
+ my $b = 0;
+
+ # is this regex sufficient?
+ $sql =~ s{\?}{$self->Quote($bind->[$b++])}eg;
+
+ return $sql;
+}
+
+# log a mason stack trace instead of a Carp::longmess because it's less painful
+# and uses mason component paths properly
+sub _LogSQLStatement {
+ my $self = shift;
+ my $statement = shift;
+ my $duration = shift;
+ my @bind = @_;
+
+ require HTML::Mason::Exceptions;
+ push @{$self->{'StatementLog'}} , ([Time::HiRes::time(), $statement, [@bind], $duration, HTML::Mason::Exception->new->as_string]);
+}
+
+
+sub _TableNames {
+ my $self = shift;
+ my $dbh = shift || $self->dbh;
+
+ {
+ local $@;
+ if (
+ $dbh->{Driver}->{Name} eq 'Pg'
+ && $dbh->{'pg_server_version'} >= 90200
+ && !eval { DBD::Pg->VERSION('2.19.3'); 1 }
+ ) {
+ die "You're using PostgreSQL 9.2 or newer. You have to upgrade DBD::Pg module to 2.19.3 or newer: $@";
+ }
+ }
+
+ my @res;
+
+ my $sth = $dbh->table_info( '', undef, undef, "'TABLE'");
+ while ( my $table = $sth->fetchrow_hashref ) {
+ push @res, $table->{TABLE_NAME} || $table->{table_name};
+ }
+
+ return @res;
+}
+
__PACKAGE__->FinalizeDatabaseType;
RT::Base->_ImportOverlays();