On 27-Sep-2005 Lee Anne Lester wrote: > I am getting a "Numeric value out of range error" when specifically > binding a placeholder for a decimal column as a decimal type. I'm using > DBD::ODBC connecting to Microsoft SQL Server from a Solaris machine. > The value being bound is 10.00. The settings in database are precision > 5 and a scale 2. I have found that I don't get the error as long as > there are no numbers to the left of the decimal. Example: A value of > .5 works. > > Can anyone advise how to make this work? Is there a way to define the > precision and scale when calling bind_param? > > Thanks in advance for any help. > > Lee Anne Lester > > SQL> create table jaeb (FieldDecimal numeric(5,2)) SQL> insert into jaeb values ('10.00') SQL> insert into jaeb values (10.00) SQL> select * from jaeb +-------------+ | FieldDecimal| +-------------+ | 10.00 | | 10.00 | +-------------+ SQLRowCount returns 2 2 rows fetched
So you can insert without binding OK but as you say: #!/usr/local/bin/perl -w use DBI; my $dbh = DBI->connect('dbi:ODBC:test', 'Martin_Evans', 'easysoft'); my $sql = q/insert into jaeb values (?)/; my $sth = $dbh->prepare($sql); $sth->bind_param(1, 10.00, {TYPE=>3}); $sth->execute(); fails. Changing the bind_param to remove the forcing the type to SQL_NUMERIC $sth->bind_param(1, 10.00); appears to insert correctly but a string "10" is still passed in (I'd presume this is because 10.00 is converted to "10"). Passing 10.98 also works correctly. In these cases the parameter is bound as SQL_C_CHAR, SQL_VARCHAR. The actual problem appears to be: SQLBindParameter(0x8258ea0,1,1(Input::),1,3,5,5,0x82580f0,5,0x82580d0) i.e. bind parameter 1 as input, ValueType=SQL_C_CHAR, ParameterType=SQL_NUMERIC, ColumnSize=5, DecimalDigits=5. This instructs MS SQL Server to convert your SQL_C_CHAR string into a numeric 5,5 before inserting - this will not fit. Interestingly, your trace shows "cbColDef=2, scale=2," and I cannot reproduce this. The problem is that you are saying this parameter must be a SQL_NUMERIC but there is no way to specify a scale and DBD::ODBC does not use SQLDescribeParam when you force a bind type. This could be changed to work but it is not a 5 minute job to do properly. The patch (to _dbd_rebind_ph) below makes it work but it is a bit of a hack: case SQL_TIME: case SQL_TYPE_TIME: /* fSqlType = SQL_VARCHAR;*/ break; + case SQL_NUMERIC: + case SQL_DECIMAL: + + if (phs->sv_buf && *phs->sv_buf) { + char *cp; + cp = strchr(phs->sv_buf, '.'); + if (cp) { + ibScale = 0; + cp++; + while (*cp != '\0' && isdigit(*cp)) { + cp++; + ibScale++; + } + } + } + break; case SQL_TIMESTAMP: case SQL_TYPE_TIMESTAMP: Why not just pass your parameters in as strings and leave the parameter type off the bind call. Martin -- Martin J. Evans Easysoft Ltd, UK Development > SAMPLE CODE > ============= >#!/usr/local/bin/perl -Tw > > use strict; > use DBI; > > my $dsn = "dbi:ODBC:dsn_IRB"; > > our $dbh = DBI->connect($dsn, '', '', {AutoCommit=>0, RaiseError=>1, > FetchHashKeyName=>'NAME_uc'}); > > unlink('dbitrace.log') if(-e 'dbitrace.log'); > > DBI->trace(9, 'dbitrace.log'); > > my $sth = $dbh->prepare(q{INSERT INTO tblDecimalTest (FieldDecimal) > VALUES (?)}); > > $sth->bind_param(1, 10.00, {TYPE=>3} ); > > $sth->execute(); > > $sth->finish; > > $dbh->commit; > > $dbh->disconnect; > ~ > > > > VERSIONS > ========= > > Microsoft SQL Server 2000 - 8.00.2039 (Intel X86) > May 3 2005 23:18:38 > Copyright (c) 1988-2003 Microsoft Corporation > Standard Edition on Windows NT 5.0 (Build 2195: Service Pack 4) > > unixODBC version: 2.2.7 using EasySoft ODBC bridge > > Perl Version = 5.008007 > DBI Version = 1.48 > DBD::ODBC Version = 1.13 > > > OUTPUT FROM TRACE - LEVEL 9 > ============================ > DBI 1.48-nothread default trace level set to 0x0/9 (pid 5169) > >> prepare DISPATCH (DBI::db=HASH(0x25300c) rc1/1 @2 g0 ima2201 > pid#5169) at ./insert.pl line 14 > -> prepare for DBD::ODBC::db (DBI::db=HASH(0x25300c)~0x260a18 > 'INSERT INTO tblDecimalTest (FieldDecimal) VALUES (?)') > New DBI::st (for DBD::ODBC::st, parent=DBI::db=HASH(0x260a18), id=) > dbih_setup_handle(DBI::st=HASH(0x260b20)=>DBI::st=HASH(0x1b9d48), > DBD::ODBC::st, 260b2c, Null!) > dbih_make_com(DBI::db=HASH(0x260a18), 136f30, DBD::ODBC::st, 212, 0) > thr#0 > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), Err, > DBI::db=HASH(0x260a18)) SCALAR(0x1face0) (already defined) > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), State, > DBI::db=HASH(0x260a18)) SCALAR(0x1fad40) (already defined) > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), Errstr, > DBI::db=HASH(0x260a18)) SCALAR(0x1fad10) (already defined) > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), TraceLevel, > DBI::db=HASH(0x260a18)) 0 (already defined) > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), FetchHashKeyName, > DBI::db=HASH(0x260a18)) 'NAME_uc' (already defined) > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), HandleSetErr, > DBI::db=HASH(0x260a18)) undef (not defined) > dbih_setup_attrib(DBI::st=HASH(0x1b9d48), HandleError, > DBI::db=HASH(0x260a18)) undef (not defined) > initializing sth query timeout to 0 > ignore named placeholders = 0 > dbd_preparse scanned 1 distinct placeholders > SQLPrepare returned 0 > > dbd_st_prepare'd sql f2787256, ExecDirect=0 > INSERT INTO tblDecimalTest (FieldDecimal) VALUES (?) > <- prepare= DBI::st=HASH(0x260b20) at ./insert.pl line 14 > >> bind_param DISPATCH (DBI::st=HASH(0x260b20) rc1/1 @4 g0 ima1 > pid#5169) at ./insert.pl line 16 > -> bind_param for DBD::ODBC::st (DBI::st=HASH(0x260b20)~0x1b9d48 1 > 10 HASH(0x1209b8)) > bind 1 <== '10' (attribs: HASH(0x1209b8)), type 3 > <- bind_param= 1 at ./insert.pl line 16 > >> execute DISPATCH (DBI::st=HASH(0x260b20) rc1/1 @1 g0 ima1041 > pid#5169) at ./insert.pl line 18 > -> execute for DBD::ODBC::st (DBI::st=HASH(0x260b20)~0x1b9d48) > dbd_st_execute (outparams = 0)... > bind 1 <== 10 (size 2/3/0, ptype 6, otype 1, sqltype 3) > bind 1 <== '10' (len 2/2, null 0) > bind 1: CTy=1, STy=DECIMAL, CD=2, Sc=2, VM=2. > SQLBindParameter: idx = 1: fParamType=1, name=1, fCtype=1, SQL_Type > = 3, cbColDef=2, scale=2, rgbValue = 13ddc0, cbValueMax=2, cbValue = 2 > Param value = 10 > rebind check char Param 1 (10) > dbd_st_execute (for hstmt 2787256 before)... > dbd_st_execute (for hstmt 2787256 after, rc = -1)... > dbd_error: err_rc=-1 rc=0 s/d/e: 2787256/2497728/2496296 > dbd_error: SQL-22003 (native 0): [unixODBC][Microsoft][ODBC SQL Server > Driver]Numeric value out of range (SQL-22003) > dbd_error: err_rc=-1 rc=0 s/d/e: 0/2497728/2496296 > dbd_error: err_rc=-1 rc=0 s/d/e: 0/0/2496296 > st_execute/SQLExecute error -1 recorded: [unixODBC][Microsoft][ODBC SQL > Server Driver]Numeric value out of range (SQL-22003)(DBD: > st_execute/SQLExecute err=-1) > !! ERROR: -1 '[unixODBC][Microsoft][ODBC SQL Server Driver]Numeric > value out of range (SQL-22003)(DBD: st_execute/SQLExecute err=-1)' > (err#0) > <- execute= undef at ./insert.pl line 18 > >> DESTROY DISPATCH (DBI::st=HASH(0x260b20) rc1/1 @1 g0 ima4 > pid#5169) > <> DESTROY(DBI::st=HASH(0x260b20)) ignored for outer handle (inner > DBI::st=HASH(0x1b9d48) has ref cnt 1) > >> DESTROY DISPATCH (DBI::st=HASH(0x1b9d48) rc1/1 @1 g0 ima4 > pid#5169) > -> DESTROY for DBD::ODBC::st (DBI::st=HASH(0x1b9d48)~INNER) > SQLFreeStmt called, returned 0. > ERROR: -1 '[unixODBC][Microsoft][ODBC SQL Server Driver]Numeric > value out of range (SQL-22003)(DBD: st_execute/SQLExecute err=-1)' > (err#0) > <- DESTROY= undef > DESTROY (dbih_clearcom) (sth 0x260b20, com 0x2a8690, imp > DBD::ODBC::st): > FLAGS 0x180191: COMSET Warn RaiseError PrintError PrintWarn > PARENT DBI::db=HASH(0x260a18) > KIDS 0 (0 Active) > IMP_DATA undef > NUM_OF_FIELDS -1 > NUM_OF_PARAMS 1 > dbih_clearcom 0x260b20 (com 0x2a8690, type 3) done. > > -- DBI::END > >> disconnect_all DISPATCH (DBI::dr=HASH(0x1fa794) rc1/4 @1 g0 > ima801 pid#5169) at > /usr/perl5.8.7/lib/site_perl/5.8.7/sun4-solaris/DBI.pm line 677 via > ./insert.pl line 0 > -> disconnect_all for DBD::ODBC::dr > (DBI::dr=HASH(0x1fa794)~0x25303c) > <- disconnect_all= '' at > /usr/perl5.8.7/lib/site_perl/5.8.7/sun4-solaris/DBI.pm line 677 via > ./insert.pl line 0 > ! >> DESTROY DISPATCH (DBI::db=HASH(0x260a18) rc1/1 @1 g0 ima4 > pid#5169) during global destruction > ! -> DESTROY for DBD::ODBC::db (DBI::db=HASH(0x260a18)~INNER) > ** auto-rollback due to disconnect without commit returned 1 > DBD::ODBC Disconnected! > ERROR: -1 '[unixODBC][Microsoft][ODBC SQL Server Driver]Numeric > value out of range (SQL-22003)(DBD: st_execute/SQLExecute err=-1)' > (err#0) > ! <- DESTROY= undef during global destruction > DESTROY (dbih_clearcom) (dbh 0x25300c, com 0x136f30, imp global > destruction): > FLAGS 0x180191: COMSET Warn RaiseError PrintError PrintWarn > PARENT DBI::dr=HASH(0x25303c) > KIDS 0 (0 Active) > IMP_DATA undef > dbih_clearcom 0x25300c (com 0x136f30, type 2) done. > > ! >> DESTROY DISPATCH (DBI::dr=HASH(0x25303c) rc1/1 @1 g0 ima4 > pid#5169) during global destruction > ! -> DESTROY in DBD::_::common for DBD::ODBC::dr > (DBI::dr=HASH(0x25303c)~INNER) > ! <- DESTROY= undef during global destruction > DESTROY (dbih_clearcom) (drh 0x1fa794, com 0x136460, imp global > destruction): > FLAGS 0x100215: COMSET Active Warn PrintWarn AutoCommit > PARENT undef > KIDS 1 (1 Active) > IMP_DATA undef > dbih_clearcom 0x1fa794 (com 0x136460, type 1) done. > > ! >> DESTROY DISPATCH (DBI::dr=HASH(0x1fa794) rc1/1 @1 g0 ima4 > pid#5169) during global destruction > ! <> DESTROY for DBI::dr=HASH(0x1fa794) ignored (inner handle gone) > ! >> DESTROY DISPATCH (DBI::db=HASH(0x25300c) rc1/1 @1 g0 ima4 > pid#5169) during global destruction > ! <> DESTROY for DBI::db=HASH(0x25300c) ignored (inner handle gone) > > >