In my endless obsession with premature optimization, I've been using
sqlite3_bind_blob, whenever I know the length of what I'm inserting, even if
it's text or whatnot. It exhibits some very strange properties though, which I
can't imagine is anything other than a bug. Here's my test case:

-----------------------------------------------------------------------mimesucks-----------------

#include <sqlite3.h>
#include <stdio.h>
#include <stdlib.h> // NULL
#include <assert.h>

#define LITLEN(lit) lit, sizeof(lit)-1

int main(int argc, char *argv[])
{
    sqlite3* db;
    sqlite3_open(":memory:",&db);
    sqlite3_exec(db,"CREATE TABLE foo (id INTEGER PRIMARY KEY, bar
TEXT)",NULL,NULL,NULL);
    sqlite3_stmt *ins,*sel;
    sqlite3_prepare(db,LITLEN("INSERT INTO foo (bar) VALUES (?)"),&ins,NULL);
    sqlite3_prepare(db,LITLEN("SELECT id FROM foo WHERE bar = ?"),&sel,NULL);

    puts("This is fine.");
    sqlite3_bind_text(ins,1,"test",4,NULL);
    sqlite3_step(ins);
    sqlite3_reset(ins);
    sqlite3_bind_text(sel,1,"test",4,NULL);
    assert(SQLITE_ROW == sqlite3_step(sel));
    printf("Got ID %d\n",sqlite3_column_int(sel,0));

    sqlite3_stmt* clear;
    sqlite3_prepare(db,LITLEN("DELETE FROM foo"),&clear,NULL);
    sqlite3_step(clear);
    sqlite3_reset(clear);
   
    puts("This is NOT fine.");
    sqlite3_bind_blob(ins,1,"test",4,NULL);
    sqlite3_step(ins);
    sqlite3_reset(ins);
    sqlite3_bind_blob(sel,1,"test",4,NULL);
    if(SQLITE_ROW != sqlite3_step(sel)) {
        printf("no results? %s\n",sqlite3_errmsg(db));
    } else {
        printf("Got ID %d\n",sqlite3_column_int(sel,0));
    }

    sqlite3_step(clear);
    sqlite3_reset(clear);

    puts("This is NOT fine.");
    sqlite3_bind_blob(ins,1,"test",4,NULL);
    sqlite3_step(ins);
    sqlite3_reset(ins);
    sqlite3_bind_text(sel,1,"test",4,NULL);
    if(SQLITE_ROW != sqlite3_step(sel)) {
        printf("no results? %s\n",sqlite3_errmsg(db));
    } else {
        printf("Got ID %d\n",sqlite3_column_int(sel,0));
    }
   
    sqlite3_step(clear);
    sqlite3_reset(clear);

    puts("This is fine though?");
    sqlite3_bind_text(ins,1,"test",4,NULL);
    sqlite3_step(ins);
    sqlite3_reset(ins);
    sqlite3_bind_blob(sel,1,"test",4,NULL);
    if(SQLITE_ROW != sqlite3_step(sel)) {
        printf("no results? %s\n",sqlite3_errmsg(db));
    } else {
        printf("Got ID %d\n",sqlite3_column_int(sel,0));
    }
   
    return 0;
}


-----------------------------------------------------------------------mimesucks-----------------

When I insert anything via sqlite3_bind_blob, sqlite then loses the record, uh,
forever. Searching for the exact same text I just inserted, I cannot get any
results, if sqlite3_bind_blob is used. Even if I use sqlite3_bind_blob on both
the search text and the insert text, sqlite still comes up with no results.
Interestingly, if I use sqlite_bind_text on insert, then sqlite_bind_blob on
select, the database DOES find a result. Only when I use sqlite3_bind_blob, on
an insert statement, does the resulting field become entirely unsearchable. If I
get the row by some other criteria, the data inserted with sqlite3_bind_blob and
sqlite3_bind_text are byte-equivalent, and when I look at them using
sqlite3_column_blob/bytes, neither one has an embedded null terminator.

I'm not... familiar with sqlite's innards, but my best guess is that there must
be a (hidden) null terminator included on disk for stuff inserted with
sqlite3_bind_text, that isn't reported, but when sqlite3_bind_blob is used, that
extra byte for the null doesn't go on disk. When sqlite encounters an "a = b"
expression, it assumes that null byte exists, and adds the null terminator to
the criteria, which then fails to find the row, since the actual data was
inserted with sqlite3_bind_blob and lacks a null terminator.

_______________________________________________
sqlite-users mailing list
sqlite-users@mailinglists.sqlite.org
http://mailinglists.sqlite.org/cgi-bin/mailman/listinfo/sqlite-users

Reply via email to