Skip to content

Commit aa5252e

Browse files
committed
Oracle: Add DATE and TIMESTAMP support
Closes #41
1 parent 82773f8 commit aa5252e

File tree

5 files changed

+115
-2
lines changed

5 files changed

+115
-2
lines changed

lib/DBDish/Connection.pm6

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ method drv { $.parent }
4040
method new(*%args) {
4141
my \con = ::?CLASS.bless(|%args);
4242
con.reset-err;
43+
con.?set-defaults;
4344
%args<parent>.Connections{con.WHICH} = con;
4445
}
4546

lib/DBDish/Oracle/Connection.pm6

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,13 @@ method prepare(Str $statement, :$RaiseError = $!RaiseError, *%attr) {
3232
} else { .fail }
3333
}
3434

35+
method set-defaults {
36+
self.do(
37+
q|ALTER SESSION SET nls_timestamp_tz_format='YYYY-MM-DD"T"HH24:MI:SS.FFTZR'|
38+
);
39+
$!last-sth-id = Nil; # Lie a little.
40+
}
41+
3542
method commit {
3643
if $!AutoCommit {
3744
warn "Commit ineffective while AutoCommit is on";

lib/DBDish/Oracle/Native.pm6

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,14 +84,18 @@ constant SQLT_NUM is export = 2;
8484
constant SQLT_INT is export = 3;
8585
constant SQLT_FLT is export = 4;
8686
constant SQLT_STR is export = 5;
87+
constant SQLT_DAT is export = 12;
8788
constant SQLT_BIN is export = 23;
89+
constant SQLT_TIMESTAMP_TZ is export = 188;
8890

8991
constant %sqltype-map is export = {
9092
+(SQLT_CHR) => Str,
9193
+(SQLT_NUM) => Rat,
9294
+(SQLT_INT) => Int,
9395
+(SQLT_FLT) => Num,
94-
+(SQLT_BIN) => Buf
96+
+(SQLT_BIN) => Buf,
97+
+(SQLT_TIMESTAMP_TZ) => DateTime,
98+
+(SQLT_DAT) => Date,
9599
};
96100

97101
constant OCISnapshot is export = Pointer;

lib/DBDish/Oracle/StatementHandle.pm6

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ method !get-meta {
5959
my $col_name = $parmd.AttrGet($!errh, utf8, OCI_ATTR_NAME);
6060
my $dtype = $parmd.AttrGet($!errh, ub2, OCI_ATTR_DATA_TYPE);
6161
my $datalen = $parmd.AttrGet($!errh, ub4, OCI_ATTR_DATA_SIZE);
62-
my $wtype = SQLT_CHR;
62+
my $wtype = SQLT_CHR; # Sane default
6363
my $buff = do given $dtype {
6464
#note "$col_name: $dtype ($datalen)";
6565
when SQLT_NUM {
@@ -72,6 +72,8 @@ method !get-meta {
7272
when SQLT_FLT { $wtype = $_; array[num64].new(0e0); }
7373
when SQLT_INT { $wtype = $_; Buf[int64].new(0); }
7474
when SQLT_BIN { $wtype = $_; proceed; }
75+
when SQLT_DAT { $wtype = $_; proceed; }
76+
when SQLT_TIMESTAMP_TZ { $datalen = 50; proceed; }
7577
default { blob-allocate(Buf, $datalen); }
7678
}
7779
my $bind = OCIDefine.new;
@@ -103,6 +105,11 @@ method execute(*@params) {
103105
$!in-indicator[$k] = 0;
104106
when Blob { $btype = SQLT_BIN; $v }
105107
when Str { .encode }
108+
when Date {
109+
$btype = SQLT_DAT;
110+
Blob.new($v.year div 100 + 100, $v.year mod 100 + 100,
111+
$v.month, $v.day, 1, 1, 1);
112+
}
106113
default { .Str.encode}
107114
} else {
108115
$!in-indicator[$k] = -1;
@@ -151,7 +158,19 @@ method _row() {
151158
when Int | Num { $res[0] }
152159
$res .= subbuf(0, $!out-lengths[$col]);
153160
when Blob { $res }
161+
when Date {
162+
my $year = ($res[0]-100)*100 + $res[1]-100;
163+
Date.new(:$year,:month($res[2]),:day($res[3]));
164+
}
165+
when DateTime {
166+
if $res.bytes == 7 {
167+
my $year = ($res[0]-100)*100 + $res[1]-100;
168+
DateTime.new(:$year,:month($res[2]),:day($res[3]),
169+
:hour($res[4]),:minute($res[5]),:second($res[6]));
170+
} else { proceed; }
171+
}
154172
$res .= decode;
173+
when DateTime { DateTime.new($res) }
155174
when Rat { $res.Rat }
156175
default { $res }
157176
}

t/47-oracle-datetime.t

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use v6;
2+
use Test;
3+
use DBIish;
4+
5+
plan 13;
6+
7+
my %con-parms = :database<XE>, :username<TESTUSER>, :password<Testpass>;
8+
my $dbh;
9+
10+
try {
11+
$dbh = DBIish.connect('Oracle', |%con-parms);
12+
CATCH {
13+
when X::DBIish::LibraryMissing | X::DBDish::ConnectionFailed {
14+
diag "$_\nCan't continue.";
15+
}
16+
default { .throw; }
17+
}
18+
}
19+
without $dbh {
20+
skip-rest 'prerequisites failed';
21+
exit;
22+
}
23+
24+
ok $dbh, 'Connected';
25+
my $dropper = q|
26+
BEGIN
27+
EXECUTE IMMEDIATE 'DROP TABLE test';
28+
EXCEPTION
29+
WHEN OTHERS THEN
30+
IF SQLCODE != -942 THEN
31+
RAISE;
32+
END IF;
33+
END;|;
34+
35+
lives-ok { $dbh.do($dropper) }, 'Clean';
36+
lives-ok {
37+
$dbh.do(qq|
38+
CREATE TABLE test (
39+
adate DATE,
40+
atimestamp TIMESTAMP(6) WITH TIME ZONE
41+
)|);
42+
}, 'Table created';
43+
44+
my $sth = $dbh.prepare(
45+
q|INSERT INTO test (adate, atimestamp) VALUES(?, ?)|);
46+
my $now = DateTime.now;
47+
48+
lives-ok {
49+
$sth.execute(
50+
$now.Date, # Need a date
51+
$now,
52+
);
53+
}, 'Can insert Perl6 values';
54+
$sth.dispose;
55+
56+
$sth = $dbh.prepare('SELECT adate, atimestamp FROM test');
57+
my @coltype = $sth.column-types;
58+
ok @coltype eqv [Date, DateTime], 'Column-types match';
59+
60+
$sth.execute;
61+
my ($date, $datetime) = $sth.row;
62+
isa-ok $date, Date;
63+
isa-ok $datetime, DateTime;
64+
65+
is $date, $now.Date, 'Today';
66+
is $datetime, $now, 'Right now';
67+
$sth.dispose;
68+
69+
$sth = $dbh.prepare('SELECT SYSDATE FROM dual');
70+
isa-ok $sth.column-types[0], Date, 'SYSDATE is Date';
71+
$sth.execute;
72+
is $sth.row[0], Date.today, 'Today';
73+
$sth.dispose;
74+
75+
$sth = $dbh.prepare('SELECT CURRENT_TIMESTAMP FROM dual');
76+
isa-ok $sth.column-types[0], DateTime, 'CURRENT_TIMESTAMP is DateTime';
77+
$sth.execute;
78+
my $datetime2 = $sth.row[0];
79+
isnt $datetime, $datetime2, 'Server drift';
80+
diag $datetime2.Instant - $datetime.Instant;
81+
82+
$dbh.do($dropper);

0 commit comments

Comments
 (0)