Merge 'trunk' into 'sybase'
[dbsrgits/DBIx-Class.git] / lib / DBIx / Class / Storage / DBI / Oracle / Generic.pm
index 92a920a..8b09f11 100644 (file)
@@ -1,12 +1,11 @@
 package DBIx::Class::Storage::DBI::Oracle::Generic;
-# -*- mode: cperl; cperl-indent-level: 2 -*-
 
 use strict;
 use warnings;
 
 =head1 NAME
 
-DBIx::Class::Storage::DBI::Oracle::Generic - Automatic primary key class for Oracle
+DBIx::Class::Storage::DBI::Oracle::Generic - Oracle Support for DBIx::Class
 
 =head1 SYNOPSIS
 
@@ -24,14 +23,8 @@ This class implements autoincrements for Oracle.
 
 =cut
 
-use Carp::Clan qw/^DBIx::Class/;
-
-use DBD::Oracle qw( :ora_types );
-#use constant ORA_BLOB => 113;  ## ORA_CLOB is 112
-
-use base qw/DBIx::Class::Storage::DBI::MultiDistinctEmulation/;
-
-# __PACKAGE__->load_components(qw/PK::Auto/);
+use base qw/DBIx::Class::Storage::DBI/;
+use mro 'c3';
 
 sub _dbh_last_insert_id {
   my ($self, $dbh, $source, @columns) = @_;
@@ -56,7 +49,7 @@ sub _dbh_get_autoinc_seq {
   };
 
   # trigger_body is a LONG
-  $dbh->{LongReadLen} = 64 * 1024 if ($dbh->{LongReadLen} < 64 * 1024);
+  local $dbh->{LongReadLen} = 64 * 1024 if ($dbh->{LongReadLen} < 64 * 1024);
 
   my $sth;
 
@@ -83,40 +76,22 @@ sub _dbh_get_autoinc_seq {
 
 sub _sequence_fetch {
   my ( $self, $type, $seq ) = @_;
-  my ($id) = $self->dbh->selectrow_array("SELECT ${seq}.${type} FROM DUAL");
+  my ($id) = $self->last_dbh->selectrow_array("SELECT ${seq}.${type} FROM DUAL");
   return $id;
 }
 
-=head2 connected
-
-Returns true if we have an open (and working) database connection, false if it is not (yet)
-open (or does not work). (Executes a simple SELECT to make sure it works.)
-
-The reason this is needed is that L<DBD::Oracle>'s ping() does not do a real
-OCIPing but just gets the server version, which doesn't help if someone killed
-your session.
-
-=cut
-
-sub connected {
+sub _ping {
   my $self = shift;
 
-  if (not $self->SUPER::connected(@_)) {
-    return 0;
-  }
-  else {
-    my $dbh = $self->_dbh;
+  my $dbh = $self->_dbh or return 0;
 
-    local $dbh->{RaiseError} = 1;
+  local $dbh->{RaiseError} = 1;
 
-    eval {
-      my $ping_sth = $dbh->prepare_cached("select 1 from dual");
-      $ping_sth->execute;
-      $ping_sth->finish;
-    };
+  eval {
+    $dbh->do("select 1 from dual");
+  };
 
-    return $@ ? 0 : 1;
-  }
+  return $@ ? 0 : 1;
 }
 
 sub _dbh_execute {
@@ -131,9 +106,9 @@ sub _dbh_execute {
     do {
       eval {
         if ($wantarray) {
-          @res    = $self->SUPER::_dbh_execute(@_);
+          @res    = $self->next::method(@_);
         } else {
-          $res[0] = $self->SUPER::_dbh_execute(@_);
+          $res[0] = $self->next::method(@_);
         }
       };
       $exception = $@;
@@ -161,7 +136,7 @@ Returns the sequence name for an autoincrement column
 
 sub get_autoinc_seq {
   my ($self, $source, $col) = @_;
-    
+
   $self->dbh_do('_dbh_get_autoinc_seq', $source, $col);
 }
 
@@ -187,10 +162,48 @@ L<DBIx::Class::InflateColumn::DateTime>.
 
 sub datetime_parser_type { return "DateTime::Format::Oracle"; }
 
-sub _svp_begin {
-    my ($self, $name) = @_;
-    $self->dbh->do("SAVEPOINT $name");
+=head2 connect_call_datetime_setup
+
+Used as:
+
+    on_connect_call => 'datetime_setup'
+
+In L<DBIx::Class::Storage::DBI/connect_info> to set the session nls date, and
+timestamp values for use with L<DBIx::Class::InflateColumn::DateTime> and the
+necessary environment variables for L<DateTime::Format::Oracle>, which is used
+by it.
+
+Maximum allowable precision is used, unless the environment variables have
+already been set.
+
+These are the defaults used:
+
+  $ENV{NLS_DATE_FORMAT}         ||= 'YYYY-MM-DD HH24:MI:SS';
+  $ENV{NLS_TIMESTAMP_FORMAT}    ||= 'YYYY-MM-DD HH24:MI:SS.FF';
+  $ENV{NLS_TIMESTAMP_TZ_FORMAT} ||= 'YYYY-MM-DD HH24:MI:SS.FF TZHTZM';
+
+To get more than second precision with L<DBIx::Class::InflateColumn::DateTime>
+for your timestamps, use something like this:
+
+  use Time::HiRes 'time';
+  my $ts = DateTime->from_epoch(epoch => time);
+
+=cut
+
+sub connect_call_datetime_setup {
+  my $self = shift;
+
+  my $date_format = $ENV{NLS_DATE_FORMAT} ||= 'YYYY-MM-DD HH24:MI:SS';
+  my $timestamp_format = $ENV{NLS_TIMESTAMP_FORMAT} ||=
+    'YYYY-MM-DD HH24:MI:SS.FF';
+  my $timestamp_tz_format = $ENV{NLS_TIMESTAMP_TZ_FORMAT} ||=
+    'YYYY-MM-DD HH24:MI:SS.FF TZHTZM';
+
+  $self->_do_query("alter session set nls_date_format = '$date_format'");
+  $self->_do_query(
+"alter session set nls_timestamp_format = '$timestamp_format'");
+  $self->_do_query(
+"alter session set nls_timestamp_tz_format='$timestamp_tz_format'");
 }
 
 =head2 source_bind_attributes
@@ -212,6 +225,7 @@ table with more than one LOB column.
 
 sub source_bind_attributes 
 {
+       require DBD::Oracle;
        my $self = shift;
        my($source) = @_;
 
@@ -224,8 +238,9 @@ sub source_bind_attributes
                my %column_bind_attrs = $self->bind_attribute_by_data_type($data_type);
 
                if ($data_type =~ /^[BC]LOB$/i) {
-                       $column_bind_attrs{'ora_type'}
-                               = uc($data_type) eq 'CLOB' ? ORA_CLOB : ORA_BLOB;
+                       $column_bind_attrs{'ora_type'} = uc($data_type) eq 'CLOB' ?
+                               DBD::Oracle::ORA_CLOB() :
+                               DBD::Oracle::ORA_BLOB();
                        $column_bind_attrs{'ora_field'} = $column;
                }
 
@@ -235,6 +250,12 @@ sub source_bind_attributes
        return \%bind_attributes;
 }
 
+sub _svp_begin {
+    my ($self, $name) = @_;
+
+    $self->last_dbh->do("SAVEPOINT $name");
+}
+
 # Oracle automatically releases a savepoint when you start another one with the
 # same name.
 sub _svp_release { 1 }
@@ -242,14 +263,12 @@ sub _svp_release { 1 }
 sub _svp_rollback {
     my ($self, $name) = @_;
 
-    $self->dbh->do("ROLLBACK TO SAVEPOINT $name")
+    $self->last_dbh->do("ROLLBACK TO SAVEPOINT $name")
 }
 
-=head1 AUTHORS
-
-Andy Grundman <andy@hybridized.org>
+=head1 AUTHOR
 
-Scott Connelly <scottsweep@yahoo.com>
+See L<DBIx::Class/CONTRIBUTORS>.
 
 =head1 LICENSE