mirror of
https://git.savannah.gnu.org/git/emacs.git
synced 2024-11-30 08:09:04 +00:00
Allow inserting and selecting binary blobs from sqlite
* doc/lispref/text.texi (Database): Document how to insert binary data. * src/sqlite.c (bind_values): Bind BLOB columns correctly (bug#54591).
This commit is contained in:
parent
613aa18945
commit
5d032f2904
@ -5309,6 +5309,24 @@ interpolation).
|
||||
@code{sqlite-execute} returns the number of affected rows. For
|
||||
instance, an @samp{insert} statement will return @samp{1}, whereas an
|
||||
@samp{update} statement may return zero or a higher number.
|
||||
|
||||
Strings in SQLite are, by default, stored as @code{utf-8}, and
|
||||
selecting a text column will decode the string using that charset.
|
||||
Selecting a blob column will return the raw data without any decoding
|
||||
(i.e., it will return a unibyte string containing the bytes as stored
|
||||
in the database). Inserting binary data into blob columns, however,
|
||||
requires some care, as @code{sqlite-execute} will, by default,
|
||||
interpret all strings as @code{utf-8}.
|
||||
|
||||
So if you have, for instance, @acronym{GIF} data in a unibyte string
|
||||
called @var{gif}, you have to mark it specially to let
|
||||
@code{sqlite-execute} know this:
|
||||
|
||||
@lisp
|
||||
(put-text-property 0 1 'coding-system 'binary gif)
|
||||
(sqlite-execute db "insert into foo values (?, ?)" (list gif 2))
|
||||
@end lisp
|
||||
|
||||
@end defun
|
||||
|
||||
@defun sqlite-select db query &optional values result-type
|
||||
|
49
src/sqlite.c
49
src/sqlite.c
@ -43,6 +43,8 @@ DEF_DLL_FN (SQLITE_API int, sqlite3_open_v2,
|
||||
DEF_DLL_FN (SQLITE_API int, sqlite3_reset, (sqlite3_stmt*));
|
||||
DEF_DLL_FN (SQLITE_API int, sqlite3_bind_text,
|
||||
(sqlite3_stmt*, int, const char*, int, void(*)(void*)));
|
||||
DEF_DLL_FN (SQLITE_API int, sqlite3_bind_blob,
|
||||
(sqlite3_stmt*, int, const char*, int, void(*)(void*)));
|
||||
DEF_DLL_FN (SQLITE_API int, sqlite3_bind_int64,
|
||||
(sqlite3_stmt*, int, sqlite3_int64));
|
||||
DEF_DLL_FN (SQLITE_API int, sqlite3_bind_double, (sqlite3_stmt*, int, double));
|
||||
@ -80,6 +82,7 @@ DEF_DLL_FN (SQLITE_API int, sqlite3_load_extension,
|
||||
# undef sqlite3_open_v2
|
||||
# undef sqlite3_reset
|
||||
# undef sqlite3_bind_text
|
||||
# undef sqlite3_bind_blob
|
||||
# undef sqlite3_bind_int64
|
||||
# undef sqlite3_bind_double
|
||||
# undef sqlite3_bind_null
|
||||
@ -103,6 +106,7 @@ DEF_DLL_FN (SQLITE_API int, sqlite3_load_extension,
|
||||
# define sqlite3_open_v2 fn_sqlite3_open_v2
|
||||
# define sqlite3_reset fn_sqlite3_reset
|
||||
# define sqlite3_bind_text fn_sqlite3_bind_text
|
||||
# define sqlite3_bind_blob fn_sqlite3_bind_blob
|
||||
# define sqlite3_bind_int64 fn_sqlite3_bind_int64
|
||||
# define sqlite3_bind_double fn_sqlite3_bind_double
|
||||
# define sqlite3_bind_null fn_sqlite3_bind_null
|
||||
@ -129,6 +133,7 @@ load_dll_functions (HMODULE library)
|
||||
LOAD_DLL_FN (library, sqlite3_open_v2);
|
||||
LOAD_DLL_FN (library, sqlite3_reset);
|
||||
LOAD_DLL_FN (library, sqlite3_bind_text);
|
||||
LOAD_DLL_FN (library, sqlite3_bind_blob);
|
||||
LOAD_DLL_FN (library, sqlite3_bind_int64);
|
||||
LOAD_DLL_FN (library, sqlite3_bind_double);
|
||||
LOAD_DLL_FN (library, sqlite3_bind_null);
|
||||
@ -309,10 +314,37 @@ bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object values)
|
||||
|
||||
if (EQ (type, Qstring))
|
||||
{
|
||||
Lisp_Object encoded = encode_string (value);
|
||||
ret = sqlite3_bind_text (stmt, i + 1,
|
||||
SSDATA (encoded), SBYTES (encoded),
|
||||
NULL);
|
||||
Lisp_Object encoded;
|
||||
bool blob = false;
|
||||
|
||||
if (SBYTES (value) == 0)
|
||||
encoded = value;
|
||||
else
|
||||
{
|
||||
Lisp_Object coding_system =
|
||||
Fget_text_property (make_fixnum (0), Qcoding_system, value);
|
||||
if (NILP (coding_system))
|
||||
/* Default to utf-8. */
|
||||
encoded = encode_string (value);
|
||||
else if (EQ (coding_system, Qbinary))
|
||||
blob = true;
|
||||
else
|
||||
encoded = Fencode_coding_string (value, coding_system,
|
||||
Qnil, Qnil);
|
||||
}
|
||||
|
||||
if (blob)
|
||||
{
|
||||
if (SBYTES (value) != SCHARS (value))
|
||||
xsignal1 (Qerror, build_string ("BLOB values must be unibyte"));
|
||||
ret = sqlite3_bind_blob (stmt, i + 1,
|
||||
SSDATA (value), SBYTES (value),
|
||||
NULL);
|
||||
}
|
||||
else
|
||||
ret = sqlite3_bind_text (stmt, i + 1,
|
||||
SSDATA (encoded), SBYTES (encoded),
|
||||
NULL);
|
||||
}
|
||||
else if (EQ (type, Qinteger))
|
||||
{
|
||||
@ -426,11 +458,8 @@ row_to_value (sqlite3_stmt *stmt)
|
||||
break;
|
||||
|
||||
case SQLITE_BLOB:
|
||||
v =
|
||||
code_convert_string_norecord
|
||||
(make_unibyte_string (sqlite3_column_blob (stmt, i),
|
||||
sqlite3_column_bytes (stmt, i)),
|
||||
Qutf_8, false);
|
||||
v = make_unibyte_string (sqlite3_column_blob (stmt, i),
|
||||
sqlite3_column_bytes (stmt, i));
|
||||
break;
|
||||
|
||||
case SQLITE_NULL:
|
||||
@ -748,4 +777,6 @@ syms_of_sqlite (void)
|
||||
DEFSYM (Qfalse, "false");
|
||||
DEFSYM (Qsqlite, "sqlite");
|
||||
DEFSYM (Qsqlite3, "sqlite3");
|
||||
DEFSYM (Qbinary, "binary");
|
||||
DEFSYM (Qcoding_system, "coding-system");
|
||||
}
|
||||
|
@ -216,4 +216,29 @@
|
||||
db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable.so")
|
||||
'(nil t)))))
|
||||
|
||||
(ert-deftest sqlite-blob ()
|
||||
(skip-unless (sqlite-available-p))
|
||||
(let (db)
|
||||
(progn
|
||||
(setq db (sqlite-open))
|
||||
(sqlite-execute
|
||||
db "create table if not exists test10 (col1 text, col2 blob, col3 numbre)")
|
||||
(let ((string (with-temp-buffer
|
||||
(set-buffer-multibyte nil)
|
||||
(insert 0 1 2)
|
||||
(buffer-string))))
|
||||
(should-not (multibyte-string-p string))
|
||||
(sqlite-execute
|
||||
db "insert into test10 values (?, ?, 1)"
|
||||
(list string
|
||||
(propertize string
|
||||
'coding-system 'binary)))
|
||||
(cl-destructuring-bind
|
||||
(c1 c2 _)
|
||||
(car (sqlite-select db "select * from test10 where col3 = 1"))
|
||||
(should (equal c1 string))
|
||||
(should (equal c2 string))
|
||||
(should (multibyte-string-p c1))
|
||||
(should-not (multibyte-string-p c2)))))))
|
||||
|
||||
;;; sqlite-tests.el ends here
|
||||
|
Loading…
Reference in New Issue
Block a user