I’ve noticed an odd problem a few years ago with using parameter bindings with 
SQLite and never really took the time to figure out the cause until now. I 
think it’ a pretty major problem that can be easily fixed, though would cause 
problems for anyone relying on the (imo) currently broken behavior.

Basically, the problem is that when using parameter bindings with strings, the 
pike glue determines the type of the data based on the width of the string: if 
it’s a wide string, the parameter is bound as a text, but if it’s 8 bit, it’s 
bound as a blob. The problem is that text and blob values aren’t evaluated the 
same, so even though a text value and blob value may be identical byte-wise, 
they are not equal when doing comparisons and so queries that would seem to 
match actually don’t. 

This is compounded by the fact that SQLite has no restrictions on what may be 
stored in a field (type definitions on a table are merely default suggestions) 
and SQLite will happily store whatever you want (such as a blob value in a text 
field).

For example, imagine a table m with an integer field id and a char field value:

s->query(“INSERT INTO m VALUES(1, 'value a’));
s->query(“INSERT INTO m VALUES(2, :value)”, ([“:value”, “value a”]));
s->query(“SELECT * FROM m where value=‘value a’”);

The third query will return 1 record instead of the expected 2 because the 
field value in the second row is stored as a blob and thus does not match a 
text query. In order to retrieve both records, you must use LIKE or know to 
cast the value to text using “AS TEXT” in the query, which is obviously a lot 
less ideal in most cases.

If all of your data is stored using the pike glue, and you’re always using 
parameters, it’s possible never to see the problem, but if not, this causes all 
kinds of problems because of the need for constantly casting values and 
possibly using blob literals, which are not human readable when you’re really 
trying to query for a non-wide string.

My suggestion is to change the binding type for 8 bit string parameters to text 
in order to match the rest of the string handling. It would be good to have a 
datatype that caused a parameter to be bound as a blob, either a native byte 
array or some object that wraps an 8 bit string (Sql.BinaryString?) in order to 
cause the binding to act accordingly.

Of course, this causes a compatibility problem for anyone who was using pike 
binding with bindings previously (is there anyone who us doing this and hasn’t 
run into this problem?), as any 8-bit strings that weren’t binary data would be 
stored as blobs, even if they were in a text typed field. These records would 
need to be re-stored with the proper text type, which could be done with a 
query to update the table. My sense is that this is the proper thing to do, as 
blob fields should be reserved for data that’s actually binary data (as opposed 
to text).

Thoughts?

Reply via email to