emacs-diffs
[Top][All Lists]
Advanced

[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 ('f‚o', 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) ("f‚o" 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



reply via email to

[Prev in Thread] Current Thread [Next in Thread]