emacs-elpa-diffs
[Top][All Lists]
Advanced

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

[nongnu] elpa/sqlite3 a51467b031 04/62: added test for Emacs 25.1


From: ELPA Syncer
Subject: [nongnu] elpa/sqlite3 a51467b031 04/62: added test for Emacs 25.1
Date: Tue, 14 Mar 2023 11:01:44 -0400 (EDT)

branch: elpa/sqlite3
commit a51467b0318359bd56ad925fa327b959f912acee
Author: Y. N. Lo <gordonynlo@yahoo.com>
Commit: Y. N. Lo <gordonynlo@yahoo.com>

    added test for Emacs 25.1
---
 .gitignore                                    |   8 +
 Makefile                                      |  20 ++-
 README.md => README-in.md                     | 159 ++++++++++--------
 README.md                                     | 198 ++++++++++++++---------
 regression.el                                 |  17 +-
 sqlite3-napi.el => sqlite3-api-constants.el   |  16 +-
 sqlite3-napi-module.c => sqlite3-api-module.c | 223 ++++++++++++--------------
 sqlite3-api.el                                |  20 +++
 sqlite3-napi-module.so                        | Bin 31944 -> 0 bytes
 tools/gen-consts.py                           |   3 +-
 tools/run.sh                                  |  26 ++-
 11 files changed, 418 insertions(+), 272 deletions(-)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000000..b800ee7c50
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,8 @@
+*.o
+*.so
+**/.DS_Store
+sqlite3-napi-module-with-create-function.c
+README-in.md
+xxx.el
+tools/def.c
+tools/def
\ No newline at end of file
diff --git a/Makefile b/Makefile
index 6583693de4..d3c714837f 100644
--- a/Makefile
+++ b/Makefile
@@ -1,11 +1,16 @@
 CC = gcc
 CFLAGS = -g3 -Wall -std=c99
-EMACS=$(HOME)/test-emacs/bin/emacs
+EMACS252=$(HOME)/test-emacs/bin/emacs
+EMACS251=$(HOME)/test-emacs-251/bin/emacs
+MODULE=sqlite3-api-module.so
 
-all: sqlite3-napi-module.so
+all: $(MODULE) misc
 
 clean:
-       rm -f *.so
+       rm -f *.so *.o
+
+misc:
+       (cd tools; ./run.sh)
 
 %.so: %.o
        $(CC) -shared -o $@ $< -lsqlite3
@@ -13,5 +18,10 @@ clean:
 %.o: %.c
        $(CC) $(CFLAGS) -fPIC -c $<
 
