SQLite User Forum

CLI output truncates blob after zero byte in list mode
Login

CLI output truncates blob after zero byte in list mode

(1) By anonymous on 2026-04-20 16:57:09 [link] [source]

.mode list
.once |od -A n -t x1
SELECT x'610062';
 61 0a

(2.1) By Adrian Ho (lexfiend) on 2026-04-21 11:49:21 edited from 2.0 in reply to 1 [link] [source]

It's been discussed before: https://sqlite.org/forum/forumpost/5a67c4e3f3e31ffe

In short, you're asking the SQLite CLI to print a BLOB, which requires first converting it to a UTF-8 TEXT value, which in turn treats null bytes as string terminators.

(3) By David Jones (vman59) on 2026-04-21 09:32:12 in reply to 2.0 [link] [source]

Treating a zero byte as terminating the blob means you are interpreting the blob as UTF-8 (or a C-string in a non-Unicode format), actually converting it to UTF-8 would do things like render the zeros as U+2400 characters. Random binary data is generally an invalid UTF-8 stream (.i.e. bytes greater than 340 don't form into valid multi-byte sequences).

(4) By anonymous on 2026-04-21 12:21:51 in reply to 2.1 [link] [source]

SELECT x'610062';
61 0a

If for the blob x'6100..' it prints '61', then by the same token it should also print '00'. We're already in the domain of hex representation of byte values, so NULL byte is '00'.

(8.1) By Adrian Ho (lexfiend) on 2026-04-21 15:32:48 edited from 8.0 in reply to 4 [link] [source]

No, you're asking the CLI to print the equivalent of a\0b, so it dutifully prints the a, stops further processing when it sees the null byte, then prints a newline (0x0a) to end the output line.

You're seeing 61 0a because you're transforming the CLI's output into its hex equivalent (.once |od -A n -t x1).

(9) By anonymous on 2026-04-21 17:20:34 in reply to 8.1 [link] [source]

...so it dutifully prints the a, stops further processing when it sees the null byte

In case of a BLOB, the expectation is that the BLOB's size should determine the number of bytes to output, not the null-byte occurrence.

In this particular example the column type is BLOB, not TEXT:

sqlite> select typeof(x'610062');
blob

(10) By Richard Hipp (drh) on 2026-04-21 19:34:03 in reply to 9 [link] [source]

 the expectation is that ...

That is your expectation. It is not my expectation. My expectation is that the CLI will render query results in an human-readable format, and an ASCII NUL character is not normally considered human readable. The CLI will happily format your BLOB as hex or base64 or a host of other formats. But it won't output a zero byte.

Perhaps if you explain what it is you are actually trying to accomplish, we could suggest an alternative approach, that doesn't involve rewriting the entire CLI so that it outputs zero-blobs from BLOBs? Maybe the writefile() SQL function might be a better approach to achieving your goal.

(11) By anonymous on 2026-04-21 21:17:58 in reply to 10 [source]

In my opinion, truncating BLOBs on first NULL occurrence does not make them much more human-readable (BLOB starts with a NULL byte?, has only unprintable chars); nor does it represent all of the actual bytes of BLOB's value/content, which may be misleading.

If binary output from CLI is not desired for some reason, then, perhaps, printing some placeholder with blob's size to signal that the column value is a BLOB would be more consistent and less misleading.

For example,

> select x'610062';
blob(3)

This allows the user to further chose the representation, say, use hex() or some other way.

If, however, CLI is allowed to output raw bytes of BLOB column values (as it currently is), then it should not silently truncate them on first NULL byte. Such result may end up being surprising to users (such as OP), if not unexpected.

(12) By Stephan Beal (stephan) on 2026-04-21 22:02:18 in reply to 11 [link] [source]

If, however, CLI is allowed to output raw bytes of BLOB column values (as it currently is), then it should...

You are beating a dead horse here. This topic has been revisited many times before and the summary is that if one insists on emitting binary, and writefile() isn't suitable, they should write some C code to do it. The sqlite shell's maintainers have long expressed disinterest in adding special handling of nul bytes to the shell, which they consider to primarily be a tool for human interaction, not binary data.

(13) By Spindrift (spindrift) on 2026-04-22 06:03:22 in reply to 11 [link] [source]

So. What do you do if the value stored in the database was the text 'blob(3)' then?

Nothing prevents an explicit

select hex(x'610062');

Or base 64 or whatever.

Or even 'blob(' len(x'2345cc') ')'

But how is the cli meant to KNOW what YOU want unless you are explicit.

There is no universal blob to text mapping that works always. There are some that can be useful.

You're not winning this one, I think.

(5) By anonymous on 2026-04-21 13:03:28 in reply to 2.1 [link] [source]

you're asking the SQLite CLI to print a BLOB, which requires first converting it to a UTF-8 TEXT value

I'm explicitly asking SQLite for 3 bytes with a blob literal syntax to demonstrate a bug in the output. In some other scenario this could be an actual column with binary data say JPEG image that gets truncated right in the middle. I don't see how any of this would require UTF-8 conversion is this the way it's implemented right now? Also byte zero is still valid UTF-8

printf 'a\0b' | isutf8 && echo yes

(6) By userABCD on 2026-04-21 13:42:06 in reply to 2.1 [link] [source]

which requires first converting it to a UTF-8 TEXT value

The CLI doesn't do any text conversion. It is just using a C function to output a zero terminated string. In this case the string has an embedded null so it terminates early when it see it.

If the CLI used the length of the string, instead of zero termination, then the entire blob could be output without any problem.

(7) By anonymous on 2026-04-21 15:13:54 in reply to 6 [link] [source]

It is just using a C function to output a zero terminated string.

Well then it shouldn't :)

Imagine if /bin/cat worked this way.

(14) By Richard Hipp (drh) on 2026-04-22 12:26:42 in reply to 1 [link] [source]

With the latest trunk check-in, you can get BLOB output sent to stdout, preserving zero bytes, using:

.mode list --escape off --rowsep ''

So, for example, if the script x1.sql is:

CREATE TABLE t1(id INTEGER PRIMARY KEY, data);
INSERT INTO t1 VALUES(1, x'6162630078797a');
.mode list --escape off --rowsep ''
SELECT data FROM t1 WHERE id=1;

And you run: "sqlite3 x1.sql | od -c", the output will be:

0000000   a   b   c  \0   x   y   z
0000007

(15) By anonymous on 2026-04-25 16:57:53 in reply to 14 [link] [source]

Thank you for the fix. Now it works in other modes as well and even allows mixing with strings as long as final result is blob:

.mode markdown --escape symbol
SELECT CAST('a' || x'00' || 'b' AS BLOB) AS res;
| res |
|-----|
| a␀b |

Very cool!