emacs-diffs
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

master 7e7dc74ffb: Support "insert into ... returning ..." in sqlite-exe


From: Lars Ingebrigtsen
Subject: master 7e7dc74ffb: Support "insert into ... returning ..." in sqlite-execute
Date: Mon, 10 Oct 2022 04:58:46 -0400 (EDT)

branch: master
commit 7e7dc74ffbab5eac863657ef719e9f47165708b3
Author: Lars Ingebrigtsen <larsi@gnus.org>
Commit: Lars Ingebrigtsen <larsi@gnus.org>

    Support "insert into ... returning ..." in sqlite-execute
    
    * doc/lispref/text.texi (Database): Mention it.
    * src/sqlite.c (Fsqlite_execute): Support syntax like "insert into
    ... returning ..." (bug#58390).
---
 doc/lispref/text.texi |   9 ++--
 src/sqlite.c          | 120 +++++++++++++++++++++++++++-----------------------
 2 files changed, 70 insertions(+), 59 deletions(-)

diff --git a/doc/lispref/text.texi b/doc/lispref/text.texi
index 8b859042ad..e0768721d9 100644
--- a/doc/lispref/text.texi
+++ b/doc/lispref/text.texi
@@ -5321,9 +5321,12 @@ This has exactly the same effect as the previous 
example, but is more
 efficient and safer (because it doesn't involve any string parsing or
 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.
+@code{sqlite-execute} usually returns the number of affected rows.
+For instance, an @samp{insert} statement will typically return
+@samp{1}, whereas an @samp{update} statement may return zero or a
+higher number.  However, when using @acronym{SQL} statements like
+@samp{insert into ... returning ...} and the like, the values
+specified by @samp{returning ...} will be returned instead.
 
 Strings in SQLite are, by default, stored as @code{utf-8}, and
 selecting a text column will decode the string using that charset.
diff --git a/src/sqlite.c b/src/sqlite.c
index 7af3760eb4..65b1dc492f 100644
--- a/src/sqlite.c
+++ b/src/sqlite.c
@@ -377,6 +377,50 @@ bind_values (sqlite3 *db, sqlite3_stmt *stmt, Lisp_Object 
values)
   return NULL;
 }
 
+static Lisp_Object
+row_to_value (sqlite3_stmt *stmt)
+{
+  int len = sqlite3_column_count (stmt);
+  Lisp_Object values = Qnil;
+
+  for (int i = 0; i < len; ++i)
+    {
+      Lisp_Object v = Qnil;
+
+      switch (sqlite3_column_type (stmt, i))
+       {
+       case SQLITE_INTEGER:
+         v = make_int (sqlite3_column_int64 (stmt, i));
+         break;
+
+       case SQLITE_FLOAT:
+         v = make_float (sqlite3_column_double (stmt, i));
+         break;
+
+       case SQLITE_BLOB:
+         v = make_unibyte_string (sqlite3_column_blob (stmt, i),
+                                  sqlite3_column_bytes (stmt, i));
+         break;
+
+       case SQLITE_NULL:
+         v = Qnil;
+         break;
+
+       case SQLITE_TEXT:
+         v =
+           code_convert_string_norecord
+           (make_unibyte_string ((const char *)sqlite3_column_text (stmt, i),
+                                 sqlite3_column_bytes (stmt, i)),
+            Qutf_8, false);
+         break;
+       }
+
+      values = Fcons (v, values);
+    }
+
+  return Fnreverse (values);
+}
+
 DEFUN ("sqlite-execute", Fsqlite_execute, Ssqlite_execute, 2, 3, 0,
        doc: /* Execute a non-select SQL statement.
 If VALUES is non-nil, it should be a vector or a list of values
@@ -393,7 +437,6 @@ Value is the number of affected rows.  */)
     xsignal1 (Qerror, build_string ("VALUES must be a list or a vector"));
 
   sqlite3 *sdb = XSQLITE (db)->db;
-  Lisp_Object retval = Qnil;
   const char *errmsg = NULL;
   Lisp_Object encoded = encode_string (query);
   sqlite3_stmt *stmt = NULL;
@@ -426,66 +469,31 @@ Value is the number of affected rows.  */)
     }
 
   ret = sqlite3_step (stmt);
-  sqlite3_finalize (stmt);
-  if (ret != SQLITE_OK && ret != SQLITE_DONE)
-    {
-      errmsg = sqlite3_errmsg (sdb);
-      goto exit;
-    }
 
-  retval = make_fixnum (sqlite3_changes (sdb));
-
- exit:
-  if (errmsg != NULL)
-    xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY?
-             Qsqlite_locked_error: Qerror,
-             build_string (errmsg));
-
-  return retval;
-}
-
-static Lisp_Object
-row_to_value (sqlite3_stmt *stmt)
-{
-  int len = sqlite3_column_count (stmt);
-  Lisp_Object values = Qnil;
-
-  for (int i = 0; i < len; ++i)
+  if (ret == SQLITE_ROW)
     {
-      Lisp_Object v = Qnil;
-
-      switch (sqlite3_column_type (stmt, i))
-       {
-       case SQLITE_INTEGER:
-         v = make_int (sqlite3_column_int64 (stmt, i));
-         break;
-
-       case SQLITE_FLOAT:
-         v = make_float (sqlite3_column_double (stmt, i));
-         break;
+      Lisp_Object data = Qnil;
+      do
+       data = Fcons (row_to_value (stmt), data);
+      while (sqlite3_step (stmt) == SQLITE_ROW);
 
-       case SQLITE_BLOB:
-         v = make_unibyte_string (sqlite3_column_blob (stmt, i),
-                                  sqlite3_column_bytes (stmt, i));
-         break;
-
-       case SQLITE_NULL:
-         v = Qnil;
-         break;
-
-       case SQLITE_TEXT:
-         v =
-           code_convert_string_norecord
-           (make_unibyte_string ((const char *)sqlite3_column_text (stmt, i),
-                                 sqlite3_column_bytes (stmt, i)),
-            Qutf_8, false);
-         break;
-       }
-
-      values = Fcons (v, values);
+      sqlite3_finalize (stmt);
+      return Fnreverse (data);
     }
+  else if (ret == SQLITE_OK || ret == SQLITE_DONE)
+    {
+      Lisp_Object rows = make_fixnum (sqlite3_changes (sdb));
+      sqlite3_finalize (stmt);
+      return rows;
+    }
+  else
+    errmsg = sqlite3_errmsg (sdb);
 
-  return Fnreverse (values);
+ exit:
+  sqlite3_finalize (stmt);
+  xsignal1 (ret == SQLITE_LOCKED || ret == SQLITE_BUSY?
+           Qsqlite_locked_error: Qerror,
+           build_string (errmsg));
 }
 
 static Lisp_Object



reply via email to

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