-test:
-       $(EMACS) -batch -Q -l regression.el
+# Emacs 25.2
+test: $(MODULE)
+       $(EMACS252) -batch -Q -l regression.el
+
+# Emacs 25.1
+test251: $(MODULE)
+       $(EMACS251) -batch -Q -l regression.el
diff --git a/README.md b/README-in.md
similarity index 50%
copy from README.md
copy to README-in.md
index 61458c10be..f66f5a1de4 100644
--- a/README.md
+++ b/README-in.md
@@ -1,63 +1,79 @@
-# SQLite3 Native API for Emacs 25+
-sqlite-napi is a dynamic module for GNU Emacs that provides 
-direct access to the SQLite3 C API.
-## Usage
-~~~el
-(require 'sqlite3-napi)
-
-(let ((dbh)
-      (stmt))
-  (unwind-protect
-      (progn
-       (setq dbh (sqlite3-open "/path/to/db"
-                               (logior sqlite-open-readwrite
-                                       sqlite-open-create)))
-       (setq stmt (sqlite3-prepare dbh "select * from some_table"))
-       (while (= sqlite-row (sqlite3-step stmt))
-         (cl-loop for i from 0 to (1- (sqlite3-column-count stmt)) do
-                  (message "Column #%d: %s => %s" i
-                           (sqlite3-column-name stmt i)
-                           (sqlite3-column-text stmt i)))))
-    ;; Clean up
-    (sqlite3-finalize stmt)
-    (sqlite3-close dbh)))
-~~~
-This is alpha software and might crash your Emacs. Save your work before
-trying it out.
+# SQLite3 API for Emacs 25+
+`sqlite3-api` is a dynamic module for GNU Emacs 25+ that provides 
+direct access to the core SQLite3 C API from Emacs Lisp.
+~~~el
+(require 'sqlite3-api)
+
+(setq dbh (sqlite3-open "person.sqlite3" sqlite-open-readwrite 
sqlite-open-create))
+(sqlite3-exec dbh "create table temp (name text, age integer)")
+(sqlite3-exec dbh "begin") ;; begin transaction
+(setq stmt (sqlite3-prepare dbh "insert into temp values (?,?)"))
+(cl-loop for i from 1 to 10 do
+        (sqlite3-bind-multi stmt (format "name%d" i) i)
+         ;; execute the SQL
+        (sqlite3-step stmt)
+        ;; call reset if you want to bind the SQL to a new set of variables
+        (sqlite3-reset stmt) )
+(sqlite3-exec dbh "commit")
+(sqlite3-finalize stmt)
+
+(setq stmt (sqlite3-prepare dbh "select * from temp"))
+(while (= sqlite-row (sqlite3-step stmt))
+  (cl-destructuring-bind (name age) (sqlite3-fetch stmt)
+    (message "name: %s, age: %d" name age)))
+(sqlite3-finalize stmt)
+(sqlite3-close dbh)
+~~~
+While this module provides only 14 functions (vs 200+ in the C API), it should 
satisfy most
+users' needs.
 
+This is an alpha release and it might crash your Emacs. Save your work before 
you try it out!
+
+<<TOC>>
 ## Requirements
-- Emacs 25.1 or above, compiled with module support (`--with-modules`)
+- Emacs 25.1 or above, compiled with module support (`./configure 
--with-modules`)
 - sqlite3 library and header file
-- C compiler
+- A C99 compiler
+
+It's been tested on macOS Sierra) and CentOS 7.
 ## Installation
 ~~~sh
-$ git co https://github.com/pekingduck/sqlite3-napi
-$ cd sqlite3-napi
+$ git co https://github.com/pekingduck/emacs-sqlite3-api
+$ cd emacs-sqlite3-api
 $ make
-$ cp sqlite3-napi.el sqlite3-napi-module.so /your/elisp/load-path/
+$ cp sqlite3-api.el sqlite3-api-constants.el sqlite3-api-module.so 
/your/elisp/load-path/
 ~~~
-Once the code stabilizes I will make it available on melpa.
-## Constants
-These constants (defined in sqlite3.h) are things such as numeric result codes 
from various interfaces (ex: `SQLITE_OK`) or flags passed into functions to 
control behavior (ex: `SQLITE_OPEN_READONLY`).
+A copy of `emacs-module.h` is included in this repo so Emacs source tree
+is not needed to build the module.
+
+## API
+An application will typically use sqlite3_open() to create a single database 
connection during initialization. 
+
+To run an SQL statement, the application follows these steps:
+
+1. Create a prepared statement using sqlite3_prepare().
+1. Evaluate the prepared statement by calling sqlite3_step() one or more times.
+1. For queries, extract results by calling sqlite3_column() in between two 
calls to sqlite3_step().
+1. Destroy the prepared statement using sqlite3_finalize().
+1. Close the database using sqlite3_close().
+
+[SQlite3 constants](https://www.sqlite.org/rescode.html), defined in 
sqlite3.h, are things such as numeric result codes from various interfaces (ex: 
`SQLITE_OK`) or flags passed into functions to control behavior (ex: 
`SQLITE_OPEN_READONLY`).
 
 In elisp they are in lowercase and words are separated by "-" instead of
 "_". For example, `SQLITE_OK` would be `sqlite-ok`.
 
-Refer to the [offical site](https://www.sqlite.org/rescode.html) 
-for a full list of constants. 
-## Functions
-Here I will briefly describe functions available in this module.
+[www.sqlite.org](https://www.sqlite.org) is always a good source of 
information, especially 
+[An Introduction to the SQLite C/C++ 
Interface](https://www.sqlite.org/cintro.html) and [C/C++ API 
Reference](https://www.sqlite.org/c3ref/intro.html).
 
-Consult the [offical API 
documentation](https://www.sqlite.org/c3ref/funclist.html) for details.
 ### sqlite3-open
 ~~~el
-(sqlite3-open "/path/to/data-file" flags)
+(sqlite3-open "/path/to/data-file" flag1 flag2 ...)
 ~~~
 Open the database file and return a database handle.
 
-In case of error, the function raises `'db-error` along with a
-corresponding error message.
+This function calls 
[`sqlite3_open_v2()`](https://www.sqlite.org/c3ref/open.html) internally and 
raises `'db-error` in case of error.
 
+*flag1*, *flag2*.... will be ORed together.
 ### sqlite3-close
 ~~~el
 (sqlite3-close database-handle)
@@ -68,6 +84,8 @@ Close the database file.
 (sqlite3-prepare database-handle sql-statement)
 ~~~
 Compile the supplied SQL statement and return a statement handle.
+
+This function calls 
[`sqlite3_prepare_v2()`](https://www.sqlite.org/c3ref/prepare.html) internally 
and raises 'sql-error (such as invalid SQL statement).
 ### sqlite3-finalize
 ~~~el
 (sqlite3-finalize statement-handle)
@@ -117,11 +135,11 @@ The Swiss Army Knife of the API, you can execute multiple 
SQL statements
 The callback function, if supplied, is invoked for *each row* and should 
accept 3
  parameters: 
  1. the first parameter is the number of columns in the current row;
- 2. the second parameter is the actual data (as a list strings); 
+ 2. the second parameter is the actual data (as a list strings or nil in case 
of NULL); 
  3. the third one is a list of column names. 
  
 To signal an error condition inside the callback, return `nil`. 
-`sqlite3_exec()` will stop the execution and return `sqlite-abort`.
+`sqlite3_exec()` will stop the execution and raise 'db-error.
 
 An example of a callback:
 ~~~el
@@ -137,9 +155,9 @@ An example of a callback:
 More examples:
 ~~~el
 ;; Update/delete/insert
-(sqlite3-exec dbh "delete from table")
+(sqlite3-exec dbh "delete from table") ;; delete returns no rows
 
-;; Retrieve the metadata of all columns of a table
+;; Retrieve the metadata of columns in a table
 (sqlite3-exec dbh "pragma table_info(table)" #'print-row)
 
 ;; Transaction support
@@ -164,19 +182,22 @@ Please note that column number starts from 1, not 0!
 ~~~
 The above functions returns the number of SQL parameters of a prepared 
 statement.
+### sqlite3-bind-multi
 ~~~el
 (sqlite3-bind-multi statement-handle &rest params)
 ~~~
-`sqlite3-bind-multi` is not part of the official API but is provided for 
+`sqlite3-bind-multi` binds multiple parameters to a prepared SQL 
+statement. It is not part of the official API but is provided for 
 convenience.
 
 Example:
 ~~~el
-(sqlite3-bind-multi stmt 1 "a" 1.555 nil) ;; nil for NULL
+(sqlite3-bind-multi stmt 1234 "a" 1.555 nil) ;; nil for NULL
 ~~~
 ### sqlite3-column-*
-These column functions retrieve data from the current row of a
-result set.
+These column functions are used to retrieve the current row
+of the result set.
+
 ~~~el
 (sqlite3-column-count statement-handle)
 ~~~
@@ -198,30 +219,36 @@ The above functions retrieve data of the specified column.
 Note: You can call `sqlite3-column-xxx` on a column even 
 if `sqlite3-column-type` returns `sqlite-yyy`: the SQLite3 engine will
 perform the necessary type conversion.
+
+Example:
 ~~~el
-(sqlite3-fetch statement-handle)
+(setq stmt (sqlite3-prepare dbh "select * from temp"))
+(while (= sqlite-row (sqlite3-step stmt))
+       (let ((name (sqlite3-column-text stmt 0))
+             (age (sqlite3-column-int64 stmt 1)))
+      (message "name: %s, age: %d" name age)))
+~~~
+### sqlite3-fetch
+~~~el
+(sqlite3-fetch statement-handle) ;; returns a list such as (123 56 "Peter 
Smith" nil)
 ~~~
 `sqlite3-fetch` is not part of the official API but provided for 
-convenience. It returns the current row as a list of values.
+convenience. It retrieves the current row as a 
+list without having to deal with sqlite3-column-* explicitly.
+
 ## A Note on Garbage Collection
 Since Emacs's garbage collection is non-deterministic, it would be 
 a good idea 
 to manually free database/statement handles once they are not needed.
 
-~~~el
-(unwind-protect
-  (progn
-    (setq dbh (sqlite3-open "..."))
-    (setq stmt (sqlite3-prepare dbh "select ..."))
-    (.....))
- (sqlite3-finalize stmt)
- (sqlite3-close dbh))
-~~~
-## Missing features
-- BLOB support
-- Custom functions written in elisp
-
 ## Known Problems
 - SQLite3 supports 64 bit integers but Emacs integers are only 61 bits.
 For integers > 61 bits you can retrieve them as text as a workaround.
-- TEXT fields with embedded NULLs are not supported.
+- BLOB/TEXT columns with embedded NULLs are not supported.
+
+## License
+The code is licensed under the [GNU GPL 
v3](https://www.gnu.org/licenses/gpl-3.0.html).
+
+## Useful Links for Writing Dynamic Modules
+- https://phst.github.io/emacs-modules
+- http://nullprogram.com/blog/2016/11/05/
diff --git a/README.md b/README.md
index 61458c10be..98dc45b3c8 100644
--- a/README.md
+++ b/README.md
@@ -1,79 +1,120 @@
 # SQLite3 Native API for Emacs 25+
-sqlite-napi is a dynamic module for GNU Emacs that provides 
-direct access to the SQLite3 C API.
-## Usage
+`sqlite-napi` is a dynamic module for GNU Emacs that provides 
+direct access to the core SQLite3 C API.
 ~~~el
 (require 'sqlite3-napi)
 
-(let ((dbh)
-      (stmt))
-  (unwind-protect
-      (progn
-       (setq dbh (sqlite3-open "/path/to/db"
-                               (logior sqlite-open-readwrite
-                                       sqlite-open-create)))
-       (setq stmt (sqlite3-prepare dbh "select * from some_table"))
-       (while (= sqlite-row (sqlite3-step stmt))
-         (cl-loop for i from 0 to (1- (sqlite3-column-count stmt)) do
-                  (message "Column #%d: %s => %s" i
-                           (sqlite3-column-name stmt i)
-                           (sqlite3-column-text stmt i)))))
-    ;; Clean up
-    (sqlite3-finalize stmt)
-    (sqlite3-close dbh)))
+(setq dbh (sqlite3-open "person.sqlite3" sqlite-open-readwrite 
sqlite-open-create))
+(sqlite3-exec dbh "create table temp (name text, age integer)")
+(sqlite3-exec dbh "begin") ;; begin transaction
+(setq stmt (sqlite3-prepare dbh "insert into temp values (?,?)"))
+(cl-loop for i from 1 to 10 do
+        (sqlite3-bind-multi stmt (format "name%d" i) i)
+         ;; execute the SQL
+        (sqlite3-step stmt)
+        ;; call reset if you want to bind the SQL to a new set of variables
+        (sqlite3-reset stmt) )
+(sqlite3-exec dbh "commit")
+(sqlite3-finalize stmt)
+
+(setq stmt (sqlite3-prepare dbh "select * from temp"))
+(while (= sqlite-row (sqlite3-step stmt))
+  (cl-destructuring-bind (name age) (sqlite3-fetch stmt)
+    (message "name: %s, age: %d" name age)))
+(sqlite3-finalize stmt)
+(sqlite3-close dbh)
 ~~~
+While this module provides only 14 functions (vs 200+ in the C API), it should 
satisfy most
+users' needs.
+
 This is alpha software and might crash your Emacs. Save your work before
 trying it out.
 
-## Requirements
+## Table of Contents
+* [Requirements](#1)
+* [Installation](#2)
+* [API](#3)
+    * [sqlite3-open](#3-1)
+    * [sqlite3-close](#3-2)
+    * [sqlite3-prepare](#3-3)
+    * [sqlite3-finalize](#3-4)
+    * [sqlite3-step](#3-5)
+    * [sqlite3-changes](#3-6)
+    * [sqlite3-reset](#3-7)
+    * [sqlite3-last-insert-rowid](#3-8)
+    * [sqlite3-get-autocommit](#3-9)
+    * [sqlite3-exec](#3-10)
+    * [sqlite3-bind-*](#3-11)
+    * [sqlite3-bind-multi](#3-12)
+    * [sqlite3-column-*](#3-13)
+    * [sqlite3-fetch](#3-14)
+* [A Note on Garbage Collection](#4)
+* [Known Problems](#5)
+* [License](#6)
+* [Useful Links for Writing Dynamic Modules](#7)
+
+## <a name="1"/> Requirements
 - Emacs 25.1 or above, compiled with module support (`--with-modules`)
 - sqlite3 library and header file
-- C compiler
-## Installation
+- A C compiler
+
+It's been tested on macOS and Linux (CentOS).
+## <a name="2"/> Installation
 ~~~sh
-$ git co https://github.com/pekingduck/sqlite3-napi
-$ cd sqlite3-napi
+$ git co https://github.com/pekingduck/emacs-sqlite3-napi
+$ cd emacs-sqlite3-napi
 $ make
-$ cp sqlite3-napi.el sqlite3-napi-module.so /your/elisp/load-path/
+$ cp sqlite3-napi.el sqlite3-napi-constants.el sqlite3-napi-module.so 
/your/elisp/load-path/
 ~~~
-Once the code stabilizes I will make it available on melpa.
-## Constants
-These constants (defined in sqlite3.h) are things such as numeric result codes 
from various interfaces (ex: `SQLITE_OK`) or flags passed into functions to 
control behavior (ex: `SQLITE_OPEN_READONLY`).
+A copy of `emacs-module.h` is included in this repo so Emacs source tree
+is not needed to build the module.
+
+## <A NAME="3"/> API
+An application will typically use sqlite3_open() to create a single database 
connection during initialization. 
+
+To run an SQL statement, the application follows these steps:
+
+1. Create a prepared statement using sqlite3_prepare().
+1. Evaluate the prepared statement by calling sqlite3_step() one or more times.
+1. For queries, extract results by calling sqlite3_column() in between two 
calls to sqlite3_step().
+1. Destroy the prepared statement using sqlite3_finalize().
+1. Close the database using sqlite3_close().
+
+[SQlite3 constants](https://www.sqlite.org/rescode.html), defined in 
sqlite3.h, are things such as numeric result codes from various interfaces (ex: 
`SQLITE_OK`) or flags passed into functions to control behavior (ex: 
`SQLITE_OPEN_READONLY`).
 
 In elisp they are in lowercase and words are separated by "-" instead of
 "_". For example, `SQLITE_OK` would be `sqlite-ok`.
 
-Refer to the [offical site](https://www.sqlite.org/rescode.html) 
-for a full list of constants. 
-## Functions
-Here I will briefly describe functions available in this module.
+[www.sqlite.org](https://www.sqlite.org) is always a good source of 
information, especially 
+[An Introduction to the SQLite C/C++ 
Interface](https://www.sqlite.org/cintro.html) and [C/C++ API 
Reference](https://www.sqlite.org/c3ref/intro.html).
 
-Consult the [offical API 
documentation](https://www.sqlite.org/c3ref/funclist.html) for details.
-### sqlite3-open
+### <a name="3-1"/> sqlite3-open
 ~~~el
-(sqlite3-open "/path/to/data-file" flags)
+(sqlite3-open "/path/to/data-file" flag1 flag2 ...)
 ~~~
 Open the database file and return a database handle.
 
-In case of error, the function raises `'db-error` along with a
-corresponding error message.
+This function calls 
[`sqlite3_open_v2()`](https://www.sqlite.org/c3ref/open.html) internally and 
raises `'db-error` in case of error.
 
-### sqlite3-close
+*flag1*, *flag2*.... will be ORed together.
+### <a name="3-2"/> sqlite3-close
 ~~~el
 (sqlite3-close database-handle)
 ~~~
 Close the database file.
-### sqlite3-prepare
+### <a name="3-3"/> sqlite3-prepare
 ~~~el
 (sqlite3-prepare database-handle sql-statement)
 ~~~
 Compile the supplied SQL statement and return a statement handle.
-### sqlite3-finalize
+
+This function calls 
[`sqlite3_prepare_v2()`](https://www.sqlite.org/c3ref/prepare.html) internally 
and raises 'sql-error (such as invalid SQL statement).
+### <a name="3-4"/> sqlite3-finalize
 ~~~el
 (sqlite3-finalize statement-handle)
 ~~~
 Destroy a prepared statement.
-### sqlite3-step
+### <a name="3-5"/> sqlite3-step
 ~~~el
 (sqlite3-step statement-handle)
 ~~~
@@ -83,31 +124,31 @@ Execute a prepared SQL statement. Some of the return codes 
are:
 
 `sqlite-row` - if the SQL statement being executed returns any data, then 
`sqlite-row` is returned each time a new row of data is ready for processing by 
the caller. 
 
-### sqlite3-changes
+### <a name="3-6"/> sqlite3-changes
 ~~~el
 (sqlite3-changes database-handle)
 ~~~
 Return the number of rows modified (for update/delete/insert statements)
 
-### sqlite3-reset
+### <a name="3-7"/> sqlite3-reset
 ~~~el
 (sqlite3-reset statement-handle)
 ~~~
 Reset a prepared statement. Call this function if you want to re-bind 
 the statement to new variables.
-### sqlite3-last-insert-rowid
+### <a name="3-8"/> sqlite3-last-insert-rowid
 ~~~el
 (sqlite3-last-insert-rowid database-handle)
 ~~~
 Retrieve the last inserted rowid (64 bit). 
 
 Notes: Beware that Emacs only supports integers up to 61 bits.
-### sqlite3-get-autocommit
+### <a name="3-9"/> sqlite3-get-autocommit
 ~~~el
 (sqlite3-get-autocommit database-handle)
 ~~~
 Return 1 / 0 if auto-commit mode is ON / OFF.
-### sqlite3-exec
+### <a name="3-10"/> sqlite3-exec
 ~~~el
 (sqlite3-exec database-handle sql-statements &optional callback)
 ~~~
@@ -117,11 +158,11 @@ The Swiss Army Knife of the API, you can execute multiple 
SQL statements
 The callback function, if supplied, is invoked for *each row* and should 
accept 3
  parameters: 
  1. the first parameter is the number of columns in the current row;
- 2. the second parameter is the actual data (as a list strings); 
+ 2. the second parameter is the actual data (as a list strings or nil in case 
of NULL); 
  3. the third one is a list of column names. 
  
 To signal an error condition inside the callback, return `nil`. 
-`sqlite3_exec()` will stop the execution and return `sqlite-abort`.
+`sqlite3_exec()` will stop the execution and raise 'db-error.
 
 An example of a callback:
 ~~~el
@@ -137,9 +178,9 @@ An example of a callback:
 More examples:
 ~~~el
 ;; Update/delete/insert
-(sqlite3-exec dbh "delete from table")
+(sqlite3-exec dbh "delete from table") ;; delete returns no rows
 
-;; Retrieve the metadata of all columns of a table
+;; Retrieve the metadata of columns in a table
 (sqlite3-exec dbh "pragma table_info(table)" #'print-row)
 
 ;; Transaction support
@@ -149,7 +190,7 @@ More examples:
 ...
 (sqlite3-exec dbh "rollback")
 ~~~
-### sqlite3-bind-*
+### <a name="3-11"/> sqlite3-bind-*
 ~~~el
 (sqlite3-bind-text statement-handle column-no value)
 (sqlite3-bind-int64 statement-handle column-no value)
@@ -164,19 +205,22 @@ Please note that column number starts from 1, not 0!
 ~~~
 The above functions returns the number of SQL parameters of a prepared 
 statement.
+### <a name="3-12"/> sqlite3-bind-multi
 ~~~el
 (sqlite3-bind-multi statement-handle &rest params)
 ~~~
-`sqlite3-bind-multi` is not part of the official API but is provided for 
+`sqlite3-bind-multi` binds multiple parameters to a prepared SQL 
+statement. It is not part of the official API but is provided for 
 convenience.
 
 Example:
 ~~~el
-(sqlite3-bind-multi stmt 1 "a" 1.555 nil) ;; nil for NULL
+(sqlite3-bind-multi stmt 1234 "a" 1.555 nil) ;; nil for NULL
 ~~~
-### sqlite3-column-*
-These column functions retrieve data from the current row of a
-result set.
+### <a name="3-13"/> sqlite3-column-*
+These column functions are used to retrieve the current row
+of the result set.
+
 ~~~el
 (sqlite3-column-count statement-handle)
 ~~~
@@ -198,30 +242,36 @@ The above functions retrieve data of the specified column.
 Note: You can call `sqlite3-column-xxx` on a column even 
 if `sqlite3-column-type` returns `sqlite-yyy`: the SQLite3 engine will
 perform the necessary type conversion.
+
+Example:
 ~~~el
-(sqlite3-fetch statement-handle)
+(setq stmt (sqlite3-prepare dbh "select * from temp"))
+(while (= sqlite-row (sqlite3-step stmt))
+       (let ((name (sqlite3-column-text stmt 0))
+             (age (sqlite3-column-int64 stmt 1)))
+      (message "name: %s, age: %d" name age)))
+~~~
+### <a name="3-14"/> sqlite3-fetch
+~~~el
+(sqlite3-fetch statement-handle) ;; returns a list such as (123 56 "Peter 
Smith" nil)
 ~~~
 `sqlite3-fetch` is not part of the official API but provided for 
-convenience. It returns the current row as a list of values.
-## A Note on Garbage Collection
+convenience. It retrieves the current row as a 
+list without having to deal with sqlite3-column-* explicitly.
+
+## <a name="4"/> A Note on Garbage Collection
 Since Emacs's garbage collection is non-deterministic, it would be 
 a good idea 
 to manually free database/statement handles once they are not needed.
 
-~~~el
-(unwind-protect
-  (progn
-    (setq dbh (sqlite3-open "..."))
-    (setq stmt (sqlite3-prepare dbh "select ..."))
-    (.....))
- (sqlite3-finalize stmt)
- (sqlite3-close dbh))
-~~~
-## Missing features
-- BLOB support
-- Custom functions written in elisp
-
-## Known Problems
+## <a name="5"/> Known Problems
 - SQLite3 supports 64 bit integers but Emacs integers are only 61 bits.
 For integers > 61 bits you can retrieve them as text as a workaround.
-- TEXT fields with embedded NULLs are not supported.
+- BLOB/ TEXT fields with embedded NULLs are not supported.
+
+## <a name="6"/> License
+The code is licensed under the [GNU GPL 
v3](https://www.gnu.org/licenses/gpl-3.0.html).
+
+## <a name="7"/> Useful Links for Writing Dynamic Modules
+- https://phst.github.io/emacs-modules
+- http://nullprogram.com/blog/2016/11/05/
diff --git a/regression.el b/regression.el
index e43b1b973e..2721ceea9d 100644
--- a/regression.el
+++ b/regression.el
@@ -1,8 +1,22 @@
 ;; -*- lexical-binding: t -*-
 
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+;;
+
 (setq lexical-binding t)
 (add-to-list 'load-path ".")
-(require 'sqlite3-napi)
+(require 'sqlite3-api)
 (require 'cl)
 
 
@@ -17,7 +31,6 @@
     (unwind-protect
        (progn
          (should (= sqlite-ok (sqlite3-exec dbh "create table temp ( id 
integer primary key autoincrement )")))
-         (should-not (= sqlite-ok (sqlite3-exec dbh "create table temp ( id 
integer primary key autoincrement )")))
          (should (= sqlite-ok (sqlite3-exec dbh "insert into temp values 
(NULL)")))
          (setq stmt (sqlite3-prepare dbh "select count(*) from temp"))
          (should (= sqlite-row (sqlite3-step stmt)))
diff --git a/sqlite3-napi.el b/sqlite3-api-constants.el
similarity index 95%
rename from sqlite3-napi.el
rename to sqlite3-api-constants.el
index b41139a767..10f9bb931b 100644
--- a/sqlite3-napi.el
+++ b/sqlite3-api-constants.el
@@ -1,4 +1,16 @@
-(require 'sqlite3-napi-module)
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+;;
 (defconst sqlite-version "3.16.0")
 (defconst sqlite-version-number 3016000)
 (defconst sqlite-source-id "2016-11-04 19:09:39 
0e5ffd9123d6d2d2b8f3701e8a73cc98a3a7ff5f")
@@ -365,4 +377,4 @@
 (defconst sqlite-scanstat-name 3)
 (defconst sqlite-scanstat-explain 4)
 (defconst sqlite-scanstat-selectid 5)
-(provide 'sqlite3-napi)
\ No newline at end of file
+(provide 'sqlite3-api-constants)
\ No newline at end of file
diff --git a/sqlite3-napi-module.c b/sqlite3-api-module.c
similarity index 80%
rename from sqlite3-napi-module.c
rename to sqlite3-api-module.c
index 91f6b113d7..546e5965b1 100644
--- a/sqlite3-napi-module.c
+++ b/sqlite3-api-module.c
@@ -1,3 +1,18 @@
+/*
+  This program 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.
+
+  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
 #include <stdlib.h>
 #include <stdio.h>
 #include <string.h>
@@ -31,7 +46,7 @@ static int SQLITE3_LOG_LEVEL_DEBUG = 0;
 static int SQLITE3_LOG_LEVEL_INFO = 1;
 static int SQLITE3_LOG_LEVEL_WARN = 2;
 static int SQLITE3_LOG_LEVEL_ERROR = 3;
-static int sqlite3_napi_log_level;
+static int sqlite3_api_log_level;
 
 int symbol_value_as_int(emacs_env *env,
                         emacs_value sym,
@@ -42,9 +57,17 @@ int symbol_value_as_int(emacs_env *env,
   return defaul;
 }
 
+/* Equivalent to (list a b c) in elisp
+   n is the number of arguments
+   elts, an array of emacs_valuem, are elements of the list
+ */
+emacs_value make_list(emacs_env *env, int n, emacs_value *elts) {
+  return env->funcall(env, SYM(env, "list"), n, elts);
+}
+
 #if 0
 static void message(emacs_env *env, int log_level, const char *fmt, ...) {
-  if (log_level < sqlite3_napi_log_level)
+  if (log_level < sqlite3_api_log_level)
     return;
 
   va_list args;
@@ -71,10 +94,11 @@ static void message(emacs_env *env, int log_level, const 
char *fmt, ...) {
 }
 #endif
 
+/* Logging function */
 static void message(emacs_env *env, int log_level, const char *fmt, ...) {
   (void)env;
 
-  if (log_level < sqlite3_napi_log_level)
+  if (log_level < sqlite3_api_log_level)
     return;
 
   static const char *LOG_LEVEL_DESC[] = {
@@ -93,10 +117,11 @@ static void message(emacs_env *env, int log_level, const 
char *fmt, ...) {
   fprintf(stderr, "\n");
 }
 
+/* Equivalent to (signal error data) in elisp */
 void signal_error(emacs_env *env, const char *symbol, const char *msg) {
   emacs_value signal = SYM(env, symbol);
   emacs_value errmsg = env->make_string(env, msg, strlen(msg));
-  env->non_local_exit_signal(env, signal, errmsg);
+  env->non_local_exit_signal(env, signal, make_list(env, 1, &errmsg));
 }
 
 /* Extract and copy string contents from function parameters */
@@ -114,7 +139,7 @@ int extract_string_arg(emacs_env *env, emacs_value arg, 
char **str) {
   return 0;
 }
 
-/* Create a LISP function callable from within Emacs */
+/* Bind the supplied function to a symbol by calling (fset ....) */
 void bind_func(emacs_env *env, const char *name, ptrdiff_t min,
                ptrdiff_t max,
                emacs_value (*function) (emacs_env *env,
@@ -130,7 +155,8 @@ void bind_func(emacs_env *env, const char *name, ptrdiff_t 
min,
   env->funcall(env, fset, 2, args);
 }
 
-static void sqlite3_db_gc(void *ptr) {
+/* finalizer for database handle (sqlite3 *) */
+static void sqlite3_dbh_gc(void *ptr) {
   INFO(0, "%s: entered", __func__);
 
   if (ptr) {
@@ -139,6 +165,7 @@ static void sqlite3_db_gc(void *ptr) {
   }
 }
 
+/* finalizer for statement handle (sqlite3_stmt *) */
 static void sqlite3_stmt_gc(void *ptr) {
   INFO(0, "%s: entered", __func__);
 
@@ -151,7 +178,7 @@ static void sqlite3_stmt_gc(void *ptr) {
 /* bind_*() functions:
    Bind SQL parameters after the SQL is prepared (compiled).
 */
-static emacs_value sqlite3_napi_bind_null(
+static emacs_value sqlite3_api_bind_null(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -159,10 +186,6 @@ static emacs_value sqlite3_napi_bind_null(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
-    /* User passed a nil stmt */
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -170,20 +193,15 @@ static emacs_value sqlite3_napi_bind_null(
 
   sqlite3_stmt *stmt = (sqlite3_stmt *)env->get_user_ptr(env, args[0]);
   NON_LOCAL_EXIT_CHECK(env);
-  /* if (env->non_local_exit_check(env) != emacs_funcall_exit_return) */
-  /*   return SYM(env, "nil"); */
 
   // The column no.
   int col = env->extract_integer(env, args[1]);
   NON_LOCAL_EXIT_CHECK(env);
-  /* if (env->non_local_exit_check(env) != emacs_funcall_exit_return) { */
-  /*   return SYM(env, "nil"); */
-  /* } */
 
   return env->make_integer(env, sqlite3_bind_null(stmt, col));
 }
 
-static emacs_value sqlite3_napi_bind_double(
+static emacs_value sqlite3_api_bind_double(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -191,9 +209,6 @@ static emacs_value sqlite3_napi_bind_double(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -212,7 +227,7 @@ static emacs_value sqlite3_napi_bind_double(
   return env->make_integer(env, sqlite3_bind_double(stmt, col, val));
 }
 
-static emacs_value sqlite3_napi_bind_parameter_count(
+static emacs_value sqlite3_api_bind_parameter_count(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -231,7 +246,7 @@ static emacs_value sqlite3_napi_bind_parameter_count(
   return env->make_integer(env, sqlite3_bind_parameter_count(stmt));
 }
 
-static emacs_value sqlite3_napi_bind_int64(
+static emacs_value sqlite3_api_bind_int64(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -239,9 +254,6 @@ static emacs_value sqlite3_napi_bind_int64(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -258,11 +270,10 @@ static emacs_value sqlite3_napi_bind_int64(
   intmax_t val = env->extract_integer(env, args[2]);
   NON_LOCAL_EXIT_CHECK(env);
 
-  /* DEBUG(env, "%s: col %d, val %d", __func__, col, val); */
   return env->make_integer(env, sqlite3_bind_int64(stmt, col, val));
 }
 
-static emacs_value sqlite3_napi_bind_text(
+static emacs_value sqlite3_api_bind_text(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -270,9 +281,6 @@ static emacs_value sqlite3_napi_bind_text(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -296,7 +304,7 @@ static emacs_value sqlite3_napi_bind_text(
   return env->make_integer(env, rv);
 }
 
-static emacs_value sqlite3_napi_bind_multi(
+static emacs_value sqlite3_api_bind_multi(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -304,9 +312,6 @@ static emacs_value sqlite3_napi_bind_multi(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -345,12 +350,10 @@ static emacs_value sqlite3_napi_bind_multi(
     }
   }
 
-  /* message(env, "bind_text [%s] to col %d", txt, col); */
-
   return env->make_integer(env, rv);
 }
 
-static emacs_value sqlite3_napi_column_name(
+static emacs_value sqlite3_api_column_name(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -358,9 +361,6 @@ static emacs_value sqlite3_napi_column_name(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -377,7 +377,7 @@ static emacs_value sqlite3_napi_column_name(
   return env->make_string(env, name, strlen(name));
 }
 
-static emacs_value sqlite3_napi_column_text(
+static emacs_value sqlite3_api_column_text(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -385,9 +385,6 @@ static emacs_value sqlite3_napi_column_text(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -406,7 +403,7 @@ static emacs_value sqlite3_napi_column_text(
                           size);
 }
 
-static emacs_value sqlite3_napi_column_int64(
+static emacs_value sqlite3_api_column_int64(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -414,9 +411,6 @@ static emacs_value sqlite3_napi_column_int64(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -432,7 +426,7 @@ static emacs_value sqlite3_napi_column_int64(
   return env->make_integer(env, (intmax_t)sqlite3_column_int64(stmt, col));
 }
 
-static emacs_value sqlite3_napi_column_double(
+static emacs_value sqlite3_api_column_double(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -440,9 +434,6 @@ static emacs_value sqlite3_napi_column_double(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -458,7 +449,7 @@ static emacs_value sqlite3_napi_column_double(
   return env->make_float(env, sqlite3_column_double(stmt, col));
 }
 
-static emacs_value sqlite3_napi_column_type(
+static emacs_value sqlite3_api_column_type(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -466,9 +457,6 @@ static emacs_value sqlite3_napi_column_type(
   (void)ptr;
   (void)n;
 
-  // TODO:
-  // should signal an error instead of return SYM(env, "nil")??
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -484,7 +472,7 @@ static emacs_value sqlite3_napi_column_type(
   return env->make_integer(env, sqlite3_column_type(stmt, col));
 }
 
-static emacs_value sqlite3_napi_changes(
+static emacs_value sqlite3_api_changes(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -492,7 +480,6 @@ static emacs_value sqlite3_napi_changes(
   (void)ptr;
   (void)n;
 
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: database handle is nil", __func__);
     return SYM(env, "nil");
@@ -504,7 +491,7 @@ static emacs_value sqlite3_napi_changes(
   return env->make_integer(env, sqlite3_changes(dbh));
 }
 
-static emacs_value sqlite3_napi_step(
+static emacs_value sqlite3_api_step(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -512,7 +499,6 @@ static emacs_value sqlite3_napi_step(
   (void)ptr;
   (void)n;
 
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -524,7 +510,7 @@ static emacs_value sqlite3_napi_step(
   return env->make_integer(env, sqlite3_step(stmt));
 }
 
-static emacs_value sqlite3_napi_reset(
+static emacs_value sqlite3_api_reset(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -544,7 +530,7 @@ static emacs_value sqlite3_napi_reset(
   return env->make_integer(env, sqlite3_reset(stmt));
 }
 
-static emacs_value sqlite3_napi_column_count(
+static emacs_value sqlite3_api_column_count(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -552,7 +538,6 @@ static emacs_value sqlite3_napi_column_count(
   (void)ptr;
   (void)n;
 
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -564,7 +549,7 @@ static emacs_value sqlite3_napi_column_count(
   return env->make_integer(env, sqlite3_column_count(stmt));
 }
 
-static emacs_value sqlite3_napi_fetch(
+static emacs_value sqlite3_api_fetch(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -572,7 +557,6 @@ static emacs_value sqlite3_napi_fetch(
   (void)ptr;
   (void)n;
 
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: statement handle is nil", __func__);
     return SYM(env, "nil");
@@ -602,13 +586,13 @@ static emacs_value sqlite3_napi_fetch(
         elts[i] = SYM(env, "nil");
     }
   }
-  emacs_value list = SYM(env, "list");
-  emacs_value res = env->funcall(env, list, ncols, elts);
+
+  emacs_value res = make_list(env, ncols, elts);
   free(elts);
   return res;
 }
 
-static emacs_value sqlite3_napi_prepare(
+static emacs_value sqlite3_api_prepare(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -616,7 +600,6 @@ static emacs_value sqlite3_napi_prepare(
   (void)ptr;
   (void)n;
 
-  // Exrtract sqlite3 db struct
   if (!env->is_not_nil(env, args[0])) {
     WARN(env, "%s: database handle is nil", __func__);
     return SYM(env, "nil");
@@ -642,13 +625,13 @@ static emacs_value sqlite3_napi_prepare(
     char buf[SQLITE3_MAX_LOG_BUF];
     snprintf(buf, SQLITE3_MAX_LOG_BUF,
              "prepare(): sqlite3_prepare_v2() returned %d", rv);
-    signal_error(env, "db-error", buf);
+    signal_error(env, "sql-error", buf);
     return SYM(env, "nil");
   }
   return env->make_user_ptr(env, sqlite3_stmt_gc, stmt);
 }
 
-static emacs_value sqlite3_napi_get_autocommit(
+static emacs_value sqlite3_api_get_autocommit(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -708,9 +691,9 @@ static int exec_callback(void *data, int ncols,
   emacs_value args[3];
   args[0] = env->make_integer(env, ncols);
   NON_LOCAL_EXIT_CHECK_AND_CLEANUP;
-  args[1] = env->funcall(env, SYM(env, "list"), ncols, data_args);
+  args[1] = make_list(env, ncols, data_args);
   NON_LOCAL_EXIT_CHECK_AND_CLEANUP;
-  args[2] = env->funcall(env, SYM(env, "list"), ncols, col_args);
+  args[2] = make_list(env, ncols, col_args);
   NON_LOCAL_EXIT_CHECK_AND_CLEANUP;
 
   emacs_value v = env->funcall(env, fe->callback, 3, args);
@@ -722,7 +705,7 @@ static int exec_callback(void *data, int ncols,
   return 1;
 }
 
-static emacs_value sqlite3_napi_exec(
+static emacs_value sqlite3_api_exec(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -741,7 +724,7 @@ static emacs_value sqlite3_napi_exec(
     return SYM(env, "nil");
   }
 
-  char *errmsg;
+  char *errmsg = 0;
   int rv;
   if (n == 3) {
     struct func_env fe = { env, args[2] };
@@ -751,15 +734,17 @@ static emacs_value sqlite3_napi_exec(
   }
 
   if (rv != SQLITE_OK) {
-    ERROR(env, "%s returned %d [%s]", __func__, rv, errmsg);
+    signal_error(env, "db-error", errmsg);
+    if (errmsg)
+      sqlite3_free(errmsg);
+    return SYM(env, "nil");
   }
-  if (errmsg)
-    sqlite3_free(errmsg);
 
   return env->make_integer(env, rv);
 }
 
-static emacs_value sqlite3_napi_finalize(
+
+static emacs_value sqlite3_api_finalize(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -781,7 +766,7 @@ static emacs_value sqlite3_napi_finalize(
 }
 
 
-static emacs_value sqlite3_napi_close(
+static emacs_value sqlite3_api_close(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -802,7 +787,7 @@ static emacs_value sqlite3_napi_close(
   return SYM(env, "nil");
 }
 
-static emacs_value sqlite3_napi_last_insert_rowid(
+static emacs_value sqlite3_api_last_insert_rowid(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -821,7 +806,7 @@ static emacs_value sqlite3_napi_last_insert_rowid(
   return env->make_integer(env, (intmax_t)sqlite3_last_insert_rowid(dbh));
 }
 
-static emacs_value sqlite3_napi_set_log_level(
+static emacs_value sqlite3_api_set_log_level(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -831,12 +816,12 @@ static emacs_value sqlite3_napi_set_log_level(
 
   int log_level = env->extract_integer(env, args[0]);
   NON_LOCAL_EXIT_CHECK(env);
-  sqlite3_napi_log_level = log_level;
+  sqlite3_api_log_level = log_level;
   return SYM(env, "nil");
 }
 
 #if 0
-static emacs_value sqlite3_napi_test(
+static emacs_value sqlite3_api_test(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -844,7 +829,6 @@ static emacs_value sqlite3_napi_test(
   (void)ptr;
   (void)n;
 
-  //return SYM(env, "nil");
   emacs_value *fargs = malloc(sizeof(emacs_value)*2);
   fargs[0] = env->make_integer(env, 1);
   fargs[1] = env->make_integer(env, 99);
@@ -852,7 +836,7 @@ static emacs_value sqlite3_napi_test(
 }
 #endif
 
-static emacs_value sqlite3_napi_open(
+static emacs_value sqlite3_api_open(
     emacs_env *env,
     ptrdiff_t n,
     emacs_value *args,
@@ -863,26 +847,29 @@ static emacs_value sqlite3_napi_open(
   // Filename
   char *db_file = 0;
   if (extract_string_arg(env, args[0], &db_file)) {
-    WARN(env, "%s: extract_string_arg return non-zero", __func__);
     return SYM(env, "nil");
   }
 
   // FLAGS
-  int flags = env->extract_integer(env, args[1]);
-  NON_LOCAL_EXIT_CHECK(env);
+  int flags = 0;
+  for (int i = 1; i < n; i++) {
+    flags |= env->extract_integer(env, args[i]);
+    NON_LOCAL_EXIT_CHECK(env);
+  }
 
-  sqlite3 *dbh;
+  sqlite3 *dbh = 0;
   int rv = sqlite3_open_v2(db_file, &dbh, flags, 0);
   INFO(env, "%s: file=%s, flags=%d, rv=%d", __func__, db_file, flags, rv);
   free(db_file);
 
   if (rv != SQLITE_OK) {
-    // TODO: more descriptive error message (with error code)
+    if (dbh)
+      sqlite3_free(dbh);
     signal_error(env, "db-error", "failed to open DB file");
     return SYM(env, "nil");
   }
 
-  return env->make_user_ptr(env, sqlite3_db_gc, dbh);
+  return env->make_user_ptr(env, sqlite3_dbh_gc, dbh);
 }
 
 int emacs_module_init(struct emacs_runtime *ert) {
@@ -900,58 +887,58 @@ int emacs_module_init(struct emacs_runtime *ert) {
     };
 
     struct lisp_func all_funcs[] = {
-      { "sqlite3-open", 1, 2, sqlite3_napi_open,
+      { "sqlite3-open", 1, 10, sqlite3_api_open,
         "Open a SQLite3 database." },
-      { "sqlite3-close", 1, 1, sqlite3_napi_close,
+      { "sqlite3-close", 1, 1, sqlite3_api_close,
         "Close a SQLite3 database." },
-      { "sqlite3-prepare", 2, 2, sqlite3_napi_prepare,
+      { "sqlite3-prepare", 2, 2, sqlite3_api_prepare,
         "Prepare (compile) a SQL statement." },
-      { "sqlite3-finalize", 1, 1, sqlite3_napi_finalize,
+      { "sqlite3-finalize", 1, 1, sqlite3_api_finalize,
         "Destroy a prepared statement." },
-      { "sqlite3-changes", 1, 1, sqlite3_napi_changes,
+      { "sqlite3-changes", 1, 1, sqlite3_api_changes,
         "Count the number of rows modified." },
-      { "sqlite3-step", 1, 1, sqlite3_napi_step,
+      { "sqlite3-step", 1, 1, sqlite3_api_step,
         "Evaluate a SQL statement." },
-      { "sqlite3-reset", 1, 1, sqlite3_napi_reset,
+      { "sqlite3-reset", 1, 1, sqlite3_api_reset,
         "Reset a prepared SQL statement." },
-      { "sqlite3-last-insert-rowid", 1, 1, sqlite3_napi_last_insert_rowid,
+      { "sqlite3-last-insert-rowid", 1, 1, sqlite3_api_last_insert_rowid,
         "Return last insert rowid." },
-      { "sqlite3-get-autocommit", 1, 1, sqlite3_napi_get_autocommit,
+      { "sqlite3-get-autocommit", 1, 1, sqlite3_api_get_autocommit,
         "Test for auto-commit mode." },
-      { "sqlite3-exec", 2, 3, sqlite3_napi_exec,
+      { "sqlite3-exec", 2, 3, sqlite3_api_exec,
         "One-step query execution interface." },
-      { "sqlite3-set-log-level", 1, 1, sqlite3_napi_set_log_level,
+      { "sqlite3-set-log-level", 1, 1, sqlite3_api_set_log_level,
         "Set log level (DEBUG 0, INFO 1, WARN 2, ERROR 3, NOLOG 100)." },
 
       /* bind interface */
-      { "sqlite3-bind-text", 3, 3, sqlite3_napi_bind_text,
+      { "sqlite3-bind-text", 3, 3, sqlite3_api_bind_text,
         "Bind text to a prepared SQL statement." },
-      { "sqlite3-bind-int64", 3, 3, sqlite3_napi_bind_int64,
+      { "sqlite3-bind-int64", 3, 3, sqlite3_api_bind_int64,
         "Bind int64 to a prepared SQL statement." },
-      { "sqlite3-bind-double", 3, 3, sqlite3_napi_bind_double,
+      { "sqlite3-bind-double", 3, 3, sqlite3_api_bind_double,
         "Bind double to a prepared SQL statement." },
-      { "sqlite3-bind-null", 2, 2, sqlite3_napi_bind_null,
+      { "sqlite3-bind-null", 2, 2, sqlite3_api_bind_null,
         "Bind NULL to a prepared SQL statement." },
       { "sqlite3-bind-parameter-count", 1, 1,
-        sqlite3_napi_bind_parameter_count,
+        sqlite3_api_bind_parameter_count,
         "Return the number of SQL parameters." },
-      { "sqlite3-bind-multi", 1, 127, sqlite3_napi_bind_multi,
+      { "sqlite3-bind-multi", 1, 127, sqlite3_api_bind_multi,
         "Bind multiple parameters to a prepared SQL statement." },
 
       /* Result */
-      { "sqlite3-column-count", 1, 1, sqlite3_napi_column_count,
+      { "sqlite3-column-count", 1, 1, sqlite3_api_column_count,
         "Return the number of rows in a result set." },
-      { "sqlite3-column-name", 2, 2, sqlite3_napi_column_name,
+      { "sqlite3-column-name", 2, 2, sqlite3_api_column_name,
         "Return the name of a column." },
-      { "sqlite3-column-type", 2, 2, sqlite3_napi_column_type,
+      { "sqlite3-column-type", 2, 2, sqlite3_api_column_type,
         "Return the datatype of a column." },
-      { "sqlite3-column-text", 2, 2, sqlite3_napi_column_text,
+      { "sqlite3-column-text", 2, 2, sqlite3_api_column_text,
         "Return text data of a column." },
-      { "sqlite3-column-int64", 2, 2, sqlite3_napi_column_int64,
+      { "sqlite3-column-int64", 2, 2, sqlite3_api_column_int64,
         "Return int64 data of a column." },
-      { "sqlite3-column-double", 2, 2, sqlite3_napi_column_double,
+      { "sqlite3-column-double", 2, 2, sqlite3_api_column_double,
         "Return double data of a column." },
-      { "sqlite3-fetch", 1, 1, sqlite3_napi_fetch,
+      { "sqlite3-fetch", 1, 1, sqlite3_api_fetch,
         "Return a row as a list." },
 
       { NULL, 0, 0, NULL, NULL }
@@ -965,11 +952,11 @@ int emacs_module_init(struct emacs_runtime *ert) {
                 all_funcs[i].function,
                 all_funcs[i].documentation);
     }
-    sqlite3_napi_log_level = SQLITE3_LOG_LEVEL_ERROR;
+    sqlite3_api_log_level = SQLITE3_LOG_LEVEL_ERROR;
 
     /* (provide 'sqlite3-module ) */
     emacs_value provide = SYM(env, "provide");
-    emacs_value mod = SYM(env, "sqlite3-napi-module");
+    emacs_value mod = SYM(env, "sqlite3-api-module");
     env->funcall(env, provide, 1, &mod);
     return 0;
 }
diff --git a/sqlite3-api.el b/sqlite3-api.el
new file mode 100644
index 0000000000..948a19971d
--- /dev/null
+++ b/sqlite3-api.el
@@ -0,0 +1,20 @@
+;; This program 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.
+
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+(require 'sqlite3-api-constants)
+(require 'sqlite3-api-module)
+
+(define-error 'db-error "Database Error")
+(define-error 'sql-error "SQL Error")
+
+(provide 'sqlite3-api)
diff --git a/sqlite3-napi-module.so b/sqlite3-napi-module.so
deleted file mode 100755
index 1a341eb5af..0000000000
Binary files a/sqlite3-napi-module.so and /dev/null differ
diff --git a/tools/gen-consts.py b/tools/gen-consts.py
index 752f606ff6..f2d21606e4 100755
--- a/tools/gen-consts.py
+++ b/tools/gen-consts.py
@@ -9,7 +9,6 @@ c_src="""
 #include <sqlite3.h>
 
 int main(int argc, char *argv[]) {
-  printf(\"(require 'sqlite3-napi-module)\\n");
 """
 print(c_src)
 for line in sys.stdin.readlines():
@@ -22,5 +21,5 @@ for line in sys.stdin.readlines():
       print('  printf("(defconst {1} \\"%s\\")\\n", {0});'.format(fields[1], 
name))
     else:
       print('  printf("(defconst {1} %d)\\n", {0});'.format(fields[1], name))
-print('  printf("(provide \'sqlite3-napi)");')
+print('  printf("(provide \'sqlite3-api-constants)");')
 print("}")
diff --git a/tools/run.sh b/tools/run.sh
index 4f052f7044..2c0a918483 100755
--- a/tools/run.sh
+++ b/tools/run.sh
@@ -1,5 +1,25 @@
 #!/bin/bash
 
-grep "^#define SQLITE" /usr/include/sqlite3.h | ./gen-consts.py > def.c
-gcc -o def def.c -lsqlite3
-./def > ../sqlite3-napi.el
+DEST=../sqlite3-api-constants.el
+cat <<EOF > $DEST
+;; This program 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.
+;;
+;; This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+;;
+EOF
+
+EXE=./def
+
+rm -f $EXE ${EXE}.c
+grep "^#define SQLITE" /usr/include/sqlite3.h | ./gen-consts.py > ${EXE}.c
+gcc -o $EXE ${EXE}.c -lsqlite3
+${EXE} >> $DEST



reply via email to

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