Skip Menu |

This queue is for tickets about the DBD-SQLite CPAN distribution.

Report information
The Basics
Id: 29058
Status: stalled
Priority: 0/
Queue: DBD-SQLite

People
Owner: Nobody in particular
Requestors: pjs [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Important
Broken in: 1.13
Fixed in: (no value)



Subject: Bind parameter in GROUP BY fails
Using a placeholder in a GROUP BY statement fails, as in the example below: #!/usr/local/bin/perl use strict; use warnings; use DBI; unlink "/tmp/db"; my $dbh = DBI->connect( 'dbi:SQLite:dbname=/tmp/db', '', '', { PrintError => 0, RaiseError => 1 } ); $dbh->do( 'CREATE TABLE foo (bar TEXT, num INT)' ); for (1..5) { $dbh->do( 'INSERT INTO foo (bar, num) VALUES (?,?)', undef, ($_%2 ? "odd" : "even"), $_ ); } my ($v) = $dbh->selectrow_array( 'SELECT bar FROM foo WHERE num = ?', undef, 3 ); print "1: $v\n"; DBI->trace(4); my $ar = $dbh->selectall_arrayref( 'SELECT bar FROM foo GROUP BY bar HAVING count(*) > 1' ); print "2: @$_\n" for @$ar; $ar = $dbh->selectall_arrayref( 'SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?', undef, 1); print "3: @$_\n" for @$ar; DBI tracing is turned on in the output below and makes it a bit harder to see that the last statement returns no results, even though it is identical to the penultimate statement: 1: odd DBI 1.52-nothread default trace level set to 0x0/4 (pid 4608) -> selectall_arrayref for DBD::SQLite::db (DBI::db=HASH(0x82e769c)~0x82ee7e8 'SELECT bar FROM foo GROUP BY bar HAVING count(*) > 1') 1 -> prepare for DBD::SQLite::db (DBI::db=HASH(0x82ee7e8)~INNER 'SELECT bar FR OM foo GROUP BY bar HAVING count(*) > 1' undef) New DBI::st (for DBD::SQLite::st, parent=DBI::db=HASH(0x82ee7e8), id=) dbih_setup_handle(DBI::st=HASH(0x82eea28)=>DBI::st=HASH(0x82ee8fc), DBD::SQL ite::st, 82eea7c, Null!) dbih_make_com(DBI::db=HASH(0x82ee7e8), 824c3f0, DBD::SQLite::st, 132, 0) thr #0 sqlite trace: prepare statement: SELECT bar FROM foo GROUP BY bar HAVING count(* ) > 1 at dbdimp.c line 258 1 <- prepare= DBI::st=HASH(0x82eea28) at /tmp/foo line 23 sqlite trace: execute at dbdimp.c line 325 sqlite trace: Execute returned 1 cols at dbdimp.c line 395 dbih_setup_fbav for 1 fields => 0x82eebcc <- selectall_arrayref= [ ARRAY(0x82eebe4) ARRAY(0x82eec08) ] at /tmp/foo lin e 23 <> DESTROY(DBI::st=HASH(0x82eea28)) ignored for outer handle (inner DBI::st= HASH(0x82ee8fc) has ref cnt 1) -> DESTROY for DBD::SQLite::st (DBI::st=HASH(0x82ee8fc)~INNER) <- DESTROY= undef at /tmp/foo line 24 via at /tmp/foo line 24 dbih_clearcom 0x82ee8fc (com 0x82f1fe8, type 3) done. 2: even 2: odd -> selectall_arrayref for DBD::SQLite::db (DBI::db=HASH(0x82e769c)~0x82ee7e8 'SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?' undef 1) 1 -> prepare for DBD::SQLite::db (DBI::db=HASH(0x82ee7e8)~INNER 'SELECT bar FR OM foo GROUP BY bar HAVING count(*) > ?' undef) New DBI::st (for DBD::SQLite::st, parent=DBI::db=HASH(0x82ee7e8), id=) dbih_setup_handle(DBI::st=HASH(0x82eeab8)=>DBI::st=HASH(0x82eea28), DBD::SQL ite::st, 82eeb48, Null!) dbih_make_com(DBI::db=HASH(0x82ee7e8), 824c3f0, DBD::SQLite::st, 132, 0) thr #0 sqlite trace: prepare statement: SELECT bar FROM foo GROUP BY bar HAVING count(* ) > ? at dbdimp.c line 258 1 <- prepare= DBI::st=HASH(0x82eeab8) at /tmp/foo line 26 sqlite trace: bind into 0x82eeb0c: 1 => 1 (0) pos 0 at dbdimp.c line 464 sqlite trace: execute at dbdimp.c line 325 sqlite trace: params left in 0x82eeb0c: 0 at dbdimp.c line 343 sqlite trace: bind 0 type 0 as 1 at dbdimp.c line 344 sqlite trace: Execute returned 1 cols at dbdimp.c line 395 <- selectall_arrayref= [ ] at /tmp/foo line 26 <> DESTROY(DBI::st=HASH(0x82eeab8)) ignored for outer handle (inner DBI::st= HASH(0x82eea28) has ref cnt 1) -> DESTROY for DBD::SQLite::st (DBI::st=HASH(0x82eea28)~INNER) <- DESTROY= undef at /tmp/foo line 27 via at /tmp/foo line 27 dbih_clearcom 0x82eea28 (com 0x82f2208, type 3) done. <> DESTROY(DBI::db=HASH(0x82e769c)) ignored for outer handle (inner DBI::db= HASH(0x82ee7e8) has ref cnt 1) -> DESTROY for DBD::SQLite::db (DBI::db=HASH(0x82ee7e8)~INNER) <- DESTROY= undef dbih_clearcom 0x82ee7e8 (com 0x824c3f0, type 2) done. -- DBI::END -> disconnect_all for DBD::SQLite::dr (DBI::dr=HASH(0x8284860)~0x82e76a8) <- disconnect_all= '' at /usr/local/lib/perl5/site_perl/5.8.8/i686-linux/DBI .pm line 700 via at /tmp/foo line 0 ! -> DESTROY in DBD::_::common for DBD::SQLite::dr (DBI::dr=HASH(0x82e76a8)~IN NER) ! <- DESTROY= undef during global destruction dbih_clearcom 0x8284860 (com 0x824c200, type 1) done. ! <> DESTROY for DBI::dr=HASH(0x8284860) ignored (inner handle gone)
Flagging this as resolved. A regression test has been added for this bug.
Sorry, DBD::SQLite 1.22_04 reopens this as the previous implementation was not good enough. There are two known workaround for this issue. See t/ rt_29058_group_by.t for details. In short, 1) use "bind_param" with TYPE => SQL_INTEGER (or whatever) attribute explicitly, or 2) add "+0" to the appropriate part of your SQL. If you find a better solution, patches are welcome. On Wed Aug 29 21:56:01 2007, PJS wrote: Show quoted text
> Using a placeholder in a GROUP BY statement fails, as in the example > below: > > #!/usr/local/bin/perl > use strict; > use warnings; > use DBI; > > unlink "/tmp/db"; > my $dbh = DBI->connect( 'dbi:SQLite:dbname=/tmp/db', '', '', > { PrintError => 0, RaiseError => 1 } ); > $dbh->do( 'CREATE TABLE foo (bar TEXT, num INT)' ); > for (1..5) > { > $dbh->do( 'INSERT INTO foo (bar, num) VALUES (?,?)', > undef, ($_%2 ? "odd" : "even"), $_ ); > } > > my ($v) = $dbh->selectrow_array( 'SELECT bar FROM foo WHERE num = ?', > undef, 3 ); > print "1: $v\n"; > DBI->trace(4); > > my $ar = $dbh->selectall_arrayref( 'SELECT bar FROM foo GROUP BY bar > HAVING count(*) > > 1' ); > print "2: @$_\n" for @$ar; > > $ar = $dbh->selectall_arrayref( 'SELECT bar FROM foo GROUP BY bar > HAVING count(*) > ?', > undef, 1); > print "3: @$_\n" for @$ar; > > DBI tracing is turned on in the output below and makes it a bit harder > to see that the last > statement returns no results, even though it is identical to the > penultimate statement: > > 1: odd > DBI 1.52-nothread default trace level set to 0x0/4 (pid 4608) > -> selectall_arrayref for DBD::SQLite::db > (DBI::db=HASH(0x82e769c)~0x82ee7e8 > 'SELECT bar FROM foo GROUP BY bar HAVING count(*) > 1') > 1 -> prepare for DBD::SQLite::db (DBI::db=HASH(0x82ee7e8)~INNER > 'SELECT bar FR > OM foo GROUP BY bar HAVING count(*) > 1' undef) > New DBI::st (for DBD::SQLite::st, parent=DBI::db=HASH(0x82ee7e8), > id=) > dbih_setup_handle(DBI::st=HASH(0x82eea28)=>DBI::st=HASH
(0x82ee8fc), Show quoted text
> DBD::SQL > ite::st, 82eea7c, Null!) > dbih_make_com(DBI::db=HASH(0x82ee7e8), 824c3f0, DBD::SQLite::st, > 132, 0) thr > #0 > sqlite trace: prepare statement: SELECT bar FROM foo GROUP BY bar > HAVING count(* > ) > 1 at dbdimp.c line 258 > 1 <- prepare= DBI::st=HASH(0x82eea28) at /tmp/foo line 23 > sqlite trace: execute at dbdimp.c line 325 > sqlite trace: Execute returned 1 cols > at dbdimp.c line 395 > dbih_setup_fbav for 1 fields => 0x82eebcc > <- selectall_arrayref= [ ARRAY(0x82eebe4) ARRAY(0x82eec08) ] at > /tmp/foo lin > e 23 > <> DESTROY(DBI::st=HASH(0x82eea28)) ignored for outer handle > (inner DBI::st= > HASH(0x82ee8fc) has ref cnt 1) > -> DESTROY for DBD::SQLite::st (DBI::st=HASH(0x82ee8fc)~INNER) > <- DESTROY= undef at /tmp/foo line 24 via at /tmp/foo line 24 > dbih_clearcom 0x82ee8fc (com 0x82f1fe8, type 3) done. > > 2: even > 2: odd > -> selectall_arrayref for DBD::SQLite::db > (DBI::db=HASH(0x82e769c)~0x82ee7e8 > 'SELECT bar FROM foo GROUP BY bar HAVING count(*) > ?' undef 1) > 1 -> prepare for DBD::SQLite::db (DBI::db=HASH(0x82ee7e8)~INNER > 'SELECT bar FR > OM foo GROUP BY bar HAVING count(*) > ?' undef) > New DBI::st (for DBD::SQLite::st, parent=DBI::db=HASH(0x82ee7e8), > id=) > dbih_setup_handle(DBI::st=HASH(0x82eeab8)=>DBI::st=HASH
(0x82eea28), Show quoted text
> DBD::SQL > ite::st, 82eeb48, Null!) > dbih_make_com(DBI::db=HASH(0x82ee7e8), 824c3f0, DBD::SQLite::st, > 132, 0) thr > #0 > sqlite trace: prepare statement: SELECT bar FROM foo GROUP BY bar > HAVING count(* > ) > ? at dbdimp.c line 258 > 1 <- prepare= DBI::st=HASH(0x82eeab8) at /tmp/foo line 26 > sqlite trace: bind into 0x82eeb0c: 1 => 1 (0) pos 0 > at dbdimp.c line 464 > sqlite trace: execute at dbdimp.c line 325 > sqlite trace: params left in 0x82eeb0c: 0 at dbdimp.c line 343 > sqlite trace: bind 0 type 0 as 1 at dbdimp.c line 344 > sqlite trace: Execute returned 1 cols > at dbdimp.c line 395 > <- selectall_arrayref= [ ] at /tmp/foo line 26 > <> DESTROY(DBI::st=HASH(0x82eeab8)) ignored for outer handle > (inner DBI::st= > HASH(0x82eea28) has ref cnt 1) > -> DESTROY for DBD::SQLite::st (DBI::st=HASH(0x82eea28)~INNER) > <- DESTROY= undef at /tmp/foo line 27 via at /tmp/foo line 27 > dbih_clearcom 0x82eea28 (com 0x82f2208, type 3) done. > > <> DESTROY(DBI::db=HASH(0x82e769c)) ignored for outer handle > (inner DBI::db= > HASH(0x82ee7e8) has ref cnt 1) > -> DESTROY for DBD::SQLite::db (DBI::db=HASH(0x82ee7e8)~INNER) > <- DESTROY= undef > dbih_clearcom 0x82ee7e8 (com 0x824c3f0, type 2) done. > > -- DBI::END > -> disconnect_all for DBD::SQLite::dr > (DBI::dr=HASH(0x8284860)~0x82e76a8) > <- disconnect_all= '' at > /usr/local/lib/perl5/site_perl/5.8.8/i686-linux/DBI > .pm line 700 via at /tmp/foo line 0 > ! -> DESTROY in DBD::_::common for DBD::SQLite::dr > (DBI::dr=HASH(0x82e76a8)~IN > NER) > ! <- DESTROY= undef during global destruction > dbih_clearcom 0x8284860 (com 0x824c200, type 1) done. > > ! <> DESTROY for DBI::dr=HASH(0x8284860) ignored (inner handle gone)