This patch depends/based on "[rfc][patch] Move parameter binding back to (sqlite|dbd)_bind_ph". Description in patch. In addition to avoiding conversion to strings and back, it fixes passing some special values (NAN, +-INF), test included (should fail before patch).
>From a0a270662c30db8ed4a17057dc400d2122364027 Mon Sep 17 00:00:00 2001 From: "Yuriy M. Kaminskiy" <yum...@gmail.com> Date: Tue, 27 Mar 2012 16:33:47 +0400 Subject: [PATCH 2/3] Avoid converting numbers to strings and back Don't coerce SV to numeric, but use numeric value if it is present. --- dbdimp.c | 24 ++++++++++++++++++++++++ t/19_bindparam.t | 53 ++++++++++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 76 insertions(+), 1 deletions(-) diff --git a/dbdimp.c b/dbdimp.c index 007638b..779ec18 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -1188,6 +1188,16 @@ sqlite_bind_ph(SV *sth, imp_sth_t *imp_sth, const char *data; int numtype = 0; + if ((imp_dbh->see_if_its_a_number || sqlite_type == SQLITE_INTEGER) && SvIOK(value)) { + numtype = -1; + } + else if ((imp_dbh->see_if_its_a_number || sqlite_type == SQLITE_FLOAT) && SvNOK(value) && (sizeof(NV) == sizeof(double) || SvNVX(value) == (double)SvNVX(value))) { + numtype = -2; + } + else if ((UV)(sqlite3_int64)UV_MAX == UV_MAX && SvIOK_UV(value)) { + numtype = -3; + } + else { if (imp_dbh->unicode) { sv_utf8_upgrade(value); } @@ -1206,6 +1216,7 @@ sqlite_bind_ph(SV *sth, imp_sth_t *imp_sth, else if (sqlite_type == SQLITE_INTEGER || sqlite_type == SQLITE_FLOAT) { numtype = sqlite_is_number(aTHX_ data, FALSE); } + } if (numtype == 1) { #if defined(USE_64_BIT_INT) @@ -1217,6 +1228,19 @@ sqlite_bind_ph(SV *sth, imp_sth_t *imp_sth, else if (numtype == 2 && sqlite_type != SQLITE_INTEGER) { rc = sqlite3_bind_double(imp_sth->stmt, pos, atof(data)); } + else if (numtype == -1) { +#if defined(USE_64_BIT_INT) + rc = sqlite3_bind_int64(imp_sth->stmt, pos, SvIVX(value)); +#else + rc = sqlite3_bind_int(imp_sth->stmt, pos, SvIVX(value)); +#endif + } + else if (numtype == -2) { + rc = sqlite3_bind_double(imp_sth->stmt, pos, SvNVX(value)); + } + else if ((UV)(sqlite3_int64)UV_MAX == UV_MAX && numtype == -3) { + rc = sqlite3_bind_int64(imp_sth->stmt, pos, (sqlite3_int64)SvUVX(value)); + } else { if (sqlite_type == SQLITE_INTEGER || sqlite_type == SQLITE_FLOAT) { sqlite_error(sth, -2, form("datatype mismatch: bind %d type %d as %s", pos, sqlite_type, SvPV_nolen_undef_ok(value))); diff --git a/t/19_bindparam.t b/t/19_bindparam.t index 955663d..62d74d5 100644 --- a/t/19_bindparam.t +++ b/t/19_bindparam.t @@ -7,7 +7,7 @@ BEGIN { } use t::lib::Test; -use Test::More tests => 33; +use Test::More tests => 52; use Test::NoWarnings; use DBI ':sql_types'; @@ -22,6 +22,13 @@ CREATE TABLE one ( ) END_SQL +ok( $dbh->do(<<'END_SQL'), 'CREATE TABLE' ); +CREATE TABLE two ( + id INTEGER NOT NULL, + value REAL +) +END_SQL + my $konig = "Andreas K\xf6nig"; SCOPE: { @@ -50,6 +57,26 @@ SCOPE: { ok( $sth->execute, '->execute' ); } +# XXX NOT VERFIED on big-endian arches ! +# XXX maybe unpack("f",pack("L", 0x7f800000)) ? +my $skip_float = pack("f", 1.0) ne "\x00\x00\x80\x3f"; +SKIP: { + skip "unusual float binary representation", 6 if $skip_float; + + my $sth = $dbh->prepare("INSERT INTO two VALUES ( ?, ? )"); + isa_ok( $sth, 'DBI::st' ); + + ok( $sth->bind_param(1, 0, SQL_INTEGER), 'bind 5' ); + ok( $sth->bind_param(2, 0, SQL_FLOAT), 'bind 6' ); + + # NAN + ok( $sth->execute(1, unpack("f", "\x00\x00\xc0\xff")), 'EXECUTE 4' ); + # +INF + ok( $sth->execute(2, unpack("f", "\x00\x00\x80\x7f")), 'EXECUTE 5' ); + # -INF + ok( $sth->execute(3, unpack("f", "\x00\x00\x80\xff")), 'EXECUTE 6' ); +} + # Reconnect ok( $dbh->disconnect, '->disconnect' ); $dbh = connect_ok( dbfile => 'foo' ); @@ -76,3 +103,27 @@ SCOPE: { is( $id, 5, 'id = 5' ); is( $name, undef, 'name = undef' ); } + +SKIP: { + skip "unusual float binary representation", 12 if $skip_float; + + my $sth = $dbh->prepare("SELECT id, typeof(value) FROM two ORDER BY id"); + isa_ok( $sth, 'DBI::st' ); + ok( $sth->execute, '->execute' ); + my $id = undef; + my $type = undef; + ok( $sth->bind_columns(undef, \$id, \$type), '->bind_columns' ); + + ok( $sth->fetch, '->fetch' ); + is( $id, 1, 'id = 1' ); + # SQLite converts NAN to NULL (currently) + ok( $type eq 'null' || $type eq 'real', 'NAN is either null or real' ); + + ok( $sth->fetch, '->fetch' ); + is( $id, 2, 'id = 2' ); + is( $type, 'real', '+INF is real' ); + + ok( $sth->fetch, '->fetch' ); + is( $id, 3, 'id = 3' ); + is( $type, 'real', '-INF is real' ); +} -- 1.7.6.3
>From 40fc7503ec7dffa89548502461d1743dbf57aed2 Mon Sep 17 00:00:00 2001 From: "Yuriy M. Kaminskiy" <yum...@gmail.com> Date: Tue, 3 Apr 2012 19:04:12 +0400 Subject: [PATCH 3/3] reindent --- dbdimp.c | 34 +++++++++++++++++----------------- 1 files changed, 17 insertions(+), 17 deletions(-) diff --git a/dbdimp.c b/dbdimp.c index 779ec18..86825fd 100644 --- a/dbdimp.c +++ b/dbdimp.c @@ -1198,24 +1198,24 @@ sqlite_bind_ph(SV *sth, imp_sth_t *imp_sth, numtype = -3; } else { - if (imp_dbh->unicode) { - sv_utf8_upgrade(value); - } - data = SvPV(value, len); + if (imp_dbh->unicode) { + sv_utf8_upgrade(value); + } + data = SvPV(value, len); - /* - * XXX: For backward compatibility, it'd be better to - * accept a value like " 4" as an integer for an integer - * type column (see t/19_bindparam.t), at least when - * we explicitly specify its type. However, we should - * keep spaces when we just guess. - */ - if (imp_dbh->see_if_its_a_number) { - numtype = sqlite_is_number(aTHX_ data, TRUE); - } - else if (sqlite_type == SQLITE_INTEGER || sqlite_type == SQLITE_FLOAT) { - numtype = sqlite_is_number(aTHX_ data, FALSE); - } + /* + * XXX: For backward compatibility, it'd be better to + * accept a value like " 4" as an integer for an integer + * type column (see t/19_bindparam.t), at least when + * we explicitly specify its type. However, we should + * keep spaces when we just guess. + */ + if (imp_dbh->see_if_its_a_number) { + numtype = sqlite_is_number(aTHX_ data, TRUE); + } + else if (sqlite_type == SQLITE_INTEGER || sqlite_type == SQLITE_FLOAT) { + numtype = sqlite_is_number(aTHX_ data, FALSE); + } } if (numtype == 1) { -- 1.7.6.3
_______________________________________________ DBD-SQLite mailing list DBD-SQLite@lists.scsys.co.uk http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/dbd-sqlite