sub select {
my ($self, $table, $fields, $where, $order, @rest) = @_;
+ $table = $self->_quote($table) unless ref($table);
@rest = (-1) unless defined $rest[0];
+ die "LIMIT 0 Does Not Compute" if $rest[0] == 0;
+ # and anyway, SQL::Abstract::Limit will cause a barf if we don't first
local $self->{having_bind} = [];
my ($sql, @ret) = $self->SUPER::select(
$table, $self->_recurse_fields($fields), $where, $order, @rest
return wantarray ? ($sql, @ret, @{$self->{having_bind}}) : $sql;
}
+sub insert {
+ my $self = shift;
+ my $table = shift;
+ $table = $self->_quote($table) unless ref($table);
+ $self->SUPER::insert($table, @_);
+}
+
+sub update {
+ my $self = shift;
+ my $table = shift;
+ $table = $self->_quote($table) unless ref($table);
+ $self->SUPER::update($table, @_);
+}
+
+sub delete {
+ my $self = shift;
+ my $table = shift;
+ $table = $self->_quote($table) unless ref($table);
+ $self->SUPER::delete($table, @_);
+}
+
sub _emulate_limit {
my $self = shift;
if ($_[3] == -1) {
} elsif (ref $from eq 'HASH') {
return $self->_make_as($from);
} else {
- return $from;
+ return $from; # would love to quote here but _table ends up getting called
+ # twice during an ->select without a limit clause due to
+ # the way S::A::Limit->select works. should maybe consider
+ # bypassing this and doing S::A::select($self, ...) in
+ # our select method above. meantime, quoting shims have
+ # been added to select/insert/update/delete here
}
}
croak($msg);
}
-=head1 NAME
+=head1 NAME
DBIx::Class::Storage::DBI - DBI storage handler
}
}
+=head2 dbh
+
+Returns the dbh - a data base handle of class L<DBI>.
+
+=cut
+
sub dbh {
my ($self) = @_;
$DBI::connect_via = 'connect';
}
- if(ref $info[0] eq 'CODE') {
- $dbh = &{$info[0]};
- }
- else {
- $dbh = DBI->connect(@info);
- }
+ eval {
+ if(ref $info[0] eq 'CODE') {
+ $dbh = &{$info[0]};
+ }
+ else {
+ $dbh = DBI->connect(@info);
+ }
+ };
$DBI::connect_via = $old_connect_via if $old_connect_via;
- $self->throw_exception("DBI Connection failed: $DBI::errstr")
- unless $dbh;
+ if (!$dbh || $@) {
+ $self->throw_exception("DBI Connection failed: " . ($@ || $DBI::errstr));
+ }
$dbh;
}
sub txn_begin {
my $self = shift;
- $self->dbh->begin_work
- if $self->{transaction_depth}++ == 0 and $self->dbh->{AutoCommit};
+ if ($self->{transaction_depth}++ == 0) {
+ my $dbh = $self->dbh;
+ if ($dbh->{AutoCommit}) {
+ $self->debugfh->print("BEGIN WORK\n")
+ if ($self->debug);
+ $dbh->begin_work;
+ }
+ }
}
=head2 txn_commit
sub txn_commit {
my $self = shift;
if ($self->{transaction_depth} == 0) {
- $self->dbh->commit unless $self->dbh->{AutoCommit};
+ my $dbh = $self->dbh;
+ unless ($dbh->{AutoCommit}) {
+ $self->debugfh->print("COMMIT\n")
+ if ($self->debug);
+ $dbh->commit;
+ }
}
else {
- $self->dbh->commit if --$self->{transaction_depth} == 0;
+ if (--$self->{transaction_depth} == 0) {
+ $self->debugfh->print("COMMIT\n")
+ if ($self->debug);
+ $self->dbh->commit;
+ }
}
}
eval {
if ($self->{transaction_depth} == 0) {
- $self->dbh->rollback unless $self->dbh->{AutoCommit};
+ my $dbh = $self->dbh;
+ unless ($dbh->{AutoCommit}) {
+ $self->debugfh->print("ROLLBACK\n")
+ if ($self->debug);
+ $dbh->rollback;
+ }
}
else {
- --$self->{transaction_depth} == 0 ?
- $self->dbh->rollback :
+ if (--$self->{transaction_depth} == 0) {
+ $self->debugfh->print("ROLLBACK\n")
+ if ($self->debug);
+ $self->dbh->rollback;
+ }
+ else {
die DBIx::Class::Storage::NESTED_ROLLBACK_EXCEPTION->new;
+ }
}
};
my @debug_bind = map { defined $_ ? qq{`$_'} : q{`NULL'} } @bind;
$self->debugfh->print("$sql: " . join(', ', @debug_bind) . "\n");
}
- my $sth = $self->sth($sql,$op);
- $self->throw_exception("no sth generated via sql: $sql") unless $sth;
+ my $sth = eval { $self->sth($sql,$op) };
+
+ if (!$sth || $@) {
+ $self->throw_exception('no sth generated via sql (' . ($@ || $self->_dbh->errstr) . "): $sql");
+ }
+
@bind = map { ref $_ ? ''.$_ : $_ } @bind; # stringify args
my $rv;
- if ($sth) {
- $rv = $sth->execute(@bind)
- or $self->throw_exception("Error executing '$sql': " . $sth->errstr);
- } else {
+ if ($sth) {
+ $rv = eval { $sth->execute(@bind) };
+
+ if ($@ || !$rv) {
+ $self->throw_exception("Error executing '$sql': ".($@ || $sth->errstr));
+ }
+ } else {
$self->throw_exception("'$sql' did not generate a statement.");
}
return (wantarray ? ($rv, $sth, @bind) : $rv);
$self->sql_maker->_default_limit_syntax eq "GenericSubQ") {
$attrs->{software_limit} = 1;
} else {
+ $self->throw_exception("rows attribute must be positive if present")
+ if (defined($attrs->{rows}) && !($attrs->{rows} > 0));
push @args, $attrs->{rows}, $attrs->{offset};
}
return $self->_execute(@args);
sub columns_info_for {
my ($self, $table) = @_;
- if ($self->dbh->can('column_info')) {
+ my $dbh = $self->dbh;
+
+ if ($dbh->can('column_info')) {
my %result;
- my $old_raise_err = $self->dbh->{RaiseError};
- my $old_print_err = $self->dbh->{PrintError};
- $self->dbh->{RaiseError} = 1;
- $self->dbh->{PrintError} = 0;
+ my $old_raise_err = $dbh->{RaiseError};
+ my $old_print_err = $dbh->{PrintError};
+ $dbh->{RaiseError} = 1;
+ $dbh->{PrintError} = 0;
eval {
- my $sth = $self->dbh->column_info( undef, undef, $table, '%' );
+ my $sth = $dbh->column_info( undef, undef, $table, '%' );
$sth->execute();
while ( my $info = $sth->fetchrow_hashref() ){
my %column_info;
$result{$info->{COLUMN_NAME}} = \%column_info;
}
};
- $self->dbh->{RaiseError} = $old_raise_err;
- $self->dbh->{PrintError} = $old_print_err;
+ $dbh->{RaiseError} = $old_raise_err;
+ $dbh->{PrintError} = $old_print_err;
return \%result if !$@;
}
my %result;
- my $sth = $self->dbh->prepare("SELECT * FROM $table WHERE 1=0");
+ my $sth = $dbh->prepare("SELECT * FROM $table WHERE 1=0");
$sth->execute;
my @columns = @{$sth->{NAME_lc}};
for my $i ( 0 .. $#columns ){
my %column_info;
my $type_num = $sth->{TYPE}->[$i];
my $type_name;
- if(defined $type_num && $self->dbh->can('type_info')) {
- my $type_info = $self->dbh->type_info($type_num);
+ if(defined $type_num && $dbh->can('type_info')) {
+ my $type_info = $dbh->type_info($type_num);
$type_name = $type_info->{TYPE_NAME} if $type_info;
}
$column_info{data_type} = $type_name ? $type_name : $type_num;
eval "use SQL::Translator";
$self->throw_exception("Can't deploy without SQL::Translator: $@") if $@;
eval "use SQL::Translator::Parser::DBIx::Class;";
- $self->throw_exception($@) if $@;
+ $self->throw_exception($@) if $@;
eval "use SQL::Translator::Producer::${type};";
$self->throw_exception($@) if $@;
my $tr = SQL::Translator->new(%$sqltargs);
sub deploy {
my ($self, $schema, $type, $sqltargs) = @_;
- my @statements = $self->deployment_statements($schema, $type, $sqltargs);
- foreach(split(";\n", @statements)) {
- $self->debugfh->print("$_\n") if $self->debug;
- $self->dbh->do($_) or warn "SQL was:\n $_";
- }
+ foreach my $statement ( $self->deployment_statements($schema, $type, $sqltargs) ) {
+ for ( split(";\n", $statement)) {
+ $self->debugfh->print("$_\n") if $self->debug;
+ $self->dbh->do($_) or warn "SQL was:\n $_";
+ }
+ }
}
sub DESTROY { shift->disconnect }