1
0
Fork 0
mirror of https://github.com/DBD-SQLite/DBD-SQLite synced 2025-06-07 22:28:47 -04:00

sqlite_see_if_its_a_number attribute to enable sqlite_is_number check

This commit is contained in:
Kenichi Ishigaki 2011-03-05 13:28:27 +00:00
parent 16cd4fd520
commit 968ecf0063
5 changed files with 72 additions and 19 deletions

View file

@ -240,6 +240,7 @@ sqlite_db_login6(SV *dbh, imp_dbh_t *imp_dbh, char *dbname, char *user, char *pa
imp_dbh->handle_binary_nulls = FALSE;
imp_dbh->allow_multiple_statements = FALSE;
imp_dbh->use_immediate_transaction = FALSE;
imp_dbh->see_if_its_a_number = FALSE;
sqlite3_busy_timeout(imp_dbh->db, SQL_TIMEOUT);
@ -439,6 +440,10 @@ sqlite_db_STORE_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv, SV *valuesv)
imp_dbh->use_immediate_transaction = !(! SvTRUE(valuesv));
return TRUE;
}
if (strEQ(key, "sqlite_see_if_its_a_number")) {
imp_dbh->see_if_its_a_number = !(! SvTRUE(valuesv));
return TRUE;
}
if (strEQ(key, "sqlite_unicode")) {
#if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
@ -477,6 +482,9 @@ sqlite_db_FETCH_attrib(SV *dbh, imp_dbh_t *imp_dbh, SV *keysv)
if (strEQ(key, "sqlite_use_immediate_transaction")) {
return sv_2mortal(newSViv(imp_dbh->use_immediate_transaction ? 1 : 0));
}
if (strEQ(key, "sqlite_see_if_its_a_number")) {
return sv_2mortal(newSViv(imp_dbh->see_if_its_a_number ? 1 : 0));
}
if (strEQ(key, "sqlite_unicode")) {
#if PERL_UNICODE_DOES_NOT_WORK_WELL
sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl.");
@ -637,15 +645,17 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
else {
STRLEN len;
const char *data;
#if 0
int numtype;
#endif
int numtype = 0;
if (imp_dbh->unicode) {
sv_utf8_upgrade(value);
}
data = SvPV(value, len);
#if 0
if (imp_dbh->see_if_its_a_number) {
numtype = sqlite_is_number(aTHX_ data);
}
if (numtype == 1) {
#if defined(USE_64_BIT_INT)
rc = sqlite3_bind_int64(imp_sth->stmt, i+1, atoi(data));
@ -657,11 +667,8 @@ sqlite_st_execute(SV *sth, imp_sth_t *imp_sth)
rc = sqlite3_bind_double(imp_sth->stmt, i+1, atof(data));
}
else {
#endif
rc = sqlite3_bind_text(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT);
#if 0
}
#endif
}
if (value) {
@ -816,7 +823,6 @@ sqlite_st_fetch(SV *sth, imp_sth_t *imp_sth)
}
switch(col_type) {
case SQLITE_INTEGER:
#if 1
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as integer", i));
#if defined(USE_64_BIT_INT)
sv_setiv(AvARRAY(av)[i], sqlite3_column_int64(imp_sth->stmt, i));
@ -824,14 +830,11 @@ sqlite_st_fetch(SV *sth, imp_sth_t *imp_sth)
sv_setnv(AvARRAY(av)[i], (double)sqlite3_column_int64(imp_sth->stmt, i));
#endif
break;
#endif
case SQLITE_FLOAT:
#if 1
/* fetching as float may lose precision info in the perl world */
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as float", i));
sv_setnv(AvARRAY(av)[i], sqlite3_column_double(imp_sth->stmt, i));
break;
#endif
case SQLITE_TEXT:
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as text", i));
val = (char*)sqlite3_column_text(imp_sth->stmt, i);

View file

@ -35,6 +35,7 @@ struct imp_dbh_st {
SV *collation_needed_callback;
bool allow_multiple_statements;
bool use_immediate_transaction;
bool see_if_its_a_number;
};
/* Statement Handle */

View file

@ -752,7 +752,7 @@ like this while executing:
SELECT bar FROM foo GROUP BY bar HAVING count(*) > "5";
There are two workarounds for this.
There are three workarounds for this.
=over 4
@ -778,6 +778,32 @@ This is somewhat weird, but works anyway.
});
$sth->execute(5);
=item Set C<sqlite_see_if_its_a_number> database handle attribute
As of version 1.32_02, you can use C<sqlite_see_if_its_a_number>
to let DBD::SQLite to see if the bind values are numbers or not.
$dbh->{sqlite_see_if_its_a_number} = 1;
my $sth = $dbh->prepare(q{
SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?;
});
$sth->execute(5);
You can set it to true when you connect to a database.
my $dbh = DBI->connect('dbi:SQLite:foo', undef, undef, {
AutoCommit => 1,
RaiseError => 1,
sqlite_see_if_its_a_number => 1,
});
This is the most straightforward solution, but as noted above,
existing data in your databases created by DBD::SQLite have not
always been stored as numbers, so this *might* cause other obscure
problems. Use this sparingly when you handle existing databases.
If you handle databases created by other tools like native C<sqlite3>
command line tool, this attribute would help you.
=back
=head2 Placeholders
@ -1033,6 +1059,12 @@ If you set this to true, DBD::SQLite tries to issue a C<begin
immediate transaction> (instead of C<begin transaction>) when
necessary. See above for details.
=item sqlite_see_if_its_a_number
If you set this to true, DBD::SQLite tries to see if the bind values
are number or not, and does not quote if they are numbers. See above
for details.
=back
=head2 Statement Handle Attributes

View file

@ -6,7 +6,7 @@ BEGIN {
}
use t::lib::Test;
use Test::More tests => 7;
use Test::More tests => 8;
use Test::NoWarnings;
use DBI qw(:sql_types);
@ -51,6 +51,16 @@ $sth->execute;
$ar = $sth->fetchall_arrayref;
is( scalar(@$ar), 2, 'Got 2 results' );
# known workaround 3
{
local $dbh->{sqlite_see_if_its_a_number} = 1;
my $sth = $dbh->selectall_arrayref(
'SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?',
undef, 1
);
is( scalar(@$ar), 2, 'Got 2 results' );
}
# and this is what should be tested
#TODO: {
local $TODO = 'This test is currently broken again. Wait for a better fix, or use known workarounds shown above';

View file

@ -7,7 +7,7 @@ BEGIN {
}
use t::lib::Test;
use Test::More tests => 17;
use Test::More tests => 19;
use Test::NoWarnings;
use DBI qw(:sql_types);
@ -74,8 +74,15 @@ is( $sth->fetchrow_arrayref->[0], 1, "result of: $statement : [2]" );
# known workarounds 2: add "+0" to let sqlite convert the binded param into number
$statement =~ s/\?/\?\+0/;
(my $tweaked_statement = $statement) =~ s/\?/\?\+0/;
$sth = $dbh->prepare($tweaked_statement);
ok( $sth->execute(2), "execute: $tweaked_statement : [2]" );
is( $sth->fetchrow_arrayref->[0], 1, "result of: $tweaked_statement : [2]" );
# workaround 3: use sqlite_see_if_its_a_number attribute
{
local $dbh->{sqlite_see_if_its_a_number} = 1;
$sth = $dbh->prepare($statement);
ok( $sth->execute(2), "execute: $statement : [2]" );
is( $sth->fetchrow_arrayref->[0], 1, "result of: $statement : [2]" );
}