# will get the same rdbms version). _determine_supports_X does not need to
# exist on a driver, as we ->can for it before calling.
-my @capabilities = (qw/insert_returning placeholders typeless_placeholders/);
+my @capabilities = (qw/insert_returning placeholders typeless_placeholders join_optimizer/);
__PACKAGE__->mk_group_accessors( dbms_capability => map { "_supports_$_" } @capabilities );
-__PACKAGE__->mk_group_accessors( use_dbms_capability => map { "_use_$_" } @capabilities );
+__PACKAGE__->mk_group_accessors( use_dbms_capability => map { "_use_$_" } (@capabilities ) );
+# on by default, not strictly a capability (pending rewrite)
+__PACKAGE__->_use_join_optimizer (1);
+sub _determine_supports_join_optimizer { 1 };
# Each of these methods need _determine_driver called before itself
# in order to function reliably. This is a purely DRY optimization
ref $coderef eq 'CODE' or $self->throw_exception
('$coderef must be a CODE reference');
- return $coderef->(@_) if $self->{transaction_depth} && ! $self->auto_savepoint;
-
local $self->{_in_dbh_do} = 1;
my @result;
try {
$self->txn_begin;
+ my $txn_start_depth = $self->transaction_depth;
if($want_array) {
@result = $coderef->(@$args);
}
else {
$coderef->(@$args);
}
- $self->txn_commit;
+
+ my $delta_txn = $txn_start_depth - $self->transaction_depth;
+ if ($delta_txn == 0) {
+ $self->txn_commit;
+ }
+ elsif ($delta_txn != 1) {
+ # an off-by-one would mean we fired a rollback
+ carp "Unexpected reduction of transaction depth by $delta_txn after execution of $coderef";
+ }
} catch {
$exception = $_;
};
if(! defined $exception) { return $want_array ? @result : $result[0] }
- if($tried++ || $self->connected) {
+ if($self->transaction_depth > 1 || $tried++ || $self->connected) {
my $rollback_exception;
try { $self->txn_rollback } catch { $rollback_exception = shift };
if(defined $rollback_exception) {
}
sub _svp_generate_name {
- my ($self) = @_;
-
- return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
+ my ($self) = @_;
+ return 'savepoint_'.scalar(@{ $self->{'savepoints'} });
}
sub txn_begin {
# this means we have not yet connected and do not know the AC status
# (e.g. coderef $dbh)
- $self->ensure_connected if (! defined $self->_dbh_autocommit);
+ if (! defined $self->_dbh_autocommit) {
+ $self->ensure_connected;
+ }
+ # otherwise re-connect on pid changes, so
+ # that the txn_depth is adjusted properly
+ # the lightweight _get_dbh is good enoug here
+ # (only superficial handle check, no pings)
+ else {
+ $self->_get_dbh;
+ }
- if($self->{transaction_depth} == 0) {
+ if($self->transaction_depth == 0) {
$self->debugobj->txn_begin()
if $self->debug;
$self->_dbh_begin_work;
$self->svp_release
if $self->auto_savepoint;
}
+ else {
+ $self->throw_exception( 'Refusing to commit without a started transaction' );
+ }
}
sub _dbh_commit {