Skip Menu |

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

Report information
The Basics
Id: 14595
Status: resolved
Priority: 0/
Queue: DBD-SQLite

People
Owner: Nobody in particular
Requestors: jose_mico [...] hotmail.com
Cc:
AdminCc:

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



Subject: BLOB cannot handle NUL (\x00) characters
SQLite documentation says that BLOB's can contain NUL characters, but data is truncated at first ocurrence of NUL. The problem seems to be in the retrieval function, as data can be found into database file. Maybe this is a bug of SQLite itself (standalone program sqlite3 exibits the same behaviour), see discussion at: http://www.perlmonks.org/?node_id=491622 - - - - - - # The following code outputs just "ABC": use DBI; my $dbh = DBI->connect('DBI:SQLite:dbname=test_blob.db', '', ''); $dbh->do('CREATE TABLE test_blob( Bindata BLOB )'); my $bindata = "ABC" . "\x00" . "DEF"; my $sth1 = $dbh->prepare('INSERT INTO test_blob VALUES(?)' ); $sth1->execute($bindata); my $sth2 = $dbh->prepare('SELECT Bindata FROM test_blob'); $sth2->execute(); my $row = $sth2->fetch(); my $fetched_data = $row->[0]; $sth2->finish(); $dbh->disconnect; print $fetched_data;
I'm having the same problem with the latest version of SQLite3 and Perl on Debian Unstable. ii libdbd-sqlite3-perl 1.09-1 Perl DBI driver with a self-contained RDBMS ii libsqlite3-0 3.2.5-1 SQLite 3 shared library It's a serious problem that makes BLOBs essentially useless. [guest - Wed Sep 14 18:20:18 2005]: Show quoted text
> SQLite documentation says that BLOB's can contain NUL characters, but > data is truncated at first ocurrence of NUL. The problem seems to be > in the retrieval function, as data can be found into database file. > > Maybe this is a bug of SQLite itself (standalone program sqlite3 > exibits the same behaviour), see discussion at: > > http://www.perlmonks.org/?node_id=491622 > > - - - - - - > > # The following code outputs just "ABC": > > use DBI; > my $dbh = DBI->connect('DBI:SQLite:dbname=test_blob.db', '', ''); > $dbh->do('CREATE TABLE test_blob( Bindata BLOB )'); > > my $bindata = "ABC" . "\x00" . "DEF"; > > my $sth1 = $dbh->prepare('INSERT INTO test_blob VALUES(?)' ); > $sth1->execute($bindata); > > my $sth2 = $dbh->prepare('SELECT Bindata FROM test_blob'); > $sth2->execute(); > > my $row = $sth2->fetch(); > my $fetched_data = $row->[0]; > $sth2->finish(); > $dbh->disconnect; > > print $fetched_data;
From: nate [...] verse.com
[Nathan Kurz - Wed Sep 14 18:20:18 2005]: I've looked a little deeper into this, and am pretty sure that it is a bug in DBD::Sqlite. The problem is that all text is being stored using 'sqlite3_bind_text', despite some code in dbdimp.c that appears to expect otherwise. I'm not sure if this is a bug or just a partial implementation. In any case, I have a workaround patch but I don't understand the internals well enough to know if it is a good idea. Basically, it uses memchr() to scan the bound variable to see if it contains any NUL's. If it does, sqlite3_bind_blob() is used; otherwise the current default of sqlite3_bind_text() remains. It's quite possible that there is a more elegant way of doing this using the TYPE attribute, but I didn't manage to make that work. Patch attached.
--- dbdimp.c.orig 2005-11-10 19:27:55.000000000 -0700 +++ dbdimp.c 2005-11-10 19:27:32.000000000 -0700 @@ -356,11 +356,17 @@ STRLEN len; char * data = SvPV(value, len); retval = sqlite3_bind_blob(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT); - } + } else { STRLEN len; char * data = SvPV(value, len); - retval = sqlite3_bind_text(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT); + if (memchr(data, 0, len)) { + sqlite_trace(4, "binding NUL containing data as a blob"); + retval = sqlite3_bind_blob(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT); + } + else { + retval = sqlite3_bind_text(imp_sth->stmt, i+1, data, len, SQLITE_TRANSIENT); + } } if (value) {
Subject: workaround with bind_param()
From: jose_mico [...] hotmail.com
A known workaround is to use bind_param() to force data type as SQL_BLOB. For example: my $sth1 = $dbh->prepare('INSERT INTO test_blob VALUES(?)' ); $sth1->bind_param(1, $bindata, SQL_BLOB ); $sth1->execute();