But that is the point.  Strings are generally defined in two ways.
Either:

1) a pointer, and count every byte up to but not including a NUL.

2) a pointer and a length, and count every byte in the specified length.

If you have a specified length, the length matters, and NULs do not.
NUL is a perfectly valid character in such a string.

Internally, SQLite uses counted strings.  It should treat NUL as just
one more character, since it is just one more character.

If a USER decides to use a negative length in sqlite3_bind_text() and
to use sqlite3_column_text() without using sqlite3_column_bytes(),
then that user's database doesn't have NULs in the strings, and
everything just works for him.  For the database as a whole to ASSUME
this breaks SQLite for users who do want NULs in their text data.

Actually, I guess I am more concerned with the "shell".  I use blob
columns that are partly text and would like to have the text portions
at least be visible.

I suspect that at least part of this problem came from SQLite's
history as a TCL add-on.  I suspect TCL, at least in it's early days,
didn't allow NUL in a string.

--David Garfield



Richard Hipp writes:
> On Thu, Sep 22, 2011 at 7:53 PM, David Garfield <
> garfi...@irving.iisd.sra.com> wrote:
> 
> > As far as I am concerned, this is a SERIOUS bug in sqlite.
> 
> 
> SQLite does whatever you ask it to do.  It makes no attempt to enforce good
> string hygiene.  If you hand it well-formed strings, it gives the expected
> results and always returning well-formed strings.  If, on the other hand,
> you give it malformed strings with embedded NULs and/or illegal UTF
> characters, SQLite will muddle through as best it can using whatever you
> gave it, without complaining, and without overflowing buffers or segfaulting
> or leaking memory or otherwise failing.  This is an intentional feature, not
> a bug.
> 
> 
> 
> 
> >  When you
> > have counted strings, which is all sqlite has (except for some API
> > functions), NULs have no special meaning.  This is fairly easily seen
> > in the command line interface, where the code ignores the length and
> > uses strlen forms.
> >
> > Testing various functions:
> >
> > hex(), relational operators, and group by get it right.  max() and
> > min() seem to get it right (but I may not have tested enough).
> >
> > length(), quote(), upper(), lower(), like(), and glob() get it wrong.
> > group_concat() gets it wrong returning the result, but looks like it
> > may have built the right thing internally.
> >
> > replace(), trim(), ltrim(), rtrim() get it right in the first
> > parameter, but not in the second parameter.  replace() gets it right
> > in the third parameter.
> >
> > I'm not sure what else would be expected to allow NULs, so I didn't
> > try numeric and date/time functions.
> >
> > Testing can be a bit of a pain.  Things like:
> >
> > BEGIN TRANSACTION;
> > CREATE TABLE t(a);
> > insert into t values (cast(x'6F6E65202020' as text));
> > insert into t values (cast(x'6F6E6520202030' as text));
> > insert into t values (cast(x'6F6E6520202000' as text));
> > insert into t values (cast(x'6F6E6520202078' as text));
> > insert into t values (cast(x'6F6E650074776F20' as text));
> > insert into t values (cast(x'20006F6E6520' as text));
> > insert into t values (cast(x'00206F6E6520' as text));
> > COMMIT;
> > .mode column
> > .width 10 20 20 20
> > .header on
> > select a, hex(a), hex(trim(a)), hex(trim(a,'one'||x'2000')) from t;
> >
> > Yields:
> >
> > a           hex(a)                hex(trim(a))
> >  hex(trim(a,'one'||x'
> > ----------  --------------------  --------------------
> >  --------------------
> > one         6F6E65202020          6F6E65
> > one   0     6F6E6520202030        6F6E6520202030        30
> > one         6F6E6520202000        6F6E6520202000        00
> > one   x     6F6E6520202078        6F6E6520202078        78
> > one         6F6E650074776F20      6F6E650074776F        007477
> >            20006F6E6520          006F6E65              00
> >            00206F6E6520          00206F6E65            00
> >
> > What I expect (including column screw-ups because NUL is zero width in
> > xterm) is:
> >
> > a           hex(a)                hex(trim(a))
> >  hex(trim(a,'one'||x'
> > ----------  --------------------  --------------------
> >  --------------------
> > one         6F6E65202020          6F6E65
> > one   0     6F6E6520202030        6F6E6520202030        30
> > one        6F6E6520202000        6F6E6520202000
> > one   x     6F6E6520202078        6F6E6520202078        78
> > onetwo     6F6E650074776F20      6F6E650074776F        7477
> >  two       20006F6E6520          006F6E65
> >  two       00206F6E6520          00206F6E65
> >
> >
> > Without the hex() calls, you can't even tell what worked and what didn't.
> >
> > --David Garfield
> >
> > Mira Suk writes:
> > > On 9/21/2011 21:22 Igor Tandetnik wrote:
> > >
> > > > You can include the NUL terminator, if you want it to actually be
> > stored
> > > > in the database.
> > >
> > > > Igor Tandetnik
> > >
> > > Actually you can't - if you do all SQL string functions will not work.
> > > to be clear -
> > > SELECT TRIM(what ever text column you stored with including null on end
> > of string)
> > > will not trim that string.
> > >
> > > found out the hard way.
> > >
> > > _______________________________________________
> > > sqlite-users mailing list
> > > sqlite-users@sqlite.org
> > > http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
> >
> > _______________________________________________
> > sqlite-users mailing list
> > sqlite-users@sqlite.org
> > http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users
> >
> 
> 
> 
> -- 
> D. Richard Hipp
> d...@sqlite.org
> _______________________________________________
> sqlite-users mailing list
> sqlite-users@sqlite.org
> http://sqlite.org:8080/cgi-bin/mailman/listinfo/sqlite-users

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

Reply via email to