[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
scratch/sqlite 3b762b3 1/3: Fix parametresised selects/executions
From: |
Lars Ingebrigtsen |
Subject: |
scratch/sqlite 3b762b3 1/3: Fix parametresised selects/executions |
Date: |
Tue, 7 Dec 2021 00:00:46 -0500 (EST) |
branch: scratch/sqlite
commit 3b762b3a387bd942092f4e4c481b0a93d5291ac4
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>
Fix parametresised selects/executions
---
src/sqlite.c | 53 +++++++++++++++++++++++++++++++++++++-----------
test/src/sqlite-tests.el | 28 +++++++++++++++++++++----
2 files changed, 65 insertions(+), 16 deletions(-)
diff --git a/src/sqlite.c b/src/sqlite.c
index 67e2a45..8bc9af2 100644
--- a/src/sqlite.c
+++ b/src/sqlite.c
@@ -88,12 +88,23 @@ static const char *
bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object values)
{
sqlite3_reset (stmt);
- int len = ASIZE (values);
+ int len;
+ if (VECTORP (values))
+ len = ASIZE (values);
+ else
+ len = XFIXNUM (Flength (values));
for (int i = 0; i < len; ++i)
{
int ret = SQLITE_MISMATCH;
- Lisp_Object value = AREF (values, i);
+ Lisp_Object value;
+ if (VECTORP (values))
+ value = AREF (values, i);
+ else
+ {
+ value = XCAR (values);
+ values = XCDR (values);
+ }
Lisp_Object type = Ftype_of (value);
if (EQ (type, Qstring))
@@ -139,6 +150,8 @@ The number of affected rows is returned. */)
{
CHECK_SQLITE (db);
CHECK_STRING (query);
+ if (!(NILP (values) || CONSP (values) || VECTORP (values)))
+ xsignal1 (Qerror, build_string ("VALUES must be a list or a vector"));
sqlite3 *sdb = XSQLITE (db)->db;
char *sql, *tail;
@@ -245,7 +258,7 @@ row_to_value (sqlite3_stmt *stmt)
values = Fcons (v, values);
}
- return Freverse (values);
+ return Fnreverse (values);
}
DEFUN ("sqlite-select", Fsqlite_select, Ssqlite_select, 2, 4, 0,
@@ -255,12 +268,19 @@ parametrised statement.
By default, the return value is a list where the first element is a
list of column names, and the rest of the elements are the matching data.
-If CURSOR is non-nil, an opaque object is returned instead that can
-be queried with `sqlite-next' and other functions to get the data. */)
- (Lisp_Object db, Lisp_Object query, Lisp_Object values, Lisp_Object cursor)
+
+RETURN-TYPE can be either nil (which means that the matching data
+should be returned as a list of rows), or `full' (the same, but the
+first element in the return list will be the column names), or `set',
+which means that we return a set object that can be queried with
+`sqlite-next' and other functions to get the data. */)
+ (Lisp_Object db, Lisp_Object query, Lisp_Object values,
+ Lisp_Object return_type)
{
CHECK_SQLITE (db);
CHECK_STRING (query);
+ if (!(NILP (values) || CONSP (values) || VECTORP (values)))
+ xsignal1 (Qerror, build_string ("VALUES must be a list or a vector"));
sqlite3 *sdb = XSQLITE (db)->db;
Lisp_Object retval = Qnil;
@@ -290,13 +310,17 @@ be queried with `sqlite-next' and other functions to get
the data. */)
/* Get the field names. */
Lisp_Object columns = Qnil;
- int count = sqlite3_column_count (stmt);
- for (int i = 0; i < count; ++i)
- columns = Fcons (build_string (sqlite3_column_name (stmt, i)), columns);
+ if (EQ (return_type, Qset)
+ || EQ (return_type, Qfull))
+ {
+ int count = sqlite3_column_count (stmt);
+ for (int i = 0; i < count; ++i)
+ columns = Fcons (build_string (sqlite3_column_name (stmt, i)), columns);
- columns = Fnreverse (columns);
+ columns = Fnreverse (columns);
+ }
- if (!NILP (cursor))
+ if (EQ (return_type, Qset))
{
retval = make_sqlite (true, db, stmt, columns);
goto exit;
@@ -307,7 +331,10 @@ be queried with `sqlite-next' and other functions to get
the data. */)
while ((ret = sqlite3_step (stmt)) == SQLITE_ROW)
data = Fcons (row_to_value (stmt), data);
- retval = Fcons (columns, Fnreverse (data));
+ if (EQ (return_type, Qfull))
+ retval = Fcons (columns, Fnreverse (data));
+ else
+ retval = Fnreverse (data);
sqlite3_finalize (stmt);
exit:
@@ -451,6 +478,8 @@ syms_of_sqlite (void)
defsubr (&Ssqlite_next);
defsubr (&Ssqlite_columns);
defsubr (&Ssqlite_more_p);
+ DEFSYM (Qset, "set");
+ DEFSYM (Qfull, "full");
#endif
defsubr (&Ssqlitep);
DEFSYM (Qsqlitep, "sqlitep");
diff --git a/test/src/sqlite-tests.el b/test/src/sqlite-tests.el
index 2a24625..808939b 100644
--- a/test/src/sqlite-tests.el
+++ b/test/src/sqlite-tests.el
@@ -52,7 +52,7 @@
(should
(equal
- (sqlite-select db "select * from test1")
+ (sqlite-select db "select * from test1" nil 'full)
'(("col1" "col2" "col3" "col4") ("foo" 2 9.45 "bar"))))))
;; (setq db (sqlite-open))
@@ -77,7 +77,7 @@
db "insert into test1 (col1, col2) values ('bar', 2)")
1))
- (setq set (sqlite-select db "select * from test1" nil t))
+ (setq set (sqlite-select db "select * from test1" nil 'set))
(should (sqlitep set))
(should (sqlite-more-p set))
(should
@@ -102,7 +102,7 @@
(sqlite-execute
db "insert into test2 (col1, col2) values ('fo', 4)")
(should
- (equal (sqlite-select db "select * from test2")
+ (equal (sqlite-select db "select * from test2" nil 'full)
'(("col1" "col2") ("fóo" 3) ("fóo" 3) ("fo" 4))))))
(ert-deftest sqlite-numbers ()
@@ -117,7 +117,27 @@
(sqlite-execute db (format "insert into test3 values (%d)" big))
(should
(equal
- (cdr (sqlite-select db "select * from test3"))
+ (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))))))
+
;;; sqlite-tests.el ends here