From 3d38d1d1345aa65c4018b42e6c648606e32216f8 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 11 Dec 2021 04:55:57 +0100 Subject: Add sqlite3 support to Emacs * configure.ac: Add check for the sqlite library. * doc/lispref/text.texi (Database): Document it. * lisp/sqlite.el: New file. * lisp/term/w32-win.el (dynamic-library-alist): Add a mapping. * src/Makefile.in (SQLITE3_LIBS): Add the libraries. * src/alloc.c (union emacs_align_type): Add a Lisp_Sqlite struct. * src/data.c (Ftype_of): Add sqlite. * src/emacs.c (main): Load the syms. * src/lisp.h (DEFINE_GDB_SYMBOL_BEGIN): Add PVEC_SQLITE. (GCALIGNED_STRUCT): New struct to keep data for sqlite database objects and statement objects. (SQLITEP, SQLITE, CHECK_SQLITE, XSQLITE): New macros for accessing the objects. * src/pdumper.c (dump_vectorlike): Update hash. (dump_vectorlike): Don't dump it. * src/print.c (print_vectorlike): Add a printer for the sqlite object. * src/sqlite.c: New file. * test/src/sqlite-tests.el: Add tests. --- test/src/sqlite-tests.el | 175 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 175 insertions(+) create mode 100644 test/src/sqlite-tests.el (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el new file mode 100644 index 00000000000..3fffa0100ba --- /dev/null +++ b/test/src/sqlite-tests.el @@ -0,0 +1,175 @@ +;;; sqlite-tests.el --- Tests for sqlite.el -*- lexical-binding: t; -*- + +;; Copyright (C) 2021 Free Software Foundation, Inc. + +;; This file is part of GNU Emacs. + +;; GNU Emacs is free software: you can redistribute it and/or modify +;; it under the terms of the GNU General Public License as published by +;; the Free Software Foundation, either version 3 of the License, or +;; (at your option) any later version. + +;; GNU Emacs is distributed in the hope that it will be useful, +;; but WITHOUT ANY WARRANTY; without even the implied warranty of +;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +;; GNU General Public License for more details. + +;; You should have received a copy of the GNU General Public License +;; along with GNU Emacs. If not, see . + +;;; Commentary: + +;; + +;;; Code: + +(require 'ert) +(require 'ert-x) + +(ert-deftest sqlite-select () + (skip-unless (sqlite-available-p)) + (let ((db (sqlite-open))) + (should (eq (type-of db) 'sqlite)) + (should (sqlitep db)) + (should-not (sqlitep 'foo)) + + (should + (zerop + (sqlite-execute + db "create table if not exists test1 (col1 text, col2 integer, col3 float, col4 blob)"))) + + (should-error + (sqlite-execute + db "insert into test1 (col1, col2, col3, col4) values ('foo', 2, 9.45, 'bar', 'zot')")) + + (should + (= + (sqlite-execute + db "insert into test1 (col1, col2, col3, col4) values ('foo', 2, 9.45, 'bar')") + 1)) + + (should + (equal + (sqlite-select db "select * from test1" nil 'full) + '(("col1" "col2" "col3" "col4") ("foo" 2 9.45 "bar")))))) + +;; (setq db (sqlite-open)) + +(ert-deftest sqlite-set () + (skip-unless (sqlite-available-p)) + (let ((db (sqlite-open)) + set) + (should + (zerop + (sqlite-execute + db "create table if not exists test1 (col1 text, col2 integer)"))) + + (should + (= + (sqlite-execute db "insert into test1 (col1, col2) values ('foo', 1)") + 1)) + (should + (= + (sqlite-execute db "insert into test1 (col1, col2) values ('bar', 2)") + 1)) + + (setq set (sqlite-select db "select * from test1" nil 'set)) + (should (sqlitep set)) + (should (sqlite-more-p set)) + (should (equal (sqlite-next set) + '("foo" 1))) + (should (equal (sqlite-next set) + '("bar" 2))) + (should-not (sqlite-next set)) + (should-not (sqlite-more-p set)))) + +(ert-deftest sqlite-chars () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (sqlite-execute + db "create table if not exists test2 (col1 text, col2 integer)") + (sqlite-execute + db "insert into test2 (col1, col2) values ('fóo', 3)") + (sqlite-execute + db "insert into test2 (col1, col2) values ('fó‚o', 3)") + (sqlite-execute + db "insert into test2 (col1, col2) values ('f‚o', 4)") + (should + (equal (sqlite-select db "select * from test2" nil 'full) + '(("col1" "col2") ("fóo" 3) ("fó‚o" 3) ("f‚o" 4)))))) + +(ert-deftest sqlite-numbers () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (sqlite-execute + db "create table if not exists test3 (col1 integer)") + (let ((big (expt 2 50)) + (small (expt 2 10))) + (sqlite-execute db (format "insert into test3 values (%d)" small)) + (sqlite-execute db (format "insert into test3 values (%d)" big)) + (should + (equal + (sqlite-select db "select * from test3") + (list (list small) (list big))))))) + +(ert-deftest sqlite-param () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (sqlite-execute + db "create table if not exists test4 (col1 text, col2 number)") + (sqlite-execute db "insert into test4 values (?, ?)" (list "foo" 1)) + (should + (equal + (sqlite-select db "select * from test4 where col2 = ?" '(1)) + '(("foo" 1)))) + (should + (equal + (sqlite-select db "select * from test4 where col2 = ?" [1]) + '(("foo" 1)))))) + +(ert-deftest sqlite-binary () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (sqlite-execute + db "create table if not exists test5 (col1 text, col2 number)") + (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 test5 values (?, ?)" (list string 2)) + (let ((out (caar + (sqlite-select db "select col1 from test5 where col2 = 2")))) + (should (equal out string)))))) + +(ert-deftest sqlite-different-dbs () + (skip-unless (sqlite-available-p)) + (let (db1 db2) + (setq db1 (sqlite-open)) + (setq db2 (sqlite-open)) + (sqlite-execute + db1 "create table if not exists test6 (col1 text, col2 number)") + (sqlite-execute + db2 "create table if not exists test6 (col1 text, col2 number)") + (sqlite-execute + db1 "insert into test6 values (?, ?)" '("foo" 2)) + (should (sqlite-select db1 "select * from test6")) + (should-not (sqlite-select db2 "select * from test6")))) + +(ert-deftest sqlite-close-dbs () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (sqlite-execute + db "create table if not exists test6 (col1 text, col2 number)") + (sqlite-execute db "insert into test6 values (?, ?)" '("foo" 2)) + (should (sqlite-select db "select * from test6")) + (sqlite-close db) + (should-error (sqlite-select db "select * from test6")))) + +;;; sqlite-tests.el ends here -- cgit v1.2.1 From 385f2faf347b18eb4624f97020a49ae7e3f315e2 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 11 Dec 2021 06:26:37 +0100 Subject: Fix some sqlite doc string typos * src/sqlite.c (Fsqlite_load_extension, Fsqlite_more_p): Fix typos in doc strings. --- test/src/sqlite-tests.el | 2 -- 1 file changed, 2 deletions(-) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 3fffa0100ba..412ea291893 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -53,8 +53,6 @@ (sqlite-select db "select * from test1" nil 'full) '(("col1" "col2" "col3" "col4") ("foo" 2 9.45 "bar")))))) -;; (setq db (sqlite-open)) - (ert-deftest sqlite-set () (skip-unless (sqlite-available-p)) (let ((db (sqlite-open)) -- cgit v1.2.1 From 17569c94954dc1d9d47155a8ca987d8ff4855180 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Sat, 11 Dec 2021 07:47:34 +0100 Subject: Fix Fsqlite_finalize book-keeping * src/sqlite.c (Fsqlite_finalize): Mark the object as dead. --- test/src/sqlite-tests.el | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 412ea291893..7ccea1c2a54 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -79,7 +79,9 @@ (should (equal (sqlite-next set) '("bar" 2))) (should-not (sqlite-next set)) - (should-not (sqlite-more-p set)))) + (should-not (sqlite-more-p set)) + (sqlite-finalize set) + (should-error (sqlite-next set)))) (ert-deftest sqlite-chars () (skip-unless (sqlite-available-p)) -- cgit v1.2.1 From 8e948ab97ebc74245064fdb8467342abb7fe2bb3 Mon Sep 17 00:00:00 2001 From: dick r. chiang Date: Sun, 12 Dec 2021 07:13:37 +0100 Subject: Fix some compilation warnings in sqlite-less builds * test/src/sqlite-tests.el: * lisp/sqlite-mode.el: Avoid compilation warnings in builds without libsqlite (bug#52440). --- test/src/sqlite-tests.el | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 7ccea1c2a54..6a88f0fd6ca 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -26,6 +26,16 @@ (require 'ert) (require 'ert-x) +(declare-function sqlite-execute "sqlite.c") +(declare-function sqlite-close "sqlite.c") +(declare-function sqlitep "sqlite.c") +(declare-function sqlite-available-p "sqlite.c") +(declare-function sqlite-finalize "sqlite.c") +(declare-function sqlite-next "sqlite.c") +(declare-function sqlite-more-p "sqlite.c") +(declare-function sqlite-select "sqlite.c") +(declare-function sqlite-open "sqlite.c") + (ert-deftest sqlite-select () (skip-unless (sqlite-available-p)) (let ((db (sqlite-open))) -- cgit v1.2.1 From 8c0f9be0d1ace6437d4c604b9af79b7b0006dec4 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Tue, 14 Dec 2021 09:29:06 +0100 Subject: Only allow SQLite extensions from an allowlist * src/sqlite.c (Fsqlite_load_extension): Only allow extensions from an allowlist. --- test/src/sqlite-tests.el | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 6a88f0fd6ca..d1076e481c4 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -182,4 +182,36 @@ (sqlite-close db) (should-error (sqlite-select db "select * from test6")))) +(ert-deftest sqlite-load-extension () + (skip-unless (sqlite-available-p)) + (let (db) + (setq db (sqlite-open)) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/notpcre.so")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/n")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3/")) + (should-error + (sqlite-load-extension db "/usr/lib/sqlite3")) + (should + (memq + (sqlite-load-extension db "/usr/lib/sqlite3/pcre.so") + '(nil t))) + + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_notcsvtable.so")) + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtablen.so")) + (should-error + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable")) + (should + (memq + (sqlite-load-extension + db "/usr/lib/x86_64-linux-gnu/libsqlite3_mod_csvtable.so") + '(nil t))))) + ;;; sqlite-tests.el ends here -- cgit v1.2.1 From bc60ce7ffdf39fc3288938337e7f6c0706b37082 Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Thu, 16 Dec 2021 07:43:29 +0100 Subject: Skip extension tests on hosts without the function --- test/src/sqlite-tests.el | 1 + 1 file changed, 1 insertion(+) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index d1076e481c4..27ba74e9d23 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -184,6 +184,7 @@ (ert-deftest sqlite-load-extension () (skip-unless (sqlite-available-p)) + (skip-unless (fboundp 'sqlite-load-extension)) (let (db) (setq db (sqlite-open)) (should-error -- cgit v1.2.1 From 19206fd1e764cfe89234ae9245bafa88ef1ec354 Mon Sep 17 00:00:00 2001 From: Mattias Engdegård Date: Mon, 20 Dec 2021 17:13:09 +0100 Subject: Silence byte-compiler warnings from absent optional features * test/src/inotify-tests.el (inotify-rm-watch): * test/src/lcms-tests.el (lcms-xyz->jch): * test/src/sqlite-tests.el (sqlite-open): Add declarations to prevent byte-compilation warnings when features are absent. --- test/src/sqlite-tests.el | 1 + 1 file changed, 1 insertion(+) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 27ba74e9d23..d7100537a4e 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -35,6 +35,7 @@ (declare-function sqlite-more-p "sqlite.c") (declare-function sqlite-select "sqlite.c") (declare-function sqlite-open "sqlite.c") +(declare-function sqlite-load-extension "sqlite.c") (ert-deftest sqlite-select () (skip-unless (sqlite-available-p)) -- cgit v1.2.1 From 823b6b8d260e6e5bc0c428c9b3d92b6822624761 Mon Sep 17 00:00:00 2001 From: Eli Zaretskii Date: Sat, 1 Jan 2022 07:07:15 -0500 Subject: ; Add 2022 to copyright years. --- test/src/sqlite-tests.el | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index d7100537a4e..6e44300f3ad 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -1,6 +1,6 @@ ;;; sqlite-tests.el --- Tests for sqlite.el -*- lexical-binding: t; -*- -;; Copyright (C) 2021 Free Software Foundation, Inc. +;; Copyright (C) 2021-2022 Free Software Foundation, Inc. ;; This file is part of GNU Emacs. -- cgit v1.2.1 From 5d032f2904d4604110e24eb3ae0daf8f7701d72f Mon Sep 17 00:00:00 2001 From: Lars Ingebrigtsen Date: Thu, 28 Apr 2022 14:58:20 +0200 Subject: 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). --- test/src/sqlite-tests.el | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test/src/sqlite-tests.el') diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el index 6e44300f3ad..5af43923012 100644 --- a/test/src/sqlite-tests.el +++ b/test/src/sqlite-tests.el @@ -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 -- cgit v1.2.1