File Coverage

blib/lib/Rose/DB/Oracle.pm
Criterion Covered Total %
statement 69 298 23.1
branch 11 132 8.3
condition 3 47 6.3
subroutine 20 58 34.4
pod 5 37 13.5
total 108 572 18.8


line stmt bran cond sub pod time code
1             package Rose::DB::Oracle;
2              
3 16     16   154 use strict;
  16         56  
  16         471  
4              
5 16     16   132 use Carp();
  16         38  
  16         261  
6 16     16   7398 use SQL::ReservedWords::Oracle();
  16         32870  
  16         442  
7              
8 16     16   411 use Rose::DB;
  16         45  
  16         877  
9              
10             our $Debug = 0;
11              
12             our $VERSION = '0.784';
13              
14             use Rose::Class::MakeMethods::Generic
15             (
16 16         216 inheritable_scalar =>
17             [
18             '_default_post_connect_sql',
19             '_booleans_are_numeric',
20             ]
21 16     16   120 );
  16         44  
22              
23             __PACKAGE__->_default_post_connect_sql
24             (
25             [
26             q(ALTER SESSION SET NLS_DATE_FORMAT = ') .
27             ($ENV{'NLS_DATE_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS') . q('),
28             q(ALTER SESSION SET NLS_TIMESTAMP_FORMAT = ') .
29             ($ENV{'NLS_TIMESTAMP_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS.FF') . q('),
30             q(ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = ') .
31             ($ENV{'NLS_TIMESTAMP_TZ_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS.FF TZHTZM') . q('),
32             ]
33             );
34              
35             __PACKAGE__->booleans_are_numeric(0);
36              
37             #
38             # Class methods
39             #
40              
41             sub booleans_are_numeric
42             {
43 16     16 1 42 my($class) = shift;
44              
45 16 50       71 if(@_)
46             {
47 16         32 my $arg = shift;
48              
49 16         60 $class->_booleans_are_numeric($arg);
50              
51 16     16   5542 no warnings 'redefine';
  16         228  
  16         22384  
52 16 50       143 if($arg)
53             {
54 0         0 *format_boolean = \&format_boolean_numeric;
55             }
56             else
57             {
58 16         46 *format_boolean = \&format_boolean_char;
59             }
60              
61 16 50       55 return $arg ? 1 : 0;
62             }
63              
64 0         0 return $class->_booleans_are_numeric;
65             }
66              
67             #
68             # Object methods
69             #
70              
71             sub default_post_connect_sql
72             {
73 10     10 1 27 my($class) = shift;
74              
75 10 50       36 if(@_)
76             {
77 0 0 0     0 if(@_ == 1 && ref $_[0] eq 'ARRAY')
78             {
79 0         0 $class->_default_post_connect_sql(@_);
80             }
81             else
82             {
83 0         0 $class->_default_post_connect_sql([ @_ ]);
84             }
85             }
86              
87 10         69 return $class->_default_post_connect_sql;
88             }
89              
90             sub post_connect_sql
91             {
92 10     10 1 37 my($self) = shift;
93              
94 10 50       52 unless(@_)
95             {
96             return wantarray ?
97 0 0       0 ( @{ $self->default_post_connect_sql || [] }, @{$self->{'post_connect_sql'} || [] } ) :
  0 0       0  
98 0 0       0 [ @{ $self->default_post_connect_sql || [] }, @{$self->{'post_connect_sql'} || [] } ];
  0 0       0  
  0 0       0  
99             }
100              
101 10 50 33     81 if(@_ == 1 && ref $_[0] eq 'ARRAY')
102             {
103 10         30 $self->{'post_connect_sql'} = $_[0];
104             }
105             else
106             {
107 0         0 $self->{'post_connect_sql'} = [ @_ ];
108             }
109              
110             return wantarray ?
111 0 0       0 ( @{ $self->default_post_connect_sql || [] }, @{$self->{'post_connect_sql'} || [] } ) :
  0 0       0  
112 10 50       41 [ @{ $self->default_post_connect_sql || [] }, @{$self->{'post_connect_sql'} || [] } ];
  10 50       84  
  10 50       467  
113             }
114              
115             sub schema
116             {
117 0     0 1 0 my($self) = shift;
118 0 0       0 $self->{'schema'} = shift if(@_);
119 0   0     0 return $self->{'schema'} || $self->username;
120             }
121              
122 0     0 0 0 sub use_auto_sequence_name { 1 }
123              
124             sub auto_sequence_name
125             {
126 0     0 0 0 my($self, %args) = @_;
127              
128 0         0 my($table) = $args{'table'};
129 0 0       0 Carp::croak 'Missing table argument' unless(defined $table);
130              
131 0         0 my($column) = $args{'column'};
132 0 0       0 Carp::croak 'Missing column argument' unless(defined $column);
133              
134 0         0 return uc "${table}_${column}_SEQ";
135             }
136              
137             sub build_dsn
138             {
139 9     9 0 78 my($self_or_class, %args) = @_;
140              
141 9   33     111 my $database = $args{'db'} || $args{'database'};
142              
143 9 50 33     83 if($args{'host'} || $args{'port'})
144             {
145 9 50       45 if ($args{'service'})
146             {
147 0         0 $args{'service_name'} = $args{'service'};
148              
149             return 'dbi:Oracle:' .
150 0         0 join(';', map { "$_=$args{$_}" } grep { $args{$_} } qw(service_name host port));
  0         0  
  0         0  
151             }
152             else
153             {
154 9         39 $args{'sid'} = $database;
155              
156             return 'dbi:Oracle:' .
157 9         33 join(';', map { "$_=$args{$_}" } grep { $args{$_} } qw(sid host port));
  18         124  
  27         92  
158             }
159             }
160              
161 0         0 return "dbi:Oracle:$database";
162             }
163              
164 0     0 0 0 sub init_date_handler { Rose::DB::Oracle::DateHandler->new }
165              
166             sub database_version
167             {
168 0     0 0 0 my($self) = shift;
169              
170 0 0       0 return $self->{'database_version'} if (defined $self->{'database_version'});
171              
172 0         0 my($version) = $self->dbh->get_info(18); # SQL_DBMS_VER.
173              
174             # Convert to an integer, e.g., 10.02.0100 -> 100020100
175              
176 0 0       0 if($version =~ /^(\d+)\.(\d+)(?:\.(\d+))?/)
177             {
178 0         0 $version = sprintf('%d%03d%04d', $1, $2, $3);
179             }
180              
181 0         0 return $self->{'database_version'} = $version;
182             }
183              
184 10     10 0 58 sub dbi_driver { 'Oracle' }
185              
186 0     0 0   sub likes_uppercase_table_names { 1 }
187 0     0 0   sub likes_uppercase_schema_names { 1 }
188 0     0 0   sub likes_uppercase_catalog_names { 1 }
189 0     0 0   sub likes_uppercase_sequence_names { 1 }
190              
191 0     0 0   sub insertid_param { '' }
192              
193             sub list_tables
194             {
195 0     0 0   my($self, %args) = @_;
196              
197 0 0         my $types = $args{'include_views'} ? "'TABLE','VIEW'" : 'TABLE';
198              
199 0           my($error, @tables);
200              
201             TRY:
202             {
203 0           local $@;
  0            
204              
205             eval
206 0           {
207 0 0         my($dbh) = $self->dbh or die $self->error;
208              
209 0           local $dbh->{'RaiseError'} = 1;
210 0           local $dbh->{'FetchHashKeyName'} = 'NAME';
211              
212 0           my $sth = $dbh->table_info($self->catalog, uc $self->schema, '%', $types);
213 0           my $info = $sth->fetchall_arrayref({}); # The {} are mandatory.
214              
215 0           for my $table (@$info)
216             {
217 0 0         push @tables, $$table{'TABLE_NAME'} if ($$table{'TABLE_NAME'} !~ /^BIN\$.+\$.+/);
218             }
219             };
220              
221 0           $error = $@;
222             }
223              
224 0 0         if($error)
225             {
226 0           Carp::croak 'Could not list tables from ', $self->dsn, " - $error";
227             }
228              
229 0 0         return wantarray ? @tables : \@tables;
230             }
231              
232             sub next_value_in_sequence
233             {
234 0     0 0   my($self, $sequence_name) = @_;
235              
236 0 0         my $dbh = $self->dbh or return undef;
237              
238 0           my($error, $value);
239              
240             TRY:
241             {
242 0           local $@;
  0            
243              
244             eval
245 0           {
246 0           local $dbh->{'PrintError'} = 0;
247 0           local $dbh->{'RaiseError'} = 1;
248 0           my $sth = $dbh->prepare("SELECT $sequence_name.NEXTVAL FROM DUAL");
249 0           $sth->execute;
250 0           $value = ${$sth->fetch}[0];
  0            
251 0           $sth->finish;
252             };
253              
254 0           $error = $@;
255             }
256              
257 0 0         if($error)
258             {
259 0           $self->error("Could not get the next value in the sequence $sequence_name - $error");
260 0           return undef;
261             }
262              
263 0           return $value;
264             }
265              
266             # Tried to execute a CURRVAL command on a sequence before the
267             # NEXTVAL command was executed at least once.
268 16     16   153 use constant ORA_08002 => 8002;
  16         41  
  16         4387  
269              
270             sub current_value_in_sequence
271             {
272 0     0 0   my($self, $sequence_name) = @_;
273              
274 0 0         my $dbh = $self->dbh or return undef;
275              
276 0           my($error, $value);
277              
278             TRY:
279             {
280 0           local $@;
  0            
281              
282             eval
283 0           {
284 0           local $dbh->{'PrintError'} = 0;
285 0           local $dbh->{'RaiseError'} = 1;
286 0           my $sth = $dbh->prepare("SELECT $sequence_name.CURRVAL FROM DUAL");
287              
288 0           $sth->execute;
289              
290 0           $value = ${$sth->fetch}[0];
  0            
291              
292 0           $sth->finish;
293             };
294              
295 0           $error = $@;
296             }
297              
298 0 0         if($error)
299             {
300 0 0         if(DBI->err == ORA_08002)
301             {
302 0 0         if(defined $self->next_value_in_sequence($sequence_name))
303             {
304 0           return $self->current_value_in_sequence($sequence_name);
305             }
306             }
307              
308 0           $self->error("Could not get the current value in the sequence $sequence_name - $error");
309 0           return undef;
310             }
311              
312 0           return $value;
313             }
314              
315             # Sequence does not exist, or the user does not have the required
316             # privilege to perform this operation.
317 16     16   139 use constant ORA_02289 => 2289;
  16         41  
  16         10242  
318              
319             sub sequence_exists
320             {
321 0     0 0   my($self, $sequence_name) = @_;
322              
323 0 0         my $dbh = $self->dbh or return undef;
324              
325 0           my $error;
326              
327             TRY:
328             {
329 0           local $@;
  0            
330              
331             eval
332 0           {
333 0           local $dbh->{'PrintError'} = 0;
334 0           local $dbh->{'RaiseError'} = 1;
335 0           my $sth = $dbh->prepare("SELECT $sequence_name.CURRVAL FROM DUAL");
336 0           $sth->execute;
337 0           $sth->fetch;
338 0           $sth->finish;
339             };
340              
341 0           $error = $@;
342             }
343              
344 0 0         if($error)
345             {
346 0           my $dbi_error = DBI->err;
347              
348 0 0         if($dbi_error == ORA_08002)
    0          
349             {
350 0 0         if(defined $self->next_value_in_sequence($sequence_name))
351             {
352 0           return $self->sequence_exists($sequence_name);
353             }
354             }
355             elsif($dbi_error == ORA_02289)
356             {
357 0           return 0;
358             }
359              
360 0           $self->error("Could not check if sequence $sequence_name exists - $error");
361 0           return undef;
362             }
363              
364 0           return 1;
365             }
366              
367             sub parse_dbi_column_info_default
368             {
369 0     0 0   my($self, $default, $col_info) = @_;
370              
371             # For some reason, given a default value like this:
372             #
373             # MYCOLUMN VARCHAR(128) DEFAULT 'foo' NOT NULL
374             #
375             # DBD::Oracle hands back a COLUMN_DEF value of:
376             #
377             # $col_info->{'COLUMN_DEF'} = "'foo' "; # WTF?
378             #
379             # I have no idea why. Anyway, we just want the value between the quotes.
380              
381 0 0         return undef unless (defined $default);
382              
383 0           $default =~ s/^\s*'(.+)'\s*$/$1/;
384              
385 0           return $default;
386             }
387              
388             *is_reserved_word = \&SQL::ReservedWords::Oracle::is_reserved;
389              
390             sub quote_identifier_for_sequence
391             {
392 0     0 0   my($self, $catalog, $schema, $table) = @_;
393 0           return join('.', map { uc } grep { defined } ($schema, $table));
  0            
  0            
394             }
395              
396             # sub auto_quote_column_name
397             # {
398             # my($self, $name) = @_;
399             #
400             # if($name =~ /[^\w#]/ || $self->is_reserved_word($name))
401             # {
402             # return $self->quote_column_name($name, @_);
403             # }
404             #
405             # return $name;
406             # }
407              
408 0     0 0   sub supports_schema { 1 }
409              
410 0     0 0   sub max_column_name_length { 30 }
411 0     0 0   sub max_column_alias_length { 30 }
412              
413             sub quote_column_name
414             {
415 0     0 0   my $name = uc $_[1];
416 0           $name =~ s/"/""/g;
417 0           return qq("$name");
418             }
419              
420             sub quote_table_name
421             {
422 0     0 0   my $name = uc $_[1];
423 0           $name =~ s/"/""/g;
424 0           return qq("$name");
425             }
426              
427             sub quote_identifier {
428 0     0 0   my($self) = shift;
429 0           my $method = ref($self)->parent_class . '::quote_identifier';
430 16     16   152 no strict 'refs';
  16         42  
  16         2548  
431 0           return uc $self->$method(@_);
432             }
433              
434             sub primary_key_column_names
435             {
436 0     0 0   my($self) = shift;
437              
438 0 0         my %args = @_ == 1 ? (table => @_) : @_;
439              
440 0 0         my $table = $args{'table'} or Carp::croak "Missing table name parameter";
441 0   0       my $schema = $args{'schema'} || $self->schema;
442 0   0       my $catalog = $args{'catalog'} || $self->catalog;
443              
444 16     16   131 no warnings 'uninitialized';
  16         41  
  16         1950  
445 0           $table = uc $table;
446 0           $schema = uc $schema;
447 0           $catalog = uc $catalog;
448              
449 0           my $table_unquoted = $self->unquote_table_name($table);
450              
451 0           my($error, $columns);
452              
453             TRY:
454             {
455 0           local $@;
  0            
456              
457             eval
458 0           {
459 0           $columns =
460             $self->_get_primary_key_column_names($catalog, $schema, $table_unquoted);
461             };
462              
463 0           $error = $@;
464             }
465              
466 0 0 0       if($error || !$columns)
467             {
468 16     16   150 no warnings 'uninitialized'; # undef strings okay
  16         37  
  16         12056  
469 0 0         $error = 'no primary key columns found' unless(defined $error);
470 0           Carp::croak "Could not get primary key columns for catalog '" .
471             $catalog . "' schema '" . $schema . "' table '" .
472             $table_unquoted . "' - " . $error;
473             }
474              
475 0 0         return wantarray ? @$columns : $columns;
476             }
477              
478             sub format_limit_with_offset
479             {
480 0     0 0   my($self, $limit, $offset, $args) = @_;
481              
482 0           delete $args->{'limit'};
483 0           delete $args->{'offset'};
484              
485 0 0         if($offset)
486             {
487             # http://www.oracle.com/technology/oramag/oracle/06-sep/o56asktom.html
488             # select *
489             # from ( select /*+ FIRST_ROWS(n) */
490             # a.*, ROWNUM rnum
491             # from ( your_query_goes_here,
492             # with order by ) a
493             # where ROWNUM <=
494             # :MAX_ROW_TO_FETCH )
495             # where rnum >= :MIN_ROW_TO_FETCH;
496              
497 0           my $size = $limit;
498 0           my $start = $offset + 1;
499 0           my $end = $start + $size - 1;
500 0           my $n = $offset + $limit;
501              
502 0           $args->{'limit_prefix'} =
503             "SELECT * FROM (SELECT /*+ FIRST_ROWS($n) */\na.*, ROWNUM oracle_rownum FROM (";
504             #"SELECT * FROM (SELECT a.*, ROWNUM oracle_rownum FROM (";
505              
506 0           $args->{'limit_suffix'} =
507             ") a WHERE ROWNUM <= $end) WHERE oracle_rownum >= $start";
508             }
509             else
510             {
511 0           $args->{'limit_prefix'} = "SELECT /*+ FIRST_ROWS($limit) */ a.* FROM (";
512             #$args->{'limit_prefix'} = "SELECT a.* FROM (";
513 0           $args->{'limit_suffix'} = ") a WHERE ROWNUM <= $limit";
514             }
515             }
516              
517             sub format_select_lock
518             {
519 0     0 0   my($self, $class, $lock, $tables) = @_;
520              
521 0 0         $lock = { type => $lock } unless(ref $lock);
522              
523 0 0 0       $lock->{'type'} ||= 'for update' if($lock->{'for_update'});
524              
525 0 0         unless($lock->{'type'} eq 'for update')
526             {
527 0           Carp::croak "Invalid lock type: $lock->{'type'}";
528             }
529              
530 0           my $sql = 'FOR UPDATE';
531              
532 0           my @columns;
533              
534 0 0         if(my $on = $lock->{'on'})
    0          
535             {
536 0           @columns = map { $self->column_sql_from_lock_on_value($class, $_, $tables) } @$on;
  0            
537             }
538             elsif(my $columns = $lock->{'columns'})
539             {
540 0           my %map;
541              
542 0 0         if($tables)
543             {
544 0           my $tn = 1;
545              
546 0           foreach my $table (@$tables)
547             {
548 0           (my $table_key = $table) =~ s/^(["']?)[^.]+\1\.//;
549 0           $map{$table_key} = 't' . $tn++;
550             }
551             }
552              
553             @columns = map
554             {
555 0           ref $_ eq 'SCALAR' ? $$_ :
556             /^([^.]+)\.([^.]+)$/ ?
557 0 0         $self->auto_quote_column_with_table($2, defined $map{$1} ? $map{$1} : $1) :
    0          
    0          
558             $self->auto_quote_column_name($_)
559             }
560             @$columns;
561             }
562              
563 0 0         if(@columns)
564             {
565 0           $sql .= ' OF ' . join(', ', @columns);
566             }
567              
568 0 0         if($lock->{'nowait'})
    0          
569             {
570 0           $sql .= ' NOWAIT';
571             }
572             elsif(my $wait = $lock->{'wait'})
573             {
574 0           $sql .= " WAIT $wait";
575             }
576              
577 0 0         if($lock->{'skip_locked'})
578             {
579 0           $sql .= ' SKIP LOCKED';
580             }
581              
582 0           return $sql;
583             }
584              
585 0 0   0 0   sub format_boolean_char { $_[1] ? 't' : 'f' }
586 0 0   0 0   sub format_boolean_numeric { $_[1] ? 1 : 0 }
587              
588 16     16   537 BEGIN { *format_boolean = \&format_boolean_char }
589              
590             #
591             # Date/time keywords and inlining
592             #
593              
594             sub validate_date_keyword
595             {
596 16     16   128 no warnings;
  16         63  
  16         4537  
597 0 0 0 0 1   $_[1] =~ /^(?:CURRENT_|SYS|LOCAL)(?:TIMESTAMP|DATE)$/i ||
598             ($_[0]->keyword_function_calls && $_[1] =~ /^\w+\(.*\)$/);
599             }
600              
601             *validate_time_keyword = \&validate_date_keyword;
602             *validate_timestamp_keyword = \&validate_date_keyword;
603             *validate_datetime_keyword = \&validate_date_keyword;
604              
605 0     0 0   sub should_inline_date_keyword { 1 }
606 0     0 0   sub should_inline_datetime_keyword { 1 }
607 0     0 0   sub should_inline_time_keyword { 1 }
608 0     0 0   sub should_inline_timestamp_keyword { 1 }
609              
610             package Rose::DB::Oracle::DateHandler;
611              
612 16     16   810 use Rose::Object;
  16         42  
  16         835  
613             our @ISA = qw(Rose::Object);
614              
615 16     16   7940 use DateTime::Format::Oracle;
  16         43308  
  16         11108  
616              
617             sub parse_date
618             {
619 0     0     my($self, $value) = @_;
620              
621 0   0       local $DateTime::Format::Oracle::nls_date_format = $ENV{'NLS_DATE_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS';
622              
623             # Add or extend the time to appease DateTime::Format::Oracle
624 0 0         if($value =~ /\d\d:/)
625             {
626 0           $value =~ s/( \d\d:\d\d)([^:]|$)/$1:00$2/;
627             }
628             else
629             {
630 0           $value .= ' 00:00:00';
631             }
632              
633 0           return DateTime::Format::Oracle->parse_date($value);
634             }
635              
636             *parse_datetime = \&parse_date;
637              
638             sub parse_timestamp
639             {
640 0     0     my($self, $value) = @_;
641              
642             local $DateTime::Format::Oracle::nls_timestamp_format =
643 0   0       $ENV{'NLS_TIMESTAMP_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS.FF';
644              
645             # Add, extend, or truncate fractional seconds to appease DateTime::Format::Oracle
646 0           for($value)
647             {
648 0 0 0       s/( \d\d:\d\d:\d\d)(?!\.)/$1.000000/ ||
649 0           s/( \d\d:\d\d:\d\d\.)(\d{1,5})(\D|$)/ "$1$2" . ('0' x (6 - length($2))) . $3/e ||
650             s/( \d\d:\d\d:\d\d\.\d{6})\d+/$1/;
651             }
652              
653 0           return DateTime::Format::Oracle->parse_timestamp($value);
654             }
655              
656             sub parse_timestamp_with_time_zone
657             {
658 0     0     my($self, $value) = @_;
659              
660             local $DateTime::Format::Oracle::nls_timestamp_tz_format =
661 0   0       $ENV{'NLS_TIMESTAMP_TZ_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS.FF TZHTZM';
662              
663             # Add, extend, or truncate fractional seconds to appease DateTime::Format::Oracle
664 0           for($value)
665             {
666 0 0 0       s/( \d\d:\d\d:\d\d)(?!\.)/$1.000000/ ||
667 0           s/( \d\d:\d\d:\d\d\.)(\d{1,5})(\D|$)/ "$1$2" . ('0' x (6 - length($2))) . $3/e ||
668             s/( \d\d:\d\d:\d\d\.\d{6})\d+/$1/;
669             }
670              
671 0           return DateTime::Format::Oracle->parse_timestamp_with_time_zone($value);
672             }
673              
674             sub format_date
675             {
676 0     0     my($self) = shift;
677              
678             local $DateTime::Format::Oracle::nls_date_format =
679 0   0       $ENV{'NLS_DATE_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS';
680              
681 0           return DateTime::Format::Oracle->format_date(@_);
682             }
683              
684             *format_datetime = \&format_date;
685              
686             sub format_timestamp
687             {
688 0     0     my($self) = shift;
689              
690             local $DateTime::Format::Oracle::nls_timestamp_format =
691 0   0       $ENV{'NLS_TIMESTAMP_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS.FF';
692              
693 0           return DateTime::Format::Oracle->format_timestamp(@_);
694             }
695              
696             sub format_timestamp_with_time_zone
697             {
698 0     0     my($self) = shift;
699              
700             local $DateTime::Format::Oracle::nls_timestamp_tz_format =
701 0   0       $ENV{'NLS_TIMESTAMP_TZ_FORMAT'} || 'YYYY-MM-DD HH24:MI:SS.FF TZHTZM';
702              
703 0           return DateTime::Format::Oracle->format_timestamp_with_time_zone(@_);
704             }
705              
706             1;
707              
708             __END__
709              
710             =head1 NAME
711              
712             Rose::DB::Oracle - Oracle driver class for Rose::DB.
713              
714             =head1 SYNOPSIS
715              
716             use Rose::DB;
717              
718             Rose::DB->register_db
719             (
720             domain => 'development',
721             type => 'main',
722             driver => 'Oracle',
723             database => 'dev_db',
724             host => 'localhost',
725             username => 'devuser',
726             password => 'mysecret',
727             );
728              
729             Rose::DB->register_db
730             (
731             domain => 'production',
732             type => 'main',
733             driver => 'Oracle',
734             service => 'my_pdb',
735             host => 'db.example.com',
736             username => 'produser',
737             password => 'prodsecret',
738             );
739              
740             Rose::DB->default_domain('development');
741             Rose::DB->default_type('main');
742             ...
743              
744             $db = Rose::DB->new; # $db is really a Rose::DB::Oracle-derived object
745             ...
746              
747             =head1 DESCRIPTION
748              
749             L<Rose::DB> blesses objects into a class derived from L<Rose::DB::Oracle> when the L<driver|Rose::DB/driver> is "oracle". This mapping of driver names to class names is configurable. See the documentation for L<Rose::DB>'s L<new()|Rose::DB/new> and L<driver_class()|Rose::DB/driver_class> methods for more information.
750              
751             This class cannot be used directly. You must use L<Rose::DB> and let its L<new()|Rose::DB/new> method return an object blessed into the appropriate class for you, according to its L<driver_class()|Rose::DB/driver_class> mappings.
752              
753             Only the methods that are new or have different behaviors than those in L<Rose::DB> are documented here. See the L<Rose::DB> documentation for the full list of methods.
754              
755             B<Oracle 9 or later is required.>
756              
757             If you want to connect to a service rather than a database, use the C<service> parameter instead of C<database> when registering the data source, as shown in the L<SYNOPSIS|/SYNOPSIS> above. This will allow you to connect to PDBs (Pluggable Databases).
758              
759             B<Note:> This class is a work in progress. Support for Oracle databases is not yet complete. If you would like to help, please contact John Siracusa at siracusa@gmail.com or post to the L<mailing list|Rose::DB/SUPPORT>.
760              
761             =head1 CLASS METHODS
762              
763             =over 4
764              
765             =item B<default_post_connect_sql [STATEMENTS]>
766              
767             Get or set the default list of SQL statements that will be run immediately after connecting to the database. STATEMENTS should be a list or reference to an array of SQL statements. Returns a reference to the array of SQL statements in scalar context, or a list of SQL statements in list context.
768              
769             The L<default_post_connect_sql|/default_post_connect_sql> statements will be run before any statements set using the L<post_connect_sql|/post_connect_sql> method. The default list contains the following:
770              
771             ALTER SESSION SET NLS_DATE_FORMAT = 'YYYY-MM-DD HH24:MI:SS'
772             ALTER SESSION SET NLS_TIMESTAMP_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF'
773             ALTER SESSION SET NLS_TIMESTAMP_TZ_FORMAT = 'YYYY-MM-DD HH24:MI:SS.FF TZHTZM'
774              
775             If one or more C<NLS_*_FORMAT> environment variables are set, the format strings above are replaced by the values that these environment variables have I<at the time this module is loaded>.
776              
777             =item B<booleans_are_numeric [BOOL]>
778              
779             Get or set a boolean value that indicates whether or not boolean columns are numeric. Oracle does not have a dedicated boolean column type. Two common stand-in column types are CHAR(1) and NUMBER(1). If C<booleans_are_numeric> is true, then boolean columns are treated as NUMBER(1) columns containing either 1 or 0. If false, they are treated as CHAR(1) columns containing either 't' or 'f'. The default is false.
780              
781             =back
782              
783             =head1 OBJECT METHODS
784              
785             =over 4
786              
787             =item B<post_connect_sql [STATEMENTS]>
788              
789             Get or set the SQL statements that will be run immediately after connecting to the database. STATEMENTS should be a list or reference to an array of SQL statements. Returns a reference to an array (in scalar) or a list of the L<default_post_connect_sql|/default_post_connect_sql> statements and the L<post_connect_sql|/post_connect_sql> statements. Example:
790              
791             $db->post_connect_sql('UPDATE mytable SET num = num + 1');
792              
793             print join("\n", $db->post_connect_sql);
794              
795             ALTER SESSION SET NLS_DATE_FORMAT='YYYY-MM-DD HH24:MI:SS'
796             ALTER SESSION SET NLS_TIMESTAMP_FORMAT='YYYY-MM-DD HH24:MI:SSxFF'
797             UPDATE mytable SET num = num + 1
798              
799             =item B<schema [SCHEMA]>
800              
801             Get or set the database schema name. In Oracle, every user has a corresponding schema. The schema is comprised of all objects that user owns, and has the same name as that user. Therefore, this attribute defaults to the L<username|Rose::DB/username> if it is not set explicitly.
802              
803             =back
804              
805             =head2 Value Parsing and Formatting
806              
807             =over 4
808              
809             =item B<validate_date_keyword STRING>
810              
811             Returns true if STRING is a valid keyword for the PostgreSQL "date" data type. Valid (case-insensitive) date keywords are:
812              
813             current_date
814             current_timestamp
815             localtimestamp
816             months_between
817             sysdate
818             systimestamp
819              
820             The keywords are case sensitive. Any string that looks like a function call (matches C</^\w+\(.*\)$/>) is also considered a valid date keyword if L<keyword_function_calls|Rose::DB/keyword_function_calls> is true.
821              
822             =item B<validate_timestamp_keyword STRING>
823              
824             Returns true if STRING is a valid keyword for the Oracle "timestamp" data type, false otherwise. Valid timestamp keywords are:
825              
826             current_date
827             current_timestamp
828             localtimestamp
829             months_between
830             sysdate
831             systimestamp
832              
833             The keywords are case sensitive. Any string that looks like a function call (matches C</^\w+\(.*\)$/>) is also considered a valid timestamp keyword if L<keyword_function_calls|Rose::DB/keyword_function_calls> is true.
834              
835             =back
836              
837             =head1 AUTHORS
838              
839             John C. Siracusa (siracusa@gmail.com), Ron Savage (ron@savage.net.au)
840              
841             =head1 LICENSE
842              
843             Copyright (c) 2008 by John Siracusa and Ron Savage. All rights reserved. This program is free software; you can redistribute it and/or modify it under the same terms as Perl itself.