first commit
This commit is contained in:
78
lua-sqlite3-0.4.1/ChangeLog
Normal file
78
lua-sqlite3-0.4.1/ChangeLog
Normal file
@@ -0,0 +1,78 @@
|
||||
|
||||
2006-05-11 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Version 0.4.1
|
||||
* libluasqlite3.c: Fix to compile with MSVC6.
|
||||
|
||||
|
||||
2006-05-09 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Version 0.4
|
||||
|
||||
|
||||
2006-04-12 Michael Roth <mroth@nessie.de>
|
||||
|
||||
* Makefile.in, configure.ac, configure: Switched to gnu
|
||||
autoconf framework.
|
||||
|
||||
|
||||
2006-04-09 Michael Roth <mroth@nessie.de>
|
||||
|
||||
* Makefile (clean): Documentation will no longer vaporize.
|
||||
* libluasqlite3-loader.lua.in: loadlib Fix for lua-5.1.
|
||||
* exmaples/*: Search path fixes for lua-5.1
|
||||
|
||||
|
||||
2005-09-14 Michael Roth <mroth@nessie.de>
|
||||
|
||||
* sqlite3.lua (call_user_func): Fix for nil arguments in lua-5.1.
|
||||
(stmt_class.first_cols): Dito but for return values.
|
||||
* tests-sqlite3.lua (bug:test_nils): Testcase for nils in lua-5.1.
|
||||
|
||||
|
||||
2005-06-15 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Version 0.3:
|
||||
* Documentation updates.
|
||||
* examples/smart.lua: New.
|
||||
* tests-sqlite3.lua: New test cases for parameter names without
|
||||
leading dollar or colon sign.
|
||||
New test cases for binding with name/value tables.
|
||||
New test cases for stmt:parameter_names().
|
||||
* sqlite3.lua (stmt_class.prepare): Support for parameter names
|
||||
without leading dollar or colon sign.
|
||||
(stmt_class.bind) Support for binding with name/value tables.
|
||||
(stmt_class.parameter_names) new.
|
||||
|
||||
|
||||
2005-06-14 Michael Roth <mroth@nessie.de>
|
||||
|
||||
* sqlite3.lua (stmt_class.prepare): Auto parameter mapping.
|
||||
* libluasqlite3.c (l_sqlite3_bind_parameter_name_x): new.
|
||||
|
||||
|
||||
2005-06-03 Michael Roth <mroth@nessie.de>
|
||||
|
||||
* sqlite3.lua (db_class.set_busy_timeout & set_busy_handler): new.
|
||||
(db_class.set_trace_handler): Fixed error handling.
|
||||
(stmt_rows): Fixed autoclose and reset behaviour (Bug #1).
|
||||
|
||||
|
||||
2005-06-02 Michael Roth <mroth@nessie.de>
|
||||
|
||||
* tests-sqlite3.lua: New test case for reported bugs.
|
||||
(bug:test_1): Bug #1, bind()/first_cols() problem on empty tables.
|
||||
|
||||
|
||||
2004-10-07 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Version 0.2:
|
||||
* Lua-Sqlite3 should now compile with older compilers.
|
||||
* Requires the sqlite library version 3.0.7.
|
||||
|
||||
|
||||
2004-09-14 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Version 0.1 (alpha):
|
||||
* This is the first public release of Lua-Sqlite3.
|
||||
|
||||
32
lua-sqlite3-0.4.1/LICENSE
Normal file
32
lua-sqlite3-0.4.1/LICENSE
Normal file
@@ -0,0 +1,32 @@
|
||||
|
||||
Lua-Sqlite3 License
|
||||
-------------------
|
||||
|
||||
Lua-Sqlite3 is written by Michael Roth <mroth@nessie.de> and is
|
||||
licensed under the terms of the MIT license reproduced below.
|
||||
|
||||
========================================================================
|
||||
|
||||
Copyright (c) 2004, 2005, 2006 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
========================================================================
|
||||
|
||||
139
lua-sqlite3-0.4.1/Makefile.in
Normal file
139
lua-sqlite3-0.4.1/Makefile.in
Normal file
@@ -0,0 +1,139 @@
|
||||
|
||||
prefix := @prefix@
|
||||
|
||||
exec_prefix := @exec_prefix@
|
||||
|
||||
bindir := @bindir@
|
||||
sbindir := @sbindir@
|
||||
libdir := @libdir@
|
||||
libexecdir := @libexecdir@
|
||||
mandir := @mandir@
|
||||
|
||||
luadir := @libdir@/lua
|
||||
|
||||
install := install
|
||||
install-data := $(install) -p -m 644
|
||||
install-prog := $(install) -p -m 755
|
||||
install-dirs := $(install) -d
|
||||
|
||||
LUA := @LUA@
|
||||
|
||||
CC := @CC@
|
||||
|
||||
CFLAGS := @CFLAGS@
|
||||
LDFLAGS := @LDFLAGS@
|
||||
|
||||
LIBS := @LIBS@
|
||||
|
||||
COMPILE = $(CC) -c $(CFLAGS) -o $@ $<
|
||||
LINK = $(CC) $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
LINKSHARED = $(CC) -shared $(LDFLAGS) -o $@ $+ $(LIBS)
|
||||
|
||||
DESTDIR =
|
||||
|
||||
PACKAGE_NAME := lua-sqlite3
|
||||
PACKAGE_VERSION := 0.4.1
|
||||
|
||||
LUA_FILES := sqlite3.lua luasql-sqlite3.lua
|
||||
|
||||
SOURCE_FILES := libluasqlite3.c
|
||||
|
||||
DOC_FILES := documentation.html README LICENSE
|
||||
|
||||
DIST_FILES := $(LUA_FILES) $(SOURCE_FILES) $(DOC_FILES) \
|
||||
Makefile.in lunit.lua tests-luasql.lua \
|
||||
tests-sqlite3.lua tests.lua \
|
||||
libluasqlite3-loader.lua.in ChangeLog \
|
||||
configure.ac configure
|
||||
|
||||
DIST_DIR := $(PACKAGE_NAME)-$(PACKAGE_VERSION)
|
||||
|
||||
CLEAN_FILES := libluasqlite3.o libluasqlite3.so \
|
||||
libluasqlite3-loader.lua libluasqlite3-loader.lua.install
|
||||
|
||||
DESTDIR :=
|
||||
|
||||
|
||||
all: libluasqlite3.so libluasqlite3-loader.lua libluasqlite3-loader.lua.install
|
||||
|
||||
install: all
|
||||
$(install-dirs) $(DESTDIR)$(luadir)
|
||||
$(install-data) $(LUA_FILES) libluasqlite3.so $(DESTDIR)$(luadir)
|
||||
$(install-data) libluasqlite3-loader.lua.install $(DESTDIR)$(luadir)/libluasqlite3-loader.lua
|
||||
|
||||
uninstall:
|
||||
( cd $(DESTDIR)$(luadir); rm -f $(LUA_FILES) libluasqlite3-loader.lua libluasqlite3.so )
|
||||
|
||||
clean:
|
||||
rm -f $(CLEAN_FILES)
|
||||
|
||||
allclean: clean distclean docsclean
|
||||
|
||||
distdir: $(DIST_FILES) docs
|
||||
rm -rf $(DIST_DIR)
|
||||
mkdir $(DIST_DIR) $(DIST_DIR)/examples
|
||||
cp -a -L $(DIST_FILES) $(DIST_DIR)
|
||||
cp -a -L examples/*.lua $(DIST_DIR)/examples
|
||||
find $(DIST_DIR) -perm +444 -exec chmod a+w {} \;
|
||||
find $(DIST_DIR) -perm +222 -exec chmod a+r {} \;
|
||||
find $(DIST_DIR) -perm +111 -exec chmod a+x {} \;
|
||||
chmod -R a-st $(DIST_DIR)
|
||||
chmod -R go-w $(DIST_DIR)
|
||||
chmod 755 $(DIST_DIR)
|
||||
touch distdir
|
||||
|
||||
dist-tar: distdir
|
||||
tar -c -f $(DIST_DIR).tar --owner=root --group=root $(DIST_DIR)
|
||||
touch dist-tar
|
||||
|
||||
dist-bz2: dist-tar
|
||||
rm -f $(DIST_DIR).tar.gz
|
||||
gzip -9 -c $(DIST_DIR).tar > $(DIST_DIR).tar.gz
|
||||
touch dist-bz2
|
||||
|
||||
dist-gz: dist-tar
|
||||
rm -f $(DIST_DIR).tar.bz2
|
||||
bzip2 -9 -c $(DIST_DIR).tar > $(DIST_DIR).tar.bz2
|
||||
touch dist-gz
|
||||
|
||||
dist-zip: distdir
|
||||
zip -rq $(DIST_DIR).zip $(DIST_DIR)
|
||||
touch dist-zip
|
||||
|
||||
dist: dist-bz2 dist-gz dist-zip
|
||||
|
||||
distclean:
|
||||
rm -rf $(DIST_DIR)
|
||||
rm -f $(DIST_DIR).tar $(DIST_DIR).tar.gz $(DIST_DIR).tar.bz2 $(DIST_DIR).zip
|
||||
rm -f distdir dist-tar dist-gz dist-bz2 dist-zip
|
||||
|
||||
devel:
|
||||
./make-devel.sh
|
||||
develclean:
|
||||
rm -rf obj-5.0 obj-5.1
|
||||
|
||||
docs: documentation.html
|
||||
|
||||
docsclean:
|
||||
rm -f documentation.html
|
||||
|
||||
check: all
|
||||
$(LUA) tests.lua
|
||||
|
||||
documentation.html: docs/doc.mrd makedoc.lua
|
||||
$(LUA) makedoc.lua >documentation.html
|
||||
|
||||
libluasqlite3.o: libluasqlite3.c
|
||||
$(COMPILE)
|
||||
|
||||
libluasqlite3.so: libluasqlite3.o
|
||||
$(LINKSHARED)
|
||||
|
||||
libluasqlite3-loader.lua.install: libluasqlite3-loader.lua.in
|
||||
m4 -DSHARED_LIB_PATH=$(luadir) \
|
||||
< libluasqlite3-loader.lua.in > libluasqlite3-loader.lua.install
|
||||
|
||||
libluasqlite3-loader.lua: libluasqlite3-loader.lua.in
|
||||
m4 -DSHARED_LIB_PATH=$(shell pwd) \
|
||||
< libluasqlite3-loader.lua.in > libluasqlite3-loader.lua
|
||||
|
||||
19
lua-sqlite3-0.4.1/README
Normal file
19
lua-sqlite3-0.4.1/README
Normal file
@@ -0,0 +1,19 @@
|
||||
|
||||
This is Lua-Sqlite3 release 0.4.1.
|
||||
|
||||
Lua-Sqlite3 is a sqlite3 wrapper for lua.
|
||||
|
||||
To learn more about lua-sqlite3 take a look in documentation.html.
|
||||
|
||||
Edit Makefile.cfg to match your environment.
|
||||
|
||||
Please note that this release is still alpha software. This mean that
|
||||
there exists a chance that function signatures and behavour will change
|
||||
in the future.
|
||||
|
||||
If you have suggestions, questions or feature request please
|
||||
feel free to contact me.
|
||||
|
||||
|
||||
Michael Roth <mroth@nessie.de>
|
||||
|
||||
457
lua-sqlite3-0.4.1/config.log
Normal file
457
lua-sqlite3-0.4.1/config.log
Normal file
@@ -0,0 +1,457 @@
|
||||
This file contains any messages produced by compilers while
|
||||
running configure, to aid debugging if configure makes a mistake.
|
||||
|
||||
It was created by lua-sqlite3 configure 0.4, which was
|
||||
generated by GNU Autoconf 2.59. Invocation command line was
|
||||
|
||||
$ ./configure
|
||||
|
||||
## --------- ##
|
||||
## Platform. ##
|
||||
## --------- ##
|
||||
|
||||
hostname = domoticz
|
||||
uname -m = armv7l
|
||||
uname -r = 4.1.13-v7+
|
||||
uname -s = Linux
|
||||
uname -v = #826 SMP PREEMPT Fri Nov 13 20:19:03 GMT 2015
|
||||
|
||||
/usr/bin/uname -p = unknown
|
||||
/bin/uname -X = unknown
|
||||
|
||||
/bin/arch = unknown
|
||||
/usr/bin/arch -k = unknown
|
||||
/usr/convex/getsysinfo = unknown
|
||||
hostinfo = unknown
|
||||
/bin/machine = unknown
|
||||
/usr/bin/oslevel = unknown
|
||||
/bin/universe = unknown
|
||||
|
||||
PATH: /usr/local/sbin
|
||||
PATH: /usr/local/bin
|
||||
PATH: /usr/sbin
|
||||
PATH: /usr/bin
|
||||
PATH: /sbin
|
||||
PATH: /bin
|
||||
|
||||
|
||||
## ----------- ##
|
||||
## Core tests. ##
|
||||
## ----------- ##
|
||||
|
||||
configure:1373: checking for gcc
|
||||
configure:1389: found /usr/bin/gcc
|
||||
configure:1399: result: gcc
|
||||
configure:1643: checking for C compiler version
|
||||
configure:1646: gcc --version </dev/null >&5
|
||||
gcc (Debian 4.6.3-14+rpi1) 4.6.3
|
||||
Copyright (C) 2011 Free Software Foundation, Inc.
|
||||
This is free software; see the source for copying conditions. There is NO
|
||||
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
configure:1649: $? = 0
|
||||
configure:1651: gcc -v </dev/null >&5
|
||||
Using built-in specs.
|
||||
COLLECT_GCC=gcc
|
||||
COLLECT_LTO_WRAPPER=/usr/lib/gcc/arm-linux-gnueabihf/4.6/lto-wrapper
|
||||
Target: arm-linux-gnueabihf
|
||||
Configured with: ../src/configure -v --with-pkgversion='Debian 4.6.3-14+rpi1' --with-bugurl=file:///usr/share/doc/gcc-4.6/README.Bugs --enable-languages=c,c++,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.6 --enable-shared --enable-linker-build-id --with-system-zlib --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.6 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --enable-plugin --enable-objc-gc --disable-sjlj-exceptions --with-arch=armv6 --with-fpu=vfp --with-float=hard --enable-checking=release --build=arm-linux-gnueabihf --host=arm-linux-gnueabihf --target=arm-linux-gnueabihf
|
||||
Thread model: posix
|
||||
gcc version 4.6.3 (Debian 4.6.3-14+rpi1)
|
||||
configure:1654: $? = 0
|
||||
configure:1656: gcc -V </dev/null >&5
|
||||
gcc: error: unrecognized option '-V'
|
||||
gcc: fatal error: no input files
|
||||
compilation terminated.
|
||||
configure:1659: $? = 4
|
||||
configure:1682: checking for C compiler default output file name
|
||||
configure:1685: gcc conftest.c >&5
|
||||
configure:1688: $? = 0
|
||||
configure:1734: result: a.out
|
||||
configure:1739: checking whether the C compiler works
|
||||
configure:1745: ./a.out
|
||||
configure:1748: $? = 0
|
||||
configure:1765: result: yes
|
||||
configure:1772: checking whether we are cross compiling
|
||||
configure:1774: result: no
|
||||
configure:1777: checking for suffix of executables
|
||||
configure:1779: gcc -o conftest conftest.c >&5
|
||||
configure:1782: $? = 0
|
||||
configure:1807: result:
|
||||
configure:1813: checking for suffix of object files
|
||||
configure:1834: gcc -c conftest.c >&5
|
||||
configure:1837: $? = 0
|
||||
configure:1859: result: o
|
||||
configure:1863: checking whether we are using the GNU C compiler
|
||||
configure:1887: gcc -c conftest.c >&5
|
||||
configure:1893: $? = 0
|
||||
configure:1897: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:1900: $? = 0
|
||||
configure:1903: test -s conftest.o
|
||||
configure:1906: $? = 0
|
||||
configure:1919: result: yes
|
||||
configure:1925: checking whether gcc accepts -g
|
||||
configure:1946: gcc -c -g conftest.c >&5
|
||||
configure:1952: $? = 0
|
||||
configure:1956: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:1959: $? = 0
|
||||
configure:1962: test -s conftest.o
|
||||
configure:1965: $? = 0
|
||||
configure:1976: result: yes
|
||||
configure:1993: checking for gcc option to accept ANSI C
|
||||
configure:2063: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2069: $? = 0
|
||||
configure:2073: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2076: $? = 0
|
||||
configure:2079: test -s conftest.o
|
||||
configure:2082: $? = 0
|
||||
configure:2100: result: none needed
|
||||
configure:2118: gcc -c -g -O2 conftest.c >&5
|
||||
conftest.c:2:3: error: unknown type name 'choke'
|
||||
conftest.c:2:3: error: expected '=', ',', ';', 'asm' or '__attribute__' at end of input
|
||||
configure:2124: $? = 1
|
||||
configure: failed program was:
|
||||
| #ifndef __cplusplus
|
||||
| choke me
|
||||
| #endif
|
||||
configure:2263: checking how to run the C preprocessor
|
||||
configure:2298: gcc -E conftest.c
|
||||
configure:2304: $? = 0
|
||||
configure:2336: gcc -E conftest.c
|
||||
conftest.c:9:28: fatal error: ac_nonexistent.h: No such file or directory
|
||||
compilation terminated.
|
||||
configure:2342: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h. */
|
||||
|
|
||||
| #define PACKAGE_NAME "lua-sqlite3"
|
||||
| #define PACKAGE_TARNAME "lua-sqlite3"
|
||||
| #define PACKAGE_VERSION "0.4"
|
||||
| #define PACKAGE_STRING "lua-sqlite3 0.4"
|
||||
| #define PACKAGE_BUGREPORT "mroth@nessie.de"
|
||||
| /* end confdefs.h. */
|
||||
| #include <ac_nonexistent.h>
|
||||
configure:2381: result: gcc -E
|
||||
configure:2405: gcc -E conftest.c
|
||||
configure:2411: $? = 0
|
||||
configure:2443: gcc -E conftest.c
|
||||
conftest.c:9:28: fatal error: ac_nonexistent.h: No such file or directory
|
||||
compilation terminated.
|
||||
configure:2449: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h. */
|
||||
|
|
||||
| #define PACKAGE_NAME "lua-sqlite3"
|
||||
| #define PACKAGE_TARNAME "lua-sqlite3"
|
||||
| #define PACKAGE_VERSION "0.4"
|
||||
| #define PACKAGE_STRING "lua-sqlite3 0.4"
|
||||
| #define PACKAGE_BUGREPORT "mroth@nessie.de"
|
||||
| /* end confdefs.h. */
|
||||
| #include <ac_nonexistent.h>
|
||||
configure:2493: checking for egrep
|
||||
configure:2503: result: grep -E
|
||||
configure:2508: checking for ANSI C header files
|
||||
configure:2533: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2539: $? = 0
|
||||
configure:2543: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2546: $? = 0
|
||||
configure:2549: test -s conftest.o
|
||||
configure:2552: $? = 0
|
||||
configure:2641: gcc -o conftest -g -O2 conftest.c >&5
|
||||
conftest.c: In function 'main':
|
||||
conftest.c:26:7: warning: incompatible implicit declaration of built-in function 'exit' [enabled by default]
|
||||
configure:2644: $? = 0
|
||||
configure:2646: ./conftest
|
||||
configure:2649: $? = 0
|
||||
configure:2664: result: yes
|
||||
configure:2688: checking for sys/types.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for sys/stat.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for stdlib.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for string.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for memory.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for strings.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for inttypes.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for stdint.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2688: checking for unistd.h
|
||||
configure:2704: gcc -c -g -O2 conftest.c >&5
|
||||
configure:2710: $? = 0
|
||||
configure:2714: test -z
|
||||
|| test ! -s conftest.err
|
||||
configure:2717: $? = 0
|
||||
configure:2720: test -s conftest.o
|
||||
configure:2723: $? = 0
|
||||
configure:2734: result: yes
|
||||
configure:2895: checking for egrep
|
||||
configure:2905: result: grep -E
|
||||
configure:2912: checking whether linking with rpath is requested
|
||||
configure:2922: result: no
|
||||
configure:2970: checking for lua
|
||||
configure:2989: found /usr/bin/lua
|
||||
configure:3001: result: /usr/bin/lua
|
||||
configure:3083: checking lua.h usability
|
||||
configure:3095: gcc -c -g -O2 conftest.c >&5
|
||||
conftest.c:53:17: fatal error: lua.h: No such file or directory
|
||||
compilation terminated.
|
||||
configure:3101: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h. */
|
||||
|
|
||||
| #define PACKAGE_NAME "lua-sqlite3"
|
||||
| #define PACKAGE_TARNAME "lua-sqlite3"
|
||||
| #define PACKAGE_VERSION "0.4"
|
||||
| #define PACKAGE_STRING "lua-sqlite3 0.4"
|
||||
| #define PACKAGE_BUGREPORT "mroth@nessie.de"
|
||||
| #define STDC_HEADERS 1
|
||||
| #define HAVE_SYS_TYPES_H 1
|
||||
| #define HAVE_SYS_STAT_H 1
|
||||
| #define HAVE_STDLIB_H 1
|
||||
| #define HAVE_STRING_H 1
|
||||
| #define HAVE_MEMORY_H 1
|
||||
| #define HAVE_STRINGS_H 1
|
||||
| #define HAVE_INTTYPES_H 1
|
||||
| #define HAVE_STDINT_H 1
|
||||
| #define HAVE_UNISTD_H 1
|
||||
| /* end confdefs.h. */
|
||||
| #include <stdio.h>
|
||||
| #if HAVE_SYS_TYPES_H
|
||||
| # include <sys/types.h>
|
||||
| #endif
|
||||
| #if HAVE_SYS_STAT_H
|
||||
| # include <sys/stat.h>
|
||||
| #endif
|
||||
| #if STDC_HEADERS
|
||||
| # include <stdlib.h>
|
||||
| # include <stddef.h>
|
||||
| #else
|
||||
| # if HAVE_STDLIB_H
|
||||
| # include <stdlib.h>
|
||||
| # endif
|
||||
| #endif
|
||||
| #if HAVE_STRING_H
|
||||
| # if !STDC_HEADERS && HAVE_MEMORY_H
|
||||
| # include <memory.h>
|
||||
| # endif
|
||||
| # include <string.h>
|
||||
| #endif
|
||||
| #if HAVE_STRINGS_H
|
||||
| # include <strings.h>
|
||||
| #endif
|
||||
| #if HAVE_INTTYPES_H
|
||||
| # include <inttypes.h>
|
||||
| #else
|
||||
| # if HAVE_STDINT_H
|
||||
| # include <stdint.h>
|
||||
| # endif
|
||||
| #endif
|
||||
| #if HAVE_UNISTD_H
|
||||
| # include <unistd.h>
|
||||
| #endif
|
||||
| #include <lua.h>
|
||||
configure:3124: result: no
|
||||
configure:3128: checking lua.h presence
|
||||
configure:3138: gcc -E conftest.c
|
||||
conftest.c:19:17: fatal error: lua.h: No such file or directory
|
||||
compilation terminated.
|
||||
configure:3144: $? = 1
|
||||
configure: failed program was:
|
||||
| /* confdefs.h. */
|
||||
|
|
||||
| #define PACKAGE_NAME "lua-sqlite3"
|
||||
| #define PACKAGE_TARNAME "lua-sqlite3"
|
||||
| #define PACKAGE_VERSION "0.4"
|
||||
| #define PACKAGE_STRING "lua-sqlite3 0.4"
|
||||
| #define PACKAGE_BUGREPORT "mroth@nessie.de"
|
||||
| #define STDC_HEADERS 1
|
||||
| #define HAVE_SYS_TYPES_H 1
|
||||
| #define HAVE_SYS_STAT_H 1
|
||||
| #define HAVE_STDLIB_H 1
|
||||
| #define HAVE_STRING_H 1
|
||||
| #define HAVE_MEMORY_H 1
|
||||
| #define HAVE_STRINGS_H 1
|
||||
| #define HAVE_INTTYPES_H 1
|
||||
| #define HAVE_STDINT_H 1
|
||||
| #define HAVE_UNISTD_H 1
|
||||
| /* end confdefs.h. */
|
||||
| #include <lua.h>
|
||||
configure:3164: result: no
|
||||
configure:3199: checking for lua.h
|
||||
configure:3206: result: no
|
||||
configure:3213: error: Cannot find lua.h
|
||||
|
||||
## ---------------- ##
|
||||
## Cache variables. ##
|
||||
## ---------------- ##
|
||||
|
||||
ac_cv_c_compiler_gnu=yes
|
||||
ac_cv_env_CC_set=
|
||||
ac_cv_env_CC_value=
|
||||
ac_cv_env_CFLAGS_set=
|
||||
ac_cv_env_CFLAGS_value=
|
||||
ac_cv_env_CPPFLAGS_set=
|
||||
ac_cv_env_CPPFLAGS_value=
|
||||
ac_cv_env_CPP_set=
|
||||
ac_cv_env_CPP_value=
|
||||
ac_cv_env_LDFLAGS_set=
|
||||
ac_cv_env_LDFLAGS_value=
|
||||
ac_cv_env_build_alias_set=
|
||||
ac_cv_env_build_alias_value=
|
||||
ac_cv_env_host_alias_set=
|
||||
ac_cv_env_host_alias_value=
|
||||
ac_cv_env_target_alias_set=
|
||||
ac_cv_env_target_alias_value=
|
||||
ac_cv_exeext=
|
||||
ac_cv_header_inttypes_h=yes
|
||||
ac_cv_header_lua_h=no
|
||||
ac_cv_header_memory_h=yes
|
||||
ac_cv_header_stdc=yes
|
||||
ac_cv_header_stdint_h=yes
|
||||
ac_cv_header_stdlib_h=yes
|
||||
ac_cv_header_string_h=yes
|
||||
ac_cv_header_strings_h=yes
|
||||
ac_cv_header_sys_stat_h=yes
|
||||
ac_cv_header_sys_types_h=yes
|
||||
ac_cv_header_unistd_h=yes
|
||||
ac_cv_objext=o
|
||||
ac_cv_path_LUA=/usr/bin/lua
|
||||
ac_cv_prog_CPP='gcc -E'
|
||||
ac_cv_prog_ac_ct_CC=gcc
|
||||
ac_cv_prog_cc_g=yes
|
||||
ac_cv_prog_cc_stdc=
|
||||
ac_cv_prog_egrep='grep -E'
|
||||
|
||||
## ----------------- ##
|
||||
## Output variables. ##
|
||||
## ----------------- ##
|
||||
|
||||
CC='gcc'
|
||||
CFLAGS='-g -O2'
|
||||
CPP='gcc -E'
|
||||
CPPFLAGS=''
|
||||
DEFS=''
|
||||
ECHO_C=''
|
||||
ECHO_N='-n'
|
||||
ECHO_T=''
|
||||
EGREP='grep -E'
|
||||
EXEEXT=''
|
||||
LDFLAGS=''
|
||||
LIBOBJS=''
|
||||
LIBS=''
|
||||
LTLIBOBJS=''
|
||||
LUA='/usr/bin/lua'
|
||||
OBJEXT='o'
|
||||
PACKAGE_BUGREPORT='mroth@nessie.de'
|
||||
PACKAGE_NAME='lua-sqlite3'
|
||||
PACKAGE_STRING='lua-sqlite3 0.4'
|
||||
PACKAGE_TARNAME='lua-sqlite3'
|
||||
PACKAGE_VERSION='0.4'
|
||||
PATH_SEPARATOR=':'
|
||||
SHELL='/bin/bash'
|
||||
ac_ct_CC='gcc'
|
||||
bindir='${exec_prefix}/bin'
|
||||
build_alias=''
|
||||
datadir='${prefix}/share'
|
||||
exec_prefix='NONE'
|
||||
host_alias=''
|
||||
includedir='${prefix}/include'
|
||||
infodir='${prefix}/info'
|
||||
libdir='${exec_prefix}/lib'
|
||||
libexecdir='${exec_prefix}/libexec'
|
||||
localstatedir='${prefix}/var'
|
||||
mandir='${prefix}/man'
|
||||
oldincludedir='/usr/include'
|
||||
prefix='NONE'
|
||||
program_transform_name='s,x,x,'
|
||||
sbindir='${exec_prefix}/sbin'
|
||||
sharedstatedir='${prefix}/com'
|
||||
sysconfdir='${prefix}/etc'
|
||||
target_alias=''
|
||||
|
||||
## ----------- ##
|
||||
## confdefs.h. ##
|
||||
## ----------- ##
|
||||
|
||||
#define HAVE_INTTYPES_H 1
|
||||
#define HAVE_MEMORY_H 1
|
||||
#define HAVE_STDINT_H 1
|
||||
#define HAVE_STDLIB_H 1
|
||||
#define HAVE_STRINGS_H 1
|
||||
#define HAVE_STRING_H 1
|
||||
#define HAVE_SYS_STAT_H 1
|
||||
#define HAVE_SYS_TYPES_H 1
|
||||
#define HAVE_UNISTD_H 1
|
||||
#define PACKAGE_BUGREPORT "mroth@nessie.de"
|
||||
#define PACKAGE_NAME "lua-sqlite3"
|
||||
#define PACKAGE_STRING "lua-sqlite3 0.4"
|
||||
#define PACKAGE_TARNAME "lua-sqlite3"
|
||||
#define PACKAGE_VERSION "0.4"
|
||||
#define STDC_HEADERS 1
|
||||
|
||||
configure: exit 1
|
||||
4490
lua-sqlite3-0.4.1/configure
vendored
Executable file
4490
lua-sqlite3-0.4.1/configure
vendored
Executable file
File diff suppressed because it is too large
Load Diff
141
lua-sqlite3-0.4.1/configure.ac
Normal file
141
lua-sqlite3-0.4.1/configure.ac
Normal file
@@ -0,0 +1,141 @@
|
||||
AC_INIT(lua-sqlite3, 0.4, mroth@nessie.de)
|
||||
AC_COPYRIGHT([Copyright (c) 2006 Michael Roth <mroth@nessie.de>])
|
||||
|
||||
|
||||
AC_PROG_CC()
|
||||
AC_CHECK_HEADERS()
|
||||
AC_PROG_EGREP()
|
||||
|
||||
|
||||
AC_MSG_CHECKING([whether linking with rpath is requested])
|
||||
AC_ARG_ENABLE(rpath,
|
||||
AC_HELP_STRING([--enable-rpath], [link with rpath option]),
|
||||
rpath=$enableval,
|
||||
rpath=no
|
||||
)
|
||||
AC_MSG_RESULT($rpath)
|
||||
|
||||
|
||||
lua_dir=""
|
||||
lua_includedir=""
|
||||
lua_libdir=""
|
||||
LUA=""
|
||||
|
||||
AC_ARG_WITH(lua-dir,
|
||||
[AC_HELP_STRING(--with-lua-dir=DIR, [where you installed lua [EPREFIX]]) ],
|
||||
[
|
||||
lua_dir="${withval}"
|
||||
lua_includedir="${lua_dir}/include"
|
||||
lua_libdir="${lua_dir}/lib"
|
||||
LUA="${lua_dir}/bin/lua"
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(lua-includedir,
|
||||
[AC_HELP_STRING(--with-lua-includedir=DIR, [where to find lua headers [LUA_DIR/include]])],
|
||||
lua_includedir="${withval}"
|
||||
)
|
||||
|
||||
AC_ARG_WITH(lua-libdir,
|
||||
[AC_HELP_STRING(--with-lua-libdir=DIR, [where to find the lua library [LUA_DIR/lib]])],
|
||||
lua_libdir="${withval}"
|
||||
)
|
||||
|
||||
AC_ARG_WITH(lua,
|
||||
[AC_HELP_STRING(--with-lua=FILE, [path to the 'lua' command [LUA_DIR/bin/lua]])],
|
||||
LUA="${withval}"
|
||||
)
|
||||
|
||||
AC_PATH_PROG(LUA, lua, [], [$bindir:$exec_prefix/bin:$prefix/bin:$PATH])
|
||||
|
||||
if test ! -x "${LUA}" ; then
|
||||
AC_MSG_WARN([No lua interpreter found!])
|
||||
fi
|
||||
|
||||
|
||||
sqlite3_dir=""
|
||||
sqlite3_includedir=""
|
||||
sqlite3_libdir=""
|
||||
|
||||
AC_ARG_WITH(sqlite3-dir,
|
||||
[AC_HELP_STRING(--with-sqlite3-dir=DIR, [where you installed sqlite3 [EPREFIX]])],
|
||||
[
|
||||
sqlite3_dir="${withval}"
|
||||
sqlite3_includedir="${sqlite3_dir}/include"
|
||||
sqlite3_libdir="${sqlite3_dir}/lib"
|
||||
]
|
||||
)
|
||||
|
||||
AC_ARG_WITH(sqlite3-includedir,
|
||||
[AC_HELP_STRING(--with-sqlite3-includedir=DIR, [where to find sqlite3 headers [SQLITE3_DIR/include]])],
|
||||
sqlite3_includedir="${withval}"
|
||||
)
|
||||
|
||||
AC_ARG_WITH(sqlite3-libdir,
|
||||
[AC_HELP_STRING(--with-sqlite3-libdir=DIR, [where to find the sqlite3 library [SQLITE3_DIR/lib]])],
|
||||
sqlite3_libdir="${withval}"
|
||||
)
|
||||
|
||||
|
||||
if test -n "$lua_includedir" ; then
|
||||
CFLAGS="-I$lua_includedir $CFLAGS"
|
||||
CPPFLAGS="-I$lua_includedir $CPPFLAGS"
|
||||
fi
|
||||
|
||||
if test -n "$lua_libdir" ; then
|
||||
if test $rpath = yes ; then
|
||||
LDFLAGS="-Wl,-rpath,${lua_libdir}"
|
||||
fi
|
||||
LDFLAGS="-L$lua_libdir $LDFLAGS"
|
||||
fi
|
||||
|
||||
if test -n "$sqlite3_includedir" -a "$sqlite3_includedir" != "$lua_includedir"; then
|
||||
CFLAGS="-I$sqlite3_includedir $CFLAGS"
|
||||
CPPFLAGS="-I$sqlite3_includedir $CPPFLAGS"
|
||||
fi
|
||||
|
||||
if test -n "$sqlite3_libdir" -a "$sqlite3_libdir" != "$lua_libdir"; then
|
||||
if test $rpath = yes ; then
|
||||
LDFLAGS="-Wl,-rpath,${sqlite3_libdir}"
|
||||
fi
|
||||
LDFLAGS="-L$sqlite3_libdir $LDFLAGS"
|
||||
fi
|
||||
|
||||
|
||||
AC_CHECK_HEADER(lua.h, [], [AC_MSG_ERROR(Cannot find lua.h)])
|
||||
AC_CHECK_HEADER(lauxlib.h, [], [AC_MSG_ERROR(Cannot find lauxlib.h)])
|
||||
AC_CHECK_HEADER(sqlite3.h, [], [AC_MSG_ERROR(Cannot find sqlite3.h)])
|
||||
|
||||
|
||||
AC_MSG_CHECKING(if we need -llua)
|
||||
need_llua=yes
|
||||
nm -D "$LUA" | $EGREP "T lua_open$" >/dev/null && need_llua=no
|
||||
AC_MSG_RESULT($need_llua)
|
||||
if test $need_llua = yes; then
|
||||
LIBS="-llua -lm $LIBS"
|
||||
fi
|
||||
|
||||
|
||||
AC_MSG_CHECKING(if we need -llualib)
|
||||
if test $need_llua = yes; then
|
||||
AC_LINK_IFELSE([
|
||||
#include "lauxlib.h"
|
||||
int main()
|
||||
{
|
||||
luaL_Buffer buf;
|
||||
luaL_buffinit(0, &buf);
|
||||
return 0;
|
||||
}
|
||||
], [need_llualib=no], [need_llualib=yes])
|
||||
else
|
||||
need_llualib=no
|
||||
fi
|
||||
AC_MSG_RESULT($need_llualib)
|
||||
if test $need_llualib = yes; then
|
||||
LIBS="-llualib $LIBS"
|
||||
fi
|
||||
|
||||
LIBS="-lsqlite3 $LIBS"
|
||||
|
||||
AC_CONFIG_FILES([Makefile])
|
||||
AC_OUTPUT
|
||||
796
lua-sqlite3-0.4.1/documentation.html
Normal file
796
lua-sqlite3-0.4.1/documentation.html
Normal file
@@ -0,0 +1,796 @@
|
||||
<html><head><title>Lua-Sqlite3 Documentation</title></head>
|
||||
<body>
|
||||
<center><h1>Lua-Sqlite3 Documentation</h1></center>
|
||||
<hr size="1">
|
||||
<h1>Table of Contents</h1>
|
||||
<blockquote><ul>
|
||||
<li><a href="#ref1">Overview</a></li>
|
||||
<ul>
|
||||
<li><a href="#ref2">Summary</a></li>
|
||||
</ul>
|
||||
<li><a href="#ref3">Installation</a></li>
|
||||
<li><a href="#ref4">Sqlite3 Frontend</a></li>
|
||||
<ul>
|
||||
<li><a href="#ref5">Error handling</a></li>
|
||||
<li><a href="#ref6">Open and Close </a></li>
|
||||
<li><a href="#ref7">Executing simple SQL Statements</a></li>
|
||||
<li><a href="#ref8">Fetching Rows using SELECT Statements</a></li>
|
||||
<li><a href="#ref9">Fetching a Single Row</a></li>
|
||||
<li><a href="#ref10">Simple Prepared Statements</a></li>
|
||||
<li><a href="#ref11">Prepared Statements with Parameters (Binding)</a></li>
|
||||
<ul>
|
||||
<li><a href="#ref12">Anonymous Parameters</a></li>
|
||||
<li><a href="#ref13">Named Parameters</a></li>
|
||||
<li><a href="#ref14">Automatic Parameter Name Mapping</a></li>
|
||||
<li><a href="#ref15">Parameter Passing with a Name/Value Table</a></li>
|
||||
<li><a href="#ref16">Querying Parameter Names </a></li>
|
||||
</ul>
|
||||
<li><a href="#ref17">Defining User Functions</a></li>
|
||||
<li><a href="#ref18">Defining User Aggregates</a></li>
|
||||
<li><a href="#ref19">Collatores and Collation Handler</a></li>
|
||||
<li><a href="#ref20">Busy Timeout and Handler</a></li>
|
||||
<ul>
|
||||
<li><a href="#ref21">Busy Timeout</a></li>
|
||||
<li><a href="#ref22">Busy Handler</a></li>
|
||||
</ul>
|
||||
<li><a href="#ref23">Progress, Authorizer, Trace and Commit Handler</a></li>
|
||||
<ul>
|
||||
<li><a href="#ref24">Trace Handler</a></li>
|
||||
</ul>
|
||||
<li><a href="#ref25">Call Chaining</a></li>
|
||||
</ul>
|
||||
<li><a href="#ref26">LuaSQL Frontend</a></li>
|
||||
<li><a href="#ref27">libluasqlite3 Wrapper</a></li>
|
||||
</ul></blockquote>
|
||||
<hr size="1">
|
||||
<h1><a name="ref1">Overview</a></h1><blockquote>
|
||||
<p class="text">
|
||||
Lua-Sqlite3 is a binding of sqlite (<a href="http://www.sqlite.org">http://www.sqlite.org</a>) Version 3 to Lua (<a href="http://www.lua.org/">http://www.lua.org/</a>).
|
||||
</p>
|
||||
<p class="text">
|
||||
Lua-Sqlite3 is unique in contrast to other database bindings that it consists of two layers.
|
||||
</p>
|
||||
<p class="text">
|
||||
The first layer, written in C, is called the 'backend'. The backend translates the C-api of the sqlite library version 3 to lua. The backend mainly converts datatypes from C to lua and vice versa and expose most C functions from the sqlite library to lua.
|
||||
</p>
|
||||
<p class="text">
|
||||
The second layers are called 'frontends' and are written in lua. A frontend provides a specific view and interface to a database. For example it's the job of a frontend to translate error codes from the sqlite library to error messages in lua. It's also the job of a fronted to arrange for garbage collection of database handles and to make sure, that the functions exposed by the backend are called in the right order.
|
||||
</p>
|
||||
<p class="text">
|
||||
Currently, Lua-Sqlite3 implements two frontends:
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
An specialiced frontend, simple named 'Sqlite3', which explodes all capabilities of the sqlite library in a comfortable way.
|
||||
</li>
|
||||
<li>
|
||||
A frontend, named 'LuaSQL-Sqlite3' which provides a LuaSQL compatible interface as used in the Kepler Project.
|
||||
</li>
|
||||
</ol>
|
||||
<p class="text">
|
||||
The first frontend named 'Sqlite3' provides following advantages:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Works in host programs that use multiple Lua states.
|
||||
</li>
|
||||
<li>
|
||||
No problems in conjunction with Lua coroutines, instead powerfull usage of coroutines possible.
|
||||
</li>
|
||||
<li>
|
||||
Reading result sets using for-loop iterators.
|
||||
</li>
|
||||
<li>
|
||||
Automatic and smart converting of data types.
|
||||
</li>
|
||||
<li>
|
||||
Blocks of multiple SQL statements could be executed at once.
|
||||
</li>
|
||||
<li>
|
||||
User functions, aggregates and collators in a natural way.
|
||||
</li>
|
||||
<li>
|
||||
Authorize, trace, commit, progress and busy handlers.
|
||||
</li>
|
||||
</ul>
|
||||
<p class="text">
|
||||
The second frontend named 'LuaSQL-Sqlite3' is fully compatible with the database standard defined by the Kepler Project. This frontend provides currently no extensions.
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref2">Summary</a></h2><blockquote>
|
||||
<p class="text">
|
||||
The complete package is named 'Lua-Sqlite3'. It consists of a backend, named 'libluasqlite3' and currently two frontends, named 'Sqlite3' and 'LuaSQL-Sqlite3'.
|
||||
</p>
|
||||
<p class="text">
|
||||
The backend is a thin wrapper to expose the C-api of sqlite library version 3 to lua. The backend is written in C.
|
||||
</p>
|
||||
<p class="text">
|
||||
The frontends are build on top of the backend and are written in lua. The frontends provide a specific interface to a database.
|
||||
</p>
|
||||
</blockquote>
|
||||
<hr size="1">
|
||||
<h1><a name="ref3">Installation</a></h1><blockquote>
|
||||
<p class="text">
|
||||
Lua-Sqlite3 comes with a configure script to customize the paths where to install and where to find headers and libraries.
|
||||
</p>
|
||||
<p class="text">
|
||||
The configure options --with-lua-dir and --with-sqlite3-dir tell where you installed lua and sqlite3 to search for headers and libraries.
|
||||
</p>
|
||||
<p class="text">
|
||||
If you are using shared libraries and didn't installed sqlite3 or lua to a standard directory searched by the dynamic linker of your operating system, you could run configure with --enable-rpath to make sure, that Lua-Sqlite3 will find the shared libraries without setting LD_LIBRARY_PATH.
|
||||
</p>
|
||||
<p class="text">
|
||||
After you run configure, run make to build the C-library. After successfull build of the C-library you could also run the provided testsuite to make sure all work as expected and finally install the package.
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
# ./configure --help
|
||||
# ./configure ...
|
||||
# make all
|
||||
# make check
|
||||
# make install
|
||||
</pre>
|
||||
<p class="text">
|
||||
If you plan to use Lua-Sqlite3 on Windows or if you would like to link Lua-Sqlite3 statically to your host program, you should fiddle with the backend loader, a lua function named load_libluasqlite3() defined in the file libluasqlite3-loader.lua. Actually this file is created from a template, called libluasqlite3-loader.lua.in. The changes needed to the loader should be obvious.
|
||||
</p>
|
||||
<p class="text">
|
||||
Warning: Maybe the loader process and behaviour will change in future releases again.
|
||||
</p>
|
||||
<p class="text">
|
||||
Warning 2: The loader process will definitively change when Lua-Sqlite3 drops support for Lua-5.0 while switching to Lua-5.1 package style.
|
||||
</p>
|
||||
</blockquote>
|
||||
<hr size="1">
|
||||
<h1><a name="ref4">Sqlite3 Frontend</a></h1><blockquote>
|
||||
<p class="text">
|
||||
The Lua-Sqlite3 frontend provides an object oriented view to a sqlite3 database. There are only two types of objects: A database object and a statement object. The objects itself are really tables, but that doesn't matters.
|
||||
</p>
|
||||
<p class="text">
|
||||
A Database object is created when opening a database was successfull. A statement object is created when you compile a SQL statement using an open database object.
|
||||
</p>
|
||||
<p class="text">
|
||||
These objects provide different methods that you call to perform the desired function. There are methods to close objects and methods to execute SQL statements.
|
||||
</p>
|
||||
<p class="text">
|
||||
A method is always called with the colon syntax. An error is raised, if you use a dot ('.') instead a colon (':').for example:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
-- Ok
|
||||
db:close()
|
||||
|
||||
-- Error! Don't do this!
|
||||
db.close()
|
||||
|
||||
-- This works too, but doesn't look nice and is error prone
|
||||
db.close(db)
|
||||
</pre>
|
||||
<p class="text">
|
||||
However, there is an exception. The 'sqlite3' namespace isn't an object, it's just a namespace, a table with functions. You must use a dot ('.'), using a colon (':') results in undefined behaviour or raises an error.
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref5">Error handling</a></h2><blockquote>
|
||||
<p class="text">
|
||||
If a method on any Lua-Sqlite3 object was successfull, something is returned that evaluates to true, if used in an expression. Mostly these are newly created objects or returned rows.
|
||||
</p>
|
||||
<p class="text">
|
||||
There are two possible error sources:
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
Errors in the application, for example SQL syntax errors, closing a database twice or trying to execute a statement on a closed database.
|
||||
</li>
|
||||
<li>
|
||||
Errors reported from sqlite3 itself, for example a locked database, or an interrupted query and so on.
|
||||
</li>
|
||||
</ol>
|
||||
<p class="text">
|
||||
In the first case, an error in Lua-Sqlite3 usage, the error is reported with the Lua function error(), which results in terminating the last protected function call.
|
||||
</p>
|
||||
<p class="text">
|
||||
In the second case, when an error during executing a SQL statement occurs, two values are returned: A nil value and an string containing the error message.
|
||||
</p>
|
||||
<p class="text">
|
||||
This behaviour will result in easy catching of all errors using assert() and pcall():
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
function foobar()
|
||||
assert( some_sqlite3_function() )
|
||||
assert( another_sqlite3_call() )
|
||||
assert( a_third_call_to_sqlite3() )
|
||||
end
|
||||
|
||||
ok, errmsg = pcall( foobar )
|
||||
|
||||
if not ok then
|
||||
print("An database error occurred:", errmsg)
|
||||
end
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2><a name="ref6">Open and Close </a></h2><blockquote>
|
||||
<p class="text">
|
||||
You can open a database that resides in a file on a disc, or you could open a database in memory. As stated above, make sure you use a single point ('.') to call the functions in the 'sqlite3' namespace. Don't use a colon (':') because 'sqlite3' isn't an object:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
-- Open a file database
|
||||
db = sqlite3.open("filename")
|
||||
|
||||
-- Open a temporary database in memory
|
||||
db = sqlite3.open_memory()
|
||||
</pre>
|
||||
<p class="text">
|
||||
To close a database you invoke the method db:close(). Because this call is a method on the database object, you must use a colon (':') to separate the method name from the object name:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
db:close()
|
||||
</pre>
|
||||
<p class="text">
|
||||
If you close a database, all uncommitted transactions are rolled back, all resources are released automatically. You don't need to close other objects related to this database, but if you would like, you could do so.
|
||||
</p>
|
||||
<p class="text">
|
||||
If closing the database was successfull db:close() returns the database object itself.
|
||||
</p>
|
||||
<p class="text">
|
||||
If there was an error, for example closing the same database twice, an error is raised. When there was an error in sqlite3 itself, a nil and the error message is returned.
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref7">Executing simple SQL Statements</a></h2><blockquote>
|
||||
<p class="text">
|
||||
To execute SQL statements which don't return rows, user db:exec() with the SQL statement as an argument:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
db:exec( "CREATE TABLE test (id, data)" )
|
||||
db:exec[[ INSERT INTO test VALUES (1, "Hello World") ]]
|
||||
</pre>
|
||||
<p class="text">
|
||||
You can also execute multiple SQL statements using a single db:exec() call. The only prerequisite is that none of the statements return rows. You can use statements like CREATE, INSERT, UPDATE, DELETE and so on, but you can't issue a SELECT statement inside a multiple db:exec(). Doing so will raise an error.
|
||||
</p>
|
||||
<p class="text">
|
||||
Multiple SQL statements must be separated using semicolons:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
db:exec[[
|
||||
BEGIN TRANSACTION;
|
||||
CREATE TABLE test (id, data);
|
||||
INSERT INTO test VALUES (1, "Hello World");
|
||||
INSERT INTO test VALUES (2, "Hello Lua");
|
||||
INSERT INTO test VALUES (3, "Hello Sqlite3");
|
||||
END TRANSACTION
|
||||
]]
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2><a name="ref8">Fetching Rows using SELECT Statements</a></h2><blockquote>
|
||||
<p class="text">
|
||||
To execute a SELECT statement, you can't use db:exec(). Doing so raises an error instead.
|
||||
</p>
|
||||
<p class="text">
|
||||
Rows returned from SELECT statements are fetched using an interator. This works like ipairs() or pairs() in for-loops on tables.
|
||||
</p>
|
||||
<p class="text">
|
||||
You have to choose among three different ways, how the fetched rows should be returned to your loop:
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
For each row an array with column data is returned. The columns are indexed with integers.
|
||||
</li>
|
||||
<li>
|
||||
For each row a table with the column data is returned, but the columns are indexed with the column names.
|
||||
</li>
|
||||
<li>
|
||||
Each column data is returned directly.
|
||||
</li>
|
||||
</ol>
|
||||
<p class="text">
|
||||
An example will make this clear:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
-- Returns a row as an integer indexed array
|
||||
for row in db:irows("SELECT * FROM test") do
|
||||
print(row[1], row[2])
|
||||
end
|
||||
|
||||
-- Returns a row as an table, indexed by column names
|
||||
for row in db:rows("SELECT * FROM test") do
|
||||
print(row.id, row.data)
|
||||
end
|
||||
|
||||
-- Returns each column directly
|
||||
for id, data in db:cols("SELECT * FROM test") do
|
||||
print(id, data)
|
||||
end
|
||||
</pre>
|
||||
<p class="text">
|
||||
Using db:cols() there exists a subtle caveat: By definition, a for loop in Lua terminates when the first value in the returned values is nil. So you can't use the db:cols() iterator, if your SELECT statement returns rows which first column may contain NULLs (which are converted to NIL). If you do so, immediately before the row that first column contains a NULL, the loop will terminate early.
|
||||
</p>
|
||||
<p class="text">
|
||||
To prevent this behaviour, you could either make sure that the first column in your SELECT statement will never be NULL, for example the first column could always be a row id, or alternatively you could insert a constant and a dummy variable. Example:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
for _, id, data in db:cols("SELECT 1, * FROM test") do
|
||||
print(id, data)
|
||||
end
|
||||
</pre>
|
||||
<p class="text">
|
||||
This loop will always return all rows, because the first column is always '1' (the '1' is stored in the dummy variable '_').
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref9">Fetching a Single Row</a></h2><blockquote>
|
||||
<p class="text">
|
||||
Often you only need the first row that a SELECT statement returns. For example counting the number of rows in a table and so on. Using db:rows() and related for such a task is a mess, instead you should use db:first_row() and related for this task:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
row = db:first_irow("SELECT count(*) FROM test")
|
||||
print(row[1])
|
||||
|
||||
row = db:first_row("SELECT count(*) AS count FROM test")
|
||||
print(row.count)
|
||||
|
||||
count = db:first_cols("SELECT count(*) FROM test")
|
||||
print(count)
|
||||
</pre>
|
||||
<p class="text">
|
||||
There doesn't exist a caveat in db:first_cols() like in db:cols(), instead always exactly the columns of the first row from the SELECT statement are returned.
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref10">Simple Prepared Statements</a></h2><blockquote>
|
||||
<p class="text">
|
||||
If you have to repeatedly execute the same SQL statement, it will be more efficient if you compile those statements and reuse the compiled form multiple times.
|
||||
</p>
|
||||
<p class="text">
|
||||
When a statement becomes compiled, the statement is parsed and translated to a virtual machine which is stored in a binary representation form in the sqlite3 library itself. This results in a much faster execution of the statement because every time you reuse a compiled statement, the parsing and building of the virtual machine is omitted.
|
||||
</p>
|
||||
<p class="text">
|
||||
Compiling a statement is done with db:prepare(). It will return a compiled statement object:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
stmt = db:prepare("SELECT * FROM test")
|
||||
</pre>
|
||||
<p class="text">
|
||||
To use a compiled statement, it defines the same methods to execute and query a statement like the db object itself. The examples above could be rewritten to:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
stmt = db:prepare("SELECT * FROM test")
|
||||
|
||||
for row in stmt:irows() do
|
||||
print(row[1], row[2])
|
||||
end
|
||||
|
||||
for row in stmt:rows() do
|
||||
print(row.id, row.data)
|
||||
end
|
||||
|
||||
for id, data in stmt:cols() do
|
||||
print(id, data)
|
||||
end
|
||||
</pre>
|
||||
<p class="text">
|
||||
And:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
stmt = db:prepare("SELECT count(*) AS count FROM test")
|
||||
|
||||
row = stmt:first_irow()
|
||||
print(row[1])
|
||||
|
||||
row = stmt:first_row()
|
||||
print(row.count)
|
||||
|
||||
count = stmt:first_cols()
|
||||
print(count)
|
||||
</pre>
|
||||
<p class="text">
|
||||
You could even compile multiple SQL statements:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
stmt = db:prepare[[
|
||||
INSERT INTO test VALUES (1, "Hello World");
|
||||
INSERT INTO test VALUES (2, "Hello Lua");
|
||||
INSERT INTO test VALUES (3, "Hello Sqlite3")
|
||||
]]
|
||||
|
||||
stmt:exec()
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2><a name="ref11">Prepared Statements with Parameters (Binding)</a></h2><blockquote>
|
||||
<p class="text">
|
||||
You can compile SQL statements with placeholder or parameters. So you can reuse the statements later and bind values to the placeholders. With this you can easily reuse parameterized and complicated SQL statements.
|
||||
</p>
|
||||
<p class="text">
|
||||
There are two possibilities to use placeholders or parameters. Mixing the two possibilities in a single compiled statement is not allowed.
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
Numbered, anonymous parameters using '?'.
|
||||
</li>
|
||||
<li>
|
||||
Named parameters using ':name' or '$name'.
|
||||
</li>
|
||||
</ol>
|
||||
</blockquote><h3><a name="ref12">Anonymous Parameters</a></h3><blockquote>
|
||||
<p class="text">
|
||||
To use a anonymous parameter simply insert a questionmark ('?') in your SQL statement where you would like later bind values to. Then, after you compiled your SQL statement using db:prepare() everytime you would like to bind values to your placeholders, call stmt:bind() to bind the values. The arguments to stmt:bind() are binded to the placeholder in the order the question marks appear in the SQL statement. If the number of arguments to stmt:bind() doesn't match the number of placeholders (questionmarks) in your SQL statement, an error will be raised.
|
||||
</p>
|
||||
<p class="text">
|
||||
You could use parameters and bindings with every valid SQL statement. You can even use placeholders with multiple statements:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
insert_stmt = db:prepare[[
|
||||
INSERT INTO test VALUES (?, ?);
|
||||
INSERT INTO test VALUES (?, ?)
|
||||
]]
|
||||
|
||||
function insert(id1, data1, id2, data2)
|
||||
insert_stmt:bind(id1, data1, id2, data2)
|
||||
insert_stmt:exec()
|
||||
end
|
||||
|
||||
insert( 1, "Hello World", 2, "Hello Lua" )
|
||||
insert( 3, "Hello Sqlite3", 4, "Hello User" )
|
||||
|
||||
get_stmt = db:prepare("SELECT data FROM test WHERE test.id = ?")
|
||||
|
||||
function get_data(id)
|
||||
get_stmt:bind(id)
|
||||
return get_stmt:first_cols()
|
||||
end
|
||||
|
||||
print( get_data(1) )
|
||||
print( get_data(2) )
|
||||
print( get_data(3) )
|
||||
print( get_data(4) )
|
||||
</pre>
|
||||
</blockquote><h3><a name="ref13">Named Parameters</a></h3><blockquote>
|
||||
<p class="text">
|
||||
If you have to bind a lot of values or if you have to use the same value twice or more times in a SQL statement, using the questionmark as a placeholder is error prone because you have to count the questionmarks and make sure you call stmt:bind() with all the values in the right order.
|
||||
</p>
|
||||
<p class="text">
|
||||
Alternatively, you can use named placeholder. A named placeholder is a parameter, which begins with a colon (':') or a dollar sign ('$') followed by alphanumerical characters that build a valid identifier.
|
||||
</p>
|
||||
<p class="text">
|
||||
To define the order of your named placeholder to the stmt:bind() function, you can optionally submit an array with the names of your parameters to db:prepare() as the first argument.
|
||||
</p>
|
||||
<p class="text">
|
||||
The leading colon or dollar sign is optional in the parameter name array. (But of course, the colon or dollar sign in the SQL statement is mandatory.)
|
||||
</p>
|
||||
<p class="text">
|
||||
The ordering of the parameter names in the array determines the order of the arguments to the later stmt:bind() call.
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
db:exec("CREATE TABLE person_name (id, name)")
|
||||
db:exec("CREATE TABLE person_email (id, email)")
|
||||
db:exec("CREATE TABLE person_address (id, address)")
|
||||
|
||||
-- '$' and ':' are optional
|
||||
parameter_names = { ":id", "$name", "address", "email" }
|
||||
|
||||
stmt = db:prepare(parameter_names, [[
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO person_name VALUES (:id, :name);
|
||||
INSERT INTO person_email VALUES (:id, :email);
|
||||
INSERT INTO person_address VALUES (:id, :address);
|
||||
COMMIT
|
||||
]])
|
||||
|
||||
function insert(id, name, address, email)
|
||||
stmt:bind(id, name, address, email)
|
||||
stmt:exec()
|
||||
end
|
||||
|
||||
insert( 1, "Michael", "Germany", "mroth@nessie.de" )
|
||||
insert( 2, "John", "USA", "john@usa.org" )
|
||||
insert( 3, "Hans", "France", "hans@france.com" )
|
||||
</pre>
|
||||
</blockquote><h3><a name="ref14">Automatic Parameter Name Mapping</a></h3><blockquote>
|
||||
<p class="text">
|
||||
If you don't submit an array containing parameter names to stmt:prepare() the parameter names array becomes automatically build. The parameter names in the automatically build array are ordered according to their first occurrence in the SQL statement.
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
...
|
||||
|
||||
stmt = db:prepare[[
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO person_name VALUES (:id, :name);
|
||||
INSERT INTO person_email VALUES (:id, :email);
|
||||
INSERT INTO person_address VALUES (:id, :address);
|
||||
COMMIT
|
||||
]]
|
||||
|
||||
function insert(id, name, address, email)
|
||||
-- Please note the different ordering
|
||||
stmt:bind(id, name, email, address)
|
||||
stmt:exec()
|
||||
end
|
||||
|
||||
...
|
||||
</pre>
|
||||
</blockquote><h3><a name="ref15">Parameter Passing with a Name/Value Table</a></h3><blockquote>
|
||||
<p class="text">
|
||||
If you are using named parameters in your statements, you can pass the arguments to stmt:bind() with a name/value table:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
...
|
||||
|
||||
stmt = db:prepare[[
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO person_name VALUES (:id, :name);
|
||||
INSERT INTO person_email VALUES (:id, :email);
|
||||
INSERT INTO person_address VALUES (:id, :address);
|
||||
COMMIT
|
||||
]]
|
||||
|
||||
function insert(id, name, address, email)
|
||||
args = { }
|
||||
args.id = id
|
||||
args.name = name
|
||||
args.address = address
|
||||
args.email = args.email
|
||||
stmt:bind(args)
|
||||
stmt:exec()
|
||||
end
|
||||
|
||||
-- A shorter version equal to the above
|
||||
function insert2(id, name, address, email)
|
||||
stmt:bind{ id=id, name=name, address=address, email=email}
|
||||
stmt:exec()
|
||||
end
|
||||
|
||||
...
|
||||
</pre>
|
||||
</blockquote><h3><a name="ref16">Querying Parameter Names </a></h3><blockquote>
|
||||
<p class="text">
|
||||
To query the available parameters in a compiled statement you can use stmt:parameter_names() which returns an array. The parameter names in the returned array have their leading colon or dollar sign stripped:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
...
|
||||
|
||||
stmt = db:prepare[[
|
||||
BEGIN TRANSACTION;
|
||||
INSERT INTO person_name VALUES (:id, :name);
|
||||
INSERT INTO person_email VALUES (:id, :email);
|
||||
INSERT INTO person_address VALUES (:id, :address);
|
||||
COMMIT
|
||||
]]
|
||||
|
||||
names = stmt:parameter_names()
|
||||
|
||||
print( table.getn(names) ) -- "4"
|
||||
print( names[1] ) -- "id"
|
||||
print( names[2] ) -- "name"
|
||||
print( names[3] ) -- "email"
|
||||
print( names[4] ) -- "address"
|
||||
|
||||
...
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2><a name="ref17">Defining User Functions</a></h2><blockquote>
|
||||
<p class="text">
|
||||
You can define user functions in Sqlite3. User defined functions are called from the SQL language interpreted by Sqlite3, back to Lua. You can define functions which calculate complicated things or you can use these user defined functions to call back to Lua from SQL triggers.
|
||||
</p>
|
||||
<p class="text">
|
||||
You need to submit the name of the user function, the number of arguments the user function receives and the function itself:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
function sql_add_ten(a)
|
||||
return a + 10
|
||||
end
|
||||
|
||||
db:set_function("add_ten", 1, sql_add_ten)
|
||||
|
||||
for id, add_ten, data in db::rows("SELECT id, add_ten(id), data FROM test") do
|
||||
print(id, add_ten, data)
|
||||
end
|
||||
</pre>
|
||||
<p class="text">
|
||||
You can define functions with variable number of arguments. To do this you have to submit -1 as the number of arguments to db:set_function(). The documentation of sqlite3 states, that any negative number will signal a variable argument function, but at least for sqlite release 3.0.5 this is wrong.
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
function my_max(...)
|
||||
local result = 0
|
||||
for _, value in ipairs(arg) do
|
||||
result = math.max(result, value)
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
db:set_function("my_max", -1, my_max)
|
||||
|
||||
max1 = db:first_cols("SELECT my_max(17, 7)")
|
||||
max2 = db:first_cols("SELECT my_max(1, 2, 3, 4, 5)")
|
||||
|
||||
print(max1, max2) -- 17 5
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2><a name="ref18">Defining User Aggregates</a></h2><blockquote>
|
||||
<p class="text">
|
||||
A aggregate is a function, which is called multiple times, for each row in the query once, that returns a single value at the end. It is only slightly more complicate than an ordinary function.
|
||||
</p>
|
||||
<p class="text">
|
||||
To define a user aggregate, you have to register a function which returns two functions everytime it is called. The first function is used to update an internal state of the user aggregate and the second function is used to fetch the result from the user aggregate.
|
||||
</p>
|
||||
<p class="text">
|
||||
The exact steps are:
|
||||
</p>
|
||||
<ul>
|
||||
<li>
|
||||
Step 1: First a function is called, without any arguments, which normally initialize some accumulators of the user aggregate and returns two functions, which are in most cases closures.
|
||||
</li>
|
||||
<li>
|
||||
Step 2: The first function returned in Step 1 is called for every row once. This function is named the 'step' function. The 'step' functions receives the column data as arguments. The 'step' function doesn't return values. It only collects the data and updates some internal state.
|
||||
</li>
|
||||
<li>
|
||||
Step 3: The second function returned in Step 1 is called exactly once, only after all rows were presented to the 'step' function in Step 2 above. This second function is named the 'finalizer' function. The 'finalizer' function receives one argument, the number of how often the 'step' function in Step 2 was called. The 'finalizer' function returns the result of the aggregate.
|
||||
</li>
|
||||
</ul>
|
||||
<p class="text">
|
||||
An example will make this more clear:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
db:exec[[
|
||||
CREATE TABLE numbers (num1, num2);
|
||||
INSERT INTO numbers VALUES(1, 2);
|
||||
INSERT INTO numbers VALUES(3, 4);
|
||||
INSERT INTO numbers VALUES(5, 6);
|
||||
]]
|
||||
|
||||
function my_product_sum_aggregate()
|
||||
local product_sum = 0
|
||||
|
||||
local function step(a, b)
|
||||
local product = a * b
|
||||
product_sum = product_sum + product
|
||||
end
|
||||
|
||||
local function final(num_called)
|
||||
return product_sum / num_called
|
||||
end
|
||||
|
||||
return step, final
|
||||
end
|
||||
|
||||
db:set_aggregate("product_sum", 2, my_product_sum_aggregate)
|
||||
|
||||
print( db:first_cols("SELECT product_sum(num1, num2) FROM numbers") )
|
||||
</pre>
|
||||
<p class="text">
|
||||
You can define user aggregates with variable number of arguments. In works analogous defining user functions with variable number of arguments.
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref19">Collatores and Collation Handler</a></h2><blockquote>
|
||||
<p class="text">
|
||||
Needs to be written...
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref20">Busy Timeout and Handler</a></h2><blockquote>
|
||||
<p class="text">
|
||||
In Sqlite3 there are two ways to deal with locked databases. You can set a timeout or set a handler.
|
||||
</p>
|
||||
</blockquote><h3><a name="ref21">Busy Timeout</a></h3><blockquote>
|
||||
<p class="text">
|
||||
If you set a timeout, Sqlite3 will try as many milliseconds as specified:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
-- Open the database
|
||||
db = sqlite3.open("filename")
|
||||
|
||||
-- Set 2 seconds busy timeout
|
||||
db:set_busy_timeout(2 * 1000)
|
||||
|
||||
-- Use the database
|
||||
db:exec(...)
|
||||
</pre>
|
||||
</blockquote><h3><a name="ref22">Busy Handler</a></h3><blockquote>
|
||||
<p class="text">
|
||||
You could also set a handler, which gets called in the most cases if the database is locked. A busy handler could do some other work or wait a few milliseconds. The return value of a busy handler determines if Sqlite3 tries to continue with the current transaction or abort the transaction with a "busy" error.
|
||||
</p>
|
||||
<p class="text">
|
||||
If the busy handler returns 0, false or nil, no additional attempts are made by Sqlite3 to proceed with a transaction. All other values result in a new attempt to be made by Sqlite3.
|
||||
</p>
|
||||
<p class="text">
|
||||
A busy handler gets called with one argument, the number of attempts prior made without success in a transaction.
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
-- Open the database
|
||||
db = sqlite3.open("filename")
|
||||
|
||||
-- Ten attempts are made to proceed, if the database is locked
|
||||
function my_busy_handler(attempts_made)
|
||||
if attempts_made < 10 then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
-- Set the new busy handler
|
||||
db:set_busy_handler(my_busy_handler)
|
||||
|
||||
-- Use the database
|
||||
db:exec(...)
|
||||
</pre>
|
||||
</blockquote>
|
||||
<h2><a name="ref23">Progress, Authorizer, Trace and Commit Handler</a></h2><blockquote>
|
||||
<p class="text">
|
||||
You guess it, needs to be written...
|
||||
</p>
|
||||
<p class="text">
|
||||
But wait, the trace handler is documented: ;-)
|
||||
</p>
|
||||
</blockquote><h3><a name="ref24">Trace Handler</a></h3><blockquote>
|
||||
<p class="text">
|
||||
The trace handler in Sqlite3 isn't really a trace handler but it traces effectively compiling SQL statements. So the trace handler is called every time a db:exec() or db:prepare() is executed. The handler gets one argument with the string that was compiled:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
function mytrace(sql_string)
|
||||
print("Sqlite3:", sql_string)
|
||||
end
|
||||
|
||||
db:set_trace_handler(mytrace)
|
||||
</pre>
|
||||
<p class="text">
|
||||
Note: The tracing behaviour will possible change in future. Then we won't use the internal Sqlite3 trace handler but a self written one which gets called every time a SQL statement is executed.
|
||||
</p>
|
||||
</blockquote>
|
||||
<h2><a name="ref25">Call Chaining</a></h2><blockquote>
|
||||
<p class="text">
|
||||
The Sqlite3 Interface makes it possible, to deploy several techniques to write short and efficient code.
|
||||
</p>
|
||||
<p class="text">
|
||||
All methods which doesn't fetch data from the database or creates new objects, return self, like methods in smalltalk.
|
||||
</p>
|
||||
<p class="text">
|
||||
So you can easily build nice chains of method calls:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
sql = "INSERT INTO test VALUES (?, ?)"
|
||||
id = 5
|
||||
data = [[That's a matter of taste, if your prefer "'" or '"'.]]
|
||||
|
||||
db:prepare(sql):bind(id, data):exec()
|
||||
</pre>
|
||||
</blockquote>
|
||||
<hr size="1">
|
||||
<h1><a name="ref26">LuaSQL Frontend</a></h1><blockquote>
|
||||
<p class="text">
|
||||
There is also a LuaSQL compatible frontend provided. To use the LuaSQL compatible frontend, open it with:
|
||||
</p>
|
||||
<pre style="background-color: #eee; border: solid 1px #666; padding: 0.5em;">
|
||||
require "luasql-sqlite3"
|
||||
</pre>
|
||||
<p class="text">
|
||||
The LuaSQL Frontend doesn't use any utility functions from the LuaSQL framework of the Keppler Project because the framework from the Keppler Project assumes that every LuaSQL compatible database layer is written in C which is not true for this Sqlite3 wrapper. But this detail doesn't matter. You could use the LuaSQL frontend with or without any other LuaSQL Keppler Project packages. The LuaSQL frontend is fully compatible and integrates nicely.
|
||||
</p>
|
||||
<p class="text">
|
||||
For a complete description of the LuaSQL interface, please take a look at <a href="http://www.keplerproject.org/luasql/manual.html">http://www.keplerproject.org/luasql/manual.html</a>.
|
||||
</p>
|
||||
<p class="text">
|
||||
Currently LuaSQL-Sqlite3 implements no extensions, but this will change in the near future too.
|
||||
</p>
|
||||
</blockquote>
|
||||
<hr size="1">
|
||||
<h1><a name="ref27">libluasqlite3 Wrapper</a></h1><blockquote>
|
||||
<p class="text">
|
||||
These parts needs to be written:
|
||||
</p>
|
||||
<ol>
|
||||
<li>
|
||||
Open Wrapper
|
||||
</li>
|
||||
<li>
|
||||
Return values and Error Handling
|
||||
</li>
|
||||
<li>
|
||||
API Conventions
|
||||
</li>
|
||||
<li>
|
||||
Type Converting
|
||||
</li>
|
||||
</ol>
|
||||
<p class="text">
|
||||
Please be patient...
|
||||
</p>
|
||||
</blockquote>
|
||||
<hr size="1">
|
||||
<p><br></p>
|
||||
<a href="index.html">Back to Lua-Sqlite3</a>
|
||||
<hr noshade size=1>
|
||||
<font size=-1>Last update: 2006-05-10<br>
|
||||
Copyright (c) 2004, 2005, 2006 Michael Roth</font>
|
||||
</body></html>
|
||||
41
lua-sqlite3-0.4.1/examples/aggregate.lua
Normal file
41
lua-sqlite3-0.4.1/examples/aggregate.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = sqlite3.open_memory()
|
||||
|
||||
assert( db:exec[[
|
||||
|
||||
CREATE TABLE test (col1, col2);
|
||||
|
||||
INSERT INTO test VALUES (1, 2);
|
||||
INSERT INTO test VALUES (2, 4);
|
||||
INSERT INTO test VALUES (3, 6);
|
||||
INSERT INTO test VALUES (4, 8);
|
||||
INSERT INTO test VALUES (5, 10);
|
||||
|
||||
]] )
|
||||
|
||||
|
||||
assert( db:set_aggregate("my_stats", 2, function()
|
||||
|
||||
local square_error_sum = 0
|
||||
|
||||
local function step(a, b)
|
||||
local error = a - b
|
||||
local square_error = error * error
|
||||
square_error_sum = square_error_sum + square_error
|
||||
end
|
||||
|
||||
local function final(num_called)
|
||||
return square_error_sum / num_called
|
||||
end
|
||||
|
||||
return step, final
|
||||
|
||||
end))
|
||||
|
||||
|
||||
local my_stats = db:first_cols("SELECT my_stats(col1, col2) FROM test")
|
||||
print("my_stats:", my_stats)
|
||||
28
lua-sqlite3-0.4.1/examples/function.lua
Normal file
28
lua-sqlite3-0.4.1/examples/function.lua
Normal file
@@ -0,0 +1,28 @@
|
||||
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = sqlite3.open_memory()
|
||||
|
||||
assert( db:exec[[
|
||||
|
||||
CREATE TABLE test (col1, col2);
|
||||
|
||||
INSERT INTO test VALUES (1, 2);
|
||||
INSERT INTO test VALUES (2, 4);
|
||||
INSERT INTO test VALUES (3, 6);
|
||||
INSERT INTO test VALUES (4, 8);
|
||||
INSERT INTO test VALUES (5, 10);
|
||||
|
||||
]] )
|
||||
|
||||
|
||||
assert( db:set_function("my_sum", 2, function(a, b)
|
||||
return a + b
|
||||
end))
|
||||
|
||||
|
||||
for col1, col2, sum in db:cols("SELECT *, my_sum(col1, col2) FROM test") do
|
||||
print(col1, col2, sum)
|
||||
end
|
||||
118
lua-sqlite3-0.4.1/examples/order.lua
Normal file
118
lua-sqlite3-0.4.1/examples/order.lua
Normal file
@@ -0,0 +1,118 @@
|
||||
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = assert( sqlite3:open_memory() )
|
||||
|
||||
|
||||
assert( db:exec[[
|
||||
|
||||
CREATE TABLE customer (
|
||||
id INTEGER PRIMARY KEY,
|
||||
name VARCHAR(40)
|
||||
);
|
||||
|
||||
CREATE TABLE invoice (
|
||||
id INTEGER PRIMARY KEY,
|
||||
customer INTEGER NOT NULL,
|
||||
title VARCHAR(80) NOT NULL,
|
||||
article1 VARCHAR(40) NOT NULL,
|
||||
price1 REAL NOT NULL,
|
||||
article2 VARCHAR(40),
|
||||
price2 REAL
|
||||
);
|
||||
|
||||
CREATE TABLE invoice_overflow (
|
||||
id INTEGER PRIMARY KEY,
|
||||
invoice INTEGER NOT NULL,
|
||||
article VARCHAR(40) NOT NULL,
|
||||
price REAL NOT NULL
|
||||
);
|
||||
|
||||
INSERT INTO customer VALUES(
|
||||
1, "Michael" );
|
||||
|
||||
INSERT INTO invoice VALUES(
|
||||
1, 1, "Computer parts", "harddisc", 89.90, "floppy", 9.99 );
|
||||
|
||||
INSERT INTO customer VALUES(
|
||||
2, "John" );
|
||||
|
||||
INSERT INTO invoice VALUES(
|
||||
2, 2, "Somme food", "apples", 2.79, "pears", 5.99 );
|
||||
|
||||
INSERT INTO invoice_overflow VALUES(
|
||||
NULL, 2, "grapes", 6.34 );
|
||||
|
||||
INSERT INTO invoice_overflow VALUES(
|
||||
NULL, 2, "strawberries", 4.12 );
|
||||
|
||||
INSERT INTO invoice_overflow VALUES(
|
||||
NULL, 2, "tomatoes", 6.17 );
|
||||
|
||||
INSERT INTO invoice VALUES(
|
||||
3, 2, "A new car", "Cybercar XL-1000", 65000.00, NULL, NULL );
|
||||
|
||||
]] )
|
||||
|
||||
|
||||
local function customer_name(id)
|
||||
local stmt = db:prepare("SELECT name FROM customer WHERE id = ?")
|
||||
return stmt:bind(id):first_cols()
|
||||
end
|
||||
|
||||
|
||||
local function all_invoices()
|
||||
return db:rows("SELECT id, customer, title FROM invoice")
|
||||
end
|
||||
|
||||
|
||||
local function all_articles(invoice)
|
||||
|
||||
local function iterator()
|
||||
local stmt, row
|
||||
|
||||
-- Get the articles that are contained in the invoice table itself.
|
||||
stmt = db:prepare("SELECT article1, price1, article2, price2 FROM invoice WHERE id = ?")
|
||||
row = stmt:bind(invoice):first_row()
|
||||
|
||||
-- Every Invoice has at least one article.
|
||||
coroutine.yield(row.article1, row.price1)
|
||||
|
||||
-- Maybe the Invoice has a second article?
|
||||
if row.article2 then
|
||||
|
||||
-- Yes, there is a second article, so return it.
|
||||
coroutine.yield(row.article2, row.price2)
|
||||
|
||||
-- When there was an second article, maybe there are even
|
||||
-- more articles in the overflow table? We will see...
|
||||
|
||||
stmt = db:prepare("SELECT article, price FROM invoice_overflow WHERE invoice = ? ORDER BY id")
|
||||
|
||||
for row in stmt:bind(invoice):rows() do
|
||||
coroutine.yield(row.article, row.price)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return coroutine.wrap(iterator)
|
||||
end
|
||||
|
||||
|
||||
for invoice in all_invoices() do
|
||||
local id = invoice.id
|
||||
local name = customer_name(invoice.customer)
|
||||
local title = invoice.title
|
||||
|
||||
print()
|
||||
print("Invoice #"..id..", "..name..": '"..title.."'")
|
||||
print("----------------------------------------")
|
||||
|
||||
for article, price in all_articles(id) do
|
||||
print( string.format("%20s %8.2f", article, price) )
|
||||
end
|
||||
|
||||
print()
|
||||
end
|
||||
8
lua-sqlite3-0.4.1/examples/path.lua
Normal file
8
lua-sqlite3-0.4.1/examples/path.lua
Normal file
@@ -0,0 +1,8 @@
|
||||
|
||||
local path = "?;?.lua;../?;../?.lua"
|
||||
|
||||
if package == nil then
|
||||
LUA_PATH = path -- Lua 5.0
|
||||
else
|
||||
package.path = path -- Lua 5.1
|
||||
end
|
||||
18
lua-sqlite3-0.4.1/examples/simple.lua
Normal file
18
lua-sqlite3-0.4.1/examples/simple.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = sqlite3.open_memory()
|
||||
|
||||
db:exec[[
|
||||
CREATE TABLE test (id INTEGER PRIMARY KEY, content);
|
||||
|
||||
INSERT INTO test VALUES (NULL, 'Hello World');
|
||||
INSERT INTO test VALUES (NULL, 'Hello Lua');
|
||||
INSERT INTO test VALUES (NULL, 'Hello Sqlite3')
|
||||
]]
|
||||
|
||||
for row in db:rows("SELECT * FROM test") do
|
||||
print(row.id, row.content)
|
||||
end
|
||||
18
lua-sqlite3-0.4.1/examples/smart.lua
Normal file
18
lua-sqlite3-0.4.1/examples/smart.lua
Normal file
@@ -0,0 +1,18 @@
|
||||
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = sqlite3.open_memory()
|
||||
|
||||
db:exec[[ CREATE TABLE test (id INTEGER PRIMARY KEY, content) ]]
|
||||
|
||||
local stmt = db:prepare[[ INSERT INTO test VALUES (:key, :value) ]]
|
||||
|
||||
stmt:bind{ key = 1, value = "Hello World" }:exec()
|
||||
stmt:bind{ key = 2, value = "Hello Lua" }:exec()
|
||||
stmt:bind{ key = 3, value = "Hello Sqlite3" }:exec()
|
||||
|
||||
for row in db:rows("SELECT * FROM test") do
|
||||
print(row.id, row.content)
|
||||
end
|
||||
40
lua-sqlite3-0.4.1/examples/statement.lua
Normal file
40
lua-sqlite3-0.4.1/examples/statement.lua
Normal file
@@ -0,0 +1,40 @@
|
||||
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = sqlite3.open_memory()
|
||||
|
||||
db:exec[[
|
||||
CREATE TABLE test (
|
||||
id INTEGER PRIMARY KEY,
|
||||
content VARCHAR
|
||||
);
|
||||
]]
|
||||
|
||||
local insert_stmt = assert( db:prepare("INSERT INTO test VALUES (NULL, ?)") )
|
||||
|
||||
local function insert(data)
|
||||
insert_stmt:bind(data)
|
||||
insert_stmt:exec()
|
||||
end
|
||||
|
||||
local select_stmt = assert( db:prepare("SELECT * FROM test") )
|
||||
|
||||
local function select()
|
||||
for row in select_stmt:rows() do
|
||||
print(row.id, row.content)
|
||||
end
|
||||
end
|
||||
|
||||
insert("Hello World")
|
||||
print("First:")
|
||||
select()
|
||||
|
||||
insert("Hello Lua")
|
||||
print("Second:")
|
||||
select()
|
||||
|
||||
insert("Hello Sqlite3")
|
||||
print("Third:")
|
||||
select()
|
||||
21
lua-sqlite3-0.4.1/examples/tracing.lua
Normal file
21
lua-sqlite3-0.4.1/examples/tracing.lua
Normal file
@@ -0,0 +1,21 @@
|
||||
require "path"
|
||||
require "sqlite3"
|
||||
|
||||
|
||||
local db = sqlite3.open_memory()
|
||||
|
||||
db:set_trace_handler( function(sql)
|
||||
print("Sqlite Trace:", sql)
|
||||
end )
|
||||
|
||||
db:exec[[
|
||||
CREATE TABLE test ( id INTEGER PRIMARY KEY, content VARCHAR );
|
||||
|
||||
INSERT INTO test VALUES (NULL, 'Hello World');
|
||||
INSERT INTO test VALUES (NULL, 'Hello Lua');
|
||||
INSERT INTO test VALUES (NULL, 'Hello Sqlite3');
|
||||
]]
|
||||
|
||||
for row in db:rows("SELECT * FROM test") do
|
||||
-- NOP
|
||||
end
|
||||
50
lua-sqlite3-0.4.1/libluasqlite3-loader.lua.in
Normal file
50
lua-sqlite3-0.4.1/libluasqlite3-loader.lua.in
Normal file
@@ -0,0 +1,50 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004, 2006 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
local shared_lib_name = "libluasqlite3.so"
|
||||
local shared_lib_init = "luaopen_sqlite3"
|
||||
local shared_lib_path = "SHARED_LIB_PATH"
|
||||
|
||||
-- Lua-5.0 / Lua-5.1
|
||||
local loadlib = loadlib or package.loadlib
|
||||
|
||||
local filename = shared_lib_path.."/"..shared_lib_name
|
||||
local init, error = loadlib(filename, shared_lib_init)
|
||||
|
||||
local api, ERR, TYPE, AUTH
|
||||
|
||||
if init then
|
||||
api, ERR, TYPE, AUTH = init()
|
||||
end
|
||||
|
||||
function load_libluasqlite3()
|
||||
assert(init, error)
|
||||
return api, ERR, TYPE, AUTH
|
||||
end
|
||||
|
||||
1641
lua-sqlite3-0.4.1/libluasqlite3.c
Normal file
1641
lua-sqlite3-0.4.1/libluasqlite3.c
Normal file
File diff suppressed because it is too large
Load Diff
270
lua-sqlite3-0.4.1/luasql-sqlite3.lua
Normal file
270
lua-sqlite3-0.4.1/luasql-sqlite3.lua
Normal file
@@ -0,0 +1,270 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
if luasql == nil then
|
||||
luasql = { }
|
||||
end
|
||||
|
||||
if type(luasql) ~= "table" then
|
||||
error("luasql needs to be a table, but is a "..type(luasql).." already", 2)
|
||||
end
|
||||
|
||||
|
||||
|
||||
local env_class = { }
|
||||
local conn_class = { }
|
||||
local cur_class = { }
|
||||
|
||||
local env_class_mt = { __index = env_class }
|
||||
local conn_class_mt = { __index = conn_class }
|
||||
local cur_class_mt = { __index = cur_class }
|
||||
|
||||
local api, ERR, TYPE, AUTH
|
||||
|
||||
local function setref(t, v) t.ref_counter = v end
|
||||
local function ref(t) t.ref_counter = t.ref_counter + 1 end
|
||||
local function unref(t) t.ref_counter = t.ref_counter - 1 end
|
||||
local function isref(t) return t.ref_counter > 0 end
|
||||
|
||||
|
||||
|
||||
|
||||
function luasql.sqlite3()
|
||||
if not api then
|
||||
api, ERR, TYPE, AUTH = load_libluasqlite3()
|
||||
end
|
||||
|
||||
local env = setmetatable( {}, env_class_mt )
|
||||
setref(env, 0)
|
||||
|
||||
env.closed = false
|
||||
return env
|
||||
end
|
||||
|
||||
|
||||
function env_class.close(env)
|
||||
if env.closed or isref(env) then return end
|
||||
env.closed = true
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function env_class.connect_memory(env)
|
||||
return env_class.connect(env, ":memory:")
|
||||
end
|
||||
|
||||
|
||||
function env_class.connect(env, filename)
|
||||
if env.closed then return end
|
||||
|
||||
local conn = setmetatable( {}, conn_class_mt )
|
||||
setref(conn, 0)
|
||||
|
||||
local err, db = api.open(filename)
|
||||
|
||||
if err ~= ERR.OK then error("api.open: "..err) end
|
||||
|
||||
conn.env = env
|
||||
conn.db = db
|
||||
conn.closed = false
|
||||
conn.autocommit = true
|
||||
conn.ta_active = false
|
||||
|
||||
ref(env)
|
||||
return conn
|
||||
end
|
||||
|
||||
|
||||
|
||||
function conn_class.close(conn)
|
||||
if conn.closed or isref(conn) then return end
|
||||
|
||||
api.close(conn.db)
|
||||
conn.db = nil
|
||||
|
||||
unref(conn.env)
|
||||
conn.env = nil
|
||||
|
||||
conn.closed = true
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
|
||||
function conn_class.commit(conn)
|
||||
if conn.closed or conn.autocommit or not conn.ta_active then return end
|
||||
api.exec(conn.db, "COMMIT")
|
||||
conn.ta_active = false
|
||||
return true
|
||||
end
|
||||
|
||||
function conn_class.rollback(conn)
|
||||
if conn.closed or conn.autocommit or not conn.ta_active then return end
|
||||
api.exec(conn.db, "ROLLBACK")
|
||||
conn.ta_active = false
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function conn_class.setautocommit(conn, autocommit)
|
||||
if not conn.autocommit and autocommit then
|
||||
api.exec("END")
|
||||
end
|
||||
conn.autocommit = autocommit
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function conn_class.execute(conn, sql)
|
||||
if conn.closed then return end
|
||||
|
||||
if not conn.autocommit and not conn.ta_active then
|
||||
api.exec(conn.db, "BEGIN")
|
||||
conn.ta_active = true
|
||||
end
|
||||
|
||||
local err, stmt = api.prepare(conn.db, sql)
|
||||
|
||||
if err ~= ERR.OK then error("api.prepare: "..err) end
|
||||
|
||||
if api.column_count(stmt) == 0 then
|
||||
-- normal excute, no cursor
|
||||
err = api.step(stmt)
|
||||
if err ~= ERR.DONE then
|
||||
error("api.step: "..err)
|
||||
end
|
||||
api.finalize(stmt)
|
||||
return api.changes(conn.db)
|
||||
else
|
||||
-- select, needs cursor
|
||||
local cur = setmetatable( {}, cur_class_mt )
|
||||
|
||||
cur.stmt = stmt
|
||||
cur.finished = false
|
||||
cur.closed = false
|
||||
|
||||
ref(conn)
|
||||
ref(conn.env)
|
||||
cur.conn = conn
|
||||
|
||||
return cur
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
function cur_class.close(cur)
|
||||
if cur.closed then return end
|
||||
|
||||
if not cur.finished then
|
||||
api.finalize(cur.stmt)
|
||||
cur.stmt = nil
|
||||
end
|
||||
|
||||
unref(cur.conn.env)
|
||||
unref(cur.conn)
|
||||
cur.conn = nil
|
||||
|
||||
cur.closed = true
|
||||
return true
|
||||
end
|
||||
|
||||
|
||||
function cur_class.fetch(cur, t, mode)
|
||||
if cur.closed or cur.finished then return end
|
||||
|
||||
-- FIXME: write nice error wrapper...
|
||||
|
||||
local err = api.step(cur.stmt)
|
||||
|
||||
if err == ERR.DONE then
|
||||
api.finalize(cur.stmt)
|
||||
cur.stmt = nil
|
||||
cur.finished = true
|
||||
return
|
||||
elseif err ~= ERR.ROW then
|
||||
error("api.step: "..err)
|
||||
end
|
||||
|
||||
-- FIXME: really ugly block follows....
|
||||
|
||||
if t == nil and mode == nil then
|
||||
-- direct mode
|
||||
return api.drow(cur.stmt)
|
||||
else
|
||||
if type(t) == "string" and mode == nil then
|
||||
mode = t
|
||||
t = { }
|
||||
end
|
||||
if mode == nil then
|
||||
mode = "n"
|
||||
end
|
||||
if type(t) ~= "table" or type(mode) ~= "string" then
|
||||
error("fetch usage error")
|
||||
end
|
||||
|
||||
if mode == nil or mode == "n" then
|
||||
return api.irow(cur.stmt, t)
|
||||
elseif mode == "a" then
|
||||
return api.arow(cur.stmt, t)
|
||||
else
|
||||
error("unknown mode: "..mode)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
local function get_col_desc(cur, desc, api_func)
|
||||
if cur.closed then return end
|
||||
if not cur[desc] then
|
||||
cur[desc] = { }
|
||||
for index = 1, api.column_count(cur.stmt) do
|
||||
table.insert( cur[desc], api_func(cur.stmt, index - 1) )
|
||||
end
|
||||
end
|
||||
return cur[desc]
|
||||
end
|
||||
|
||||
function cur_class.getcolnames(cur)
|
||||
return get_col_desc(cur, "colnames", api.column_name)
|
||||
end
|
||||
|
||||
function cur_class.getcoltypes(cur)
|
||||
return get_col_desc(cur, "coltypes", api.column_decltype)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
693
lua-sqlite3-0.4.1/lunit.lua
Normal file
693
lua-sqlite3-0.4.1/lunit.lua
Normal file
@@ -0,0 +1,693 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
This file is part of lunit 0.4pre (alpha).
|
||||
|
||||
For Details about lunit look at: http://www.nessie.de/mroth/lunit/
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------
|
||||
-- Intialize package --
|
||||
-----------------------
|
||||
|
||||
local P = { }
|
||||
lunit = P
|
||||
|
||||
-- Import
|
||||
local type = type
|
||||
local print = print
|
||||
local ipairs = ipairs
|
||||
local pairs = pairs
|
||||
local string = string
|
||||
local table = table
|
||||
local pcall = pcall
|
||||
local xpcall = xpcall
|
||||
local traceback = debug.traceback
|
||||
local error = error
|
||||
local setmetatable = setmetatable
|
||||
local rawset = rawset
|
||||
local orig_assert = assert
|
||||
local getfenv = getfenv
|
||||
local setfenv = setfenv
|
||||
local tostring = tostring
|
||||
|
||||
|
||||
-- Start package scope
|
||||
setfenv(1, P)
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------
|
||||
-- Private data and functions --
|
||||
--------------------------------
|
||||
|
||||
local run_testcase
|
||||
local do_assert, check_msg
|
||||
local stats = { }
|
||||
local testcases = { }
|
||||
local stats_inc, tc_mt
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------
|
||||
-- Type check functions --
|
||||
--------------------------
|
||||
|
||||
function is_nil(x)
|
||||
return type(x) == "nil"
|
||||
end
|
||||
|
||||
function is_boolean(x)
|
||||
return type(x) == "boolean"
|
||||
end
|
||||
|
||||
function is_number(x)
|
||||
return type(x) == "number"
|
||||
end
|
||||
|
||||
function is_string(x)
|
||||
return type(x) == "string"
|
||||
end
|
||||
|
||||
function is_table(x)
|
||||
return type(x) == "table"
|
||||
end
|
||||
|
||||
function is_function(x)
|
||||
return type(x) == "function"
|
||||
end
|
||||
|
||||
function is_thread(x)
|
||||
return type(x) == "thread"
|
||||
end
|
||||
|
||||
function is_userdata(x)
|
||||
return type(x) == "userdata"
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------
|
||||
-- Assert functions --
|
||||
----------------------
|
||||
|
||||
function assert(assertion, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert", msg)
|
||||
do_assert(not not assertion, "assertion failed (was: "..tostring(assertion)..")", msg) -- (convert assertion to bool)
|
||||
return assertion
|
||||
end
|
||||
|
||||
|
||||
function assert_fail(msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_fail", msg)
|
||||
do_assert(false, "failure", msg)
|
||||
end
|
||||
|
||||
|
||||
function assert_true(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_true", msg)
|
||||
do_assert(is_boolean(actual), "true expected but was a "..type(actual), msg)
|
||||
do_assert(actual == true, "true expected but was false", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_false(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_false", msg)
|
||||
do_assert(is_boolean(actual), "false expected but was a "..type(actual), msg)
|
||||
do_assert(actual == false, "false expected but was true", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_equal(expected, actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_equal", msg)
|
||||
do_assert(expected == actual, "expected '"..tostring(expected).."' but was '"..tostring(actual).."'", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_equal(unexpected, actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_equal", msg)
|
||||
do_assert(unexpected ~= actual, "'"..tostring(expected).."' not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_match(pattern, actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_match", msg)
|
||||
do_assert(is_string(pattern), "assert_match expects the pattern as a string")
|
||||
do_assert(is_string(actual), "expected a string to match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
|
||||
do_assert(not not string.find(actual, pattern), "expected '"..actual.."' to match pattern '"..pattern.."' but doesn't", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_match(pattern, actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_match", msg)
|
||||
do_assert(is_string(actual), "expected a string to not match pattern '"..pattern.."' but was a '"..type(actual).."'", msg)
|
||||
do_assert(string.find(actual, pattern) == nil, "expected '"..actual.."' to not match pattern '"..pattern.."' but it does", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_nil(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_nil", msg)
|
||||
do_assert(is_nil(actual), "nil expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_nil(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_nil", msg)
|
||||
do_assert(not is_nil(actual), "nil not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_boolean(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_boolean", msg)
|
||||
do_assert(is_boolean(actual), "boolean expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_boolean(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_boolean", msg)
|
||||
do_assert(not is_boolean(actual), "boolean not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_number(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_number", msg)
|
||||
do_assert(is_number(actual), "number expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_number(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_number", msg)
|
||||
do_assert(not is_number(actual), "number not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_string(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_string", msg)
|
||||
do_assert(is_string(actual), "string expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_string(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_string", msg)
|
||||
do_assert(not is_string(actual), "string not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_table(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_table", msg)
|
||||
do_assert(is_table(actual), "table expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_table(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_table", msg)
|
||||
do_assert(not is_table(actual), "table not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_function(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_function", msg)
|
||||
do_assert(is_function(actual), "function expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_function(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_function", msg)
|
||||
do_assert(not is_function(actual), "function not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_thread(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_thread", msg)
|
||||
do_assert(is_thread(actual), "thread expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_thread(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_thread", msg)
|
||||
do_assert(not is_thread(actual), "thread not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_userdata(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_userdata", msg)
|
||||
do_assert(is_userdata(actual), "userdata expected but was a "..type(actual), msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_not_userdata(actual, msg)
|
||||
stats_inc("assertions")
|
||||
check_msg("assert_not_userdata", msg)
|
||||
do_assert(not is_userdata(actual), "userdata not expected but was one", msg)
|
||||
return actual
|
||||
end
|
||||
|
||||
|
||||
function assert_error(msg, func)
|
||||
stats_inc("assertions")
|
||||
if is_nil(func) then func, msg = msg, nil end
|
||||
check_msg("assert_error", msg)
|
||||
do_assert(is_function(func), "assert_error expects a function as the last argument but it was a "..type(func))
|
||||
local ok, errmsg = pcall(func)
|
||||
do_assert(ok == false, "error expected but no error occurred", msg)
|
||||
end
|
||||
|
||||
|
||||
function assert_pass(msg, func)
|
||||
stats_inc("assertions")
|
||||
if is_nil(func) then func, msg = msg, nil end
|
||||
check_msg("assert_pass", msg)
|
||||
do_assert(is_function(func), "assert_pass expects a function as the last argument but it was a "..type(func))
|
||||
local ok, errmsg = pcall(func)
|
||||
if not ok then do_assert(ok == true, "no error expected but error was: "..errmsg, msg) end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------------
|
||||
-- Assert implementation that assumes it was called from --
|
||||
-- lunit code which was called directly from user code. --
|
||||
-----------------------------------------------------------
|
||||
|
||||
function do_assert(assertion, base_msg, user_msg)
|
||||
orig_assert(is_boolean(assertion))
|
||||
orig_assert(is_string(base_msg))
|
||||
orig_assert(is_string(user_msg) or is_nil(user_msg))
|
||||
if not assertion then
|
||||
if user_msg then
|
||||
error(base_msg..": "..user_msg, 3)
|
||||
else
|
||||
error(base_msg.."!", 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------------------------------
|
||||
-- Checks the msg argument in assert_xxx --
|
||||
-------------------------------------------
|
||||
|
||||
function check_msg(name, msg)
|
||||
orig_assert(is_string(name))
|
||||
if not (is_nil(msg) or is_string(msg)) then
|
||||
error("lunit."..name.."() expects the optional message as a string but it was a "..type(msg).."!" ,3)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-------------------------------------
|
||||
-- Creates a new TestCase 'Object' --
|
||||
-------------------------------------
|
||||
|
||||
function TestCase(name)
|
||||
do_assert(is_string(name), "lunit.TestCase() needs a string as an argument")
|
||||
local tc = {
|
||||
__lunit_name = name;
|
||||
__lunit_setup = nil;
|
||||
__lunit_tests = { };
|
||||
__lunit_teardown = nil;
|
||||
}
|
||||
setmetatable(tc, tc_mt)
|
||||
table.insert(testcases, tc)
|
||||
return tc
|
||||
end
|
||||
|
||||
tc_mt = {
|
||||
__newindex = function(tc, key, value)
|
||||
rawset(tc, key, value)
|
||||
if is_string(key) and is_function(value) then
|
||||
local name = string.lower(key)
|
||||
if string.find(name, "^test") or string.find(name, "test$") then
|
||||
table.insert(tc.__lunit_tests, key)
|
||||
elseif name == "setup" then
|
||||
tc.__lunit_setup = value
|
||||
elseif name == "teardown" then
|
||||
tc.__lunit_teardown = value
|
||||
end
|
||||
end
|
||||
end
|
||||
}
|
||||
|
||||
|
||||
|
||||
-----------------------------------------
|
||||
-- Wrap Functions in a TestCase object --
|
||||
-----------------------------------------
|
||||
|
||||
function wrap(name, ...)
|
||||
if is_function(name) then
|
||||
table.insert(arg, 1, name)
|
||||
name = "Anonymous Testcase"
|
||||
end
|
||||
|
||||
local tc = TestCase(name)
|
||||
for index, test in ipairs(arg) do
|
||||
tc["Test #"..index] = test
|
||||
end
|
||||
return tc
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
----------------------------------
|
||||
-- Runs the complete Test Suite --
|
||||
----------------------------------
|
||||
|
||||
function run()
|
||||
|
||||
---------------------------
|
||||
-- Initialize statistics --
|
||||
---------------------------
|
||||
|
||||
stats.testcases = 0 -- Total number of Test Cases
|
||||
stats.tests = 0 -- Total number of all Tests in all Test Cases
|
||||
stats.run = 0 -- Number of Tests run
|
||||
stats.notrun = 0 -- Number of Tests not run
|
||||
stats.failed = 0 -- Number of Tests failed
|
||||
stats.warnings = 0 -- Number of Warnings (teardown)
|
||||
stats.errors = 0 -- Number of Errors (setup)
|
||||
stats.passed = 0 -- Number of Test passed
|
||||
stats.assertions = 0 -- Number of all assertions made in all Test in all Test Cases
|
||||
|
||||
--------------------------------
|
||||
-- Count Test Cases and Tests --
|
||||
--------------------------------
|
||||
|
||||
stats.testcases = table.getn(testcases)
|
||||
|
||||
for _, tc in ipairs(testcases) do
|
||||
stats_inc("tests" , table.getn(tc.__lunit_tests))
|
||||
end
|
||||
|
||||
------------------
|
||||
-- Print Header --
|
||||
------------------
|
||||
|
||||
print()
|
||||
print("#### Test Suite with "..stats.tests.." Tests in "..stats.testcases.." Test Cases loaded.")
|
||||
|
||||
------------------------
|
||||
-- Run all Test Cases --
|
||||
------------------------
|
||||
|
||||
for _, tc in ipairs(testcases) do
|
||||
run_testcase(tc)
|
||||
end
|
||||
|
||||
------------------
|
||||
-- Print Footer --
|
||||
------------------
|
||||
|
||||
print()
|
||||
print("#### Test Suite finished.")
|
||||
|
||||
local msg_assertions = stats.assertions.." Assertions checked. "
|
||||
local msg_passed = stats.passed == stats.tests and "All Tests passed" or stats.passed.." Tests passed"
|
||||
local msg_failed = stats.failed > 0 and ", "..stats.failed.." failed" or ""
|
||||
local msg_run = stats.notrun > 0 and ", "..stats.notrun.." not run" or ""
|
||||
local msg_warn = stats.warnings > 0 and ", "..stats.warnings.." warnings" or ""
|
||||
|
||||
print()
|
||||
print(msg_assertions..msg_passed..msg_failed..msg_run..msg_warn.."!")
|
||||
|
||||
-----------------
|
||||
-- Return code --
|
||||
-----------------
|
||||
|
||||
if stats.passed == stats.tests then
|
||||
return 0
|
||||
else
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
-----------------------------
|
||||
-- Runs a single Test Case --
|
||||
-----------------------------
|
||||
|
||||
function run_testcase(tc)
|
||||
|
||||
orig_assert(is_table(tc))
|
||||
orig_assert(is_table(tc.__lunit_tests))
|
||||
orig_assert(is_string(tc.__lunit_name))
|
||||
orig_assert(is_nil(tc.__lunit_setup) or is_function(tc.__lunit_setup))
|
||||
orig_assert(is_nil(tc.__lunit_teardown) or is_function(tc.__lunit_teardown))
|
||||
|
||||
----------------------------------
|
||||
-- Protected call to a function --
|
||||
----------------------------------
|
||||
|
||||
local function call(errprefix, func)
|
||||
orig_assert(is_string(errprefix))
|
||||
orig_assert(is_function(func))
|
||||
local ok, errmsg = xpcall(function() func(tc) end, traceback)
|
||||
if not ok then
|
||||
print()
|
||||
print(errprefix..": "..errmsg)
|
||||
end
|
||||
return ok
|
||||
end
|
||||
|
||||
------------------------------------
|
||||
-- Calls setup() on the Test Case --
|
||||
------------------------------------
|
||||
|
||||
local function setup(testname)
|
||||
if tc.__lunit_setup then
|
||||
return call("ERROR: "..testname..": setup() failed", tc.__lunit_setup)
|
||||
else
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------
|
||||
-- Calls a single Test on the Test Case --
|
||||
------------------------------------------
|
||||
|
||||
local function run(testname)
|
||||
orig_assert(is_string(testname))
|
||||
orig_assert(is_function(tc[testname]))
|
||||
local ok = call("FAIL: "..testname, tc[testname])
|
||||
if not ok then
|
||||
stats_inc("failed")
|
||||
else
|
||||
stats_inc("passed")
|
||||
end
|
||||
return ok
|
||||
end
|
||||
|
||||
---------------------------------------
|
||||
-- Calls teardown() on the Test Case --
|
||||
---------------------------------------
|
||||
|
||||
local function teardown(testname)
|
||||
if tc.__lunit_teardown then
|
||||
if not call("WARNING: "..testname..": teardown() failed", tc.__lunit_teardown) then
|
||||
stats_inc("warnings")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
---------------------------------
|
||||
-- Run all Tests on a TestCase --
|
||||
---------------------------------
|
||||
|
||||
print()
|
||||
print("#### Running '"..tc.__lunit_name.."' ("..table.getn(tc.__lunit_tests).." Tests)...")
|
||||
|
||||
for _, testname in ipairs(tc.__lunit_tests) do
|
||||
if setup(testname) then
|
||||
run(testname)
|
||||
stats_inc("run")
|
||||
teardown(testname)
|
||||
else
|
||||
print("WARN: Skipping '"..testname.."'...")
|
||||
stats_inc("notrun")
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------
|
||||
-- Import function --
|
||||
---------------------
|
||||
|
||||
function import(name)
|
||||
|
||||
do_assert(is_string(name), "lunit.import() expects a single string as argument")
|
||||
|
||||
local user_env = getfenv(2)
|
||||
|
||||
--------------------------------------------------
|
||||
-- Installs a specific function in the user env --
|
||||
--------------------------------------------------
|
||||
|
||||
local function install(funcname)
|
||||
user_env[funcname] = P[funcname]
|
||||
end
|
||||
|
||||
|
||||
----------------------------------------------------------
|
||||
-- Install functions matching a pattern in the user env --
|
||||
----------------------------------------------------------
|
||||
|
||||
local function install_pattern(pattern)
|
||||
for funcname, _ in pairs(P) do
|
||||
if string.find(funcname, pattern) then
|
||||
install(funcname)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------------------------------------------------------
|
||||
-- Installs assert() and all assert_xxx() in the user env --
|
||||
------------------------------------------------------------
|
||||
|
||||
local function install_asserts()
|
||||
install_pattern("^assert.*")
|
||||
end
|
||||
|
||||
-------------------------------------------
|
||||
-- Installs all is_xxx() in the user env --
|
||||
-------------------------------------------
|
||||
|
||||
local function install_tests()
|
||||
install_pattern("^is_.+")
|
||||
end
|
||||
|
||||
if name == "asserts" or name == "assertions" then
|
||||
install_asserts()
|
||||
elseif name == "tests" or name == "checks" then
|
||||
install_tests()
|
||||
elseif name == "all" then
|
||||
install_asserts()
|
||||
install_tests()
|
||||
install("TestCase")
|
||||
elseif string.find(name, "^assert.*") and P[name] then
|
||||
install(name)
|
||||
elseif string.find(name, "^is_.+") and P[name] then
|
||||
install(name)
|
||||
elseif name == "TestCase" then
|
||||
install("TestCase")
|
||||
else
|
||||
error("luniit.import(): invalid function '"..name.."' to import", 2)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------
|
||||
-- Installs a private environment on the caller --
|
||||
--------------------------------------------------
|
||||
|
||||
function setprivfenv()
|
||||
local new_env = { }
|
||||
local new_env_mt = { __index = getfenv(2) }
|
||||
setmetatable(new_env, new_env_mt)
|
||||
setfenv(2, new_env)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------------------------
|
||||
-- Increments a counter in the statistics table --
|
||||
--------------------------------------------------
|
||||
|
||||
function stats_inc(varname, value)
|
||||
orig_assert(is_table(stats))
|
||||
orig_assert(is_string(varname))
|
||||
orig_assert(is_nil(value) or is_number(value))
|
||||
if not stats[varname] then return end
|
||||
stats[varname] = stats[varname] + (value or 1)
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
843
lua-sqlite3-0.4.1/sqlite3.lua
Normal file
843
lua-sqlite3-0.4.1/sqlite3.lua
Normal file
@@ -0,0 +1,843 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004, 2005 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
--[[
|
||||
|
||||
TODO:
|
||||
collation set_collation(name, func)
|
||||
collation_needed set_collation_handler(func)
|
||||
progress_handler set_progress_handler(func)
|
||||
authorizer set_auth_handler(func)
|
||||
commit_hook set_commit_handler(func)
|
||||
|
||||
--]]
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
require "libluasqlite3-loader"
|
||||
|
||||
local api, ERR, TYPE, AUTH = load_libluasqlite3()
|
||||
|
||||
local db_class = { }
|
||||
local stmt_class = { }
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
local function check_stmt(stmt)
|
||||
assert(type(stmt.handles) == "table", "Prepared statement expected")
|
||||
return stmt
|
||||
end
|
||||
|
||||
local function check_single_stmt(stmt)
|
||||
assert(type(stmt.handles) == "table" and table.getn(stmt.handles) == 1, "Single prepared statement expected")
|
||||
return stmt.handles[1]
|
||||
end
|
||||
|
||||
local function check_db(db)
|
||||
assert(db.handle, "Open database handle expected")
|
||||
return db
|
||||
end
|
||||
|
||||
local function check_table(tab, msg)
|
||||
assert(type(tab) == "table", msg)
|
||||
return tab
|
||||
end
|
||||
|
||||
local function check_string(str, msg)
|
||||
assert( type(str) == "string", msg )
|
||||
return str
|
||||
end
|
||||
|
||||
local function check_number(num, msg)
|
||||
assert( type(num) == "number", msg )
|
||||
return num
|
||||
end
|
||||
|
||||
|
||||
|
||||
-----------------------------------------------------
|
||||
-- Error test und report helper for sqlite3 errors --
|
||||
-----------------------------------------------------
|
||||
|
||||
local function is_error(status)
|
||||
return not ( status == ERR.OK or status == ERR.ROW or status == ERR.DONE )
|
||||
end
|
||||
|
||||
local function is_row(status)
|
||||
return status == ERR.ROW
|
||||
end
|
||||
|
||||
local function is_done(status)
|
||||
return status == ERR.DONE
|
||||
end
|
||||
|
||||
local function errmsg(db_handle)
|
||||
return api.errmsg(db_handle) or "Unknown error"
|
||||
end
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------------------------------
|
||||
-- Creates an oject. An object is a table with itself set as metatable --
|
||||
-------------------------------------------------------------------------
|
||||
|
||||
local function object()
|
||||
local t = { }
|
||||
setmetatable(t, t)
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
-----------------------------------
|
||||
-- Registry for tables (objects) --
|
||||
-----------------------------------
|
||||
|
||||
local function create_registry()
|
||||
return { 0 }
|
||||
end
|
||||
|
||||
local function register(registry, object)
|
||||
local id = registry[1]
|
||||
if id == 0 then
|
||||
table.insert(registry, object)
|
||||
return table.getn(registry)
|
||||
else
|
||||
registry[1] = registry[id]
|
||||
registry[id] = object
|
||||
return id
|
||||
end
|
||||
end
|
||||
|
||||
local function unregister(registry, id)
|
||||
registry[id] = registry[1]
|
||||
registry[1] = id
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-------------
|
||||
-- sqlite3 --
|
||||
-------------
|
||||
|
||||
sqlite3 = { }
|
||||
|
||||
function sqlite3.open(filename)
|
||||
check_string(filename, "Filename as string expected")
|
||||
|
||||
local status, handle = api.open(filename)
|
||||
|
||||
if is_error(status) then
|
||||
local errmsg = errmsg(handle)
|
||||
api.close(handle)
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
local db = object()
|
||||
|
||||
db.__gc = db_class.close
|
||||
db.__index = db_class
|
||||
db.filename = filename
|
||||
db.handle = handle
|
||||
db.stmts = create_registry()
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function sqlite3.open_memory()
|
||||
return sqlite3.open(":memory:")
|
||||
end
|
||||
|
||||
|
||||
|
||||
--------------------
|
||||
-- Database Class --
|
||||
--------------------
|
||||
|
||||
function db_class.close(db)
|
||||
check_db(db)
|
||||
|
||||
for _, obj in ipairs(db.stmts) do
|
||||
if type(obj) == "table" then
|
||||
obj:close()
|
||||
end
|
||||
end
|
||||
|
||||
local status = api.close(db.handle)
|
||||
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
|
||||
db.handle = nil
|
||||
db.stmts = nil
|
||||
db.__gc = nil
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.interrupt(db)
|
||||
check_db(db)
|
||||
|
||||
local status = api.interrupt(db.handle)
|
||||
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.last_insert_rowid(db)
|
||||
check_db(db)
|
||||
return api.last_insert_rowid(db.handle)
|
||||
end
|
||||
|
||||
|
||||
function db_class.changes(db)
|
||||
check_db(db)
|
||||
return api.changes(db.handle)
|
||||
end
|
||||
|
||||
|
||||
function db_class.total_changes(db)
|
||||
check_db(db)
|
||||
return api.total_changes(db.handle)
|
||||
end
|
||||
|
||||
|
||||
function db_class.exec(db, sql)
|
||||
check_db(db)
|
||||
check_string(sql)
|
||||
|
||||
local status = api.exec(db.handle, sql)
|
||||
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.irows(db, sql, tab)
|
||||
check_db(db)
|
||||
return db:prepare(sql):irows(tab, true)
|
||||
end
|
||||
|
||||
|
||||
function db_class.rows(db, sql, tab)
|
||||
check_db(db)
|
||||
return db:prepare(sql):rows(tab, true)
|
||||
end
|
||||
|
||||
|
||||
function db_class.cols(db, sql)
|
||||
check_db(db)
|
||||
return db:prepare(sql):cols(true)
|
||||
end
|
||||
|
||||
|
||||
function db_class.first_irow(db, sql, tab)
|
||||
check_db(db)
|
||||
return db:prepare(sql):first_irow(tab, true)
|
||||
end
|
||||
|
||||
|
||||
function db_class.first_row(db, sql, tab)
|
||||
check_db(db)
|
||||
return db:prepare(sql):first_row(tab, true)
|
||||
end
|
||||
|
||||
|
||||
function db_class.first_cols(db, sql)
|
||||
check_db(db)
|
||||
return db:prepare(sql):first_cols(true)
|
||||
end
|
||||
|
||||
|
||||
function db_class.prepare(db, paranames, sql)
|
||||
check_db(db)
|
||||
|
||||
if sql == nil then
|
||||
sql = paranames
|
||||
paranames = nil
|
||||
end
|
||||
|
||||
check_string(sql, "db:prepare: SQL statement as string expected")
|
||||
|
||||
local function cleanup(handles)
|
||||
for _, handle in ipairs(handles) do
|
||||
api.finalize(handle)
|
||||
end
|
||||
end
|
||||
|
||||
local function count_parameters(handles)
|
||||
local parameter_count = 0
|
||||
for _, handle in ipairs(handles) do
|
||||
parameter_count = parameter_count + api.bind_parameter_count(handle)
|
||||
end
|
||||
return parameter_count
|
||||
end
|
||||
|
||||
local function build_handles(sql)
|
||||
local status, handle
|
||||
local remaining = sql
|
||||
local handles = { }
|
||||
|
||||
while remaining do
|
||||
status, handle, remaining = api.prepare(db.handle, remaining)
|
||||
|
||||
if is_error(status) then
|
||||
local errmsg = errmsg(db.handle)
|
||||
cleanup(handles)
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
table.insert(handles, handle)
|
||||
end
|
||||
|
||||
return handles
|
||||
end
|
||||
|
||||
local function anonymous_parameters(handles)
|
||||
for _, handle in ipairs(handles) do
|
||||
for i = 1, api.bind_parameter_count(handle) do
|
||||
if api.bind_parameter_name_x(handle, i) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function named_parameters(handles)
|
||||
for _, handle in ipairs(handles) do
|
||||
for i = 1, api.bind_parameter_count(handle) do
|
||||
if not api.bind_parameter_name_x(handle, i) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
local function create_mapping(handles, paranames)
|
||||
local invers = { }
|
||||
|
||||
for index, name in ipairs(paranames) do
|
||||
invers[name] = index
|
||||
end
|
||||
|
||||
local mapping = { }
|
||||
|
||||
for _, handle in ipairs(handles) do
|
||||
for index = 1, api.bind_parameter_count(handle) do
|
||||
local parameter_name = api.bind_parameter_name_x(handle, index)
|
||||
local pos = invers[parameter_name]
|
||||
if pos == nil then
|
||||
cleanup(handles)
|
||||
return nil, "db:prepare: Unknown parameter name '" .. parameter_name .. "'in statement."
|
||||
end
|
||||
table.insert(mapping, pos)
|
||||
end
|
||||
end
|
||||
|
||||
return mapping
|
||||
end
|
||||
|
||||
local function collect_parameter_names(handles)
|
||||
local seen = { }
|
||||
local names = { }
|
||||
|
||||
for _, handle in ipairs(handles) do
|
||||
for index = 1, api.bind_parameter_count(handle) do
|
||||
local parameter_name = api.bind_parameter_name_x(handle, index)
|
||||
if not seen[parameter_name] then
|
||||
table.insert(names, parameter_name)
|
||||
seen[parameter_name] = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return names
|
||||
end
|
||||
|
||||
local function fix_parameter_names(unfixed_parameters)
|
||||
local fixed_parameters = { }
|
||||
for _, unfixed_name in ipairs(unfixed_parameters) do
|
||||
local _, _, fixed_name = string.find(unfixed_name, "^[:$]?(%a%w*)$")
|
||||
if not fixed_name then
|
||||
return nil, "db:prepare: Invalid parameter name: '" .. unfixed_name .."'."
|
||||
end
|
||||
table.insert(fixed_parameters, fixed_name)
|
||||
end
|
||||
return fixed_parameters
|
||||
end
|
||||
|
||||
local function create_stmt(db, handles, parameter_count)
|
||||
local stmt = object()
|
||||
stmt.__gc = stmt_class.close
|
||||
stmt.__index = stmt_class
|
||||
stmt.handles = handles
|
||||
stmt.db = db
|
||||
stmt.reg_id = register(db.stmts, stmt)
|
||||
stmt.parameter_count= parameter_count
|
||||
return stmt
|
||||
end
|
||||
|
||||
local handles, errmsg = build_handles(sql)
|
||||
|
||||
if errmsg then
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
local parameter_count = count_parameters(handles)
|
||||
|
||||
if parameter_count == 0 then -- No parameters at all
|
||||
return create_stmt(db, handles, 0)
|
||||
else
|
||||
if anonymous_parameters(handles) then -- All parameters are anonymous ("?")
|
||||
|
||||
return create_stmt(db, handles, parameter_count)
|
||||
|
||||
elseif named_parameters(handles) then -- All parameters are named (":foobar" & "$foobar")
|
||||
|
||||
if paranames then -- Fixed mapping of parameter names
|
||||
|
||||
check_table(paranames, "db:prepare: Names of parameters expected as strings")
|
||||
|
||||
local fixed_parameter_names, errmsg = fix_parameter_names(paranames)
|
||||
|
||||
if errmsg then
|
||||
cleanup(handles)
|
||||
return nil, errmgs
|
||||
end
|
||||
|
||||
local mapping, errmsg = create_mapping(handles, fixed_parameter_names)
|
||||
|
||||
if errmsg then
|
||||
cleanup(handles)
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
local stmt = create_stmt(db, handles, table.getn(fixed_parameter_names))
|
||||
stmt.mapping = mapping
|
||||
stmt.paranames = fixed_parameter_names
|
||||
|
||||
return stmt
|
||||
|
||||
else -- Automatic mapping of paramter names
|
||||
|
||||
local parameter_names = collect_parameter_names(handles)
|
||||
local mapping = create_mapping(handles, parameter_names)
|
||||
local stmt = create_stmt(db, handles, table.getn(parameter_names))
|
||||
stmt.mapping = mapping
|
||||
stmt.paranames = parameter_names
|
||||
|
||||
return stmt
|
||||
|
||||
end
|
||||
|
||||
else -- Mixed paramters are not allowed
|
||||
|
||||
cleanup(handles)
|
||||
return nil, "db:prepare: Mixed anonymous and named parameters are not allowed."
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function call_user_func(context, func, num_values, values)
|
||||
-- Don't use table.insert() because of nils in lua-5.1
|
||||
local arg = { }
|
||||
for index = 1, num_values do
|
||||
arg[index] = api.value(values, index-1)
|
||||
end
|
||||
-- Make lua-5.0.2 unpack() happy
|
||||
arg.n = num_values
|
||||
-- lua-5.1 unpack() style / lua-5.0.2 ignores additional arguments
|
||||
local ok, result = pcall(func, unpack(arg, 1, num_values))
|
||||
|
||||
if not ok then
|
||||
api.result_error(context, tostring(result))
|
||||
else
|
||||
api.result(context, result)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
function db_class.set_function(db, name, num_args, func)
|
||||
check_db(db)
|
||||
|
||||
local function xfunc(context, num_values, values)
|
||||
call_user_func(context, func, num_values, values)
|
||||
end
|
||||
|
||||
local status = api.create_function(db.handle, name, num_args, xfunc, nil, nil)
|
||||
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.set_aggregate(db, name, num_args, create_funcs)
|
||||
check_db(db)
|
||||
|
||||
local step, final
|
||||
|
||||
local function xstep(context, num_values, values)
|
||||
if not step and not final then
|
||||
step, final = create_funcs()
|
||||
end
|
||||
call_user_func(context, step, num_values, values)
|
||||
end
|
||||
|
||||
local function xfinal(context)
|
||||
local ok, result = pcall(final, api.aggregate_count(context))
|
||||
if not ok then
|
||||
api.result_error(context, tostring(result))
|
||||
else
|
||||
api.result(context, result)
|
||||
end
|
||||
end
|
||||
|
||||
local status = api.create_function(db.handle, name, num_args, nil, xstep, xfinal)
|
||||
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.set_trace_handler(db, func)
|
||||
check_db(db)
|
||||
local status = api.trace(db.handle, func)
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.set_busy_timeout(db, ms)
|
||||
check_db(db)
|
||||
local status = api.busy_timeout(db.handle, ms)
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
function db_class.set_busy_handler(db, func)
|
||||
check_db(db)
|
||||
local status = api.busy_handler(db.handle, func)
|
||||
if is_error(status) then
|
||||
return nil, errmsg(db.handle)
|
||||
end
|
||||
return db
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
---------------------
|
||||
-- Statement Class --
|
||||
---------------------
|
||||
|
||||
function stmt_class.bind(stmt, ...)
|
||||
|
||||
local function bind_with_mapping(parameters)
|
||||
local mapping = stmt.mapping
|
||||
local map_index = 1
|
||||
for _, handle in ipairs(stmt.handles) do
|
||||
for index = 1, api.bind_parameter_count(handle) do
|
||||
local status = api.bind(handle, index, parameters[mapping[map_index]])
|
||||
if is_error(status) then
|
||||
return nil, errmsg(stmt.db.handle)
|
||||
end
|
||||
map_index = map_index + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function bind_without_mapping(parameters)
|
||||
local parameter_index = 1
|
||||
for _, handle in ipairs(stmt.handles) do
|
||||
for index = 1, api.bind_parameter_count(handle) do
|
||||
local status = api.bind(handle, index, parameters[parameter_index])
|
||||
if is_error(status) then
|
||||
return nil, errmsg(stmt.db.handle)
|
||||
end
|
||||
parameter_index = parameter_index + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function bind_by_names(parameters)
|
||||
local parameter_names = stmt.paranames
|
||||
local mapping = stmt.mapping
|
||||
for _, handle in ipairs(stmt.handles) do
|
||||
for index = 1, api.bind_parameter_count(handle) do
|
||||
local status = api.bind(handle, index, parameters[parameter_names[mapping[index]]])
|
||||
if is_error(status) then
|
||||
return nil, errmsg(stmt.db.handle)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
check_stmt(stmt)
|
||||
if stmt.parameter_count == 0 then error("stmt:bind: statement contains no parameters.") end
|
||||
|
||||
if type(arg[1]) == "table" and arg.n == 1 and stmt.mapping and stmt.paranames then
|
||||
bind_by_names(arg[1])
|
||||
else
|
||||
if arg.n < stmt.parameter_count then error("stmt:bind: to few parameters.") end
|
||||
if arg.n > stmt.parameter_count then error("stmt:bind: to many parameters.") end
|
||||
|
||||
if stmt.mapping then
|
||||
bind_with_mapping(arg)
|
||||
else
|
||||
bind_without_mapping(arg)
|
||||
end
|
||||
end
|
||||
|
||||
return stmt
|
||||
end
|
||||
|
||||
|
||||
function stmt_class.reset(stmt)
|
||||
check_stmt(stmt)
|
||||
for _, handle in ipairs(stmt.handles) do
|
||||
api.reset(handle)
|
||||
end
|
||||
return stmt
|
||||
end
|
||||
|
||||
|
||||
function stmt_class.close(stmt)
|
||||
check_stmt(stmt)
|
||||
|
||||
for _, handle in ipairs(stmt.handles) do
|
||||
api.finalize(handle)
|
||||
end
|
||||
|
||||
unregister(stmt.db.stmts, stmt.reg_id)
|
||||
|
||||
stmt.db = nil
|
||||
stmt.handles = nil
|
||||
stmt.mapping = nil
|
||||
stmt.__gc = nil
|
||||
|
||||
return stmt
|
||||
end
|
||||
|
||||
|
||||
local no_parameter_names = { }
|
||||
function stmt_class.parameter_names(stmt)
|
||||
check_stmt(stmt)
|
||||
if not stmt.paranames then
|
||||
return no_parameter_names
|
||||
else
|
||||
return stmt.paranames
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function stmt_column_info(stmt, info_func)
|
||||
local handle = check_single_stmt(stmt)
|
||||
local info = { }
|
||||
for index = 1, api.column_count(handle) do
|
||||
table.insert(info, info_func(handle, index-1) )
|
||||
end
|
||||
return info
|
||||
end
|
||||
|
||||
function stmt_class.column_names(stmt)
|
||||
return stmt_column_info(stmt, api.column_name)
|
||||
end
|
||||
|
||||
function stmt_class.column_decltypes(stmt)
|
||||
return stmt_column_info(stmt, api.column_decltype)
|
||||
end
|
||||
|
||||
|
||||
function stmt_class.column_count(stmt)
|
||||
local handle = check_single_stmt(stmt)
|
||||
return api.column_count(handle)
|
||||
end
|
||||
|
||||
|
||||
function stmt_class.exec(stmt)
|
||||
check_stmt(stmt)
|
||||
stmt:reset()
|
||||
for _, handle in ipairs(stmt.handles) do
|
||||
while true do
|
||||
local status = api.step(handle)
|
||||
|
||||
if is_error(status) then
|
||||
local errmsg = errmsg(stmt.db.handle)
|
||||
api.reset(handle)
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
if is_done(status) then
|
||||
break
|
||||
end
|
||||
end
|
||||
api.reset(handle)
|
||||
end
|
||||
return stmt
|
||||
end
|
||||
|
||||
|
||||
local function stmt_rows(stmt, get_row_func, tab, autoclose)
|
||||
local handle = check_single_stmt(stmt)
|
||||
api.reset(handle)
|
||||
|
||||
local function check_autoclose()
|
||||
if autoclose == true then
|
||||
stmt:close()
|
||||
else
|
||||
api.reset(handle)
|
||||
end
|
||||
end
|
||||
|
||||
local iterator = function()
|
||||
local status = api.step(handle)
|
||||
|
||||
if is_error(status) then
|
||||
local errmsg = errmsg(stmt.db.handle)
|
||||
check_autoclose()
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
if is_row(status) then
|
||||
return get_row_func(handle, tab)
|
||||
end
|
||||
|
||||
if is_done(status) then
|
||||
check_autoclose()
|
||||
return nil
|
||||
end
|
||||
|
||||
return nil, "stmt:rows: Internal error!"
|
||||
end
|
||||
|
||||
return iterator
|
||||
end
|
||||
|
||||
function stmt_class.irows(stmt, tab, autoclose)
|
||||
return stmt_rows(stmt, api.irow, tab, autoclose)
|
||||
end
|
||||
|
||||
function stmt_class.rows(stmt, tab, autoclose)
|
||||
return stmt_rows(stmt, api.arow, tab, autoclose)
|
||||
end
|
||||
|
||||
function stmt_class.cols(stmt, autoclose)
|
||||
return stmt_rows(stmt, api.drow, nil, autoclose)
|
||||
end
|
||||
|
||||
|
||||
local function first_row(stmt, get_row_func, tab, autoclose)
|
||||
local handle = check_single_stmt(stmt)
|
||||
api.reset(handle)
|
||||
|
||||
local function check_autoclose()
|
||||
if autoclose == true then
|
||||
stmt:close()
|
||||
else
|
||||
api.reset(handle)
|
||||
end
|
||||
end
|
||||
|
||||
local status = api.step(handle)
|
||||
|
||||
if is_error(status) then
|
||||
local errmsg = errmsg(stmt.db.handle)
|
||||
check_autoclose()
|
||||
return nil, errmsg
|
||||
end
|
||||
|
||||
if is_row(status) then
|
||||
local row = get_row_func(handle, tab)
|
||||
check_autoclose()
|
||||
return row
|
||||
end
|
||||
|
||||
if is_done(status) then
|
||||
check_autoclose()
|
||||
return nil, "No row returned."
|
||||
end
|
||||
|
||||
return nil, "stmt:first_row: Internal error!"
|
||||
|
||||
end
|
||||
|
||||
function stmt_class.first_irow(stmt, tab, autoclose)
|
||||
return first_row(stmt, api.irow, tab, autoclose)
|
||||
end
|
||||
|
||||
function stmt_class.first_row(stmt, tab, autoclose)
|
||||
return first_row(stmt, api.arow, tab, autoclose)
|
||||
end
|
||||
|
||||
function stmt_class.first_cols(stmt, autoclose)
|
||||
local count = api.column_count(stmt.handles[1])
|
||||
local row, errmsg = first_row(stmt, api.irow, nil, autoclose)
|
||||
if errmsg then
|
||||
return nil, errmsg
|
||||
else
|
||||
row.n = count -- Make lua-5.0.2 unpack() happy
|
||||
return unpack(row, 1, count) -- lua-5.1 style / lua-5.0.2 ignores additional arguments
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
|
||||
241
lua-sqlite3-0.4.1/tests-luasql.lua
Normal file
241
lua-sqlite3-0.4.1/tests-luasql.lua
Normal file
@@ -0,0 +1,241 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
|
||||
-------------------------------------------------
|
||||
-- This is the luaSql compatible sqlite driver --
|
||||
-------------------------------------------------
|
||||
require "luasql-sqlite3"
|
||||
|
||||
require "lunit"
|
||||
|
||||
lunit.setprivfenv()
|
||||
lunit.import "asserts"
|
||||
|
||||
|
||||
|
||||
|
||||
lunit.wrap("Driver Interface", function()
|
||||
assert_table( luasql )
|
||||
assert_function( luasql.sqlite3 )
|
||||
local env = assert_table( luasql.sqlite3() )
|
||||
assert_function( env.connect )
|
||||
assert_function( env.connect_memory ) -- sqlite3 extension
|
||||
assert_function( env.close )
|
||||
assert_true( env:close(), "Closing an unused environment must return 'true'" )
|
||||
assert_nil( env:close(), "Closing a closed environment must return 'nil'" )
|
||||
end)
|
||||
|
||||
|
||||
|
||||
lunit.wrap("Connection Interface", function()
|
||||
local env = assert_table( luasql.sqlite3() )
|
||||
local con = assert_table( env:connect_memory() )
|
||||
assert_function( con.close )
|
||||
assert_function( con.execute )
|
||||
assert_function( con.rollback )
|
||||
assert_function( con.commit )
|
||||
assert_function( con.setautocommit )
|
||||
assert_true( con:close(), "Closing an open connection must return 'true'" )
|
||||
assert_nil( con:close(), "Closing a closed connection must return 'nil'" )
|
||||
assert_true( env:close() )
|
||||
end)
|
||||
|
||||
|
||||
|
||||
lunit.wrap("Simple connection usage", function()
|
||||
local env = assert_table( luasql.sqlite3() )
|
||||
local con = assert_table( env:connect_memory() )
|
||||
assert_equal( 0, con:execute("CREATE TABLE test (id, name)") )
|
||||
assert_equal( 1, con:execute("INSERT INTO test VALUES (1, 'Hello World')") )
|
||||
assert_true( con:close() )
|
||||
assert_true( env:close() )
|
||||
end)
|
||||
|
||||
|
||||
|
||||
lunit.wrap("Cursor Interface", function()
|
||||
local env = assert_table( luasql.sqlite3() )
|
||||
local con = assert_table( env:connect_memory() )
|
||||
assert_equal( 0, con:execute("CREATE TABLE test (id, name)") )
|
||||
local cur = assert_table( con:execute("SELECT * FROM test") )
|
||||
assert_function( cur.close )
|
||||
assert_function( cur.fetch )
|
||||
assert_function( cur.getcolnames )
|
||||
assert_function( cur.getcoltypes )
|
||||
assert_true( cur:close(), "Closing an open cursor must return 'true'" )
|
||||
assert_nil( cur:close(), "Closing a closed cursor must return 'nil'" )
|
||||
assert_true( con:close() )
|
||||
assert_true( env:close() )
|
||||
end)
|
||||
|
||||
|
||||
|
||||
local scu = lunit.TestCase("Simple cursor usage")
|
||||
|
||||
function scu:setup()
|
||||
-- open database
|
||||
self.env = assert_table( luasql.sqlite3() )
|
||||
self.con = assert_table( self.env:connect_memory() )
|
||||
|
||||
-- prepare database
|
||||
assert_equal( 0, self.con:execute("CREATE TABLE test (id INTEGER, item TEXT)") )
|
||||
assert_equal( 1, self.con:execute("INSERT INTO test VALUES (1, 'Hello World')") )
|
||||
assert_equal( 1, self.con:execute("INSERT INTO test VALUES (2, 'Hello Lua')") )
|
||||
assert_equal( 1, self.con:execute("INSERT INTO test VALUES (3, 'Hello sqlite3')") )
|
||||
|
||||
-- open cursor
|
||||
self.cur = assert_table( self.con:execute("SELECT * FROM test ORDER BY id") )
|
||||
end
|
||||
|
||||
function scu:teardown()
|
||||
assert_true( self.cur:close() )
|
||||
assert_true( self.con:close() )
|
||||
assert_true( self.env:close() )
|
||||
end
|
||||
|
||||
function scu:test_fetch_direct()
|
||||
local id, item
|
||||
id, item = self.cur:fetch(); assert_equal(1, id); assert_equal("Hello World", item)
|
||||
id, item = self.cur:fetch(); assert_equal(2, id); assert_equal("Hello Lua", item)
|
||||
id, item = self.cur:fetch(); assert_equal(3, id); assert_equal("Hello sqlite3", item)
|
||||
assert_nil( self.cur:fetch() )
|
||||
end
|
||||
|
||||
function scu.check(key_id, id, key_item, item, row)
|
||||
assert_table(row)
|
||||
assert_equal(id, row[key_id])
|
||||
assert_equal(item, row[key_item])
|
||||
end
|
||||
|
||||
function scu:test_fetch_default()
|
||||
self.check(1, 1, 2, "Hello World", self.cur:fetch({}) )
|
||||
self.check(1, 2, 2, "Hello Lua", self.cur:fetch({}) )
|
||||
self.check(1, 3, 2, "Hello sqlite3", self.cur:fetch({}) )
|
||||
assert_nil( self.cur:fetch({}) )
|
||||
end
|
||||
|
||||
function scu:test_fetch_numeric()
|
||||
self.check(1, 1, 2, "Hello World", self.cur:fetch({}, "n") )
|
||||
self.check(1, 2, 2, "Hello Lua", self.cur:fetch({}, "n") )
|
||||
self.check(1, 3, 2, "Hello sqlite3", self.cur:fetch({}, "n") )
|
||||
assert_nil( self.cur:fetch({}, "n") )
|
||||
end
|
||||
|
||||
function scu:test_fetch_alphanumeric()
|
||||
self.check("id", 1, "item", "Hello World", self.cur:fetch({}, "a"))
|
||||
self.check("id", 2, "item", "Hello Lua", self.cur:fetch({}, "a"))
|
||||
self.check("id", 3, "item", "Hello sqlite3", self.cur:fetch({}, "a"))
|
||||
assert_nil( self.cur:fetch({}, "a") )
|
||||
end
|
||||
|
||||
function scu:test_getcolnames()
|
||||
local names = assert_table( self.cur:getcolnames() )
|
||||
assert_equal(2, table.getn(names) )
|
||||
assert_equal("id", names[1])
|
||||
assert_equal("item", names[2])
|
||||
end
|
||||
|
||||
function scu:test_getcoltypes()
|
||||
local types = assert_table( self.cur:getcoltypes() )
|
||||
assert_equal(2, table.getn(types) )
|
||||
assert_equal("INTEGER", types[1])
|
||||
assert_equal("TEXT", types[2])
|
||||
end
|
||||
|
||||
|
||||
|
||||
local ta = lunit.TestCase("Transaction Tests")
|
||||
|
||||
function ta:setup()
|
||||
-- open database
|
||||
self.env = assert_table( luasql.sqlite3() )
|
||||
self.con = assert_table( self.env:connect_memory() )
|
||||
|
||||
-- prepare database
|
||||
assert_equal( 0, self.con:execute("CREATE TABLE test (id INTEGER, item TEXT)") )
|
||||
assert_equal( 1, self.con:execute("INSERT INTO test VALUES (1, 'Hello World')") )
|
||||
assert_equal( 1, self.con:execute("INSERT INTO test VALUES (2, 'Hello Lua')") )
|
||||
assert_equal( 1, self.con:execute("INSERT INTO test VALUES (3, 'Hello sqlite3')") )
|
||||
|
||||
-- switch to manual transaction controll
|
||||
assert_true( self.con:setautocommit(false) )
|
||||
end
|
||||
|
||||
function ta:teardown()
|
||||
assert_true( self.con:close() )
|
||||
assert_true( self.env:close() )
|
||||
end
|
||||
|
||||
function ta:insert(id, item)
|
||||
assert_equal(1, self.con:execute("INSERT INTO test VALUES ("..id..", '"..item.."')") )
|
||||
end
|
||||
|
||||
function ta:update(id, item)
|
||||
assert_equal(1, self.con:execute("UPDATE test SET item = '"..item.."' WHERE id = "..id) )
|
||||
end
|
||||
|
||||
function ta:check(expected)
|
||||
assert_table(expected)
|
||||
|
||||
local cur = assert_table( self.con:execute("SELECT * FROM test ORDER BY id") )
|
||||
local id = 0
|
||||
local row = cur:fetch({}, "a")
|
||||
while row do
|
||||
assert_table(row)
|
||||
id = id + 1
|
||||
assert_equal(id, row.id, "Unexpected 'id' read (wrong row?)")
|
||||
assert( id <= table.getn(expected), "'Id' read to large (to many rows?)")
|
||||
assert_equal(expected[id], row.item, "Invalid content in row")
|
||||
row = cur:fetch({}, "a")
|
||||
end
|
||||
assert_equal(id, table.getn(expected), "To less rows read")
|
||||
assert_true( cur:close() )
|
||||
end
|
||||
|
||||
function ta:test_prepared_content()
|
||||
self:check { "Hello World", "Hello Lua", "Hello sqlite3" }
|
||||
end
|
||||
|
||||
function ta:test_transactions()
|
||||
self:insert(4, "Hello again")
|
||||
self:insert(5, "Goodbye")
|
||||
self:check { "Hello World", "Hello Lua", "Hello sqlite3", "Hello again", "Goodbye" }
|
||||
assert_true( self.con:commit() )
|
||||
self:update(1, "Good morning")
|
||||
self:insert(6, "Foobar")
|
||||
self:check { "Good morning", "Hello Lua", "Hello sqlite3", "Hello again", "Goodbye", "Foobar" }
|
||||
assert_true( self.con:rollback() )
|
||||
self:check { "Hello World", "Hello Lua", "Hello sqlite3", "Hello again", "Goodbye" }
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
472
lua-sqlite3-0.4.1/tests-sqlite3.lua
Normal file
472
lua-sqlite3-0.4.1/tests-sqlite3.lua
Normal file
@@ -0,0 +1,472 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004, 2005 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
require "sqlite3"
|
||||
|
||||
require "lunit"
|
||||
|
||||
lunit.setprivfenv()
|
||||
lunit.import "assertions"
|
||||
lunit.import "checks"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
-------------------------------
|
||||
-- Basic open and close test --
|
||||
-------------------------------
|
||||
|
||||
lunit.wrap("open_memory", function()
|
||||
local db = assert_table( sqlite3.open_memory() )
|
||||
assert( db:close() )
|
||||
end)
|
||||
|
||||
lunit.wrap("open", function()
|
||||
local filename = "/tmp/__lua-sqlite3-20040906135849." .. os.time()
|
||||
local db = assert_table( sqlite3.open(filename) )
|
||||
assert( db:close() )
|
||||
os.remove(filename)
|
||||
end)
|
||||
|
||||
|
||||
|
||||
-------------------------------------
|
||||
-- Presence of db member functions --
|
||||
-------------------------------------
|
||||
|
||||
local db_funcs = lunit.TestCase("Database Member Functions")
|
||||
|
||||
function db_funcs:setup()
|
||||
self.db = assert( sqlite3.open_memory() )
|
||||
end
|
||||
|
||||
function db_funcs:teardown()
|
||||
assert( self.db:close() )
|
||||
end
|
||||
|
||||
function db_funcs:test()
|
||||
local db = self.db
|
||||
assert_function( db.close )
|
||||
assert_function( db.exec )
|
||||
assert_function( db.irows )
|
||||
assert_function( db.rows )
|
||||
assert_function( db.cols )
|
||||
assert_function( db.first_irow )
|
||||
assert_function( db.first_row )
|
||||
assert_function( db.first_cols )
|
||||
assert_function( db.prepare )
|
||||
assert_function( db.interrupt )
|
||||
assert_function( db.last_insert_rowid )
|
||||
assert_function( db.changes )
|
||||
assert_function( db.total_changes )
|
||||
end
|
||||
|
||||
|
||||
|
||||
---------------------------------------
|
||||
-- Presence of stmt member functions --
|
||||
---------------------------------------
|
||||
|
||||
local stmt_funcs = lunit.TestCase("Statement Member Functions")
|
||||
|
||||
function stmt_funcs:setup()
|
||||
self.db = assert( sqlite3.open_memory() )
|
||||
self.stmt = assert( self.db:prepare("CREATE TABLE test (id, content)") )
|
||||
end
|
||||
|
||||
function stmt_funcs:teardown()
|
||||
assert( self.stmt:close() )
|
||||
assert( self.db:close() )
|
||||
end
|
||||
|
||||
function stmt_funcs:test()
|
||||
local stmt = self.stmt
|
||||
assert_function( stmt.close )
|
||||
assert_function( stmt.reset )
|
||||
assert_function( stmt.exec )
|
||||
assert_function( stmt.bind )
|
||||
assert_function( stmt.irows )
|
||||
assert_function( stmt.rows )
|
||||
assert_function( stmt.cols )
|
||||
assert_function( stmt.first_irow )
|
||||
assert_function( stmt.first_row )
|
||||
assert_function( stmt.first_cols )
|
||||
assert_function( stmt.column_names )
|
||||
assert_function( stmt.column_decltypes )
|
||||
assert_function( stmt.column_count )
|
||||
end
|
||||
|
||||
|
||||
|
||||
------------------
|
||||
-- Tests basics --
|
||||
------------------
|
||||
|
||||
local basics = lunit.TestCase("Basics")
|
||||
|
||||
function basics:setup()
|
||||
self.db = assert_table( sqlite3.open_memory() )
|
||||
end
|
||||
|
||||
function basics:teardown()
|
||||
assert_table( self.db:close() )
|
||||
end
|
||||
|
||||
function basics:create_table()
|
||||
assert_table( self.db:exec("CREATE TABLE test (id, name)") )
|
||||
end
|
||||
|
||||
function basics:drop_table()
|
||||
assert_table( self.db:exec("DROP TABLE test") )
|
||||
end
|
||||
|
||||
function basics:insert(id, name)
|
||||
assert_table( self.db:exec("INSERT INTO test VALUES ("..id..", '"..name.."')") )
|
||||
end
|
||||
|
||||
function basics:update(id, name)
|
||||
assert_table( self.db:exec("UPDATE test SET name = '"..name.."' WHERE id = "..id) )
|
||||
end
|
||||
|
||||
function basics:test_create_drop()
|
||||
self:create_table()
|
||||
self:drop_table()
|
||||
end
|
||||
|
||||
function basics:test_multi_create_drop()
|
||||
self:create_table()
|
||||
self:drop_table()
|
||||
self:create_table()
|
||||
self:drop_table()
|
||||
end
|
||||
|
||||
function basics:test_insert()
|
||||
self:create_table()
|
||||
self:insert(1, "Hello World")
|
||||
self:insert(2, "Hello Lua")
|
||||
self:insert(3, "Hello sqlite3")
|
||||
end
|
||||
|
||||
function basics:test_update()
|
||||
self:create_table()
|
||||
self:insert(1, "Hello Home")
|
||||
self:insert(2, "Hello Lua")
|
||||
self:update(1, "Hello World")
|
||||
end
|
||||
|
||||
|
||||
---------------------------------
|
||||
-- Statement Column Info Tests --
|
||||
---------------------------------
|
||||
|
||||
lunit.wrap("Column Info Test", function()
|
||||
local db = assert_table( sqlite3.open_memory() )
|
||||
assert_table( db:exec("CREATE TABLE test (id INTEGER, name TEXT)") )
|
||||
local stmt = assert_table( db:prepare("SELECT * FROM test") )
|
||||
|
||||
assert_equal(2, stmt:column_count(), "Wrong number of columns." )
|
||||
|
||||
local names = assert_table( stmt:column_names() )
|
||||
assert_equal(2, table.getn(names), "Wrong number of names.")
|
||||
assert_equal("id", names[1] )
|
||||
assert_equal("name", names[2] )
|
||||
|
||||
local types = assert_table( stmt:column_decltypes() )
|
||||
assert_equal(2, table.getn(types), "Wrong number of declaration types.")
|
||||
assert_equal("INTEGER", types[1] )
|
||||
assert_equal("TEXT", types[2] )
|
||||
|
||||
assert_table( stmt:close() )
|
||||
assert_table( db:close() )
|
||||
end)
|
||||
|
||||
|
||||
|
||||
---------------------
|
||||
-- Statement Tests --
|
||||
---------------------
|
||||
|
||||
st = lunit.TestCase("Statement Tests")
|
||||
|
||||
function st:setup()
|
||||
self.db = assert( sqlite3.open_memory() )
|
||||
assert_table( self.db:exec("CREATE TABLE test (id, name)") )
|
||||
assert_table( self.db:exec("INSERT INTO test VALUES (1, 'Hello World')") )
|
||||
assert_table( self.db:exec("INSERT INTO test VALUES (2, 'Hello Lua')") )
|
||||
assert_table( self.db:exec("INSERT INTO test VALUES (3, 'Hello sqlite3')") )
|
||||
end
|
||||
|
||||
function st:teardown()
|
||||
assert_table( self.db:close() )
|
||||
end
|
||||
|
||||
function st:check_content(expected)
|
||||
local stmt = assert( self.db:prepare("SELECT * FROM test ORDER BY id") )
|
||||
local i = 0
|
||||
for row in stmt:irows() do
|
||||
i = i + 1
|
||||
assert( i <= table.getn(expected), "To much rows." )
|
||||
assert_equal(2, table.getn(row), "Two result column expected.")
|
||||
assert_equal(i, row[1], "Wrong 'id'.")
|
||||
assert_equal(expected[i], row[2], "Wrong 'name'.")
|
||||
end
|
||||
assert_equal( table.getn(expected), i, "To few rows." )
|
||||
assert_table( stmt:close() )
|
||||
end
|
||||
|
||||
function st:test_setup()
|
||||
assert_pass(function() self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3" } end)
|
||||
assert_error(function() self:check_content{ "Hello World", "Hello Lua" } end)
|
||||
assert_error(function() self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "To much" } end)
|
||||
assert_error(function() self:check_content{ "Hello World", "Hello Lua", "Wrong" } end)
|
||||
assert_error(function() self:check_content{ "Hello World", "Wrong", "Hello sqlite3" } end)
|
||||
assert_error(function() self:check_content{ "Wrong", "Hello Lua", "Hello sqlite3" } end)
|
||||
end
|
||||
|
||||
function st:test_questionmark_args()
|
||||
local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (?, ?)") )
|
||||
assert_table( stmt:bind(0, "Test") )
|
||||
assert_error(function() stmt:bind("To few") end)
|
||||
assert_error(function() stmt:bind(0, "Test", "To many") end)
|
||||
end
|
||||
|
||||
function st:test_questionmark()
|
||||
local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (?, ?)") )
|
||||
assert_table( stmt:bind(4, "Good morning") )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
|
||||
assert_table( stmt:bind(5, "Foo Bar") )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_questionmark_multi()
|
||||
local stmt = assert_table( self.db:prepare([[
|
||||
INSERT INTO test VALUES (?, ?); INSERT INTO test VALUES (?, ?) ]]))
|
||||
assert( stmt:bind(5, "Foo Bar", 4, "Good morning") )
|
||||
assert( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_identifiers()
|
||||
local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (:id, :name)") )
|
||||
assert_table( stmt:bind(4, "Good morning") )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
|
||||
assert_table( stmt:bind(5, "Foo Bar") )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_identifiers_multi()
|
||||
local stmt = assert_table( self.db:prepare([[
|
||||
INSERT INTO test VALUES (:id1, :name1); INSERT INTO test VALUES (:id2, :name2) ]]))
|
||||
assert( stmt:bind(5, "Foo Bar", 4, "Good morning") )
|
||||
assert( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_identifiers_names()
|
||||
local stmt = assert_table( self.db:prepare({"name", "id"}, "INSERT INTO test VALUES (:id, $name)") )
|
||||
assert_table( stmt:bind("Good morning", 4) )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
|
||||
assert_table( stmt:bind("Foo Bar", 5) )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_identifiers_multi_names()
|
||||
local stmt = assert_table( self.db:prepare( {"name", "id1", "id2"},[[
|
||||
INSERT INTO test VALUES (:id1, $name); INSERT INTO test VALUES ($id2, :name) ]]))
|
||||
assert( stmt:bind("Hoho", 4, 5) )
|
||||
assert( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hoho", "Hoho" }
|
||||
end
|
||||
|
||||
function st:test_colon_identifiers_names()
|
||||
local stmt = assert_table( self.db:prepare({":name", ":id"}, "INSERT INTO test VALUES (:id, $name)") )
|
||||
assert_table( stmt:bind("Good morning", 4) )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
|
||||
assert_table( stmt:bind("Foo Bar", 5) )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_colon_identifiers_multi_names()
|
||||
local stmt = assert_table( self.db:prepare( {":name", ":id1", ":id2"},[[
|
||||
INSERT INTO test VALUES (:id1, $name); INSERT INTO test VALUES ($id2, :name) ]]))
|
||||
assert( stmt:bind("Hoho", 4, 5) )
|
||||
assert( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hoho", "Hoho" }
|
||||
end
|
||||
|
||||
function st:test_dollar_identifiers_names()
|
||||
local stmt = assert_table( self.db:prepare({"$name", "$id"}, "INSERT INTO test VALUES (:id, $name)") )
|
||||
assert_table( stmt:bind("Good morning", 4) )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
|
||||
assert_table( stmt:bind("Foo Bar", 5) )
|
||||
assert_table( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
|
||||
end
|
||||
|
||||
function st:test_dollar_identifiers_multi_names()
|
||||
local stmt = assert_table( self.db:prepare( {"$name", "$id1", "$id2"},[[
|
||||
INSERT INTO test VALUES (:id1, $name); INSERT INTO test VALUES ($id2, :name) ]]))
|
||||
assert( stmt:bind("Hoho", 4, 5) )
|
||||
assert( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hoho", "Hoho" }
|
||||
end
|
||||
|
||||
|
||||
function st:test_bind_by_names()
|
||||
local stmt = assert_table( self.db:prepare("INSERT INTO test VALUES (:id, :name)") )
|
||||
local args = { }
|
||||
args.id = 5
|
||||
args.name = "Hello girls"
|
||||
assert( stmt:bind(args) )
|
||||
assert( stmt:exec() )
|
||||
args.id = 4
|
||||
args.name = "Hello boys"
|
||||
assert( stmt:bind(args) )
|
||||
assert( stmt:exec() )
|
||||
self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hello boys", "Hello girls" }
|
||||
end
|
||||
|
||||
|
||||
|
||||
--------------------------------
|
||||
-- Tests binding of arguments --
|
||||
--------------------------------
|
||||
|
||||
b = lunit.TestCase("Binding Tests")
|
||||
|
||||
function b:setup()
|
||||
self.db = assert( sqlite3.open_memory() )
|
||||
assert_table( self.db:exec("CREATE TABLE test (id, name)") )
|
||||
end
|
||||
|
||||
function b:teardown()
|
||||
assert_table( self.db:close() )
|
||||
end
|
||||
|
||||
function b:test_auto_parameter_names()
|
||||
local stmt = assert_table( self.db:prepare([[
|
||||
INSERT INTO test VALUES(:a, $b);
|
||||
INSERT INTO test VALUES(:a2, :b2);
|
||||
INSERT INTO test VALUES($a, :b);
|
||||
INSERT INTO test VALUES($a3, $b3)
|
||||
]]))
|
||||
local parameters = assert_table( stmt:parameter_names() )
|
||||
assert_equal( 6, table.getn(parameters) )
|
||||
assert_equal( "a", parameters[1] )
|
||||
assert_equal( "b", parameters[2] )
|
||||
assert_equal( "a2", parameters[3] )
|
||||
assert_equal( "b2", parameters[4] )
|
||||
assert_equal( "a3", parameters[5] )
|
||||
assert_equal( "b3", parameters[6] )
|
||||
end
|
||||
|
||||
function b:test_no_parameter_names_1()
|
||||
local stmt = assert_table( self.db:prepare([[ SELECT * FROM test ]]))
|
||||
local parameters = assert_table( stmt:parameter_names() )
|
||||
assert_equal( 0, table.getn(parameters) )
|
||||
end
|
||||
|
||||
function b:test_no_parameter_names_2()
|
||||
local stmt = assert_table( self.db:prepare([[ INSERT INTO test VALUES(?, ?) ]]))
|
||||
local parameters = assert_table( stmt:parameter_names() )
|
||||
assert_equal( 0, table.getn(parameters) )
|
||||
end
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
--------------------------------------------
|
||||
-- Tests loop break and statement reusage --
|
||||
--------------------------------------------
|
||||
|
||||
|
||||
|
||||
----------------------------
|
||||
-- Test for bugs reported --
|
||||
----------------------------
|
||||
|
||||
bug = lunit.TestCase("Bug-Report Tests")
|
||||
|
||||
function bug:setup()
|
||||
self.db = assert( sqlite3.open_memory() )
|
||||
end
|
||||
|
||||
function bug:teardown()
|
||||
assert_table( self.db:close() )
|
||||
end
|
||||
|
||||
|
||||
function bug:test_1()
|
||||
self.db:exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")
|
||||
|
||||
local query = assert_table( self.db:prepare("SELECT id FROM test WHERE value=?") )
|
||||
|
||||
assert_table ( query:bind("1") )
|
||||
assert_nil ( query:first_cols() )
|
||||
assert_table ( query:bind("2") )
|
||||
assert_nil ( query:first_cols() )
|
||||
end
|
||||
|
||||
|
||||
function bug:test_nils() -- appeared in lua-5.1 (holes in arrays)
|
||||
local function check(arg1, arg2, arg3, arg4, arg5)
|
||||
assert_equal(1, arg1)
|
||||
assert_equal(2, arg2)
|
||||
assert_nil(arg3)
|
||||
assert_equal(4, arg4)
|
||||
assert_nil(arg5)
|
||||
end
|
||||
|
||||
self.db:set_function("test_nils", 5, function(arg1, arg2, arg3, arg4, arg5)
|
||||
check(arg1, arg2, arg3, arg4, arg5)
|
||||
end)
|
||||
|
||||
assert_table( self.db:exec([[ SELECT test_nils(1, 2, NULL, 4, NULL) ]]) )
|
||||
|
||||
local arg1, arg2, arg3, arg4, arg5 = self.db:first_cols([[ SELECT 1, 2, NULL, 4, NULL ]])
|
||||
check(arg1, arg2, arg3, arg4, arg5)
|
||||
|
||||
local row = assert_table( self.db:first_irow([[ SELECT 1, 2, NULL, 4, NULL ]]) )
|
||||
check(row[1], row[2], row[3], row[4], row[5])
|
||||
end
|
||||
|
||||
36
lua-sqlite3-0.4.1/tests.lua
Normal file
36
lua-sqlite3-0.4.1/tests.lua
Normal file
@@ -0,0 +1,36 @@
|
||||
|
||||
--[[--------------------------------------------------------------------------
|
||||
|
||||
Author: Michael Roth <mroth@nessie.de>
|
||||
|
||||
Copyright (c) 2004 Michael Roth <mroth@nessie.de>
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
||||
--]]--------------------------------------------------------------------------
|
||||
|
||||
|
||||
require "lunit"
|
||||
|
||||
require "tests-sqlite3"
|
||||
require "tests-luasql"
|
||||
|
||||
lunit.run()
|
||||
|
||||
Reference in New Issue
Block a user