Garrett, Philip (MAN-Corporate) wrote:
Martin Evans wrote:
Hoping someone can help me here as I'm really stuck with this. I
have a large amount of code which reads some XML and inserts data
from the XML into a database. One particular insert fails:

[snip]
After much head scratching I discovered the problem P4 has utf8 set
on it and downgrading it makes the code work i.e. when utf8::is_utf8
returns 1 on the timestamp scalar it fails and if I do a
utf8::downgrade(scalar) on it before calling execute it works.
I think you've triggered this bug:
http://www.mail-archive.com/dbi-users@perl.org/msg26927.html
I've read that but I don't see the resolution.

There wasn't an official one, afaik. :-/
Just checking. I think I got the wrong end of the stick - I thought you were meaning setting SQLCS_NCHAR fixes the problem but it appears it is the other way around.

If I remember correctly, the fix is to set ora_ph_csform:

  use DBD::Oracle qw(SQLCS_NCHAR);
  ...
  # default for all future placeholders
  $dbh->{'ora_ph_csform'} = SQLCS_NCHAR;
I've tried that - no luck :-(

Surprisingly, setting ora_ph_csform as above actually *caused* the
problem for me.  See below...

It makes my problems worse also as I was not setting it in the first place.
The bug only manifests when you bind a utf8-on value to a statement
parameter that was originally bound to a non-utf8 value.
The whole DBI interaction is:

$do = ['begin dbms_output.enable(:1); end;',undef,20000];
do: 'alter session set nls_timestamp_format = 'yyyy-mm-dd hh24:mi:ss''
do: 'alter session set nls_date_format = 'yyyy-mm-dd''
prepare_cached: 'select * from document where id = ?'
execute: "XXXXXXXXXXXX"
finish

The following is generated with a brand new statement handle:

prepare_cached:
'insert into document
(book,category,country,expiry,id,last_update,mnem,name,ode
c,route,source,tdate,ttimestamp,ttype,version)
values(?,?,?,?,?,?,?,?,?,?,?,?,?,
?,?)'
$execute = ['SD','HR','UK','2017-07-08
14:10:00','XXXXXXXXXXX','1183290197812','ES','XXXXX','N',
'534453','XXXXXXXXXX','2007-07-01','1183269593843','XXXXXX','XXXXX'];

I've even tried disconnecting just before the prepare_cached call and
reconnecting or opening a brand new connection for the prepare_cached
call - still no luck. So either, it is not the same bug or the
resolution is not quite right.

I think you're right. It's a different bug, but I'd wager it's related.

See my other post - it looks remarkably similar to me now. For a start your example has a timestamp and a date as mine does.

The attached script reproduces the problem reliably on my system. There
are three lines in the script that will trigger the error when
uncommented: lines 11, 12, and 19.

The problem manifests on (at least):
  DBI 1.50
  DBD::Oracle 1.18, 1.19
  Oracle client 9.2.0.4.0
  Oracle server 9.2.0.7.0, 10.2.0.3.0

What's *really* strange is that if I remove the "dt" column from the
table, and run the script using only the "ts" timestamp column, there
is no error.

Same for me. I can insert a row containing only dates or only timestamps no problem - soon as I mix them - bang! What led me astray at first is that if I have a table with a timestamp and a date and the timestamp is in the insert list first, Oracle reports the timestamp parameter in error - so naturally you are drawn to that. If you then remove the date in the insert problem goes away so you start thinking it is the date field.
- Philip


#!/usr/bin/env perl
use strict;
use warnings;

use DBI;
use DBD::Oracle qw(SQLCS_NCHAR);
use Encode qw(decode);
use utf8;

# uncomment either one of these to trigger error
#$ENV{'NLS_LANG'}  = 'AMERICAN_AMERICA.AL32UTF8';
#$ENV{'NLS_NCHAR'} = 'AL32UTF8';

my $dbh = DBI->connect( undef, undef, undef, # $ENV{DBI_DSN}, etc.
    { AutoCommit => 1, RaiseError => 1, PrintError => 0 })
    || die $DBI::errstr;

# or, uncomment this to trigger error
#$dbh->{ora_ph_csform} = SQLCS_NCHAR;

eval { $dbh->do('drop table utf8test cascade constraints'); };
$dbh->do('create table utf8test (dt date, ts timestamp)');

my $fmt = 'YYYY-MM-DD HH24:MI:SS';
$dbh->do("alter session set nls_date_format = '$fmt'");
$dbh->do("alter session set nls_timestamp_format = '$fmt'");

my $dml = 'insert into utf8test (dt,ts) values (?,?)';
my $sth = $dbh->prepare($dml);

my $utf8_date = decode('utf8','2007-07-05 12:00:00');
$sth->execute($utf8_date, $utf8_date);

This is remarkably similar to the final test case I came up with that does not work. I've run the above exactly as it stands and it fails with "ORA-01843: not a valid month" i.e. I ran without uncommenting anything HOWEVER, my NLS_LANG is already set to AMERICAN_AMERICA.AL32UTF8 before the script was run (as per advice on making unicode/utf8 work with Oracle and DBD::Oracle).

Out of interest what did you end up doing in the end - make all your date/times timestamps?

Thanks again for the input Philip.

Martin

Reply via email to