Hi,

I'm working with DBD::Oracle at the moment and getting a little frustrated with integer numbers. I'd like my database returned integers to look like integers to Perl but they currently don't until I add 0 to them. Here is the problem:

The code calls an Oracle procedure which returns a reference cursor and fetching from this cursor leads to a mixture of utf8 encoded strings and integers. Mostly the data is fetched in one go with fetchall_arrayref but occasionally it is bound and fetched one row at a time. Either way the resulting array representing the database result-set is converted to JSON via JSON::XS. For a simple case where 1 row is returned containing 1 integer column I get the resulting JSON:

["1"] # this is a JSON string

However, if I add 0 to the fields I know are integers before I convert to JSON I get:

[1] # smaller and more accurate JSON number

The reason for this is that adding 0 to a Perl scalar seems to persuade Perl the scalar is an integer. The difference from Deve::Peek is as follows:

$num as returned from database:
SV = PV(0x9068f04) at 0x90288d4
  REFCNT = 2
  FLAGS = (PADBUSY,PADMY,POK,pPOK,UTF8)
  PV = 0x90c1120 "1"\0 [UTF8 "1"]
  CUR = 1
  LEN = 4
$num after adding 0:
SV = PVMG(0x8f6f900) at 0x90288d4
  REFCNT = 2
  FLAGS = (PADBUSY,PADMY,SMG,IOK,pIOK)
  IV = 1
  NV = 0
  PV = 0x90c1120 "1"\0
  CUR = 1
  LEN = 4
  MAGIC = 0x90c0d78
    MG_VIRTUAL = &PL_vtbl_utf8
    MG_TYPE = PERL_MAGIC_utf8(w)
    MG_LEN = -1

The thing is that JSON::XS (and a number of other modules we've using) uses SvIOKp (sv) (initially) to decide whether to try using this as a number and this seems perfectly reasonable to me. The problem is that now I have to go through all my result-sets from the database and add 0 to all the integers.

I was hoping binding the columns and declaring the bound type as ora_type => ORA_LONG would return me numbers but as the code I include below shows, this makes no difference.

Does anyone know of a way to get numbers (as I've described) back from DBD::Oracle.

And before anyone points it out, I know scalars in perl are strings or numbers depending on the context in which they are used but JSON::XS is not the only module looking at the underlying scalar flags.

use strict;
use warnings;
use DBI;
use DBD::Oracle qw(:ora_types SQLCS_IMPLICIT);
use Devel::Peek;
use JSON::XS;
use Data::Dumper;
use Encode;

my $h = DBI->connect('dbi:Oracle:XX', 'xxx', 'xxx') or die "connect!";
eval {local $h->{PrintError} = 0;$h->do(q/drop table martin_long/)};
$h->do(q/create table martin_long (a integer)/);
$h->do(q/insert into martin_long values(1)/);

my $s = $h->prepare(q/select * from martin_long/);
$s->execute;
my $num;
$s->bind_col(1, \$num, {ora_type => ORA_LONG});
my @data;
my @altdata;
while ($s->fetch) {
    push @data, $num;
    print "\$num as returned from database:\n";
    Dump($num);
    $num = $num + 0;
    print "\$num after adding 0:\n";
    Dump($num);
    push @altdata, $num;
}
print Dumper(\...@data);

print JSON::XS->new->encode(\...@data), "\n";
print JSON::XS->new->encode(\...@altdata), "\n";

Martin
--
Martin J. Evans
Easysoft Limited
http://www.easysoft.com

Reply via email to