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:
parent
16cd4fd520
commit
968ecf0063
5 changed files with 72 additions and 19 deletions
25
dbdimp.c
25
dbdimp.c
|
@ -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->handle_binary_nulls = FALSE;
|
||||||
imp_dbh->allow_multiple_statements = FALSE;
|
imp_dbh->allow_multiple_statements = FALSE;
|
||||||
imp_dbh->use_immediate_transaction = FALSE;
|
imp_dbh->use_immediate_transaction = FALSE;
|
||||||
|
imp_dbh->see_if_its_a_number = FALSE;
|
||||||
|
|
||||||
sqlite3_busy_timeout(imp_dbh->db, SQL_TIMEOUT);
|
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));
|
imp_dbh->use_immediate_transaction = !(! SvTRUE(valuesv));
|
||||||
return TRUE;
|
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 (strEQ(key, "sqlite_unicode")) {
|
||||||
#if PERL_UNICODE_DOES_NOT_WORK_WELL
|
#if PERL_UNICODE_DOES_NOT_WORK_WELL
|
||||||
sqlite_trace(dbh, imp_dbh, 3, form("Unicode support is disabled for this version of perl."));
|
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")) {
|
if (strEQ(key, "sqlite_use_immediate_transaction")) {
|
||||||
return sv_2mortal(newSViv(imp_dbh->use_immediate_transaction ? 1 : 0));
|
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 (strEQ(key, "sqlite_unicode")) {
|
||||||
#if PERL_UNICODE_DOES_NOT_WORK_WELL
|
#if PERL_UNICODE_DOES_NOT_WORK_WELL
|
||||||
sqlite_trace(dbh, imp_dbh, 3, "Unicode support is disabled for this version of perl.");
|
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 {
|
else {
|
||||||
STRLEN len;
|
STRLEN len;
|
||||||
const char *data;
|
const char *data;
|
||||||
#if 0
|
int numtype = 0;
|
||||||
int numtype;
|
|
||||||
#endif
|
|
||||||
if (imp_dbh->unicode) {
|
if (imp_dbh->unicode) {
|
||||||
sv_utf8_upgrade(value);
|
sv_utf8_upgrade(value);
|
||||||
}
|
}
|
||||||
data = SvPV(value, len);
|
data = SvPV(value, len);
|
||||||
#if 0
|
|
||||||
|
if (imp_dbh->see_if_its_a_number) {
|
||||||
numtype = sqlite_is_number(aTHX_ data);
|
numtype = sqlite_is_number(aTHX_ data);
|
||||||
|
}
|
||||||
|
|
||||||
if (numtype == 1) {
|
if (numtype == 1) {
|
||||||
#if defined(USE_64_BIT_INT)
|
#if defined(USE_64_BIT_INT)
|
||||||
rc = sqlite3_bind_int64(imp_sth->stmt, i+1, atoi(data));
|
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));
|
rc = sqlite3_bind_double(imp_sth->stmt, i+1, atof(data));
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#endif
|
|
||||||
rc = sqlite3_bind_text(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT);
|
rc = sqlite3_bind_text(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT);
|
||||||
#if 0
|
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value) {
|
if (value) {
|
||||||
|
@ -816,7 +823,6 @@ sqlite_st_fetch(SV *sth, imp_sth_t *imp_sth)
|
||||||
}
|
}
|
||||||
switch(col_type) {
|
switch(col_type) {
|
||||||
case SQLITE_INTEGER:
|
case SQLITE_INTEGER:
|
||||||
#if 1
|
|
||||||
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as integer", i));
|
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as integer", i));
|
||||||
#if defined(USE_64_BIT_INT)
|
#if defined(USE_64_BIT_INT)
|
||||||
sv_setiv(AvARRAY(av)[i], sqlite3_column_int64(imp_sth->stmt, i));
|
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));
|
sv_setnv(AvARRAY(av)[i], (double)sqlite3_column_int64(imp_sth->stmt, i));
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case SQLITE_FLOAT:
|
case SQLITE_FLOAT:
|
||||||
#if 1
|
|
||||||
/* fetching as float may lose precision info in the perl world */
|
/* fetching as float may lose precision info in the perl world */
|
||||||
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as float", i));
|
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));
|
sv_setnv(AvARRAY(av)[i], sqlite3_column_double(imp_sth->stmt, i));
|
||||||
break;
|
break;
|
||||||
#endif
|
|
||||||
case SQLITE_TEXT:
|
case SQLITE_TEXT:
|
||||||
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as text", i));
|
sqlite_trace(sth, imp_sth, 5, form("fetch column %d as text", i));
|
||||||
val = (char*)sqlite3_column_text(imp_sth->stmt, i);
|
val = (char*)sqlite3_column_text(imp_sth->stmt, i);
|
||||||
|
|
1
dbdimp.h
1
dbdimp.h
|
@ -35,6 +35,7 @@ struct imp_dbh_st {
|
||||||
SV *collation_needed_callback;
|
SV *collation_needed_callback;
|
||||||
bool allow_multiple_statements;
|
bool allow_multiple_statements;
|
||||||
bool use_immediate_transaction;
|
bool use_immediate_transaction;
|
||||||
|
bool see_if_its_a_number;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Statement Handle */
|
/* Statement Handle */
|
||||||
|
|
|
@ -752,7 +752,7 @@ like this while executing:
|
||||||
|
|
||||||
SELECT bar FROM foo GROUP BY bar HAVING count(*) > "5";
|
SELECT bar FROM foo GROUP BY bar HAVING count(*) > "5";
|
||||||
|
|
||||||
There are two workarounds for this.
|
There are three workarounds for this.
|
||||||
|
|
||||||
=over 4
|
=over 4
|
||||||
|
|
||||||
|
@ -778,6 +778,32 @@ This is somewhat weird, but works anyway.
|
||||||
});
|
});
|
||||||
$sth->execute(5);
|
$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
|
=back
|
||||||
|
|
||||||
=head2 Placeholders
|
=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
|
immediate transaction> (instead of C<begin transaction>) when
|
||||||
necessary. See above for details.
|
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
|
=back
|
||||||
|
|
||||||
=head2 Statement Handle Attributes
|
=head2 Statement Handle Attributes
|
||||||
|
|
|
@ -6,7 +6,7 @@ BEGIN {
|
||||||
}
|
}
|
||||||
|
|
||||||
use t::lib::Test;
|
use t::lib::Test;
|
||||||
use Test::More tests => 7;
|
use Test::More tests => 8;
|
||||||
use Test::NoWarnings;
|
use Test::NoWarnings;
|
||||||
use DBI qw(:sql_types);
|
use DBI qw(:sql_types);
|
||||||
|
|
||||||
|
@ -51,6 +51,16 @@ $sth->execute;
|
||||||
$ar = $sth->fetchall_arrayref;
|
$ar = $sth->fetchall_arrayref;
|
||||||
is( scalar(@$ar), 2, 'Got 2 results' );
|
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
|
# and this is what should be tested
|
||||||
#TODO: {
|
#TODO: {
|
||||||
local $TODO = 'This test is currently broken again. Wait for a better fix, or use known workarounds shown above';
|
local $TODO = 'This test is currently broken again. Wait for a better fix, or use known workarounds shown above';
|
||||||
|
|
|
@ -7,7 +7,7 @@ BEGIN {
|
||||||
}
|
}
|
||||||
|
|
||||||
use t::lib::Test;
|
use t::lib::Test;
|
||||||
use Test::More tests => 17;
|
use Test::More tests => 19;
|
||||||
use Test::NoWarnings;
|
use Test::NoWarnings;
|
||||||
use DBI qw(:sql_types);
|
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
|
# 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($statement);
|
$sth = $dbh->prepare($tweaked_statement);
|
||||||
ok( $sth->execute(2), "execute: $statement : [2]" );
|
ok( $sth->execute(2), "execute: $tweaked_statement : [2]" );
|
||||||
is( $sth->fetchrow_arrayref->[0], 1, "result of: $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]" );
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue