summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2015-01-10 14:50:15 +0100
committer Miodrag Milanovic <mmicko@gmail.com>2015-01-10 14:50:15 +0100
commit001b907d02cc15414b396625549c5d09faf1a223 (patch)
tree2f910e652e1d34ae29e103c2c0a3189dd277131b
parentb8e52b09c37877bf301ca64e76db3131010c5fb6 (diff)
added lsqlite3 full source
-rw-r--r--3rdparty/lsqlite3/.travis.yml51
-rw-r--r--3rdparty/lsqlite3/CMakeLists.txt21
-rw-r--r--3rdparty/lsqlite3/HISTORY133
-rw-r--r--3rdparty/lsqlite3/Makefile106
-rw-r--r--3rdparty/lsqlite3/README8
-rw-r--r--3rdparty/lsqlite3/cmake/FindLua.cmake118
-rw-r--r--3rdparty/lsqlite3/cmake/FindSQLite3.cmake37
-rw-r--r--3rdparty/lsqlite3/cmake/dist.cmake321
-rw-r--r--3rdparty/lsqlite3/cmake/lua.cmake293
-rw-r--r--3rdparty/lsqlite3/dist.info15
-rw-r--r--3rdparty/lsqlite3/doc/lsqlite3.html893
-rw-r--r--3rdparty/lsqlite3/doc/lsqlite3.pod866
-rw-r--r--3rdparty/lsqlite3/doc/pod2html.pl7
-rw-r--r--3rdparty/lsqlite3/examples/aggregate.lua35
-rw-r--r--3rdparty/lsqlite3/examples/function.lua21
-rw-r--r--3rdparty/lsqlite3/examples/order.lua122
-rw-r--r--3rdparty/lsqlite3/examples/simple.lua16
-rw-r--r--3rdparty/lsqlite3/examples/smart.lua22
-rw-r--r--3rdparty/lsqlite3/examples/statement.lua39
-rw-r--r--3rdparty/lsqlite3/examples/tracing.lua20
-rw-r--r--3rdparty/lsqlite3/lsqlite3.c1886
-rw-r--r--3rdparty/lsqlite3/lsqlite3.def2
-rw-r--r--3rdparty/lsqlite3/lunit.lua693
-rw-r--r--3rdparty/lsqlite3/test.lua153
-rw-r--r--3rdparty/lsqlite3/tests-sqlite3.lua587
-rw-r--r--src/lib/lib.mak6
-rw-r--r--src/lib/lua/lib/lsqlite3.c2157
-rw-r--r--src/lib/lua/lib/lualibs.h8
28 files changed, 6470 insertions, 2166 deletions
diff --git a/3rdparty/lsqlite3/.travis.yml b/3rdparty/lsqlite3/.travis.yml
new file mode 100644
index 00000000000..57493ebbc3b
--- /dev/null
+++ b/3rdparty/lsqlite3/.travis.yml
@@ -0,0 +1,51 @@
+#
+# LuaDist Travis-CI Hook
+#
+
+# We assume C build environments
+language: C
+
+# Try using multiple Lua Implementations
+env:
+ - TOOL="gcc" # Use native compiler (GCC usually)
+ - TOOL="clang" # Use clang
+ - TOOL="i686-w64-mingw32" # 32bit MinGW
+ - TOOL="x86_64-w64-mingw32" # 64bit MinGW
+ - TOOL="arm-linux-gnueabihf" # ARM hard-float (hf), linux
+
+# Crosscompile builds may fail
+matrix:
+ allow_failures:
+ - env: TOOL="i686-w64-mingw32"
+ - env: TOOL="x86_64-w64-mingw32"
+ - env: TOOL="arm-linux-gnueabihf"
+
+# Install dependencies
+install:
+ - git clone git://github.com/LuaDist/Tools.git ~/_tools
+ - ~/_tools/travis/travis install
+
+# Bootstap
+before_script:
+ - ~/_tools/travis/travis bootstrap
+
+# Build the module
+script:
+ - ~/_tools/travis/travis build
+
+# Execute additional tests or commands
+after_script:
+ - ~/_tools/travis/travis test
+
+# Only watch the master branch
+branches:
+ only:
+ - master
+
+# Notify the LuaDist Dev group if needed
+notifications:
+ recipients:
+ - luadist-dev@googlegroups.com
+ email:
+ on_success: change
+ on_failure: always
diff --git a/3rdparty/lsqlite3/CMakeLists.txt b/3rdparty/lsqlite3/CMakeLists.txt
new file mode 100644
index 00000000000..ceed60d2cbb
--- /dev/null
+++ b/3rdparty/lsqlite3/CMakeLists.txt
@@ -0,0 +1,21 @@
+# Copyright (C) 2007-2012 LuaDist.
+# Created by Peter Kapec
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+project ( lsqlite3 C )
+cmake_minimum_required ( VERSION 2.8 )
+include ( cmake/dist.cmake )
+include ( lua )
+
+# Find SQLite3
+find_package ( SQLite3 REQUIRED )
+include_directories ( ${SQLITE3_INCLUDE_DIRS} )
+
+# Create lsqlite module
+install_lua_module ( lsqlite3 lsqlite3.c lsqlite3.def LINK ${SQLITE3_LIBRARIES} )
+install_data ( HISTORY README )
+install_doc( doc/ )
+install_test ( lunit.lua test.lua tests-sqlite3.lua )
+install_example ( examples/ )
diff --git a/3rdparty/lsqlite3/HISTORY b/3rdparty/lsqlite3/HISTORY
new file mode 100644
index 00000000000..f42ff663c03
--- /dev/null
+++ b/3rdparty/lsqlite3/HISTORY
@@ -0,0 +1,133 @@
+2007-August-15 e
+
+Version "0.6-devel"
+
+Since the "0.5-devel" release of this Lua library...
+
+Tested with SQLite 3.4.2
+
+Added some documentation.
+
+Thanks to Thomas Lauer...
+
+Moved line 525 ("luaL_checktype(L, 2, LUA_TTABLE);")
+below the declarations to eliminate non-gcc compiler errors.
+
+Added create-collation, and associated test case.
+
+-=-
+
+2006-October-02 e
+
+Since the "0.1-devel" release of this Lua library...
+- updated for Lua 5.1
+- provide automatic re-preparation of queries after schema changes
+- made prepared statements with bindings work with for-loops
+- added some compatibility names
+- added many test cases, and ported Mike Roth's tests and examples
+
+-=-
+
+Below is a header comment from the 2004 "0.1" version of the library...
+
+/************************************************************************
+$Id: lsqlite3.c,v 1.3 2004/09/05 17:50:32 tngd Exp $
+
+To consider:
+------------
+
+EXPERIMENTAL APIs
+
+* sqlite3_progress_handler (implemented)
+* sqlite3_commit_hook
+
+TODO?
+
+* sqlite3_create_collation
+
+Changes:
+04-09-2004
+----------
+ * changed second return value of db:compile to be the rest of the
+ sql statement that was not processed instead of the number of
+ characters of sql not processed (situation in case of success).
+ * progress callback register function parameter order changed.
+ number of opcodes is given before the callback now.
+
+29-08-2004 e
+------------
+ * added version() (now supported in sqlite 3.0.5)
+ * added db:errmsg db:errcode db:total_changes
+ * rename vm:get_column to vm:get_value
+ * merge in Tiago's v1.11 change in dbvm_tostring
+
+23-06-2004 e
+------------
+ * heavily revised for SQLite3 C API
+ * row values now returned as native type (not always text)
+ * added db:nrows (named rows)
+ * added vm:bind_blob
+ * added vm:get_column
+ * removed encode_binary decode_binary (no longer needed or supported)
+ * removed version encoding error_string (unsupported in v 3.0.1 -- soon?)
+
+09-04-2004
+----------
+ * renamed db:rows to db:urows
+ * renamed db:prows to db:rows
+
+ * added vm:get_unames()
+ * added vm:get_utypes()
+ * added vm:get_uvalues()
+
+08-04-2004
+----------
+ * changed db:encoding() and db:version() to use sqlite_libencoding() and
+ sqlite_libversion()
+
+ * added vm:columns()
+ * added vm:get_named_types()
+ * added vm:get_named_values()
+
+ * added db:prows - like db:rows but returns a table with the column values
+ instead of returning multiple columns seperatly on each iteration
+
+ * added compatibility functions idata,iname,itype,data,type
+
+ * added luaopen_sqlite_module. allow the library to be loaded without
+ setting a global variable. does the same as luaopen_sqlite, but does not
+ set the global name "sqlite".
+
+ * vm:bind now also returns an error string in case of error
+
+31-03-2004 - 01-04-2004
+-----------------------
+ * changed most of the internals. now using references (luaL_ref) in
+ most of the places
+
+ * make the virtual machine interface seperate from the database
+ handle. db:compile now returns a vm handle
+
+ * added db:rows [for ... in db:rows(...) do ... end]
+
+ * added db:close_vm
+
+ * added sqlite.encode_binary and sqlite.decode_binary
+
+ * attempt to do a strict checking on the return type of the user
+ defined functions returned values
+
+18-01-2004
+----------
+ * add check on sql function callback to ensure there is enough stack
+ space to pass column values as parameters
+
+03-12-2003
+----------
+ * callback functions now have to return boolean values to abort or
+ continue operation instead of a zero or non-zero value
+
+06-12-2003
+----------
+ * make version member of sqlite table a function instead of a string
+************************************************************************/
diff --git a/3rdparty/lsqlite3/Makefile b/3rdparty/lsqlite3/Makefile
new file mode 100644
index 00000000000..6718b5a2a92
--- /dev/null
+++ b/3rdparty/lsqlite3/Makefile
@@ -0,0 +1,106 @@
+# makefile for lsqlite3 library for Lua
+
+ifneq "$(shell pkg-config --version)" ""
+ # automagic setup (OS X fink, Linux apt-get, ..)
+ #
+ LUAINC= $(shell pkg-config --cflags lua)
+ LUALIB= $(shell pkg-config --libs lua)
+ LUAEXE= lua
+ # Now, we actually want to _not_ push in stuff to the distro Lua CMOD directory,
+ # way better to play within /usr/local/lib/lua/5.1/
+ #LUACMOD= $(shell pkg-config --variable=INSTALL_CMOD lua)
+ LUACMOD= /usr/local/lib/lua/5.1/
+ #
+ SQLITE3INC= $(shell pkg-config --cflags sqlite3)
+ SQLITE3LIB= $(shell pkg-config --libs sqlite3)
+else
+ # manual setup (change these to reflect your Lua installation)
+ #
+ BASE= /usr/local
+ LUAINC= -I$(BASE)/include
+ LUAEXE= $(BASE)/bin/lua.exe
+# LUALIB= -L$(BASE)/lib -llua51
+# LUACMOD= $(BASE)/lib/lua/5.1/
+# Windows' LUA_CDIR and LUALIB are both the same as the Lua executable's directory...
+ LUALIB= -L$(BASE)/bin -llua51
+ LUACMOD= $(BASE)/bin
+ #
+ SQLITE3INC= -I$(BASE)/include
+ SQLITE3LIB= -L$(BASE)/bin -lsqlite3
+ #
+ POD2HTML= perl -x -S doc/pod2html.pl
+endif
+
+TMP=./tmp
+DISTDIR=./archive
+
+# OS detection
+#
+SHFLAGS=-shared
+UNAME= $(shell uname)
+ifeq "$(UNAME)" "Linux"
+ _SO=so
+ SHFLAGS= -fPIC
+endif
+ifneq "" "$(findstring BSD,$(UNAME))"
+ _SO=so
+endif
+ifeq "$(UNAME)" "Darwin"
+ _SO=bundle
+ SHFLAGS= -bundle
+endif
+ifneq "" "$(findstring msys,$(OSTYPE))" # 'msys'
+ _SO=dll
+endif
+
+ifndef _SO
+ $(error $(UNAME))
+ $(error Unknown OS)
+endif
+
+# no need to change anything below here - HAH!
+CFLAGS= $(INCS) $(DEFS) $(WARN) -O2 $(SHFLAGS)
+WARN= -Wall #-ansi -pedantic -Wall
+INCS= $(LUAINC) $(SQLITE3INC)
+LIBS= $(LUALIB) $(SQLITE3LIB)
+
+MYNAME= sqlite3
+MYLIB= l$(MYNAME)
+
+VER=$(shell svnversion -c . | sed 's/.*://')
+TARFILE = $(DISTDIR)/$(MYLIB)-$(VER).tar.gz
+
+OBJS= $(MYLIB).o
+T= $(MYLIB).$(_SO)
+
+all: $T
+
+test: $T
+ $(LUAEXE) test.lua
+ $(LUAEXE) tests-sqlite3.lua
+
+$T: $(OBJS)
+ $(CC) $(SHFLAGS) -o $@ $(OBJS) $(LIBS)
+
+install:
+ cp $T $(LUACMOD)
+
+clean:
+ rm -f $(OBJS) $T core core.* a.out test.db
+
+html:
+ $(POD2HTML) --title="LuaSQLite 3" --infile=doc/lsqlite3.pod --outfile=doc/lsqlite3.html
+
+dist: html
+ echo 'Exporting...'
+ mkdir -p $(TMP)
+ mkdir -p $(DISTDIR)
+ svn export -r HEAD . $(TMP)/$(MYLIB)-$(VER)
+ mkdir -p $(TMP)/$(MYLIB)-$(VER)/doc
+ cp -p doc/lsqlite3.html $(TMP)/$(MYLIB)-$(VER)/doc
+ echo 'Compressing...'
+ tar -zcf $(TARFILE) -C $(TMP) $(MYLIB)-$(VER)
+ rm -fr $(TMP)/$(MYLIB)-$(VER)
+ echo 'Done.'
+
+.PHONY: all test clean dist install
diff --git a/3rdparty/lsqlite3/README b/3rdparty/lsqlite3/README
new file mode 100644
index 00000000000..92c27b2770b
--- /dev/null
+++ b/3rdparty/lsqlite3/README
@@ -0,0 +1,8 @@
+
+LuaSQLite 3 provides a means to manipulate SQLite3
+databases directly from lua using Lua 5.
+
+To use this library you need SQLite3 library.
+You can get it from http://www.sqlite.org/
+
+Lua 5 is available from http://www.lua.org/
diff --git a/3rdparty/lsqlite3/cmake/FindLua.cmake b/3rdparty/lsqlite3/cmake/FindLua.cmake
new file mode 100644
index 00000000000..7fb7ca3f4f9
--- /dev/null
+++ b/3rdparty/lsqlite3/cmake/FindLua.cmake
@@ -0,0 +1,118 @@
+# Locate Lua library
+# This module defines
+# LUA_EXECUTABLE, if found
+# LUA_FOUND, if false, do not try to link to Lua
+# LUA_LIBRARIES
+# LUA_INCLUDE_DIR, where to find lua.h
+# LUA_VERSION_STRING, the version of Lua found (since CMake 2.8.8)
+#
+# Note that the expected include convention is
+# #include "lua.h"
+# and not
+# #include <lua/lua.h>
+# This is because, the lua location is not standardized and may exist
+# in locations other than lua/
+
+#=============================================================================
+# Copyright 2007-2009 Kitware, Inc.
+# Modified to support Lua 5.2 by LuaDist 2012
+#
+# Distributed under the OSI-approved BSD License (the "License");
+# see accompanying file Copyright.txt for details.
+#
+# This software is distributed WITHOUT ANY WARRANTY; without even the
+# implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+# See the License for more information.
+#=============================================================================
+# (To distribute this file outside of CMake, substitute the full
+# License text for the above reference.)
+#
+# The required version of Lua can be specified using the
+# standard syntax, e.g. FIND_PACKAGE(Lua 5.1)
+# Otherwise the module will search for any available Lua implementation
+
+# Always search for non-versioned lua first (recommended)
+SET(_POSSIBLE_LUA_INCLUDE include include/lua)
+SET(_POSSIBLE_LUA_EXECUTABLE lua)
+SET(_POSSIBLE_LUA_LIBRARY lua)
+
+# Determine possible naming suffixes (there is no standard for this)
+IF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
+ SET(_POSSIBLE_SUFFIXES "${Lua_FIND_VERSION_MAJOR}${Lua_FIND_VERSION_MINOR}" "${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}" "-${Lua_FIND_VERSION_MAJOR}.${Lua_FIND_VERSION_MINOR}")
+ELSE(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
+ SET(_POSSIBLE_SUFFIXES "52" "5.2" "-5.2" "51" "5.1" "-5.1")
+ENDIF(Lua_FIND_VERSION_MAJOR AND Lua_FIND_VERSION_MINOR)
+
+# Set up possible search names and locations
+FOREACH(_SUFFIX ${_POSSIBLE_SUFFIXES})
+ LIST(APPEND _POSSIBLE_LUA_INCLUDE "include/lua${_SUFFIX}")
+ LIST(APPEND _POSSIBLE_LUA_EXECUTABLE "lua${_SUFFIX}")
+ LIST(APPEND _POSSIBLE_LUA_LIBRARY "lua${_SUFFIX}")
+ENDFOREACH(_SUFFIX)
+
+# Find the lua executable
+FIND_PROGRAM(LUA_EXECUTABLE
+ NAMES ${_POSSIBLE_LUA_EXECUTABLE}
+)
+
+# Find the lua header
+FIND_PATH(LUA_INCLUDE_DIR lua.h
+ HINTS
+ $ENV{LUA_DIR}
+ PATH_SUFFIXES ${_POSSIBLE_LUA_INCLUDE}
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw # Fink
+ /opt/local # DarwinPorts
+ /opt/csw # Blastwave
+ /opt
+)
+
+# Find the lua library
+FIND_LIBRARY(LUA_LIBRARY
+ NAMES ${_POSSIBLE_LUA_LIBRARY}
+ HINTS
+ $ENV{LUA_DIR}
+ PATH_SUFFIXES lib64 lib
+ PATHS
+ ~/Library/Frameworks
+ /Library/Frameworks
+ /usr/local
+ /usr
+ /sw
+ /opt/local
+ /opt/csw
+ /opt
+)
+
+IF(LUA_LIBRARY)
+ # include the math library for Unix
+ IF(UNIX AND NOT APPLE)
+ FIND_LIBRARY(LUA_MATH_LIBRARY m)
+ SET( LUA_LIBRARIES "${LUA_LIBRARY};${LUA_MATH_LIBRARY}" CACHE STRING "Lua Libraries")
+ # For Windows and Mac, don't need to explicitly include the math library
+ ELSE(UNIX AND NOT APPLE)
+ SET( LUA_LIBRARIES "${LUA_LIBRARY}" CACHE STRING "Lua Libraries")
+ ENDIF(UNIX AND NOT APPLE)
+ENDIF(LUA_LIBRARY)
+
+# Determine Lua version
+IF(LUA_INCLUDE_DIR AND EXISTS "${LUA_INCLUDE_DIR}/lua.h")
+ FILE(STRINGS "${LUA_INCLUDE_DIR}/lua.h" lua_version_str REGEX "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua .+\"")
+
+ STRING(REGEX REPLACE "^#define[ \t]+LUA_RELEASE[ \t]+\"Lua ([^\"]+)\".*" "\\1" LUA_VERSION_STRING "${lua_version_str}")
+ UNSET(lua_version_str)
+ENDIF()
+
+INCLUDE(FindPackageHandleStandardArgs)
+# handle the QUIETLY and REQUIRED arguments and set LUA_FOUND to TRUE if
+# all listed variables are TRUE
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(Lua
+ REQUIRED_VARS LUA_LIBRARIES LUA_INCLUDE_DIR
+ VERSION_VAR LUA_VERSION_STRING)
+
+MARK_AS_ADVANCED(LUA_INCLUDE_DIR LUA_LIBRARIES LUA_LIBRARY LUA_MATH_LIBRARY LUA_EXECUTABLE)
+
diff --git a/3rdparty/lsqlite3/cmake/FindSQLite3.cmake b/3rdparty/lsqlite3/cmake/FindSQLite3.cmake
new file mode 100644
index 00000000000..2792d0a0d6c
--- /dev/null
+++ b/3rdparty/lsqlite3/cmake/FindSQLite3.cmake
@@ -0,0 +1,37 @@
+# Copyright (C) 2007-2009 LuaDist.
+# Created by Peter Kapec <kapecp@gmail.com>
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Note:
+# Searching headers and libraries is very simple and is NOT as powerful as scripts
+# distributed with CMake, because LuaDist defines directories to search for.
+# Everyone is encouraged to contact the author with improvements. Maybe this file
+# becomes part of CMake distribution sometimes.
+
+# - Find sqlite3
+# Find the native SQLITE3 headers and libraries.
+#
+# SQLITE3_INCLUDE_DIRS - where to find sqlite3.h, etc.
+# SQLITE3_LIBRARIES - List of libraries when using sqlite.
+# SQLITE3_FOUND - True if sqlite found.
+
+# Look for the header file.
+FIND_PATH(SQLITE3_INCLUDE_DIR NAMES sqlite3.h)
+
+# Look for the library.
+FIND_LIBRARY(SQLITE3_LIBRARY NAMES sqlite3 libsqlite3 sqlite libsqlite)
+
+# Handle the QUIETLY and REQUIRED arguments and set SQLITE3_FOUND to TRUE if all listed variables are TRUE.
+INCLUDE(FindPackageHandleStandardArgs)
+FIND_PACKAGE_HANDLE_STANDARD_ARGS(SQLITE3 DEFAULT_MSG SQLITE3_LIBRARY SQLITE3_INCLUDE_DIR)
+
+# Copy the results to the output variables.
+IF(SQLITE3_FOUND)
+ SET(SQLITE3_LIBRARIES ${SQLITE3_LIBRARY})
+ SET(SQLITE3_INCLUDE_DIRS ${SQLITE3_INCLUDE_DIR})
+ELSE(SQLITE3_FOUND)
+ SET(SQLITE3_LIBRARIES)
+ SET(SQLITE3_INCLUDE_DIRS)
+ENDIF(SQLITE3_FOUND)
+
+MARK_AS_ADVANCED(SQLITE3_INCLUDE_DIRS SQLITE3_LIBRARIES)
diff --git a/3rdparty/lsqlite3/cmake/dist.cmake b/3rdparty/lsqlite3/cmake/dist.cmake
new file mode 100644
index 00000000000..310ef94cc9d
--- /dev/null
+++ b/3rdparty/lsqlite3/cmake/dist.cmake
@@ -0,0 +1,321 @@
+# LuaDist CMake utility library.
+# Provides sane project defaults and macros common to LuaDist CMake builds.
+#
+# Copyright (C) 2007-2012 LuaDist.
+# by David Manura, Peter Drahoš
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+## Extract information from dist.info
+if ( NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/dist.info )
+ message ( FATAL_ERROR
+ "Missing dist.info file (${CMAKE_CURRENT_SOURCE_DIR}/dist.info)." )
+endif ()
+file ( READ ${CMAKE_CURRENT_SOURCE_DIR}/dist.info DIST_INFO )
+if ( "${DIST_INFO}" STREQUAL "" )
+ message ( FATAL_ERROR "Failed to load dist.info." )
+endif ()
+# Reads field `name` from dist.info string `DIST_INFO` into variable `var`.
+macro ( _parse_dist_field name var )
+ string ( REGEX REPLACE ".*${name}[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1"
+ ${var} "${DIST_INFO}" )
+ if ( ${var} STREQUAL DIST_INFO )
+ message ( FATAL_ERROR "Failed to extract \"${var}\" from dist.info" )
+ endif ()
+endmacro ()
+#
+_parse_dist_field ( name DIST_NAME )
+_parse_dist_field ( version DIST_VERSION )
+_parse_dist_field ( license DIST_LICENSE )
+_parse_dist_field ( author DIST_AUTHOR )
+_parse_dist_field ( maintainer DIST_MAINTAINER )
+_parse_dist_field ( url DIST_URL )
+_parse_dist_field ( desc DIST_DESC )
+message ( "DIST_NAME: ${DIST_NAME}")
+message ( "DIST_VERSION: ${DIST_VERSION}")
+message ( "DIST_LICENSE: ${DIST_LICENSE}")
+message ( "DIST_AUTHOR: ${DIST_AUTHOR}")
+message ( "DIST_MAINTAINER: ${DIST_MAINTAINER}")
+message ( "DIST_URL: ${DIST_URL}")
+message ( "DIST_DESC: ${DIST_DESC}")
+string ( REGEX REPLACE ".*depends[ \t]?=[ \t]?[\"']([^\"']+)[\"'].*" "\\1"
+ DIST_DEPENDS ${DIST_INFO} )
+if ( DIST_DEPENDS STREQUAL DIST_INFO )
+ set ( DIST_DEPENDS "" )
+endif ()
+message ( "DIST_DEPENDS: ${DIST_DEPENDS}")
+## 2DO: Parse DIST_DEPENDS and try to install Dependencies with automatically using externalproject_add
+
+
+## INSTALL DEFAULTS (Relative to CMAKE_INSTALL_PREFIX)
+# Primary paths
+set ( INSTALL_BIN bin CACHE PATH "Where to install binaries to." )
+set ( INSTALL_LIB lib CACHE PATH "Where to install libraries to." )
+set ( INSTALL_INC include CACHE PATH "Where to install headers to." )
+set ( INSTALL_ETC etc CACHE PATH "Where to store configuration files" )
+set ( INSTALL_SHARE share CACHE PATH "Directory for shared data." )
+
+# Secondary paths
+option ( INSTALL_VERSION
+ "Install runtime libraries and executables with version information." OFF)
+set ( INSTALL_DATA ${INSTALL_SHARE}/${DIST_NAME} CACHE PATH
+ "Directory the package can store documentation, tests or other data in.")
+set ( INSTALL_DOC ${INSTALL_DATA}/doc CACHE PATH
+ "Recommended directory to install documentation into.")
+set ( INSTALL_EXAMPLE ${INSTALL_DATA}/example CACHE PATH
+ "Recommended directory to install examples into.")
+set ( INSTALL_TEST ${INSTALL_DATA}/test CACHE PATH
+ "Recommended directory to install tests into.")
+set ( INSTALL_FOO ${INSTALL_DATA}/etc CACHE PATH
+ "Where to install additional files")
+
+# Tweaks and other defaults
+# Setting CMAKE to use loose block and search for find modules in source directory
+set ( CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true )
+set ( CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH} )
+option ( BUILD_SHARED_LIBS "Build shared libraries" ON )
+
+# In MSVC, prevent warnings that can occur when using standard libraries.
+if ( MSVC )
+ add_definitions ( -D_CRT_SECURE_NO_WARNINGS )
+endif ()
+
+# RPath and relative linking
+option ( USE_RPATH "Use relative linking." ON)
+if ( USE_RPATH )
+ string ( REGEX REPLACE "[^!/]+" ".." UP_DIR ${INSTALL_BIN} )
+ set ( CMAKE_SKIP_BUILD_RPATH FALSE CACHE STRING "" FORCE )
+ set ( CMAKE_BUILD_WITH_INSTALL_RPATH FALSE CACHE STRING "" FORCE )
+ set ( CMAKE_INSTALL_RPATH $ORIGIN/${UP_DIR}/${INSTALL_LIB}
+ CACHE STRING "" FORCE )
+ set ( CMAKE_INSTALL_RPATH_USE_LINK_PATH TRUE CACHE STRING "" FORCE )
+ set ( CMAKE_INSTALL_NAME_DIR @executable_path/${UP_DIR}/${INSTALL_LIB}
+ CACHE STRING "" FORCE )
+endif ()
+
+## MACROS
+# Parser macro
+macro ( parse_arguments prefix arg_names option_names)
+ set ( DEFAULT_ARGS )
+ foreach ( arg_name ${arg_names} )
+ set ( ${prefix}_${arg_name} )
+ endforeach ()
+ foreach ( option ${option_names} )
+ set ( ${prefix}_${option} FALSE )
+ endforeach ()
+
+ set ( current_arg_name DEFAULT_ARGS )
+ set ( current_arg_list )
+ foreach ( arg ${ARGN} )
+ set ( larg_names ${arg_names} )
+ list ( FIND larg_names "${arg}" is_arg_name )
+ if ( is_arg_name GREATER -1 )
+ set ( ${prefix}_${current_arg_name} ${current_arg_list} )
+ set ( current_arg_name ${arg} )
+ set ( current_arg_list )
+ else ()
+ set ( loption_names ${option_names} )
+ list ( FIND loption_names "${arg}" is_option )
+ if ( is_option GREATER -1 )
+ set ( ${prefix}_${arg} TRUE )
+ else ()
+ set ( current_arg_list ${current_arg_list} ${arg} )
+ endif ()
+ endif ()
+ endforeach ()
+ set ( ${prefix}_${current_arg_name} ${current_arg_list} )
+endmacro ()
+
+
+# install_executable ( executable_targets )
+# Installs any executables generated using "add_executable".
+# USE: install_executable ( lua )
+# NOTE: subdirectories are NOT supported
+set ( CPACK_COMPONENT_RUNTIME_DISPLAY_NAME "${DIST_NAME} Runtime" )
+set ( CPACK_COMPONENT_RUNTIME_DESCRIPTION
+ "Executables and runtime libraries. Installed into ${INSTALL_BIN}." )
+macro ( install_executable )
+ foreach ( _file ${ARGN} )
+ if ( INSTALL_VERSION )
+ set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION}
+ SOVERSION ${DIST_VERSION} )
+ endif ()
+ install ( TARGETS ${_file} RUNTIME DESTINATION ${INSTALL_BIN}
+ COMPONENT Runtime )
+ endforeach()
+endmacro ()
+
+# install_library ( library_targets )
+# Installs any libraries generated using "add_library" into apropriate places.
+# USE: install_library ( libexpat )
+# NOTE: subdirectories are NOT supported
+set ( CPACK_COMPONENT_LIBRARY_DISPLAY_NAME "${DIST_NAME} Development Libraries" )
+set ( CPACK_COMPONENT_LIBRARY_DESCRIPTION
+ "Static and import libraries needed for development. Installed into ${INSTALL_LIB} or ${INSTALL_BIN}." )
+macro ( install_library )
+ foreach ( _file ${ARGN} )
+ if ( INSTALL_VERSION )
+ set_target_properties ( ${_file} PROPERTIES VERSION ${DIST_VERSION}
+ SOVERSION ${DIST_VERSION} )
+ endif ()
+ install ( TARGETS ${_file}
+ RUNTIME DESTINATION ${INSTALL_BIN} COMPONENT Runtime
+ LIBRARY DESTINATION ${INSTALL_LIB} COMPONENT Runtime
+ ARCHIVE DESTINATION ${INSTALL_LIB} COMPONENT Library )
+ endforeach()
+endmacro ()
+
+# helper function for various install_* functions, for PATTERN/REGEX args.
+macro ( _complete_install_args )
+ if ( NOT("${_ARG_PATTERN}" STREQUAL "") )
+ set ( _ARG_PATTERN PATTERN ${_ARG_PATTERN} )
+ endif ()
+ if ( NOT("${_ARG_REGEX}" STREQUAL "") )
+ set ( _ARG_REGEX REGEX ${_ARG_REGEX} )
+ endif ()
+endmacro ()
+
+# install_header ( files/directories [INTO destination] )
+# Install a directories or files into header destination.
+# USE: install_header ( lua.h luaconf.h ) or install_header ( GL )
+# USE: install_header ( mylib.h INTO mylib )
+# For directories, supports optional PATTERN/REGEX arguments like install().
+set ( CPACK_COMPONENT_HEADER_DISPLAY_NAME "${DIST_NAME} Development Headers" )
+set ( CPACK_COMPONENT_HEADER_DESCRIPTION
+ "Headers needed for development. Installed into ${INSTALL_INC}." )
+macro ( install_header )
+ parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+ _complete_install_args()
+ foreach ( _file ${_ARG_DEFAULT_ARGS} )
+ if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+ install ( DIRECTORY ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO}
+ COMPONENT Header ${_ARG_PATTERN} ${_ARG_REGEX} )
+ else ()
+ install ( FILES ${_file} DESTINATION ${INSTALL_INC}/${_ARG_INTO}
+ COMPONENT Header )
+ endif ()
+ endforeach()
+endmacro ()
+
+# install_data ( files/directories [INTO destination] )
+# This installs additional data files or directories.
+# USE: install_data ( extra data.dat )
+# USE: install_data ( image1.png image2.png INTO images )
+# For directories, supports optional PATTERN/REGEX arguments like install().
+set ( CPACK_COMPONENT_DATA_DISPLAY_NAME "${DIST_NAME} Data" )
+set ( CPACK_COMPONENT_DATA_DESCRIPTION
+ "Application data. Installed into ${INSTALL_DATA}." )
+macro ( install_data )
+ parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+ _complete_install_args()
+ foreach ( _file ${_ARG_DEFAULT_ARGS} )
+ if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+ install ( DIRECTORY ${_file}
+ DESTINATION ${INSTALL_DATA}/${_ARG_INTO}
+ COMPONENT Data ${_ARG_PATTERN} ${_ARG_REGEX} )
+ else ()
+ install ( FILES ${_file} DESTINATION ${INSTALL_DATA}/${_ARG_INTO}
+ COMPONENT Data )
+ endif ()
+ endforeach()
+endmacro ()
+
+# INSTALL_DOC ( files/directories [INTO destination] )
+# This installs documentation content
+# USE: install_doc ( doc/ doc.pdf )
+# USE: install_doc ( index.html INTO html )
+# For directories, supports optional PATTERN/REGEX arguments like install().
+set ( CPACK_COMPONENT_DOCUMENTATION_DISPLAY_NAME "${DIST_NAME} Documentation" )
+set ( CPACK_COMPONENT_DOCUMENTATION_DESCRIPTION
+ "Application documentation. Installed into ${INSTALL_DOC}." )
+macro ( install_doc )
+ parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+ _complete_install_args()
+ foreach ( _file ${_ARG_DEFAULT_ARGS} )
+ if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+ install ( DIRECTORY ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO}
+ COMPONENT Documentation ${_ARG_PATTERN} ${_ARG_REGEX} )
+ else ()
+ install ( FILES ${_file} DESTINATION ${INSTALL_DOC}/${_ARG_INTO}
+ COMPONENT Documentation )
+ endif ()
+ endforeach()
+endmacro ()
+
+# install_example ( files/directories [INTO destination] )
+# This installs additional examples
+# USE: install_example ( examples/ exampleA )
+# USE: install_example ( super_example super_data INTO super)
+# For directories, supports optional PATTERN/REGEX argument like install().
+set ( CPACK_COMPONENT_EXAMPLE_DISPLAY_NAME "${DIST_NAME} Examples" )
+set ( CPACK_COMPONENT_EXAMPLE_DESCRIPTION
+ "Examples and their associated data. Installed into ${INSTALL_EXAMPLE}." )
+macro ( install_example )
+ parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+ _complete_install_args()
+ foreach ( _file ${_ARG_DEFAULT_ARGS} )
+ if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+ install ( DIRECTORY ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO}
+ COMPONENT Example ${_ARG_PATTERN} ${_ARG_REGEX} )
+ else ()
+ install ( FILES ${_file} DESTINATION ${INSTALL_EXAMPLE}/${_ARG_INTO}
+ COMPONENT Example )
+ endif ()
+ endforeach()
+endmacro ()
+
+# install_test ( files/directories [INTO destination] )
+# This installs tests and test files, DOES NOT EXECUTE TESTS
+# USE: install_test ( my_test data.sql )
+# USE: install_test ( feature_x_test INTO x )
+# For directories, supports optional PATTERN/REGEX argument like install().
+set ( CPACK_COMPONENT_TEST_DISPLAY_NAME "${DIST_NAME} Tests" )
+set ( CPACK_COMPONENT_TEST_DESCRIPTION
+ "Tests and associated data. Installed into ${INSTALL_TEST}." )
+macro ( install_test )
+ parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+ _complete_install_args()
+ foreach ( _file ${_ARG_DEFAULT_ARGS} )
+ if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+ install ( DIRECTORY ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO}
+ COMPONENT Test ${_ARG_PATTERN} ${_ARG_REGEX} )
+ else ()
+ install ( FILES ${_file} DESTINATION ${INSTALL_TEST}/${_ARG_INTO}
+ COMPONENT Test )
+ endif ()
+ endforeach()
+endmacro ()
+
+# install_foo ( files/directories [INTO destination] )
+# This installs optional or otherwise unneeded content
+# USE: install_foo ( etc/ example.doc )
+# USE: install_foo ( icon.png logo.png INTO icons)
+# For directories, supports optional PATTERN/REGEX argument like install().
+set ( CPACK_COMPONENT_OTHER_DISPLAY_NAME "${DIST_NAME} Unspecified Content" )
+set ( CPACK_COMPONENT_OTHER_DESCRIPTION
+ "Other unspecified content. Installed into ${INSTALL_FOO}." )
+macro ( install_foo )
+ parse_arguments ( _ARG "INTO;PATTERN;REGEX" "" ${ARGN} )
+ _complete_install_args()
+ foreach ( _file ${_ARG_DEFAULT_ARGS} )
+ if ( IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/${_file}" )
+ install ( DIRECTORY ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO}
+ COMPONENT Other ${_ARG_PATTERN} ${_ARG_REGEX} )
+ else ()
+ install ( FILES ${_file} DESTINATION ${INSTALL_FOO}/${_ARG_INTO}
+ COMPONENT Other )
+ endif ()
+ endforeach()
+endmacro ()
+
+## CTest defaults
+
+## CPack defaults
+set ( CPACK_GENERATOR "ZIP" )
+set ( CPACK_STRIP_FILES TRUE )
+set ( CPACK_PACKAGE_NAME "${DIST_NAME}" )
+set ( CPACK_PACKAGE_VERSION "${DIST_VERSION}")
+set ( CPACK_PACKAGE_VENDOR "LuaDist" )
+set ( CPACK_COMPONENTS_ALL Runtime Library Header Data Documentation Example Other )
+include ( CPack )
diff --git a/3rdparty/lsqlite3/cmake/lua.cmake b/3rdparty/lsqlite3/cmake/lua.cmake
new file mode 100644
index 00000000000..80bbc5f3568
--- /dev/null
+++ b/3rdparty/lsqlite3/cmake/lua.cmake
@@ -0,0 +1,293 @@
+# LuaDist CMake utility library for Lua.
+#
+# Copyright (C) 2007-2012 LuaDist.
+# by David Manura, Peter Drahos
+# Redistribution and use of this file is allowed according to the terms of the MIT license.
+# For details see the COPYRIGHT file distributed with LuaDist.
+# Please note that the package source code is licensed under its own license.
+
+set ( INSTALL_LMOD ${INSTALL_LIB}/lua
+ CACHE PATH "Directory to install Lua modules." )
+set ( INSTALL_CMOD ${INSTALL_LIB}/lua
+ CACHE PATH "Directory to install Lua binary modules." )
+
+option ( SKIP_LUA_WRAPPER
+ "Do not build and install Lua executable wrappers." OFF)
+
+# List of (Lua module name, file path) pairs.
+# Used internally by add_lua_test. Built by add_lua_module.
+set ( _lua_modules )
+
+# utility function: appends path `path` to path `basepath`, properly
+# handling cases when `path` may be relative or absolute.
+macro ( _append_path basepath path result )
+ if ( IS_ABSOLUTE "${path}" )
+ set ( ${result} "${path}" )
+ else ()
+ set ( ${result} "${basepath}/${path}" )
+ endif ()
+endmacro ()
+
+# install_lua_executable ( target source )
+# Automatically generate a binary if srlua package is available
+# The application or its source will be placed into /bin
+# If the application source did not have .lua suffix then it will be added
+# USE: lua_executable ( sputnik src/sputnik.lua )
+macro ( install_lua_executable _name _source )
+ get_filename_component ( _source_name ${_source} NAME_WE )
+ # Find srlua and glue
+ find_program( SRLUA_EXECUTABLE NAMES srlua )
+ find_program( GLUE_EXECUTABLE NAMES glue )
+ # Executable output
+ set ( _exe ${CMAKE_CURRENT_BINARY_DIR}/${_name}${CMAKE_EXECUTABLE_SUFFIX} )
+ if ( NOT SKIP_LUA_WRAPPER AND SRLUA_EXECUTABLE AND GLUE_EXECUTABLE )
+ # Generate binary gluing the lua code to srlua, this is a robuust approach for most systems
+ add_custom_command(
+ OUTPUT ${_exe}
+ COMMAND ${GLUE_EXECUTABLE}
+ ARGS ${SRLUA_EXECUTABLE} ${_source} ${_exe}
+ DEPENDS ${_source}
+ WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
+ VERBATIM
+ )
+ # Make sure we have a target associated with the binary
+ add_custom_target(${_name} ALL
+ DEPENDS ${_exe}
+ )
+ # Install with run permissions
+ install ( PROGRAMS ${_exe} DESTINATION ${INSTALL_BIN} COMPONENT Runtime)
+ # Also install source as optional resurce
+ install ( FILES ${_source} DESTINATION ${INSTALL_FOO} COMPONENT Other )
+ else()
+ # Install into bin as is but without the lua suffix, we assume the executable uses UNIX shebang/hash-bang magic
+ install ( PROGRAMS ${_source} DESTINATION ${INSTALL_BIN}
+ RENAME ${_source_name}
+ COMPONENT Runtime
+ )
+ endif()
+endmacro ()
+
+macro ( _lua_module_helper is_install _name )
+ parse_arguments ( _MODULE "LINK;ALL_IN_ONE" "" ${ARGN} )
+ # _target is CMake-compatible target name for module (e.g. socket_core).
+ # _module is relative path of target (e.g. socket/core),
+ # without extension (e.g. .lua/.so/.dll).
+ # _MODULE_SRC is list of module source files (e.g. .lua and .c files).
+ # _MODULE_NAMES is list of module names (e.g. socket.core).
+ if ( _MODULE_ALL_IN_ONE )
+ string ( REGEX REPLACE "\\..*" "" _target "${_name}" )
+ string ( REGEX REPLACE "\\..*" "" _module "${_name}" )
+ set ( _target "${_target}_all_in_one")
+ set ( _MODULE_SRC ${_MODULE_ALL_IN_ONE} )
+ set ( _MODULE_NAMES ${_name} ${_MODULE_DEFAULT_ARGS} )
+ else ()
+ string ( REPLACE "." "_" _target "${_name}" )
+ string ( REPLACE "." "/" _module "${_name}" )
+ set ( _MODULE_SRC ${_MODULE_DEFAULT_ARGS} )
+ set ( _MODULE_NAMES ${_name} )
+ endif ()
+ if ( NOT _MODULE_SRC )
+ message ( FATAL_ERROR "no module sources specified" )
+ endif ()
+ list ( GET _MODULE_SRC 0 _first_source )
+
+ get_filename_component ( _ext ${_first_source} EXT )
+ if ( _ext STREQUAL ".lua" ) # Lua source module
+ list ( LENGTH _MODULE_SRC _len )
+ if ( _len GREATER 1 )
+ message ( FATAL_ERROR "more than one source file specified" )
+ endif ()
+
+ set ( _module "${_module}.lua" )
+
+ get_filename_component ( _module_dir ${_module} PATH )
+ get_filename_component ( _module_filename ${_module} NAME )
+ _append_path ( "${CMAKE_CURRENT_SOURCE_DIR}" "${_first_source}" _module_path )
+ list ( APPEND _lua_modules "${_name}" "${_module_path}" )
+
+ if ( ${is_install} )
+ install ( FILES ${_first_source} DESTINATION ${INSTALL_LMOD}/${_module_dir}
+ RENAME ${_module_filename}
+ COMPONENT Runtime
+ )
+ endif ()
+ else () # Lua C binary module
+ enable_language ( C )
+ find_package ( Lua REQUIRED )
+ include_directories ( ${LUA_INCLUDE_DIR} )
+
+ set ( _module "${_module}${CMAKE_SHARED_MODULE_SUFFIX}" )
+
+ get_filename_component ( _module_dir ${_module} PATH )
+ get_filename_component ( _module_filenamebase ${_module} NAME_WE )
+ foreach ( _thisname ${_MODULE_NAMES} )
+ list ( APPEND _lua_modules "${_thisname}"
+ "${CMAKE_CURRENT_BINARY_DIR}/\${CMAKE_CFG_INTDIR}/${_module}" )
+ endforeach ()
+
+ add_library( ${_target} MODULE ${_MODULE_SRC})
+ target_link_libraries ( ${_target} ${LUA_LIBRARY} ${_MODULE_LINK} )
+ set_target_properties ( ${_target} PROPERTIES LIBRARY_OUTPUT_DIRECTORY
+ "${_module_dir}" PREFIX "" OUTPUT_NAME "${_module_filenamebase}" )
+ if ( ${is_install} )
+ install ( TARGETS ${_target} DESTINATION ${INSTALL_CMOD}/${_module_dir} COMPONENT Runtime)
+ endif ()
+ endif ()
+endmacro ()
+
+# add_lua_module
+# Builds a Lua source module into a destination locatable by Lua
+# require syntax.
+# Binary modules are also supported where this function takes sources and
+# libraries to compile separated by LINK keyword.
+# USE: add_lua_module ( socket.http src/http.lua )
+# USE2: add_lua_module ( mime.core src/mime.c )
+# USE3: add_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} )
+# USE4: add_lua_module ( ssl.context ssl.core ALL_IN_ONE src/context.c src/ssl.c )
+# This form builds an "all-in-one" module (e.g. ssl.so or ssl.dll containing
+# both modules ssl.context and ssl.core). The CMake target name will be
+# ssl_all_in_one.
+# Also sets variable _module_path (relative path where module typically
+# would be installed).
+macro ( add_lua_module )
+ _lua_module_helper ( 0 ${ARGN} )
+endmacro ()
+
+
+# install_lua_module
+# This is the same as `add_lua_module` but also installs the module.
+# USE: install_lua_module ( socket.http src/http.lua )
+# USE2: install_lua_module ( mime.core src/mime.c )
+# USE3: install_lua_module ( socket.core ${SRC_SOCKET} LINK ${LIB_SOCKET} )
+macro ( install_lua_module )
+ _lua_module_helper ( 1 ${ARGN} )
+endmacro ()
+
+# Builds string representing Lua table mapping Lua modules names to file
+# paths. Used internally.
+macro ( _make_module_table _outvar )
+ set ( ${_outvar} )
+ list ( LENGTH _lua_modules _n )
+ if ( ${_n} GREATER 0 ) # avoids cmake complaint
+ foreach ( _i RANGE 1 ${_n} 2 )
+ list ( GET _lua_modules ${_i} _path )
+ math ( EXPR _ii ${_i}-1 )
+ list ( GET _lua_modules ${_ii} _name )
+ set ( ${_outvar} "${_table} ['${_name}'] = '${_path}'\;\n")
+ endforeach ()
+ endif ()
+ set ( ${_outvar}
+"local modules = {
+${_table}}" )
+endmacro ()
+
+# add_lua_test ( _testfile [ WORKING_DIRECTORY _working_dir ] )
+# Runs Lua script `_testfile` under CTest tester.
+# Optional named argument `WORKING_DIRECTORY` is current working directory to
+# run test under (defaults to ${CMAKE_CURRENT_BINARY_DIR}).
+# Both paths, if relative, are relative to ${CMAKE_CURRENT_SOURCE_DIR}.
+# Any modules previously defined with install_lua_module are automatically
+# preloaded (via package.preload) prior to running the test script.
+# Under LuaDist, set test=true in config.lua to enable testing.
+# USE: add_lua_test ( test/test1.lua [args...] [WORKING_DIRECTORY dir])
+macro ( add_lua_test _testfile )
+ if ( NOT SKIP_TESTING )
+ parse_arguments ( _ARG "WORKING_DIRECTORY" "" ${ARGN} )
+ include ( CTest )
+ find_program ( LUA NAMES lua lua.bat )
+ get_filename_component ( TESTFILEABS ${_testfile} ABSOLUTE )
+ get_filename_component ( TESTFILENAME ${_testfile} NAME )
+ get_filename_component ( TESTFILEBASE ${_testfile} NAME_WE )
+
+ # Write wrapper script.
+ # Note: One simple way to allow the script to find modules is
+ # to just put them in package.preload.
+ set ( TESTWRAPPER ${CMAKE_CURRENT_BINARY_DIR}/${TESTFILENAME} )
+ _make_module_table ( _table )
+ set ( TESTWRAPPERSOURCE
+"local CMAKE_CFG_INTDIR = ... or '.'
+${_table}
+local function preload_modules(modules)
+ for name, path in pairs(modules) do
+ if path:match'%.lua' then
+ package.preload[name] = assert(loadfile(path))
+ else
+ local name = name:gsub('.*%-', '') -- remove any hyphen prefix
+ local symbol = 'luaopen_' .. name:gsub('%.', '_')
+ --improve: generalize to support all-in-one loader?
+ local path = path:gsub('%$%{CMAKE_CFG_INTDIR%}', CMAKE_CFG_INTDIR)
+ package.preload[name] = assert(package.loadlib(path, symbol))
+ end
+ end
+end
+preload_modules(modules)
+arg[0] = '${TESTFILEABS}'
+table.remove(arg, 1)
+return assert(loadfile '${TESTFILEABS}')(unpack(arg))
+" )
+ if ( _ARG_WORKING_DIRECTORY )
+ get_filename_component (
+ TESTCURRENTDIRABS ${_ARG_WORKING_DIRECTORY} ABSOLUTE )
+ # note: CMake 2.6 (unlike 2.8) lacks WORKING_DIRECTORY parameter.
+ set ( _pre ${CMAKE_COMMAND} -E chdir "${TESTCURRENTDIRABS}" )
+ endif ()
+ file ( WRITE ${TESTWRAPPER} ${TESTWRAPPERSOURCE})
+ add_test ( NAME ${TESTFILEBASE} COMMAND ${_pre} ${LUA}
+ ${TESTWRAPPER} "${CMAKE_CFG_INTDIR}"
+ ${_ARG_DEFAULT_ARGS} )
+ endif ()
+ # see also http://gdcm.svn.sourceforge.net/viewvc/gdcm/Sandbox/CMakeModules/UsePythonTest.cmake
+ # Note: ${CMAKE_CFG_INTDIR} is a command-line argument to allow proper
+ # expansion by the native build tool.
+endmacro ()
+
+
+# Converts Lua source file `_source` to binary string embedded in C source
+# file `_target`. Optionally compiles Lua source to byte code (not available
+# under LuaJIT2, which doesn't have a bytecode loader). Additionally, Lua
+# versions of bin2c [1] and luac [2] may be passed respectively as additional
+# arguments.
+#
+# [1] http://lua-users.org/wiki/BinToCee
+# [2] http://lua-users.org/wiki/LuaCompilerInLua
+function ( add_lua_bin2c _target _source )
+ find_program ( LUA NAMES lua lua.bat )
+ execute_process ( COMMAND ${LUA} -e "string.dump(function()end)"
+ RESULT_VARIABLE _LUA_DUMP_RESULT ERROR_QUIET )
+ if ( NOT ${_LUA_DUMP_RESULT} )
+ SET ( HAVE_LUA_DUMP true )
+ endif ()
+ message ( "-- string.dump=${HAVE_LUA_DUMP}" )
+
+ if ( ARGV2 )
+ get_filename_component ( BIN2C ${ARGV2} ABSOLUTE )
+ set ( BIN2C ${LUA} ${BIN2C} )
+ else ()
+ find_program ( BIN2C NAMES bin2c bin2c.bat )
+ endif ()
+ if ( HAVE_LUA_DUMP )
+ if ( ARGV3 )
+ get_filename_component ( LUAC ${ARGV3} ABSOLUTE )
+ set ( LUAC ${LUA} ${LUAC} )
+ else ()
+ find_program ( LUAC NAMES luac luac.bat )
+ endif ()
+ endif ( HAVE_LUA_DUMP )
+ message ( "-- bin2c=${BIN2C}" )
+ message ( "-- luac=${LUAC}" )
+
+ get_filename_component ( SOURCEABS ${_source} ABSOLUTE )
+ if ( HAVE_LUA_DUMP )
+ get_filename_component ( SOURCEBASE ${_source} NAME_WE )
+ add_custom_command (
+ OUTPUT ${_target} DEPENDS ${_source}
+ COMMAND ${LUAC} -o ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo
+ ${SOURCEABS}
+ COMMAND ${BIN2C} ${CMAKE_CURRENT_BINARY_DIR}/${SOURCEBASE}.lo
+ ">${_target}" )
+ else ()
+ add_custom_command (
+ OUTPUT ${_target} DEPENDS ${SOURCEABS}
+ COMMAND ${BIN2C} ${_source} ">${_target}" )
+ endif ()
+endfunction()
diff --git a/3rdparty/lsqlite3/dist.info b/3rdparty/lsqlite3/dist.info
new file mode 100644
index 00000000000..a6664e2386c
--- /dev/null
+++ b/3rdparty/lsqlite3/dist.info
@@ -0,0 +1,15 @@
+--- This dist file is part of LuaDist project
+
+name = "lsqlite3"
+version = "0.6devel"
+
+desc = "LuaSQLite 3 is a thin wrapper around the public domain SQLite3 database engine."
+author = "Tiago Dionizio, Doug Currie"
+license = "MIT"
+url = "http://luaforge.net/projects/luasqlite/"
+maintainer = "Peter Kapec"
+
+depends = {
+ "lua ~> 5.1",
+ "libsqlite3 >=3.5"
+}
diff --git a/3rdparty/lsqlite3/doc/lsqlite3.html b/3rdparty/lsqlite3/doc/lsqlite3.html
new file mode 100644
index 00000000000..db704f9ce62
--- /dev/null
+++ b/3rdparty/lsqlite3/doc/lsqlite3.html
@@ -0,0 +1,893 @@
+<HTML>
+<HEAD>
+<TITLE>LuaSQLite 3</TITLE>
+<LINK REV="made" HREF="mailto:unknown@du216771.users">
+</HEAD>
+
+<BODY>
+
+<A NAME="__index__"></A>
+<!-- INDEX BEGIN -->
+
+<UL>
+
+ <LI><A HREF="#name">NAME</A></LI>
+ <LI><A HREF="#overview">OVERVIEW</A></LI>
+ <LI><A HREF="#download">DOWNLOAD</A></LI>
+ <LI><A HREF="#installation">INSTALLATION</A></LI>
+ <LI><A HREF="#examples">EXAMPLES</A></LI>
+ <LI><A HREF="#verification tests">VERIFICATION TESTS</A></LI>
+ <LI><A HREF="#reference">REFERENCE</A></LI>
+ <LI><A HREF="#sqlite3 functions">SQLite3 functions</A></LI>
+ <UL>
+
+ <LI><A HREF="#sqlite3.complete">sqlite3.complete</A></LI>
+ <LI><A HREF="#sqlite3.open">sqlite3.open</A></LI>
+ <LI><A HREF="#sqlite3.open_memory">sqlite3.open_memory</A></LI>
+ <LI><A HREF="#sqlite3.temp_directory">sqlite3.temp_directory</A></LI>
+ <LI><A HREF="#sqlite3.version">sqlite3.version</A></LI>
+ </UL>
+
+ <LI><A HREF="#database methods">Database methods</A></LI>
+ <UL>
+
+ <LI><A HREF="#db:busy_handler">db:busy_handler</A></LI>
+ <LI><A HREF="#db:busy_timeout">db:busy_timeout</A></LI>
+ <LI><A HREF="#db:changes">db:changes</A></LI>
+ <LI><A HREF="#db:close">db:close</A></LI>
+ <LI><A HREF="#db:close_vm">db:close_vm</A></LI>
+ <LI><A HREF="#db:create_aggregate">db:create_aggregate</A></LI>
+ <LI><A HREF="#db:create_collation">db:create_collation</A></LI>
+ <LI><A HREF="#db:create_function">db:create_function</A></LI>
+ <LI><A HREF="#db:errcode">db:errcode</A></LI>
+ <LI><A HREF="#db:errmsg">db:errmsg</A></LI>
+ <LI><A HREF="#db:exec">db:exec</A></LI>
+ <LI><A HREF="#db:interrupt">db:interrupt</A></LI>
+ <LI><A HREF="#db:isopen">db:isopen</A></LI>
+ <LI><A HREF="#db:last_insert_rowid">db:last_insert_rowid</A></LI>
+ <LI><A HREF="#db:nrows">db:nrows</A></LI>
+ <LI><A HREF="#db:prepare">db:prepare</A></LI>
+ <LI><A HREF="#db:progress_handler">db:progress_handler</A></LI>
+ <LI><A HREF="#db:rows">db:rows</A></LI>
+ <LI><A HREF="#db:total_changes">db:total_changes</A></LI>
+ <LI><A HREF="#db:trace">db:trace</A></LI>
+ <LI><A HREF="#db:urows">db:urows</A></LI>
+ </UL>
+
+ <LI><A HREF="#methods for prepared statements">Methods for prepared statements</A></LI>
+ <UL>
+
+ <LI><A HREF="#stmt:bind">stmt:bind</A></LI>
+ <LI><A HREF="#stmt:bind_blob">stmt:bind_blob</A></LI>
+ <LI><A HREF="#stmt:bind_names">stmt:bind_names</A></LI>
+ <LI><A HREF="#stmt:bind_parameter_count">stmt:bind_parameter_count</A></LI>
+ <LI><A HREF="#stmt:bind_parameter_name">stmt:bind_parameter_name</A></LI>
+ <LI><A HREF="#stmt:bind_values">stmt:bind_values</A></LI>
+ <LI><A HREF="#stmt:columns">stmt:columns</A></LI>
+ <LI><A HREF="#stmt:finalize">stmt:finalize</A></LI>
+ <LI><A HREF="#stmt:get_name">stmt:get_name</A></LI>
+ <LI><A HREF="#stmt:get_named_types">stmt:get_named_types</A></LI>
+ <LI><A HREF="#stmt:get_named_values">stmt:get_named_values</A></LI>
+ <LI><A HREF="#stmt:get_names">stmt:get_names</A></LI>
+ <LI><A HREF="#stmt:get_type">stmt:get_type</A></LI>
+ <LI><A HREF="#stmt:get_types">stmt:get_types</A></LI>
+ <LI><A HREF="#stmt:get_unames">stmt:get_unames</A></LI>
+ <LI><A HREF="#stmt:get_utypes">stmt:get_utypes</A></LI>
+ <LI><A HREF="#stmt:get_uvalues">stmt:get_uvalues</A></LI>
+ <LI><A HREF="#stmt:get_value">stmt:get_value</A></LI>
+ <LI><A HREF="#stmt:get_values">stmt:get_values</A></LI>
+ <LI><A HREF="#stmt:isopen">stmt:isopen</A></LI>
+ <LI><A HREF="#stmt:nrows">stmt:nrows</A></LI>
+ <LI><A HREF="#stmt:reset">stmt:reset</A></LI>
+ <LI><A HREF="#stmt:rows">stmt:rows</A></LI>
+ <LI><A HREF="#stmt:step">stmt:step</A></LI>
+ <LI><A HREF="#stmt:urows">stmt:urows</A></LI>
+ </UL>
+
+ <LI><A HREF="#methods for callback contexts">Methods for callback contexts</A></LI>
+ <UL>
+
+ <LI><A HREF="#context:aggregate_count">context:aggregate_count</A></LI>
+ <LI><A HREF="#context:get_aggregate_data">context:get_aggregate_data</A></LI>
+ <LI><A HREF="#context:set_aggregate_data">context:set_aggregate_data</A></LI>
+ <LI><A HREF="#context:result">context:result</A></LI>
+ <LI><A HREF="#context:result_null">context:result_null</A></LI>
+ <LI><A HREF="#context:result_number">context:result_number</A></LI>
+ <LI><A HREF="#context:result_int">context:result_int</A></LI>
+ <LI><A HREF="#context:result_text">context:result_text</A></LI>
+ <LI><A HREF="#context:result_blob">context:result_blob</A></LI>
+ <LI><A HREF="#context:result_error">context:result_error</A></LI>
+ <LI><A HREF="#context:user_data">context:user_data</A></LI>
+ </UL>
+
+ <LI><A HREF="#numerical error and result codes">Numerical error and result codes</A></LI>
+ <LI><A HREF="#version">VERSION</A></LI>
+ <LI><A HREF="#credits">CREDITS</A></LI>
+ <LI><A HREF="#license">LICENSE</A></LI>
+</UL>
+<!-- INDEX END -->
+
+<HR>
+<P>
+<HR>
+<H1><A NAME="name">NAME</A></H1>
+<P><STRONG>LuaSQLite 3</STRONG> - a Lua 5.1 wrapper for the SQLite3 library</P>
+<P>
+<HR>
+<H1><A NAME="overview">OVERVIEW</A></H1>
+<P><STRONG>LuaSQLite 3</STRONG> is a thin wrapper around the public domain SQLite3
+database engine.</P>
+<P>The <CODE>lsqlite3</CODE> module supports the creation and manipulation of
+SQLite3 databases. After a <CODE>require('lsqlite3')</CODE> the exported
+functions are called with prefix <CODE>sqlite3</CODE>. However, most sqlite3
+functions are called via an object-oriented interface to either
+database or SQL statement objects; see below for details.</P>
+<P>This documentation does not attempt to describe how SQLite3 itself
+works, it just describes the Lua binding and the available functions.
+For more information about the SQL features supported by SQLite3 and
+details about the syntax of SQL statements and queries, please see the
+<STRONG>SQLite3 documentation</STRONG> <A HREF="http://www.sqlite.org/">http://www.sqlite.org/</A>. Using some of the
+advanced features (how to use callbacks, for instance) will require
+some familiarity with the SQLite3 API.</P>
+<P>
+<HR>
+<H1><A NAME="download">DOWNLOAD</A></H1>
+<P><STRONG>LuaSQLite 3</STRONG> source code can be downloaded from its
+LuaForge (<A HREF="http://luaforge.net/projects/luasqlite/">http://luaforge.net/projects/luasqlite/</A>) page.</P>
+<P>You will also need to build or obtain an SQLite3 loadable library
+(DLL or .so). See <A HREF="http://www.sqlite.org/">http://www.sqlite.org/</A> for obtaining SQLite3
+source code or downloading a binary SQLite3 library.</P>
+<P>
+<HR>
+<H1><A NAME="installation">INSTALLATION</A></H1>
+<P>A <EM>Makefile</EM> is provided; it assumes an SQLite3 library is already
+installed.</P>
+<P>
+<HR>
+<H1><A NAME="examples">EXAMPLES</A></H1>
+<P>The distribution contains an <EM>examples</EM> directory. The unit tests
+also show some example use.</P>
+<P>
+<HR>
+<H1><A NAME="verification tests">VERIFICATION TESTS</A></H1>
+<P>The distribution contains some units tests using Michael Roth's
+<CODE>lunit</CODE> (which is also included). Some of the tests were also derived
+from Michael's <STRONG>lua-sqlite3</STRONG> module, and more unit tests added by
+Doug Currie.</P>
+<P>The distribution also contains some functional tests by Tiago.</P>
+<P>This version of <CODE>lsqlite3</CODE> was tested with SQLite 3.4.2.</P>
+<P>
+<HR>
+<H1><A NAME="reference">REFERENCE</A></H1>
+<P>
+<HR>
+<H1><A NAME="sqlite3 functions">SQLite3 functions</A></H1>
+<P>
+<H2><A NAME="sqlite3.complete">sqlite3.complete</A></H2>
+<PRE>
+ sqlite3.complete(sql)</PRE>
+<P>Returns true if the string <CODE>sql</CODE> comprises one or more complete SQL
+statements and false otherwise.</P>
+<P>
+<H2><A NAME="sqlite3.open">sqlite3.open</A></H2>
+<PRE>
+ sqlite3.open(filename)</PRE>
+<P>Opens (or creates if it does not exist) an SQLite database with name
+<CODE>filename</CODE> and returns its handle as userdata (the returned object
+should be used for all further method calls in connection with this
+specific database, see <A HREF="#database methods">Database methods</A>). Example:</P>
+<PRE>
+ myDB=sqlite3.open('MyDatabase.sqlite3') -- open
+ -- do some database calls...
+ myDB:close() -- close</PRE>
+<P>In case of an error, the function returns nil, an error code and an
+error message.</P>
+<P>
+<H2><A NAME="sqlite3.open_memory">sqlite3.open_memory</A></H2>
+<PRE>
+ sqlite3.open_memory()</PRE>
+<P>Opens an SQLite database <STRONG>in memory</STRONG> and returns its handle as
+userdata. In case of an error, the function returns nil, an error code
+and an error message. (In-memory databases are volatile as they are
+never stored on disk.)</P>
+<P>
+<H2><A NAME="sqlite3.temp_directory">sqlite3.temp_directory</A></H2>
+<PRE>
+ sqlite3.temp_directory([temp])</PRE>
+<P>Sets or queries the directory used by SQLite for temporary files. If
+string <CODE>temp</CODE> is a directory name or nil, the temporary directory is
+set accordingly and the old value is returned. If <CODE>temp</CODE> is missing,
+the function simply returns the current temporary directory.</P>
+<P>
+<H2><A NAME="sqlite3.version">sqlite3.version</A></H2>
+<PRE>
+ sqlite3.version()</PRE>
+<P>Returns a string with SQLite version information, in the form 'x.y[.z]'.</P>
+<P>
+<HR>
+<H1><A NAME="database methods">Database methods</A></H1>
+<P>After opening a database with <A HREF="#sqlite3.open"><CODE>sqlite3.open()</CODE></A> or
+<A HREF="#sqlite3.open_memory"><CODE>sqlite3.open_memory()</CODE></A>
+the returned database object should be used for all further method calls
+in connection with that database. An open database object supports the
+following methods.</P>
+<P>
+<H2><A NAME="db:busy_handler">db:busy_handler</A></H2>
+<PRE>
+ db:busy_handler([func[,udata]])</PRE>
+<P>Sets or removes a busy handler for a database. <CODE>func</CODE> is either a Lua
+function that implements the busy handler or nil to remove a previously
+set handler. This function returns nothing.</P>
+<P>The handler function is called with two parameters: <CODE>udata</CODE> and the
+number of (re-)tries for a pending transaction. It should return nil,
+false or 0 if the transaction is to be aborted. All other values will
+result in another attempt to perform the transaction. (See the SQLite
+documentation for important hints about writing busy handlers.)</P>
+<P>
+<H2><A NAME="db:busy_timeout">db:busy_timeout</A></H2>
+<PRE>
+ db:busy_timeout(t)</PRE>
+<P>Sets a busy handler that waits for <CODE>t</CODE> milliseconds if a transaction
+cannot proceed. Calling this function will remove any busy handler set
+by <A HREF="#db:busy_handler"><CODE>db:busy_handler()</CODE></A>; calling it with an argument
+less than or equal to 0 will turn off all busy handlers.</P>
+<P>
+<H2><A NAME="db:changes">db:changes</A></H2>
+<PRE>
+ db:changes()</PRE>
+<P>This function returns the number of database rows that were changed (or
+inserted or deleted) by the most recent SQL statement. Only changes that
+are directly specified by INSERT, UPDATE, or DELETE statements are
+counted. Auxiliary changes caused by triggers are not counted. Use
+<A HREF="#db:total_changes"><CODE>db:total_changes()</CODE></A> to find the total number of
+changes.</P>
+<P>
+<H2><A NAME="db:close">db:close</A></H2>
+<PRE>
+ db:close()</PRE>
+<P>Closes a database. All SQL statements prepared using
+<A HREF="#db:prepare"><CODE>db:prepare()</CODE></A> should
+have been finalized before this function is called. The function returns
+<CODE>sqlite3.OK</CODE> on success or else a numerical error code (see the list of
+<A HREF="#numerical error and result codes">Numerical error and result codes</A>).</P>
+<P>
+<H2><A NAME="db:close_vm">db:close_vm</A></H2>
+<PRE>
+ db:close_vm(temponly)</PRE>
+<P>Finalizes all statements that have not been explicitly finalized. If
+<CODE>temponly</CODE> is true, only internal, temporary statements are finalized.
+This function returns nothing.</P>
+<P>
+<H2><A NAME="db:create_aggregate">db:create_aggregate</A></H2>
+<PRE>
+ db:create_aggregate(name,nargs,step,final)</PRE>
+<P>This function creates an aggregate callback function. Aggregates perform
+an operation over all rows in a query. <CODE>name</CODE> is a string with the name
+of the aggregate function as given in an SQL statement; <CODE>nargs</CODE> is the
+number of arguments this call will provide. <CODE>step</CODE> is the actual Lua
+function that gets called once for every row; it should accept a function
+context (see <A HREF="#methods for callback contexts">Methods for callback contexts</A>) plus the same number of
+parameters as given in <CODE>nargs</CODE>. <CODE>final</CODE> is a function that is called
+once after all rows have been processed; it receives one argument, the
+function context.</P>
+<P>The function context can be used inside the two callback functions to
+communicate with SQLite3. Here is a simple example:</P>
+<PRE>
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ local num_sum=0
+ local function oneRow(context,num) -- add one column in all rows
+ num_sum=num_sum+num
+ end
+ local function afterLast(context) -- return sum after last row has been processed
+ context:result_number(num_sum)
+ num_sum=0
+ end
+ db:create_aggregate(&quot;do_the_sums&quot;,1,oneRow,afterLast)
+ for sum in db:urows('SELECT do_the_sums(num1) FROM numbers') do print(&quot;Sum of col 1:&quot;,sum) end
+ for sum in db:urows('SELECT do_the_sums(num2) FROM numbers') do print(&quot;Sum of col 2:&quot;,sum) end</PRE>
+<P>This prints:</P>
+<PRE>
+ Sum of col 1: 6
+ Sum of col 2: 66</PRE>
+<P>
+<H2><A NAME="db:create_collation">db:create_collation</A></H2>
+<PRE>
+ db:create_collation(name,func)</PRE>
+<P>This creates a collation callback. A collation callback is used to
+establish a collation order, mostly for string comparisons and sorting
+purposes. <CODE>name</CODE> is a string with the name of the collation to be created;
+<CODE>func</CODE> is a function that accepts two string arguments, compares them
+and returns 0 if both strings are identical, -1 if the first argument is
+lower in the collation order than the second and 1 if the first argument
+is higher in the collation order than the second. A simple example:</P>
+<PRE>
+ local function collate(s1,s2)
+ s1=s1:lower()
+ s2=s2:lower()
+ if s1==s2 then return 0
+ elseif s1&lt;s2 then return -1
+ else return 1 end
+ end
+ db:exec[=[
+ CREATE TABLE test(id INTEGER PRIMARY KEY,content COLLATE CINSENS);
+ INSERT INTO test VALUES(NULL,'hello world');
+ INSERT INTO test VALUES(NULL,'Buenos dias');
+ INSERT INTO test VALUES(NULL,'HELLO WORLD');
+ ]=]
+ db:create_collation('CINSENS',collate)
+ for row in db:nrows('SELECT * FROM test') do print(row.id,row.content) end</PRE>
+<P>
+<H2><A NAME="db:create_function">db:create_function</A></H2>
+<PRE>
+ db:create_function(name,nargs,func)</PRE>
+<P>This function creates a callback function. Callback function are called
+by SQLite3 once for every row in a query. <CODE>name</CODE> is a string with the
+name of the callback function as given in an SQL statement; <CODE>nargs</CODE> is
+the number of arguments this call will provide. <CODE>func</CODE> is the actual Lua
+function that gets called once for every row; it should accept a
+function context (see <A HREF="#methods for callback contexts">Methods for callback contexts</A>) plus the same
+number of parameters as given in nargs. Here is an example:</P>
+<PRE>
+ db:exec'CREATE TABLE test(col1,col2,col3)'
+ db:exec'INSERT INTO test VALUES(1,2,4)'
+ db:exec'INSERT INTO test VALUES(2,4,9)'
+ db:exec'INSERT INTO test VALUES(3,6,16)'
+ db:create_function('sum_cols',3,function(ctx,a,b,c)
+ ctx:result_number(a+b+c)
+ end))
+ for col1,col2,col3,sum in db:urows('SELECT *,sum_cols(col1,col2,col3) FROM test') do
+ util.printf('%2i+%2i+%2i=%2i\n',col1,col2,col3,sum)
+ end</PRE>
+<P>
+<H2><A NAME="db:errcode">db:errcode</A></H2>
+<PRE>
+ db:errcode()
+ db:error_code()</PRE>
+<P>Returns the numerical result code (or extended result code) for the most
+recent failed call associated with database db. See
+<A HREF="#numerical error and result codes">Numerical error and result codes</A> for details.</P>
+<P>
+<H2><A NAME="db:errmsg">db:errmsg</A></H2>
+<PRE>
+ db:errmsg()
+ db:error_message()</PRE>
+<P>Returns a string that contains an error message for the most recent
+failed call associated with database db.</P>
+<P>
+<H2><A NAME="db:exec">db:exec</A></H2>
+<PRE>
+ db:exec(sql[,func[,udata]])
+ db:execute(sql[,func[,udata]])</PRE>
+<P>Compiles and executes the SQL <CODE>statement(s)</CODE> given in string <CODE>sql</CODE>. The
+statements are simply executed one after the other and not stored. The
+function returns <CODE>sqlite3.OK</CODE> on success or else a numerical error code
+(see <A HREF="#numerical error and result codes">Numerical error and result codes</A>).</P>
+<P>If one or more of the SQL statements are queries, then the callback
+function specified in <CODE>func</CODE> is invoked once for each row of the query
+result (if <CODE>func</CODE> is nil, no callback is invoked). The callback receives
+four arguments: <CODE>udata</CODE> (the third parameter of the <CODE>db:exec()</CODE> call),
+the number of columns in the row, a table with the column values and
+another table with the column names. The callback function should return
+0. If the callback returns a non-zero value then the query is aborted,
+all subsequent SQL statements are skipped and <CODE>db:exec()</CODE> returns
+<CODE>sqlite3.ABORT</CODE>. Here is a simple example:</P>
+<PRE>
+ sql=[=[
+ CREATE TABLE numbers(num1,num2,str);
+ INSERT INTO numbers VALUES(1,11,&quot;ABC&quot;);
+ INSERT INTO numbers VALUES(2,22,&quot;DEF&quot;);
+ INSERT INTO numbers VALUES(3,33,&quot;UVW&quot;);
+ INSERT INTO numbers VALUES(4,44,&quot;XYZ&quot;);
+ SELECT * FROM numbers;
+ ]=]
+ function showrow(udata,cols,values,names)
+ assert(udata=='test_udata')
+ print('exec:')
+ for i=1,cols do print('',names[i],values[i]) end
+ return 0
+ end
+ db:exec(sql,showrow,'test_udata')</PRE>
+<P>
+<H2><A NAME="db:interrupt">db:interrupt</A></H2>
+<PRE>
+ db:interrupt()</PRE>
+<P>This function causes any pending database operation to abort and return
+at the next opportunity. This function returns nothing.</P>
+<P>
+<H2><A NAME="db:isopen">db:isopen</A></H2>
+<PRE>
+ db:isopen()</PRE>
+<P>Returns true if database db is open, false otherwise.</P>
+<P>
+<H2><A NAME="db:last_insert_rowid">db:last_insert_rowid</A></H2>
+<PRE>
+ db:last_insert_rowid()</PRE>
+<P>This function returns the rowid of the most recent INSERT into the
+database. If no inserts have ever occurred, 0 is returned. (Each row in
+an SQLite table has a unique 64-bit signed integer key called the
+'rowid'. This id is always available as an undeclared column named
+ROWID, OID, or _ROWID_. If the table has a column of type INTEGER
+PRIMARY KEY then that column is another alias for the rowid.)</P>
+<P>If an INSERT occurs within a trigger, then the rowid of the inserted row
+is returned as long as the trigger is running. Once the trigger
+terminates, the value returned reverts to the last value inserted before
+the trigger fired.</P>
+<P>
+<H2><A NAME="db:nrows">db:nrows</A></H2>
+<PRE>
+ db:nrows(sql)</PRE>
+<P>Creates an iterator that returns the successive rows selected by the SQL
+statement given in string <CODE>sql</CODE>. Each call to the iterator returns a
+table in which the named fields correspond to the columns in the database.
+Here is an example:</P>
+<PRE>
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ for a in db:nrows('SELECT * FROM numbers') do table.print(a) end</PRE>
+<P>This script prints:</P>
+<PRE>
+ num2: 11
+ num1: 1
+ num2: 22
+ num1: 2
+ num2: 33
+ num1: 3</PRE>
+<P>
+<H2><A NAME="db:prepare">db:prepare</A></H2>
+<PRE>
+ db:prepare(sql)</PRE>
+<P>This function compiles the SQL statement in string <CODE>sql</CODE> into an internal
+representation and returns this as userdata. The returned object should
+be used for all further method calls in connection with this specific
+SQL statement (see <A HREF="#methods for prepared statements">Methods for prepared statements</A>).</P>
+<P>
+<H2><A NAME="db:progress_handler">db:progress_handler</A></H2>
+<PRE>
+ db:progress_handler(n,func,udata)</PRE>
+<P>This function installs a callback function <CODE>func</CODE> that is invoked
+periodically during long-running calls to <A HREF="#db:exec"><CODE>db:exec()</CODE></A>
+or <A HREF="#stmt:step"><CODE>stmt:step()</CODE></A>. The
+progress callback is invoked once for every <CODE>n</CODE> internal operations,
+where <CODE>n</CODE> is the first argument to this function. <CODE>udata</CODE> is passed to
+the progress callback function each time it is invoked. If a call to
+<CODE>db:exec()</CODE> or <CODE>stmt:step()</CODE> results in fewer than <CODE>n</CODE> operations
+being executed, then the progress callback is never invoked. Only a
+single progress callback function may be registered for each opened
+database and a call to this function will overwrite any previously set
+callback function. To remove the progress callback altogether, pass nil
+as the second argument.</P>
+<P>If the progress callback returns a result other than 0, then the current
+query is immediately terminated, any database changes are rolled back
+and the containing <CODE>db:exec()</CODE> or <CODE>stmt:step()</CODE> call returns
+<CODE>sqlite3.INTERRUPT</CODE>. This feature can be used to cancel long-running
+queries.</P>
+<P>
+<H2><A NAME="db:rows">db:rows</A></H2>
+<PRE>
+ db:rows(sql)</PRE>
+<P>Creates an iterator that returns the successive rows selected by the SQL
+statement given in string <CODE>sql</CODE>. Each call to the iterator returns a table
+in which the numerical indices 1 to n correspond to the selected columns
+1 to n in the database. Here is an example:</P>
+<PRE>
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ for a in db:rows('SELECT * FROM numbers') do table.print(a) end</PRE>
+<P>This script prints:</P>
+<PRE>
+ 1: 1
+ 2: 11
+ 1: 2
+ 2: 22
+ 1: 3
+ 2: 33</PRE>
+<P>
+<H2><A NAME="db:total_changes">db:total_changes</A></H2>
+<PRE>
+ db:total_changes()</PRE>
+<P>This function returns the number of database rows that have been
+modified by INSERT, UPDATE or DELETE statements since the database was
+opened. This includes UPDATE, INSERT and DELETE statements executed as
+part of trigger programs. All changes are counted as soon as the
+statement that produces them is completed by calling either
+<A HREF="#stmt:reset"><CODE>stmt:reset()</CODE></A> or <A HREF="#stmt:finalize"><CODE>stmt:finalize()</CODE></A>.</P>
+<P>
+<H2><A NAME="db:trace">db:trace</A></H2>
+<PRE>
+ db:trace(func,udata)</PRE>
+<P>This function installs a trace callback handler. <CODE>func</CODE> is a Lua
+function that is called by SQLite3 just before the evaluation of an SQL
+statement. This callback receives two arguments: the first is the
+<CODE>udata</CODE> argument used when the callback was installed; the second is a
+string with the SQL statement about to be executed.</P>
+<P>
+<H2><A NAME="db:urows">db:urows</A></H2>
+<PRE>
+ db:urows(sql)</PRE>
+<P>Creates an iterator that returns the successive rows selected by the SQL
+statement given in string <CODE>sql</CODE>. Each call to the iterator returns the
+values that correspond to the columns in the currently selected row.
+Here is an example:</P>
+<PRE>
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ for num1,num2 in db:urows('SELECT * FROM numbers') do print(num1,num2) end</PRE>
+<P>This script prints:</P>
+<PRE>
+ 1 11
+ 2 22
+ 3 33</PRE>
+<P>
+<HR>
+<H1><A NAME="methods for prepared statements">Methods for prepared statements</A></H1>
+<P>After creating a prepared statement with <A HREF="#db:prepare"><CODE>db:prepare()</CODE></A>
+the returned statement object should be used for all further calls in
+connection with that statement. Statement objects support the following
+methods.</P>
+<P>
+<H2><A NAME="stmt:bind">stmt:bind</A></H2>
+<PRE>
+ stmt:bind(n[,value])</PRE>
+<P>Binds value to statement parameter <CODE>n</CODE>. If the type of value is string
+or number, it is bound as text or double, respectively. If <CODE>value</CODE> is a
+boolean or nil or missing, any previous binding is removed. The function
+returns <CODE>sqlite3.OK</CODE> on success or else a numerical error code (see
+<A HREF="#numerical error and result codes">Numerical error and result codes</A>).</P>
+<P>
+<H2><A NAME="stmt:bind_blob">stmt:bind_blob</A></H2>
+<PRE>
+ stmt:bind_blob(n,blob)</PRE>
+<P>Binds string <CODE>blob</CODE> (which can be a binary string) as a blob to
+statement parameter <CODE>n</CODE>. The function returns <CODE>sqlite3.OK</CODE> on success
+or else a numerical error code (see <A HREF="#numerical error and result codes">Numerical error and result codes</A>).</P>
+<P>
+<H2><A NAME="stmt:bind_names">stmt:bind_names</A></H2>
+<PRE>
+ stmt:bind_names(nametable)</PRE>
+<P>Binds the values in <CODE>nametable</CODE> to statement parameters. If the
+statement parameters are named (i.e., of the form ``:AAA'' or ``$AAA'')
+then this function looks for appropriately named fields in <CODE>nametable</CODE>;
+if the statement parameters are
+not named, it looks for numerical fields 1 to the number of statement
+parameters. The function returns <CODE>sqlite3.OK</CODE> on success or else a
+numerical error code (see <A HREF="#numerical error and result codes">Numerical error and result codes</A>).</P>
+<P>
+<H2><A NAME="stmt:bind_parameter_count">stmt:bind_parameter_count</A></H2>
+<PRE>
+ stmt:bind_parameter_count()</PRE>
+<P>Returns the largest statement parameter index in prepared statement
+<CODE>stmt</CODE>. When the statement parameters are of the forms ``:AAA'' or ``?'',
+then they are assigned sequentially increasing numbers beginning with
+one, so the value returned is the number of parameters. However if the
+same statement parameter name is used multiple times, each occurrence
+is given the same number, so the value returned is the number of unique
+statement parameter names.</P>
+<P>If statement parameters of the form ``?NNN'' are used (where NNN is an
+integer) then there might be gaps in the numbering and the value
+returned by this interface is the index of the statement parameter with
+the largest index value.</P>
+<P>
+<H2><A NAME="stmt:bind_parameter_name">stmt:bind_parameter_name</A></H2>
+<PRE>
+ stmt:bind_parameter_name(n)</PRE>
+<P>Returns the name of the <CODE>n</CODE>-th parameter in prepared statement <CODE>stmt</CODE>.
+Statement parameters of the form ``:AAA'' or ``@AAA'' or ``$VVV'' have a name
+which is the string ``:AAA'' or ``@AAA'' or ``$VVV''. In other words, the
+initial ``:'' or ``$'' or ``@'' is included as part of the name. Parameters
+of the form ``?'' or ``?NNN'' have no name. The first bound parameter has
+an index of 1.
+If the value <CODE>n</CODE> is out of range or if the <CODE>n</CODE>-th parameter is
+nameless, then nil is returned. The function returns <CODE>sqlite3.OK</CODE> on
+success or else a numerical error code (see
+<A HREF="#numerical error and result codes">Numerical error and result codes</A>)</P>
+<P>
+<H2><A NAME="stmt:bind_values">stmt:bind_values</A></H2>
+<PRE>
+ stmt:bind_values(value1,value2,...,valueN)</PRE>
+<P>Binds the given values to statement parameters. The function returns
+<CODE>sqlite3.OK</CODE> on success or else a numerical error code (see
+<A HREF="#numerical error and result codes">Numerical error and result codes</A>).</P>
+<P>
+<H2><A NAME="stmt:columns">stmt:columns</A></H2>
+<PRE>
+ stmt:columns()</PRE>
+<P>Returns the number of columns in the result set returned by statement
+stmt or 0 if the statement does not return data (for example an UPDATE).</P>
+<P>
+<H2><A NAME="stmt:finalize">stmt:finalize</A></H2>
+<PRE>
+ stmt:finalize()</PRE>
+<P>This function frees prepared statement stmt. If the statement was
+executed successfully, or not executed at all, then <CODE>sqlite3.OK</CODE> is
+returned. If execution of the statement failed then an error code is
+returned.</P>
+<P>
+<H2><A NAME="stmt:get_name">stmt:get_name</A></H2>
+<PRE>
+ stmt:get_name(n)</PRE>
+<P>Returns the name of column <CODE>n</CODE> in the result set of statement stmt. (The
+left-most column is number 0.)</P>
+<P>
+<H2><A NAME="stmt:get_named_types">stmt:get_named_types</A></H2>
+<PRE>
+ stmt:get_named_types()</PRE>
+<P>Returns a table with the names and types of all columns in the result
+set of statement stmt.</P>
+<P>
+<H2><A NAME="stmt:get_named_values">stmt:get_named_values</A></H2>
+<PRE>
+ stmt:get_named_values()</PRE>
+<P>This function returns a table with names and values of all columns in
+the current result row of a query.</P>
+<P>
+<H2><A NAME="stmt:get_names">stmt:get_names</A></H2>
+<PRE>
+ stmt:get_names()</PRE>
+<P>This function returns an array with the names of all columns in the
+result set returned by statement stmt.</P>
+<P>
+<H2><A NAME="stmt:get_type">stmt:get_type</A></H2>
+<PRE>
+ stmt:get_type(n)</PRE>
+<P>Returns the type of column <CODE>n</CODE> in the result set of statement stmt. (The
+left-most column is number 0.)</P>
+<P>
+<H2><A NAME="stmt:get_types">stmt:get_types</A></H2>
+<PRE>
+ stmt:get_types()</PRE>
+<P>This function returns an array with the types of all columns in the
+result set returned by statement stmt.</P>
+<P>
+<H2><A NAME="stmt:get_unames">stmt:get_unames</A></H2>
+<PRE>
+ stmt:get_unames()</PRE>
+<P>This function returns a list with the names of all columns in the result
+set returned by statement stmt.</P>
+<P>
+<H2><A NAME="stmt:get_utypes">stmt:get_utypes</A></H2>
+<PRE>
+ stmt:get_utypes()</PRE>
+<P>This function returns a list with the types of all columns in the result
+set returned by statement stmt.</P>
+<P>
+<H2><A NAME="stmt:get_uvalues">stmt:get_uvalues</A></H2>
+<PRE>
+ stmt:get_uvalues()</PRE>
+<P>This function returns a list with the values of all columns in the
+current result row of a query.</P>
+<P>
+<H2><A NAME="stmt:get_value">stmt:get_value</A></H2>
+<PRE>
+ stmt:get_value(n)</PRE>
+<P>Returns the value of column <CODE>n</CODE> in the result set of statement stmt. (The
+left-most column is number 0.)</P>
+<P>
+<H2><A NAME="stmt:get_values">stmt:get_values</A></H2>
+<PRE>
+ stmt:get_values()</PRE>
+<P>This function returns an array with the values of all columns in the
+result set returned by statement stmt.</P>
+<P>
+<H2><A NAME="stmt:isopen">stmt:isopen</A></H2>
+<PRE>
+ stmt:isopen()</PRE>
+<P>Returns true if stmt has not yet been finalized, false otherwise.</P>
+<P>
+<H2><A NAME="stmt:nrows">stmt:nrows</A></H2>
+<PRE>
+ stmt:nrows()</PRE>
+<P>Returns an function that iterates over the names and values of the
+result set of statement <CODE>stmt</CODE>. Each iteration returns a table with the
+names and values for the current row.
+This is the prepared statement equivalent of <A HREF="#db:nrows"><CODE>db:nrows()</CODE></A>.</P>
+<P>
+<H2><A NAME="stmt:reset">stmt:reset</A></H2>
+<PRE>
+ stmt:reset()</PRE>
+<P>This function resets SQL statement <CODE>stmt</CODE>, so that it is ready to be
+re-executed. Any statement variables that had values bound to them using
+the <CODE>stmt:bind*()</CODE> functions retain their values.</P>
+<P>
+<H2><A NAME="stmt:rows">stmt:rows</A></H2>
+<PRE>
+ stmt:rows()</PRE>
+<P>Returns an function that iterates over the values of the result set of
+statement stmt. Each iteration returns an array with the values for the
+current row.
+This is the prepared statement equivalent of <A HREF="#db:rows"><CODE>db:rows()</CODE></A>.</P>
+<P>
+<H2><A NAME="stmt:step">stmt:step</A></H2>
+<PRE>
+ stmt:step()</PRE>
+<P>This function must be called to evaluate the (next iteration of the)
+prepared statement stmt. It will return one of the following values:</P>
+<UL>
+<LI>
+<CODE>sqlite3.BUSY</CODE>: the engine was unable to acquire the locks needed. If the
+statement is a COMMIT or occurs outside of an explicit transaction, then
+you can retry the statement. If the statement is not a COMMIT and occurs
+within a explicit transaction then you should rollback the transaction
+before continuing.
+<P></P>
+<LI>
+<CODE>sqlite3.DONE</CODE>: the statement has finished executing successfully.
+<A HREF="#stmt:step"><CODE>stmt:step()</CODE></A> should not be called again on this statement
+without first calling <A HREF="#stmt:reset"><CODE>stmt:reset()</CODE></A> to reset the virtual
+machine back to the initial state.
+<P></P>
+<LI>
+<CODE>sqlite3.ROW</CODE>: this is returned each time a new row of data is ready for
+processing by the caller. The values may be accessed using the column
+access functions. <A HREF="#stmt:step"><CODE>stmt:step()</CODE></A> can be called again to
+retrieve the next row of data.
+<P></P>
+<LI>
+<CODE>sqlite3.ERROR</CODE>: a run-time error (such as a constraint violation) has
+occurred. <A HREF="#stmt:step"><CODE>stmt:step()</CODE></A> should not be called again. More
+information may be found by calling <A HREF="#db:errmsg"><CODE>db:errmsg()</CODE></A>. A more
+specific error
+code (can be obtained by calling <A HREF="#stmt:reset"><CODE>stmt:reset()</CODE></A>.
+<P></P>
+<LI>
+<CODE>sqlite3.MISUSE</CODE>: the function was called inappropriately, perhaps
+because the statement has already been finalized or a previous call to
+<A HREF="#stmt:step"><CODE>stmt:step()</CODE></A> has returned <CODE>sqlite3.ERROR</CODE> or
+<CODE>sqlite3.DONE</CODE>.
+<P></P></UL>
+<P>
+<H2><A NAME="stmt:urows">stmt:urows</A></H2>
+<PRE>
+ stmt:urows()</PRE>
+<P>Returns an function that iterates over the values of the result set of
+statement stmt. Each iteration returns the values for the current row.
+This is the prepared statement equivalent of <A HREF="#db:urows"><CODE>db:urows()</CODE></A>.</P>
+<P>
+<HR>
+<H1><A NAME="methods for callback contexts">Methods for callback contexts</A></H1>
+<P>A callback context is available as a parameter inside the callback
+functions <A HREF="#db:create_aggregate"><CODE>db:create_aggregate()</CODE></A> and
+<A HREF="#db:create_function"><CODE>db:create_function()</CODE></A>. It can be used
+to get further information about the state of a query.</P>
+<P>
+<H2><A NAME="context:aggregate_count">context:aggregate_count</A></H2>
+<PRE>
+ context:aggregate_count()</PRE>
+<P>Returns the number of calls to the aggregate step function.</P>
+<P>
+<H2><A NAME="context:get_aggregate_data">context:get_aggregate_data</A></H2>
+<PRE>
+ context:get_aggregate_data()</PRE>
+<P>Returns the user-definable data field for callback funtions.</P>
+<P>
+<H2><A NAME="context:set_aggregate_data">context:set_aggregate_data</A></H2>
+<PRE>
+ context:set_aggregate_data(udata)</PRE>
+<P>Set the user-definable data field for callback funtions to <CODE>udata</CODE>.</P>
+<P>
+<H2><A NAME="context:result">context:result</A></H2>
+<PRE>
+ context:result(res)</PRE>
+<P>This function sets the result of a callback function to res. The type of
+the result depends on the type of res and is either a number or a string
+or nil. All other values will raise an error message.</P>
+<P>
+<H2><A NAME="context:result_null">context:result_null</A></H2>
+<PRE>
+ context:result_null()</PRE>
+<P>This function sets the result of a callback function to nil. It returns
+nothing.</P>
+<P>
+<H2><A NAME="context:result_number">context:result_number</A></H2>
+<PRE>
+ context:result_number(number)
+ context:result_double(number)</PRE>
+<P>This function sets the result of a callback function to the value
+<CODE>number</CODE>. It returns nothing.</P>
+<P>
+<H2><A NAME="context:result_int">context:result_int</A></H2>
+<PRE>
+ context:result_int(number)</PRE>
+<P>This function sets the result of a callback function to the integer
+value in <CODE>number</CODE>. It returns nothing.</P>
+<P>
+<H2><A NAME="context:result_text">context:result_text</A></H2>
+<PRE>
+ context:result_text(str)</PRE>
+<P>This function sets the result of a callback function to the string in
+<CODE>str</CODE>. It returns nothing.</P>
+<P>
+<H2><A NAME="context:result_blob">context:result_blob</A></H2>
+<PRE>
+ context:result_blob(blob)</PRE>
+<P>This function sets the result of a callback function to the binary
+string in <CODE>blob</CODE>. It returns nothing.</P>
+<P>
+<H2><A NAME="context:result_error">context:result_error</A></H2>
+<PRE>
+ context:result_error(err)</PRE>
+<P>This function sets the result of a callback function to the error value
+in <CODE>err</CODE>. It returns nothing.</P>
+<P>
+<H2><A NAME="context:user_data">context:user_data</A></H2>
+<PRE>
+ context:user_data()</PRE>
+<P>Returns the userdata parameter given in the call to install the callback
+function (see <A HREF="#db:create_aggregate"><CODE>db:create_aggregate()</CODE></A> and
+<A HREF="#db:create_function"><CODE>db:create_function()</CODE></A> for details).</P>
+<P>
+<HR>
+<H1><A NAME="numerical error and result codes">Numerical error and result codes</A></H1>
+<P>The following constants are defined by module sqlite3:</P>
+<PRE>
+ OK: 0 ERROR: 1 INTERNAL: 2 PERM: 3 ABORT: 4
+ BUSY: 5 LOCKED: 6 NOMEM: 7 READONLY: 8 INTERRUPT: 9
+ IOERR: 10 CORRUPT: 11 NOTFOUND: 12 FULL: 13 CANTOPEN: 14
+ PROTOCOL: 15 EMPTY: 16 SCHEMA: 17 TOOBIG: 18 CONSTRAINT: 19
+ MISMATCH: 20 MISUSE: 21 NOLFS: 22 FORMAT: 24 RANGE: 25
+ NOTADB: 26 ROW: 100 DONE: 101</PRE>
+<P>For details about their exact meaning please see the <STRONG>SQLite3
+documentation</STRONG> <A HREF="http://www.sqlite.org/">http://www.sqlite.org/</A>.</P>
+<P>
+<HR>
+<H1><A NAME="version">VERSION</A></H1>
+<P>This is <CODE>lsqlite3</CODE> subversion 6, also known as ``devel-0.6''.</P>
+<P>
+<HR>
+<H1><A NAME="credits">CREDITS</A></H1>
+<P><CODE>lsqlite3</CODE> was developed by Tiago Dionizio and Doug Currie with
+contributions from Thomas Lauer and Michael Roth.</P>
+<P>This documentation is based on the ``(very) preliminary'' documents
+for the Idle-SQLite3 database module. Thanks to Thomas Lauer for
+making it available.</P>
+<P>
+<HR>
+<H1><A NAME="license">LICENSE</A></H1>
+<PRE>
+ /************************************************************************
+ * lsqlite3 *
+ * Copyright (C) 2002-2007 Tiago Dionizio, Doug Currie *
+ * All rights reserved. *
+ * Author : Tiago Dionizio &lt;tiago.dionizio@ist.utl.pt&gt; *
+ * Author : Doug Currie &lt;doug.currie@alum.mit.edu&gt; *
+ * Library : lsqlite3 - a SQLite 3 database binding for Lua 5 *
+ * *
+ * Permission is hereby granted, free of charge, to any person obtaining *
+ * a copy of this software and associated documentation files (the *
+ * &quot;Software&quot;), 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 &quot;AS IS&quot;, 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. *
+ ************************************************************************/</PRE>
+
+</BODY>
+
+</HTML>
diff --git a/3rdparty/lsqlite3/doc/lsqlite3.pod b/3rdparty/lsqlite3/doc/lsqlite3.pod
new file mode 100644
index 00000000000..5e696f72fd7
--- /dev/null
+++ b/3rdparty/lsqlite3/doc/lsqlite3.pod
@@ -0,0 +1,866 @@
+=pod
+
+=head1 NAME
+
+B<LuaSQLite 3> - a Lua 5.1 wrapper for the SQLite3 library
+
+=head1 OVERVIEW
+
+B<LuaSQLite 3> is a thin wrapper around the public domain SQLite3
+database engine.
+
+The C<lsqlite3> module supports the creation and manipulation of
+SQLite3 databases. After a C<require('lsqlite3')> the exported
+functions are called with prefix C<sqlite3>. However, most sqlite3
+functions are called via an object-oriented interface to either
+database or SQL statement objects; see below for details.
+
+This documentation does not attempt to describe how SQLite3 itself
+works, it just describes the Lua binding and the available functions.
+For more information about the SQL features supported by SQLite3 and
+details about the syntax of SQL statements and queries, please see the
+B<SQLite3 documentation> L<http://www.sqlite.org/>. Using some of the
+advanced features (how to use callbacks, for instance) will require
+some familiarity with the SQLite3 API.
+
+=head1 DOWNLOAD
+
+B<LuaSQLite 3> source code can be downloaded from its
+LuaForge (L<http://luaforge.net/projects/luasqlite/>) page.
+
+You will also need to build or obtain an SQLite3 loadable library
+(DLL or .so). See L<http://www.sqlite.org/> for obtaining SQLite3
+source code or downloading a binary SQLite3 library.
+
+=head1 INSTALLATION
+
+A I<Makefile> is provided; it assumes an SQLite3 library is already
+installed.
+
+=head1 EXAMPLES
+
+The distribution contains an I<examples> directory. The unit tests
+also show some example use.
+
+=head1 VERIFICATION TESTS
+
+The distribution contains some units tests using Michael Roth's
+C<lunit> (which is also included). Some of the tests were also derived
+from Michael's B<lua-sqlite3> module, and more unit tests added by
+Doug Currie.
+
+The distribution also contains some functional tests by Tiago.
+
+This version of C<lsqlite3> was tested with SQLite 3.4.2.
+
+=head1 REFERENCE
+
+=head1 SQLite3 functions
+
+=head2 sqlite3.complete
+
+ sqlite3.complete(sql)
+
+Returns true if the string C<sql> comprises one or more complete SQL
+statements and false otherwise.
+
+=head2 sqlite3.open
+
+ sqlite3.open(filename)
+
+Opens (or creates if it does not exist) an SQLite database with name
+C<filename> and returns its handle as userdata (the returned object
+should be used for all further method calls in connection with this
+specific database, see L</Database methods>). Example:
+
+ myDB=sqlite3.open('MyDatabase.sqlite3') -- open
+ -- do some database calls...
+ myDB:close() -- close
+
+In case of an error, the function returns nil, an error code and an
+error message.
+
+=head2 sqlite3.open_memory
+
+ sqlite3.open_memory()
+
+Opens an SQLite database B<in memory> and returns its handle as
+userdata. In case of an error, the function returns nil, an error code
+and an error message. (In-memory databases are volatile as they are
+never stored on disk.)
+
+=head2 sqlite3.temp_directory
+
+ sqlite3.temp_directory([temp])
+
+Sets or queries the directory used by SQLite for temporary files. If
+string C<temp> is a directory name or nil, the temporary directory is
+set accordingly and the old value is returned. If C<temp> is missing,
+the function simply returns the current temporary directory.
+
+=head2 sqlite3.version
+
+ sqlite3.version()
+
+Returns a string with SQLite version information, in the form 'x.y[.z]'.
+
+=head1 Database methods
+
+After opening a database with L<C<sqlite3.open()>|/sqlite3.open> or
+L<C<sqlite3.open_memory()>|/sqlite3.open_memory>
+the returned database object should be used for all further method calls
+in connection with that database. An open database object supports the
+following methods.
+
+=head2 db:busy_handler
+
+ db:busy_handler([func[,udata]])
+
+Sets or removes a busy handler for a database. C<func> is either a Lua
+function that implements the busy handler or nil to remove a previously
+set handler. This function returns nothing.
+
+The handler function is called with two parameters: C<udata> and the
+number of (re-)tries for a pending transaction. It should return nil,
+false or 0 if the transaction is to be aborted. All other values will
+result in another attempt to perform the transaction. (See the SQLite
+documentation for important hints about writing busy handlers.)
+
+=head2 db:busy_timeout
+
+ db:busy_timeout(t)
+
+Sets a busy handler that waits for C<t> milliseconds if a transaction
+cannot proceed. Calling this function will remove any busy handler set
+by L<C<db:busy_handler()>|/db:busy_handler>; calling it with an argument
+less than or equal to 0 will turn off all busy handlers.
+
+=head2 db:changes
+
+ db:changes()
+
+This function returns the number of database rows that were changed (or
+inserted or deleted) by the most recent SQL statement. Only changes that
+are directly specified by INSERT, UPDATE, or DELETE statements are
+counted. Auxiliary changes caused by triggers are not counted. Use
+L<C<db:total_changes()>|/db:total_changes> to find the total number of
+changes.
+
+=head2 db:close
+
+ db:close()
+
+Closes a database. All SQL statements prepared using
+L<C<db:prepare()>|/db:prepare> should
+have been finalized before this function is called. The function returns
+C<sqlite3.OK> on success or else a numerical error code (see the list of
+L</Numerical error and result codes>).
+
+=head2 db:close_vm
+
+ db:close_vm(temponly)
+
+Finalizes all statements that have not been explicitly finalized. If
+C<temponly> is true, only internal, temporary statements are finalized.
+This function returns nothing.
+
+=head2 db:create_aggregate
+
+ db:create_aggregate(name,nargs,step,final)
+
+This function creates an aggregate callback function. Aggregates perform
+an operation over all rows in a query. C<name> is a string with the name
+of the aggregate function as given in an SQL statement; C<nargs> is the
+number of arguments this call will provide. C<step> is the actual Lua
+function that gets called once for every row; it should accept a function
+context (see L</Methods for callback contexts>) plus the same number of
+parameters as given in C<nargs>. C<final> is a function that is called
+once after all rows have been processed; it receives one argument, the
+function context.
+
+The function context can be used inside the two callback functions to
+communicate with SQLite3. Here is a simple example:
+
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ local num_sum=0
+ local function oneRow(context,num) -- add one column in all rows
+ num_sum=num_sum+num
+ end
+ local function afterLast(context) -- return sum after last row has been processed
+ context:result_number(num_sum)
+ num_sum=0
+ end
+ db:create_aggregate("do_the_sums",1,oneRow,afterLast)
+ for sum in db:urows('SELECT do_the_sums(num1) FROM numbers') do print("Sum of col 1:",sum) end
+ for sum in db:urows('SELECT do_the_sums(num2) FROM numbers') do print("Sum of col 2:",sum) end
+
+This prints:
+
+ Sum of col 1: 6
+ Sum of col 2: 66
+
+=head2 db:create_collation
+
+ db:create_collation(name,func)
+
+This creates a collation callback. A collation callback is used to
+establish a collation order, mostly for string comparisons and sorting
+purposes. C<name> is a string with the name of the collation to be created;
+C<func> is a function that accepts two string arguments, compares them
+and returns 0 if both strings are identical, -1 if the first argument is
+lower in the collation order than the second and 1 if the first argument
+is higher in the collation order than the second. A simple example:
+
+ local function collate(s1,s2)
+ s1=s1:lower()
+ s2=s2:lower()
+ if s1==s2 then return 0
+ elseif s1<s2 then return -1
+ else return 1 end
+ end
+ db:exec[=[
+ CREATE TABLE test(id INTEGER PRIMARY KEY,content COLLATE CINSENS);
+ INSERT INTO test VALUES(NULL,'hello world');
+ INSERT INTO test VALUES(NULL,'Buenos dias');
+ INSERT INTO test VALUES(NULL,'HELLO WORLD');
+ ]=]
+ db:create_collation('CINSENS',collate)
+ for row in db:nrows('SELECT * FROM test') do print(row.id,row.content) end
+
+=head2 db:create_function
+
+ db:create_function(name,nargs,func)
+
+This function creates a callback function. Callback function are called
+by SQLite3 once for every row in a query. C<name> is a string with the
+name of the callback function as given in an SQL statement; C<nargs> is
+the number of arguments this call will provide. C<func> is the actual Lua
+function that gets called once for every row; it should accept a
+function context (see L</Methods for callback contexts>) plus the same
+number of parameters as given in nargs. Here is an example:
+
+ db:exec'CREATE TABLE test(col1,col2,col3)'
+ db:exec'INSERT INTO test VALUES(1,2,4)'
+ db:exec'INSERT INTO test VALUES(2,4,9)'
+ db:exec'INSERT INTO test VALUES(3,6,16)'
+ db:create_function('sum_cols',3,function(ctx,a,b,c)
+ ctx:result_number(a+b+c)
+ end))
+ for col1,col2,col3,sum in db:urows('SELECT *,sum_cols(col1,col2,col3) FROM test') do
+ util.printf('%2i+%2i+%2i=%2i\n',col1,col2,col3,sum)
+ end
+
+=head2 db:errcode
+
+ db:errcode()
+ db:error_code()
+
+Returns the numerical result code (or extended result code) for the most
+recent failed call associated with database db. See
+L</Numerical error and result codes> for details.
+
+=head2 db:errmsg
+
+ db:errmsg()
+ db:error_message()
+
+Returns a string that contains an error message for the most recent
+failed call associated with database db.
+
+=head2 db:exec
+
+ db:exec(sql[,func[,udata]])
+ db:execute(sql[,func[,udata]])
+
+Compiles and executes the SQL statement(s) given in string C<sql>. The
+statements are simply executed one after the other and not stored. The
+function returns C<sqlite3.OK> on success or else a numerical error code
+(see L</Numerical error and result codes>).
+
+If one or more of the SQL statements are queries, then the callback
+function specified in C<func> is invoked once for each row of the query
+result (if C<func> is nil, no callback is invoked). The callback receives
+four arguments: C<udata> (the third parameter of the C<db:exec()> call),
+the number of columns in the row, a table with the column values and
+another table with the column names. The callback function should return
+0. If the callback returns a non-zero value then the query is aborted,
+all subsequent SQL statements are skipped and C<db:exec()> returns
+C<sqlite3.ABORT>. Here is a simple example:
+
+ sql=[=[
+ CREATE TABLE numbers(num1,num2,str);
+ INSERT INTO numbers VALUES(1,11,"ABC");
+ INSERT INTO numbers VALUES(2,22,"DEF");
+ INSERT INTO numbers VALUES(3,33,"UVW");
+ INSERT INTO numbers VALUES(4,44,"XYZ");
+ SELECT * FROM numbers;
+ ]=]
+ function showrow(udata,cols,values,names)
+ assert(udata=='test_udata')
+ print('exec:')
+ for i=1,cols do print('',names[i],values[i]) end
+ return 0
+ end
+ db:exec(sql,showrow,'test_udata')
+
+=head2 db:interrupt
+
+ db:interrupt()
+
+This function causes any pending database operation to abort and return
+at the next opportunity. This function returns nothing.
+
+=head2 db:isopen
+
+ db:isopen()
+
+Returns true if database db is open, false otherwise.
+
+=head2 db:last_insert_rowid
+
+ db:last_insert_rowid()
+
+This function returns the rowid of the most recent INSERT into the
+database. If no inserts have ever occurred, 0 is returned. (Each row in
+an SQLite table has a unique 64-bit signed integer key called the
+'rowid'. This id is always available as an undeclared column named
+ROWID, OID, or _ROWID_. If the table has a column of type INTEGER
+PRIMARY KEY then that column is another alias for the rowid.)
+
+If an INSERT occurs within a trigger, then the rowid of the inserted row
+is returned as long as the trigger is running. Once the trigger
+terminates, the value returned reverts to the last value inserted before
+the trigger fired.
+
+=head2 db:nrows
+
+ db:nrows(sql)
+
+Creates an iterator that returns the successive rows selected by the SQL
+statement given in string C<sql>. Each call to the iterator returns a
+table in which the named fields correspond to the columns in the database.
+Here is an example:
+
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ for a in db:nrows('SELECT * FROM numbers') do table.print(a) end
+
+This script prints:
+
+ num2: 11
+ num1: 1
+ num2: 22
+ num1: 2
+ num2: 33
+ num1: 3
+
+=head2 db:prepare
+
+ db:prepare(sql)
+
+This function compiles the SQL statement in string C<sql> into an internal
+representation and returns this as userdata. The returned object should
+be used for all further method calls in connection with this specific
+SQL statement (see L</Methods for prepared statements>).
+
+=head2 db:progress_handler
+
+ db:progress_handler(n,func,udata)
+
+This function installs a callback function C<func> that is invoked
+periodically during long-running calls to L<C<db:exec()>|/db:exec>
+or L<C<stmt:step()>|/stmt:step>. The
+progress callback is invoked once for every C<n> internal operations,
+where C<n> is the first argument to this function. C<udata> is passed to
+the progress callback function each time it is invoked. If a call to
+C<db:exec()> or C<stmt:step()> results in fewer than C<n> operations
+being executed, then the progress callback is never invoked. Only a
+single progress callback function may be registered for each opened
+database and a call to this function will overwrite any previously set
+callback function. To remove the progress callback altogether, pass nil
+as the second argument.
+
+If the progress callback returns a result other than 0, then the current
+query is immediately terminated, any database changes are rolled back
+and the containing C<db:exec()> or C<stmt:step()> call returns
+C<sqlite3.INTERRUPT>. This feature can be used to cancel long-running
+queries.
+
+=head2 db:rows
+
+ db:rows(sql)
+
+Creates an iterator that returns the successive rows selected by the SQL
+statement given in string C<sql>. Each call to the iterator returns a table
+in which the numerical indices 1 to n correspond to the selected columns
+1 to n in the database. Here is an example:
+
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ for a in db:rows('SELECT * FROM numbers') do table.print(a) end
+
+This script prints:
+
+ 1: 1
+ 2: 11
+ 1: 2
+ 2: 22
+ 1: 3
+ 2: 33
+
+=head2 db:total_changes
+
+ db:total_changes()
+
+This function returns the number of database rows that have been
+modified by INSERT, UPDATE or DELETE statements since the database was
+opened. This includes UPDATE, INSERT and DELETE statements executed as
+part of trigger programs. All changes are counted as soon as the
+statement that produces them is completed by calling either
+L<C<stmt:reset()>|/stmt:reset> or L<C<stmt:finalize()>|/stmt:finalize>.
+
+=head2 db:trace
+
+ db:trace(func,udata)
+
+This function installs a trace callback handler. C<func> is a Lua
+function that is called by SQLite3 just before the evaluation of an SQL
+statement. This callback receives two arguments: the first is the
+C<udata> argument used when the callback was installed; the second is a
+string with the SQL statement about to be executed.
+
+=head2 db:urows
+
+ db:urows(sql)
+
+Creates an iterator that returns the successive rows selected by the SQL
+statement given in string C<sql>. Each call to the iterator returns the
+values that correspond to the columns in the currently selected row.
+Here is an example:
+
+ db:exec[=[
+ CREATE TABLE numbers(num1,num2);
+ INSERT INTO numbers VALUES(1,11);
+ INSERT INTO numbers VALUES(2,22);
+ INSERT INTO numbers VALUES(3,33);
+ ]=]
+ for num1,num2 in db:urows('SELECT * FROM numbers') do print(num1,num2) end
+
+This script prints:
+
+ 1 11
+ 2 22
+ 3 33
+
+=head1 Methods for prepared statements
+
+After creating a prepared statement with L<C<db:prepare()>|/db:prepare>
+the returned statement object should be used for all further calls in
+connection with that statement. Statement objects support the following
+methods.
+
+=head2 stmt:bind
+
+ stmt:bind(n[,value])
+
+Binds value to statement parameter C<n>. If the type of value is string
+or number, it is bound as text or double, respectively. If C<value> is a
+boolean or nil or missing, any previous binding is removed. The function
+returns C<sqlite3.OK> on success or else a numerical error code (see
+L</Numerical error and result codes>).
+
+=head2 stmt:bind_blob
+
+ stmt:bind_blob(n,blob)
+
+Binds string C<blob> (which can be a binary string) as a blob to
+statement parameter C<n>. The function returns C<sqlite3.OK> on success
+or else a numerical error code (see L</Numerical error and result codes>).
+
+=head2 stmt:bind_names
+
+ stmt:bind_names(nametable)
+
+Binds the values in C<nametable> to statement parameters. If the
+statement parameters are named (i.e., of the form ":AAA" or "$AAA")
+then this function looks for appropriately named fields in C<nametable>;
+if the statement parameters are
+not named, it looks for numerical fields 1 to the number of statement
+parameters. The function returns C<sqlite3.OK> on success or else a
+numerical error code (see L</Numerical error and result codes>).
+
+=head2 stmt:bind_parameter_count
+
+ stmt:bind_parameter_count()
+
+Returns the largest statement parameter index in prepared statement
+C<stmt>. When the statement parameters are of the forms ":AAA" or "?",
+then they are assigned sequentially increasing numbers beginning with
+one, so the value returned is the number of parameters. However if the
+same statement parameter name is used multiple times, each occurrence
+is given the same number, so the value returned is the number of unique
+statement parameter names.
+
+If statement parameters of the form "?NNN" are used (where NNN is an
+integer) then there might be gaps in the numbering and the value
+returned by this interface is the index of the statement parameter with
+the largest index value.
+
+=head2 stmt:bind_parameter_name
+
+ stmt:bind_parameter_name(n)
+
+Returns the name of the C<n>-th parameter in prepared statement C<stmt>.
+Statement parameters of the form ":AAA" or "@AAA" or "$VVV" have a name
+which is the string ":AAA" or "@AAA" or "$VVV". In other words, the
+initial ":" or "$" or "@" is included as part of the name. Parameters
+of the form "?" or "?NNN" have no name. The first bound parameter has
+an index of 1.
+If the value C<n> is out of range or if the C<n>-th parameter is
+nameless, then nil is returned. The function returns C<sqlite3.OK> on
+success or else a numerical error code (see
+L</Numerical error and result codes>)
+
+=head2 stmt:bind_values
+
+ stmt:bind_values(value1,value2,...,valueN)
+
+Binds the given values to statement parameters. The function returns
+C<sqlite3.OK> on success or else a numerical error code (see
+L</Numerical error and result codes>).
+
+=head2 stmt:columns
+
+ stmt:columns()
+
+Returns the number of columns in the result set returned by statement
+stmt or 0 if the statement does not return data (for example an UPDATE).
+
+=head2 stmt:finalize
+
+ stmt:finalize()
+
+This function frees prepared statement stmt. If the statement was
+executed successfully, or not executed at all, then C<sqlite3.OK> is
+returned. If execution of the statement failed then an error code is
+returned.
+
+=head2 stmt:get_name
+
+ stmt:get_name(n)
+
+Returns the name of column C<n> in the result set of statement stmt. (The
+left-most column is number 0.)
+
+=head2 stmt:get_named_types
+
+ stmt:get_named_types()
+
+Returns a table with the names and types of all columns in the result
+set of statement stmt.
+
+=head2 stmt:get_named_values
+
+ stmt:get_named_values()
+
+This function returns a table with names and values of all columns in
+the current result row of a query.
+
+=head2 stmt:get_names
+
+ stmt:get_names()
+
+This function returns an array with the names of all columns in the
+result set returned by statement stmt.
+
+=head2 stmt:get_type
+
+ stmt:get_type(n)
+
+Returns the type of column C<n> in the result set of statement stmt. (The
+left-most column is number 0.)
+
+=head2 stmt:get_types
+
+ stmt:get_types()
+
+This function returns an array with the types of all columns in the
+result set returned by statement stmt.
+
+=head2 stmt:get_unames
+
+ stmt:get_unames()
+
+This function returns a list with the names of all columns in the result
+set returned by statement stmt.
+
+=head2 stmt:get_utypes
+
+ stmt:get_utypes()
+
+This function returns a list with the types of all columns in the result
+set returned by statement stmt.
+
+=head2 stmt:get_uvalues
+
+ stmt:get_uvalues()
+
+This function returns a list with the values of all columns in the
+current result row of a query.
+
+=head2 stmt:get_value
+
+ stmt:get_value(n)
+
+Returns the value of column C<n> in the result set of statement stmt. (The
+left-most column is number 0.)
+
+=head2 stmt:get_values
+
+ stmt:get_values()
+
+This function returns an array with the values of all columns in the
+result set returned by statement stmt.
+
+=head2 stmt:isopen
+
+ stmt:isopen()
+
+Returns true if stmt has not yet been finalized, false otherwise.
+
+=head2 stmt:nrows
+
+ stmt:nrows()
+
+Returns an function that iterates over the names and values of the
+result set of statement C<stmt>. Each iteration returns a table with the
+names and values for the current row.
+This is the prepared statement equivalent of L<C<db:nrows()>|/db:nrows>.
+
+=head2 stmt:reset
+
+ stmt:reset()
+
+This function resets SQL statement C<stmt>, so that it is ready to be
+re-executed. Any statement variables that had values bound to them using
+the C<stmt:bind*()> functions retain their values.
+
+=head2 stmt:rows
+
+ stmt:rows()
+
+Returns an function that iterates over the values of the result set of
+statement stmt. Each iteration returns an array with the values for the
+current row.
+This is the prepared statement equivalent of L<C<db:rows()>|/db:rows>.
+
+=head2 stmt:step
+
+ stmt:step()
+
+This function must be called to evaluate the (next iteration of the)
+prepared statement stmt. It will return one of the following values:
+
+=over 4
+
+=item *
+
+C<sqlite3.BUSY>: the engine was unable to acquire the locks needed. If the
+statement is a COMMIT or occurs outside of an explicit transaction, then
+you can retry the statement. If the statement is not a COMMIT and occurs
+within a explicit transaction then you should rollback the transaction
+before continuing.
+
+=item *
+
+C<sqlite3.DONE>: the statement has finished executing successfully.
+L<C<stmt:step()>|/stmt:step> should not be called again on this statement
+without first calling L<C<stmt:reset()>|/stmt:reset> to reset the virtual
+machine back to the initial state.
+
+=item *
+
+C<sqlite3.ROW>: this is returned each time a new row of data is ready for
+processing by the caller. The values may be accessed using the column
+access functions. L<C<stmt:step()>|/stmt:step> can be called again to
+retrieve the next row of data.
+
+=item *
+
+C<sqlite3.ERROR>: a run-time error (such as a constraint violation) has
+occurred. L<C<stmt:step()>|/stmt:step> should not be called again. More
+information may be found by calling L<C<db:errmsg()>|/db:errmsg>. A more
+specific error
+code (can be obtained by calling L<C<stmt:reset()>|/stmt:reset>.
+
+=item *
+
+C<sqlite3.MISUSE>: the function was called inappropriately, perhaps
+because the statement has already been finalized or a previous call to
+L<C<stmt:step()>|/stmt:step> has returned C<sqlite3.ERROR> or
+C<sqlite3.DONE>.
+
+=back
+
+=head2 stmt:urows
+
+ stmt:urows()
+
+Returns an function that iterates over the values of the result set of
+statement stmt. Each iteration returns the values for the current row.
+This is the prepared statement equivalent of L<C<db:urows()>|/db:urows>.
+
+=head1 Methods for callback contexts
+
+A callback context is available as a parameter inside the callback
+functions L<C<db:create_aggregate()>|/db:create_aggregate> and
+L<C<db:create_function()>|/db:create_function>. It can be used
+to get further information about the state of a query.
+
+=head2 context:aggregate_count
+
+ context:aggregate_count()
+
+Returns the number of calls to the aggregate step function.
+
+=head2 context:get_aggregate_data
+
+ context:get_aggregate_data()
+
+Returns the user-definable data field for callback funtions.
+
+=head2 context:set_aggregate_data
+
+ context:set_aggregate_data(udata)
+
+Set the user-definable data field for callback funtions to C<udata>.
+
+=head2 context:result
+
+ context:result(res)
+
+This function sets the result of a callback function to res. The type of
+the result depends on the type of res and is either a number or a string
+or nil. All other values will raise an error message.
+
+=head2 context:result_null
+
+ context:result_null()
+
+This function sets the result of a callback function to nil. It returns
+nothing.
+
+=head2 context:result_number
+
+ context:result_number(number)
+ context:result_double(number)
+
+This function sets the result of a callback function to the value
+C<number>. It returns nothing.
+
+=head2 context:result_int
+
+ context:result_int(number)
+
+This function sets the result of a callback function to the integer
+value in C<number>. It returns nothing.
+
+=head2 context:result_text
+
+ context:result_text(str)
+
+This function sets the result of a callback function to the string in
+C<str>. It returns nothing.
+
+=head2 context:result_blob
+
+ context:result_blob(blob)
+
+This function sets the result of a callback function to the binary
+string in C<blob>. It returns nothing.
+
+=head2 context:result_error
+
+ context:result_error(err)
+
+This function sets the result of a callback function to the error value
+in C<err>. It returns nothing.
+
+=head2 context:user_data
+
+ context:user_data()
+
+Returns the userdata parameter given in the call to install the callback
+function (see L<C<db:create_aggregate()>|/db:create_aggregate> and
+L<C<db:create_function()>|/db:create_function> for details).
+
+=head1 Numerical error and result codes
+
+The following constants are defined by module sqlite3:
+
+ OK: 0 ERROR: 1 INTERNAL: 2 PERM: 3 ABORT: 4
+ BUSY: 5 LOCKED: 6 NOMEM: 7 READONLY: 8 INTERRUPT: 9
+ IOERR: 10 CORRUPT: 11 NOTFOUND: 12 FULL: 13 CANTOPEN: 14
+ PROTOCOL: 15 EMPTY: 16 SCHEMA: 17 TOOBIG: 18 CONSTRAINT: 19
+ MISMATCH: 20 MISUSE: 21 NOLFS: 22 FORMAT: 24 RANGE: 25
+ NOTADB: 26 ROW: 100 DONE: 101
+
+For details about their exact meaning please see the B<SQLite3
+documentation> L<http://www.sqlite.org/>.
+
+=head1 VERSION
+
+This is C<lsqlite3> subversion 6, also known as "devel-0.6".
+
+=head1 CREDITS
+
+C<lsqlite3> was developed by Tiago Dionizio and Doug Currie with
+contributions from Thomas Lauer and Michael Roth.
+
+This documentation is based on the "(very) preliminary" documents
+for the Idle-SQLite3 database module. Thanks to Thomas Lauer for
+making it available.
+
+=head1 LICENSE
+
+ /************************************************************************
+ * lsqlite3 *
+ * Copyright (C) 2002-2007 Tiago Dionizio, Doug Currie *
+ * All rights reserved. *
+ * Author : Tiago Dionizio <tiago.dionizio@ist.utl.pt> *
+ * Author : Doug Currie <doug.currie@alum.mit.edu> *
+ * Library : lsqlite3 - a SQLite 3 database binding for Lua 5 *
+ * *
+ * 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. *
+ ************************************************************************/
+
diff --git a/3rdparty/lsqlite3/doc/pod2html.pl b/3rdparty/lsqlite3/doc/pod2html.pl
new file mode 100644
index 00000000000..474e86e177f
--- /dev/null
+++ b/3rdparty/lsqlite3/doc/pod2html.pl
@@ -0,0 +1,7 @@
+#!perl
+
+use Pod::Html;
+
+pod2html @ARGV;
+
+__END__
diff --git a/3rdparty/lsqlite3/examples/aggregate.lua b/3rdparty/lsqlite3/examples/aggregate.lua
new file mode 100644
index 00000000000..86081f5d81f
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/aggregate.lua
@@ -0,0 +1,35 @@
+
+require("lsqlite3")
+
+local db = sqlite3.open_memory()
+
+assert( db:exec "CREATE TABLE test (col1, col2)" )
+assert( db:exec "INSERT INTO test VALUES (1, 2)" )
+assert( db:exec "INSERT INTO test VALUES (2, 4)" )
+assert( db:exec "INSERT INTO test VALUES (3, 6)" )
+assert( db:exec "INSERT INTO test VALUES (4, 8)" )
+assert( db:exec "INSERT INTO test VALUES (5, 10)" )
+
+do
+
+ local square_error_sum = 0
+
+ local function step(ctx, a, b)
+ local error = a - b
+ local square_error = error * error
+ square_error_sum = square_error_sum + square_error
+ end
+
+ local function final(ctx)
+ ctx:result_number( square_error_sum / ctx:aggregate_count() )
+ end
+
+ assert( db:create_aggregate("my_stats", 2, step, final) )
+
+end
+
+--for a,b in db:urows("SELECT col1, col2 FROM test")
+--do print("a b: ", a, b) end
+
+for my_stats in db:urows("SELECT my_stats(col1, col2) FROM test")
+do print("my_stats:", my_stats) end
diff --git a/3rdparty/lsqlite3/examples/function.lua b/3rdparty/lsqlite3/examples/function.lua
new file mode 100644
index 00000000000..fdafc4e129b
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/function.lua
@@ -0,0 +1,21 @@
+
+require("lsqlite3")
+
+
+local db = sqlite3.open_memory()
+
+assert( db:exec "CREATE TABLE test (col1, col2)" )
+assert( db:exec "INSERT INTO test VALUES (1, 2)" )
+assert( db:exec "INSERT INTO test VALUES (2, 4)" )
+assert( db:exec "INSERT INTO test VALUES (3, 6)" )
+assert( db:exec "INSERT INTO test VALUES (4, 8)" )
+assert( db:exec "INSERT INTO test VALUES (5, 10)" )
+
+assert( db:create_function("my_sum", 2, function(ctx, a, b)
+ ctx:result_number( a + b )
+end))
+
+
+for col1, col2, sum in db:urows("SELECT *, my_sum(col1, col2) FROM test") do
+ print(col1, col2, sum)
+end
diff --git a/3rdparty/lsqlite3/examples/order.lua b/3rdparty/lsqlite3/examples/order.lua
new file mode 100644
index 00000000000..d344467e71e
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/order.lua
@@ -0,0 +1,122 @@
+
+require("lsqlite3")
+
+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 = ?")
+ stmt:bind_values(id)
+ stmt:step()
+ local r = stmt:get_uvalues()
+ stmt:finalize()
+ return r
+end
+
+
+local function all_invoices()
+ return db:nrows("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 = ?")
+ stmt:bind_values(invoice)
+ stmt:step()
+ row = stmt:get_named_values()
+
+ -- 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")
+ stmt:bind_values(invoice)
+
+ for row in stmt:nrows() 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
diff --git a/3rdparty/lsqlite3/examples/simple.lua b/3rdparty/lsqlite3/examples/simple.lua
new file mode 100644
index 00000000000..b10a48bd015
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/simple.lua
@@ -0,0 +1,16 @@
+
+require("lsqlite3")
+
+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:nrows("SELECT * FROM test") do
+ print(row.id, row.content)
+end
diff --git a/3rdparty/lsqlite3/examples/smart.lua b/3rdparty/lsqlite3/examples/smart.lua
new file mode 100644
index 00000000000..9ee807d8bdb
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/smart.lua
@@ -0,0 +1,22 @@
+
+require("lsqlite3")
+
+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_names{ key = 1, value = "Hello World" }
+stmt:step()
+stmt:reset()
+stmt:bind_names{ key = 2, value = "Hello Lua" }
+stmt:step()
+stmt:reset()
+stmt:bind_names{ key = 3, value = "Hello Sqlite3" }
+stmt:step()
+stmt:finalize()
+
+for row in db:nrows("SELECT * FROM test") do
+ print(row.id, row.content)
+end
diff --git a/3rdparty/lsqlite3/examples/statement.lua b/3rdparty/lsqlite3/examples/statement.lua
new file mode 100644
index 00000000000..ed57d8740d8
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/statement.lua
@@ -0,0 +1,39 @@
+
+require("lsqlite3")
+
+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_values(data)
+ insert_stmt:step()
+ insert_stmt:reset()
+end
+
+local select_stmt = assert( db:prepare("SELECT * FROM test") )
+
+local function select()
+ for row in select_stmt:nrows() 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()
diff --git a/3rdparty/lsqlite3/examples/tracing.lua b/3rdparty/lsqlite3/examples/tracing.lua
new file mode 100644
index 00000000000..6638ea5df70
--- /dev/null
+++ b/3rdparty/lsqlite3/examples/tracing.lua
@@ -0,0 +1,20 @@
+
+require("lsqlite3")
+
+local db = sqlite3.open_memory()
+
+db:trace( function(ud, 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
diff --git a/3rdparty/lsqlite3/lsqlite3.c b/3rdparty/lsqlite3/lsqlite3.c
new file mode 100644
index 00000000000..0106007760b
--- /dev/null
+++ b/3rdparty/lsqlite3/lsqlite3.c
@@ -0,0 +1,1886 @@
+/************************************************************************
+* lsqlite3 *
+* Copyright (C) 2002-2007 Tiago Dionizio, Doug Currie *
+* All rights reserved. *
+* Author : Tiago Dionizio <tiago.dionizio@ist.utl.pt> *
+* Author : Doug Currie <doug.currie@alum.mit.edu> *
+* Library : lsqlite3 - a SQLite 3 database binding for Lua 5 *
+* *
+* 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. *
+************************************************************************/
+
+#include <stdlib.h>
+#include <string.h>
+#include <assert.h>
+
+#include "lua.h"
+#include "lauxlib.h"
+
+#include "sqlite3.h"
+
+/* compile time features */
+#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK)
+ #define SQLITE_OMIT_PROGRESS_CALLBACK 0
+#endif
+
+typedef struct sdb sdb;
+typedef struct sdb_vm sdb_vm;
+typedef struct sdb_func sdb_func;
+
+/* to use as C user data so i know what function sqlite is calling */
+struct sdb_func {
+ /* references to associated lua values */
+ int fn_step;
+ int fn_finalize;
+ int udata;
+
+ sdb *db;
+ char aggregate;
+
+ sdb_func *next;
+};
+
+/* information about database */
+struct sdb {
+ /* associated lua state */
+ lua_State *L;
+ /* sqlite database handle */
+ sqlite3 *db;
+
+ /* sql functions stack usage */
+ sdb_func *func; /* top SQL function being called */
+
+ /* references */
+ int busy_cb; /* busy callback */
+ int busy_udata;
+
+ int progress_cb; /* progress handler */
+ int progress_udata;
+
+ int trace_cb; /* trace callback */
+ int trace_udata;
+};
+
+static const char *sqlite_meta = ":sqlite3";
+static const char *sqlite_vm_meta = ":sqlite3:vm";
+static const char *sqlite_ctx_meta = ":sqlite3:ctx";
+static int sqlite_ctx_meta_ref;
+
+/*
+** =======================================================
+** Database Virtual Machine Operations
+** =======================================================
+*/
+
+static void vm_push_column(lua_State *L, sqlite3_stmt *vm, int idx) {
+ switch (sqlite3_column_type(vm, idx)) {
+ case SQLITE_INTEGER:
+ {
+ sqlite_int64 i64 = sqlite3_column_int64(vm, idx);
+ lua_Number n = (lua_Number)i64;
+ if (n == i64)
+ lua_pushnumber(L, n);
+ else
+ lua_pushlstring(L, sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
+ }
+ break;
+ case SQLITE_FLOAT:
+ lua_pushnumber(L, sqlite3_column_double(vm, idx));
+ break;
+ case SQLITE_TEXT:
+ lua_pushlstring(L, sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
+ break;
+ case SQLITE_BLOB:
+ lua_pushlstring(L, sqlite3_column_blob(vm, idx), sqlite3_column_bytes(vm, idx));
+ break;
+ case SQLITE_NULL:
+ lua_pushnil(L);
+ break;
+ default:
+ lua_pushnil(L);
+ break;
+ }
+}
+
+/* virtual machine information */
+struct sdb_vm {
+ sdb *db; /* associated database handle */
+ sqlite3_stmt *vm; /* virtual machine */
+
+ /* sqlite3_step info */
+ int columns; /* number of columns in result */
+ char has_values; /* true when step succeeds */
+
+ char temp; /* temporary vm used in db:rows */
+};
+
+/* called with sql text on the lua stack */
+static sdb_vm *newvm(lua_State *L, sdb *db) {
+ sdb_vm *svm = (sdb_vm*)lua_newuserdata(L, sizeof(sdb_vm));
+
+ luaL_getmetatable(L, sqlite_vm_meta);
+ lua_setmetatable(L, -2); /* set metatable */
+
+ svm->db = db;
+ svm->columns = 0;
+ svm->has_values = 0;
+ svm->vm = NULL;
+ svm->temp = 0;
+
+ /* add an entry on the database table: svm -> sql text */
+ lua_pushlightuserdata(L, db);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ lua_pushlightuserdata(L, svm);
+ lua_pushvalue(L, -4); /* the sql text */
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+
+ return svm;
+}
+
+static int cleanupvm(lua_State *L, sdb_vm *svm) {
+ /* remove entry in database table - no harm if not present in the table */
+ lua_pushlightuserdata(L, svm->db);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ lua_pushlightuserdata(L, svm);
+ lua_pushnil(L);
+ lua_rawset(L, -3);
+ lua_pop(L, 1);
+
+ svm->columns = 0;
+ svm->has_values = 0;
+
+ if (!svm->vm) return 0;
+
+ lua_pushnumber(L, sqlite3_finalize(svm->vm));
+ svm->vm = NULL;
+ return 1;
+}
+
+static int stepvm(lua_State *L, sdb_vm *svm) {
+ int result;
+ int loop_limit = 3;
+ while ( loop_limit-- ) {
+ result = sqlite3_step(svm->vm);
+ if ( result==SQLITE_ERROR ) {
+ result = sqlite3_reset (svm->vm);
+ }
+ if ( result==SQLITE_SCHEMA ) {
+ sqlite3_stmt *vn;
+ const char *sql;
+ /* recover sql text */
+ lua_pushlightuserdata(L, svm->db);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+ lua_pushlightuserdata(L, svm);
+ lua_rawget(L, -2); /* sql text */
+ sql = luaL_checkstring(L, -1);
+ /* re-prepare */
+ result = sqlite3_prepare(svm->db->db, sql, -1, &vn, NULL);
+ if (result != SQLITE_OK) break;
+ sqlite3_transfer_bindings(svm->vm, vn);
+ sqlite3_finalize(svm->vm);
+ svm->vm = vn;
+ lua_pop(L,2);
+ } else {
+ break;
+ }
+ }
+ return result;
+}
+
+static sdb_vm *lsqlite_getvm(lua_State *L, int index) {
+ sdb_vm *svm = (sdb_vm*)luaL_checkudata(L, index, sqlite_vm_meta);
+ if (svm == NULL) luaL_argerror(L, index, "bad sqlite virtual machine");
+ return svm;
+}
+
+static sdb_vm *lsqlite_checkvm(lua_State *L, int index) {
+ sdb_vm *svm = lsqlite_getvm(L, index);
+ if (svm->vm == NULL) luaL_argerror(L, index, "attempt to use closed sqlite virtual machine");
+ return svm;
+}
+
+static int dbvm_isopen(lua_State *L) {
+ sdb_vm *svm = lsqlite_getvm(L, 1);
+ lua_pushboolean(L, svm->vm != NULL ? 1 : 0);
+ return 1;
+}
+
+static int dbvm_tostring(lua_State *L) {
+ char buff[39];
+ sdb_vm *svm = lsqlite_getvm(L, 1);
+ if (svm->vm == NULL)
+ strcpy(buff, "closed");
+ else
+ sprintf(buff, "%p", svm);
+ lua_pushfstring(L, "sqlite virtual machine (%s)", buff);
+ return 1;
+}
+
+static int dbvm_gc(lua_State *L) {
+ sdb_vm *svm = lsqlite_getvm(L, 1);
+ if (svm->vm != NULL) /* ignore closed vms */
+ cleanupvm(L, svm);
+ return 0;
+}
+
+static int dbvm_step(lua_State *L) {
+ int result;
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+
+ result = stepvm(L, svm);
+ svm->has_values = result == SQLITE_ROW ? 1 : 0;
+ svm->columns = sqlite3_data_count(svm->vm);
+
+ lua_pushnumber(L, result);
+ return 1;
+}
+
+static int dbvm_finalize(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ return cleanupvm(L, svm);
+}
+
+static int dbvm_reset(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_reset(svm->vm);
+ lua_pushnumber(L, sqlite3_errcode(svm->db->db));
+ return 1;
+}
+
+static void dbvm_check_contents(lua_State *L, sdb_vm *svm) {
+ if (!svm->has_values) {
+ luaL_error(L, "misuse of function");
+ }
+}
+
+static void dbvm_check_index(lua_State *L, sdb_vm *svm, int index) {
+ if (index < 0 || index >= svm->columns) {
+ luaL_error(L, "index out of range [0..%d]", svm->columns - 1);
+ }
+}
+
+static void dbvm_check_bind_index(lua_State *L, sdb_vm *svm, int index) {
+ if (index < 1 || index > sqlite3_bind_parameter_count(svm->vm)) {
+ luaL_error(L, "bind index out of range [1..%d]", sqlite3_bind_parameter_count(svm->vm));
+ }
+}
+
+/*
+** =======================================================
+** Virtual Machine - generic info
+** =======================================================
+*/
+static int dbvm_columns(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ lua_pushnumber(L, sqlite3_column_count(svm->vm));
+ return 1;
+}
+
+/*
+** =======================================================
+** Virtual Machine - getters
+** =======================================================
+*/
+
+static int dbvm_get_value(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ int index = luaL_checkint(L, 2);
+ dbvm_check_contents(L, svm);
+ dbvm_check_index(L, svm, index);
+ vm_push_column(L, svm->vm, index);
+ return 1;
+}
+
+static int dbvm_get_name(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ int index = luaL_checknumber(L, 2);
+ dbvm_check_index(L, svm, index);
+ lua_pushstring(L, sqlite3_column_name(svm->vm, index));
+ return 1;
+}
+
+static int dbvm_get_type(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ int index = luaL_checknumber(L, 2);
+ dbvm_check_index(L, svm, index);
+ lua_pushstring(L, sqlite3_column_decltype(svm->vm, index));
+ return 1;
+}
+
+static int dbvm_get_values(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = svm->columns;
+ int n;
+ dbvm_check_contents(L, svm);
+
+ lua_newtable(L);
+ for (n = 0; n < columns;) {
+ vm_push_column(L, vm, n++);
+ lua_rawseti(L, -2, n);
+ }
+ return 1;
+}
+
+static int dbvm_get_names(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
+ int n;
+
+ lua_newtable(L);
+ for (n = 0; n < columns;) {
+ lua_pushstring(L, sqlite3_column_name(vm, n++));
+ lua_rawseti(L, -2, n);
+ }
+ return 1;
+}
+
+static int dbvm_get_types(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
+ int n;
+
+ lua_newtable(L);
+ for (n = 0; n < columns;) {
+ lua_pushstring(L, sqlite3_column_decltype(vm, n++));
+ lua_rawseti(L, -2, n);
+ }
+ return 1;
+}
+
+static int dbvm_get_uvalues(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = svm->columns;
+ int n;
+ dbvm_check_contents(L, svm);
+
+ lua_checkstack(L, columns);
+ for (n = 0; n < columns; ++n)
+ vm_push_column(L, vm, n);
+ return columns;
+}
+
+static int dbvm_get_unames(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
+ int n;
+
+ lua_checkstack(L, columns);
+ for (n = 0; n < columns; ++n)
+ lua_pushstring(L, sqlite3_column_name(vm, n));
+ return columns;
+}
+
+static int dbvm_get_utypes(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
+ int n;
+
+ lua_checkstack(L, columns);
+ for (n = 0; n < columns; ++n)
+ lua_pushstring(L, sqlite3_column_decltype(vm, n));
+ return columns;
+}
+
+static int dbvm_get_named_values(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = svm->columns;
+ int n;
+ dbvm_check_contents(L, svm);
+
+ lua_newtable(L);
+ for (n = 0; n < columns; ++n) {
+ lua_pushstring(L, sqlite3_column_name(vm, n));
+ vm_push_column(L, vm, n);
+ lua_rawset(L, -3);
+ }
+ return 1;
+}
+
+static int dbvm_get_named_types(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int columns = sqlite3_column_count(vm);
+ int n;
+
+ lua_newtable(L);
+ for (n = 0; n < columns; ++n) {
+ lua_pushstring(L, sqlite3_column_name(vm, n));
+ lua_pushstring(L, sqlite3_column_decltype(vm, n));
+ lua_rawset(L, -3);
+ }
+ return 1;
+}
+
+/*
+** =======================================================
+** Virtual Machine - Bind
+** =======================================================
+*/
+
+static int dbvm_bind_index(lua_State *L, sqlite3_stmt *vm, int index, int lindex) {
+ switch (lua_type(L, lindex)) {
+ case LUA_TSTRING:
+ return sqlite3_bind_text(vm, index, lua_tostring(L, lindex), lua_strlen(L, lindex), SQLITE_TRANSIENT);
+ case LUA_TNUMBER:
+ return sqlite3_bind_double(vm, index, lua_tonumber(L, lindex));
+ case LUA_TNONE:
+ case LUA_TNIL:
+ /* allow boolean values so i have a way to know which
+ ** values were actually not set */
+ case LUA_TBOOLEAN:
+ return sqlite3_bind_null(vm, index);
+ default:
+ luaL_error(L, "index (%d) - invalid data type for bind (%s)", index, lua_typename(L, lindex));
+ return SQLITE_MISUSE; /*!*/
+ }
+}
+
+
+static int dbvm_bind_parameter_count(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ lua_pushnumber(L, sqlite3_bind_parameter_count(svm->vm));
+ return 1;
+}
+
+static int dbvm_bind_parameter_name(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ int index = luaL_checknumber(L, 2);
+ dbvm_check_bind_index(L, svm, index);
+ lua_pushstring(L, sqlite3_bind_parameter_name(svm->vm, index));
+ return 1;
+}
+
+static int dbvm_bind(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int index = luaL_checkint(L, 2);
+ int result;
+
+ dbvm_check_bind_index(L, svm, index);
+ result = dbvm_bind_index(L, vm, index, 3);
+
+ lua_pushnumber(L, result);
+ return 1;
+}
+
+static int dbvm_bind_blob(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ int index = luaL_checkint(L, 2);
+ const char *value = luaL_checkstring(L, 3);
+ int len = lua_strlen(L, 3);
+
+ lua_pushnumber(L, sqlite3_bind_blob(svm->vm, index, value, len, SQLITE_TRANSIENT));
+ return 1;
+}
+
+static int dbvm_bind_values(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int top = lua_gettop(L);
+ int result, n;
+
+ if (top - 1 != sqlite3_bind_parameter_count(vm))
+ luaL_error(L,
+ "incorrect number of parameters to bind (%d given, %d to bind)",
+ top - 1,
+ sqlite3_bind_parameter_count(vm)
+ );
+
+ for (n = 2; n <= top; ++n) {
+ if ((result = dbvm_bind_index(L, vm, n - 1, n)) != SQLITE_OK) {
+ lua_pushnumber(L, result);
+ return 1;
+ }
+ }
+
+ lua_pushnumber(L, SQLITE_OK);
+ return 1;
+}
+
+static int dbvm_bind_names(lua_State *L) {
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm = svm->vm;
+ int count = sqlite3_bind_parameter_count(vm);
+ const char *name;
+ int result, n;
+ luaL_checktype(L, 2, LUA_TTABLE);
+
+ for (n = 1; n <= count; ++n) {
+ name = sqlite3_bind_parameter_name(vm, n);
+ if (name && (name[0] == ':' || name[0] == '$')) {
+ lua_pushstring(L, ++name);
+ lua_gettable(L, 2);
+ result = dbvm_bind_index(L, vm, n, -1);
+ }
+ else {
+ lua_pushnumber(L, n);
+ lua_gettable(L, 2);
+ result = dbvm_bind_index(L, vm, n, -1);
+ lua_pop(L, 1);
+ }
+
+ if (result != SQLITE_OK) {
+ lua_pushnumber(L, result);
+ return 1;
+ }
+ }
+
+ lua_pushnumber(L, SQLITE_OK);
+ return 1;
+}
+
+/*
+** =======================================================
+** Database (internal management)
+** =======================================================
+*/
+
+/*
+** When creating database handles, always creates a `closed' database handle
+** before opening the actual database; so, if there is a memory error, the
+** database is not left opened.
+**
+** Creates a new 'table' and leaves it in the stack
+*/
+static sdb *newdb (lua_State *L) {
+ sdb *db = (sdb*)lua_newuserdata(L, sizeof(sdb));
+ db->L = L;
+ db->db = NULL; /* database handle is currently `closed' */
+ db->func = NULL;
+
+ db->busy_cb =
+ db->busy_udata =
+ db->progress_cb =
+ db->progress_udata =
+ db->trace_cb =
+ db->trace_udata = LUA_NOREF;
+
+ luaL_getmetatable(L, sqlite_meta);
+ lua_setmetatable(L, -2); /* set metatable */
+
+ /* to keep track of 'open' virtual machines */
+ lua_pushlightuserdata(L, db);
+ lua_newtable(L);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ return db;
+}
+
+static int cleanupdb(lua_State *L, sdb *db) {
+ sdb_func *func;
+ sdb_func *func_next;
+ int top;
+ int result;
+
+ /* free associated virtual machines */
+ lua_pushlightuserdata(L, db);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+
+ /* close all used handles */
+ top = lua_gettop(L);
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ sdb_vm *svm = lua_touserdata(L, -2); /* key: vm; val: sql text */
+ cleanupvm(L, svm);
+
+ lua_settop(L, top);
+ lua_pushnil(L);
+ }
+
+ lua_pop(L, 1); /* pop vm table */
+
+ /* remove entry in lua registry table */
+ lua_pushlightuserdata(L, db);
+ lua_pushnil(L);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ /* 'free' all references */
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
+
+ /* close database */
+ result = sqlite3_close(db->db);
+ db->db = NULL;
+
+ /* free associated memory with created functions */
+ func = db->func;
+ while (func) {
+ func_next = func->next;
+ luaL_unref(L, LUA_REGISTRYINDEX, func->fn_step);
+ luaL_unref(L, LUA_REGISTRYINDEX, func->fn_finalize);
+ luaL_unref(L, LUA_REGISTRYINDEX, func->udata);
+ free(func);
+ func = func_next;
+ }
+ db->func = NULL;
+ return result;
+}
+
+static sdb *lsqlite_getdb(lua_State *L, int index) {
+ sdb *db = (sdb*)luaL_checkudata(L, index, sqlite_meta);
+ if (db == NULL) luaL_typerror(L, index, "sqlite database");
+ return db;
+}
+
+static sdb *lsqlite_checkdb(lua_State *L, int index) {
+ sdb *db = lsqlite_getdb(L, index);
+ if (db->db == NULL) luaL_argerror(L, index, "attempt to use closed sqlite database");
+ return db;
+}
+
+
+/*
+** =======================================================
+** User Defined Functions - Context Methods
+** =======================================================
+*/
+typedef struct {
+ sqlite3_context *ctx;
+ int ud;
+} lcontext;
+
+static lcontext *lsqlite_make_context(lua_State *L) {
+ lcontext *ctx = (lcontext*)lua_newuserdata(L, sizeof(lcontext));
+ lua_rawgeti(L, LUA_REGISTRYINDEX, sqlite_ctx_meta_ref);
+ lua_setmetatable(L, -2);
+ ctx->ctx = NULL;
+ ctx->ud = LUA_NOREF;
+ return ctx;
+}
+
+static lcontext *lsqlite_getcontext(lua_State *L, int index) {
+ lcontext *ctx = (lcontext*)luaL_checkudata(L, index, sqlite_ctx_meta);
+ if (ctx == NULL) luaL_typerror(L, index, "sqlite context");
+ return ctx;
+}
+
+static lcontext *lsqlite_checkcontext(lua_State *L, int index) {
+ lcontext *ctx = lsqlite_getcontext(L, index);
+ if (ctx->ctx == NULL) luaL_argerror(L, index, "invalid sqlite context");
+ return ctx;
+}
+
+static int lcontext_tostring(lua_State *L) {
+ char buff[39];
+ lcontext *ctx = lsqlite_getcontext(L, 1);
+ if (ctx->ctx == NULL)
+ strcpy(buff, "closed");
+ else
+ sprintf(buff, "%p", ctx->ctx);
+ lua_pushfstring(L, "sqlite function context (%s)", buff);
+ return 1;
+}
+
+static void lcontext_check_aggregate(lua_State *L, lcontext *ctx) {
+ sdb_func *func = (sdb_func*)sqlite3_user_data(ctx->ctx);
+ if (!func->aggregate) {
+ luaL_error(L, "attempt to call aggregate method from scalar function");
+ }
+}
+
+static int lcontext_user_data(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ sdb_func *func = (sdb_func*)sqlite3_user_data(ctx->ctx);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, func->udata);
+ return 1;
+}
+
+static int lcontext_get_aggregate_context(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ lcontext_check_aggregate(L, ctx);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->ud);
+ return 1;
+}
+
+static int lcontext_set_aggregate_context(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ lcontext_check_aggregate(L, ctx);
+ lua_settop(L, 2);
+ luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
+ ctx->ud = luaL_ref(L, LUA_REGISTRYINDEX);
+ return 0;
+}
+
+static int lcontext_aggregate_count(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ lcontext_check_aggregate(L, ctx);
+ lua_pushnumber(L, sqlite3_aggregate_count(ctx->ctx));
+ return 1;
+}
+
+#if 0
+void *sqlite3_get_auxdata(sqlite3_context*, int);
+void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
+#endif
+
+static int lcontext_result(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ switch (lua_type(L, 2)) {
+ case LUA_TNUMBER:
+ sqlite3_result_double(ctx->ctx, luaL_checknumber(L, 2));
+ break;
+ case LUA_TSTRING:
+ sqlite3_result_text(ctx->ctx, luaL_checkstring(L, 2), lua_strlen(L, 2), SQLITE_TRANSIENT);
+ break;
+ case LUA_TNIL:
+ case LUA_TNONE:
+ sqlite3_result_null(ctx->ctx);
+ break;
+ default:
+ luaL_error(L, "invalid result type %s", lua_typename(L, 2));
+ break;
+ }
+
+ return 0;
+}
+
+static int lcontext_result_blob(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ const char *blob = luaL_checkstring(L, 2);
+ int size = lua_strlen(L, 2);
+ sqlite3_result_blob(ctx->ctx, (const void*)blob, size, SQLITE_TRANSIENT);
+ return 0;
+}
+
+static int lcontext_result_double(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ double d = luaL_checknumber(L, 2);
+ sqlite3_result_double(ctx->ctx, d);
+ return 0;
+}
+
+static int lcontext_result_error(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ const char *err = luaL_checkstring(L, 2);
+ int size = lua_strlen(L, 2);
+ sqlite3_result_error(ctx->ctx, err, size);
+ return 0;
+}
+
+static int lcontext_result_int(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ int i = luaL_checkint(L, 2);
+ sqlite3_result_int(ctx->ctx, i);
+ return 0;
+}
+
+static int lcontext_result_null(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ sqlite3_result_null(ctx->ctx);
+ return 0;
+}
+
+static int lcontext_result_text(lua_State *L) {
+ lcontext *ctx = lsqlite_checkcontext(L, 1);
+ const char *text = luaL_checkstring(L, 2);
+ int size = lua_strlen(L, 2);
+ sqlite3_result_text(ctx->ctx, text, size, SQLITE_TRANSIENT);
+ return 0;
+}
+
+/*
+** =======================================================
+** Database Methods
+** =======================================================
+*/
+
+static int db_isopen(lua_State *L) {
+ sdb *db = lsqlite_getdb(L, 1);
+ lua_pushboolean(L, db->db != NULL ? 1 : 0);
+ return 1;
+}
+
+static int db_last_insert_rowid(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ /* conversion warning: int64 -> luaNumber */
+ sqlite_int64 rowid = sqlite3_last_insert_rowid(db->db);
+ lua_Number n = (lua_Number)rowid;
+ if (n == rowid)
+ lua_pushnumber(L, n);
+ else
+ lua_pushfstring(L, "%ll", rowid);
+ return 1;
+}
+
+static int db_changes(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ lua_pushnumber(L, sqlite3_changes(db->db));
+ return 1;
+}
+
+static int db_total_changes(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ lua_pushnumber(L, sqlite3_total_changes(db->db));
+ return 1;
+}
+
+static int db_errcode(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ lua_pushnumber(L, sqlite3_errcode(db->db));
+ return 1;
+}
+
+static int db_errmsg(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ lua_pushstring(L, sqlite3_errmsg(db->db));
+ return 1;
+}
+
+static int db_interrupt(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ sqlite3_interrupt(db->db);
+ return 0;
+}
+
+/*
+** Registering SQL functions:
+*/
+
+static void db_push_value(lua_State *L, sqlite3_value *value) {
+ switch (sqlite3_value_type(value)) {
+ case SQLITE_TEXT:
+ lua_pushlstring(L, sqlite3_value_text(value), sqlite3_value_bytes(value));
+ break;
+
+ case SQLITE_INTEGER:
+ {
+ sqlite_int64 i64 = sqlite3_value_int64(value);
+ lua_Number n = (lua_Number)i64;
+ if (n == i64)
+ lua_pushnumber(L, n);
+ else
+ lua_pushlstring(L, sqlite3_value_text(value), sqlite3_value_bytes(value));
+ }
+ break;
+
+ case SQLITE_FLOAT:
+ lua_pushnumber(L, sqlite3_value_double(value));
+ break;
+
+ case SQLITE_BLOB:
+ lua_pushlstring(L, sqlite3_value_blob(value), sqlite3_value_bytes(value));
+ break;
+
+ case SQLITE_NULL:
+ lua_pushnil(L);
+ break;
+
+ default:
+ /* things done properly (SQLite + Lua SQLite)
+ ** this should never happen */
+ lua_pushnil(L);
+ break;
+ }
+}
+
+/*
+** callback functions used when calling registered sql functions
+*/
+
+/* scalar function to be called
+** callback params: context, values... */
+static void db_sql_normal_function(sqlite3_context *context, int argc, sqlite3_value **argv) {
+ sdb_func *func = (sdb_func*)sqlite3_user_data(context);
+ lua_State *L = func->db->L;
+ int n;
+ lcontext *ctx;
+
+ int top = lua_gettop(L);
+
+ /* ensure there is enough space in the stack */
+ lua_checkstack(L, argc + 3);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_step); /* function to call */
+
+ if (!func->aggregate) {
+ ctx = lsqlite_make_context(L); /* push context - used to set results */
+ }
+ else {
+ // reuse context userdata value
+
+ void *p = sqlite3_aggregate_context(context, 1);
+ /* i think it is OK to use assume that using a light user data
+ ** as an entry on LUA REGISTRY table will be unique */
+ lua_pushlightuserdata(L, p);
+ lua_rawget(L, LUA_REGISTRYINDEX); /* context table */
+
+ if (lua_isnil(L, -1)) { /* not yet created? */
+ lua_pop(L, 1);
+ ctx = lsqlite_make_context(L);
+ lua_pushlightuserdata(L, p);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ else
+ ctx = lsqlite_getcontext(L, -1);
+ }
+
+ /* push params */
+ for (n = 0; n < argc; ++n) {
+ db_push_value(L, argv[n]);
+ }
+
+ // set context
+ ctx->ctx = context;
+
+ if (lua_pcall(L, argc + 1, 0, 0)) {
+ const char *errmsg = lua_tostring(L, -1);
+ int size = lua_strlen(L, -1);
+ sqlite3_result_error(context, errmsg, size);
+ }
+
+ // invalidate context
+ ctx->ctx = NULL;
+
+ if (!func->aggregate) {
+ luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
+ }
+
+ lua_settop(L, top);
+}
+
+static void db_sql_finalize_function(sqlite3_context *context) {
+ sdb_func *func = (sdb_func*)sqlite3_user_data(context);
+ lua_State *L = func->db->L;
+ void *p = sqlite3_aggregate_context(context, 1); /* minimal mem usage */
+ lcontext *ctx;
+ int top = lua_gettop(L);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_finalize); /* function to call */
+
+ /* i think it is OK to use assume that using a light user data
+ ** as an entry on LUA REGISTRY table will be unique */
+ lua_pushlightuserdata(L, p);
+ lua_rawget(L, LUA_REGISTRYINDEX); /* context table */
+
+ if (lua_isnil(L, -1)) { /* not yet created? - shouldn't happen in finalize function */
+ lua_pop(L, 1);
+ ctx = lsqlite_make_context(L);
+ lua_pushlightuserdata(L, p);
+ lua_pushvalue(L, -2);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+ }
+ else
+ ctx = lsqlite_getcontext(L, -1);
+
+ // set context
+ ctx->ctx = context;
+
+ if (lua_pcall(L, 1, 0, 0)) {
+ sqlite3_result_error(context, lua_tostring(L, -1), -1);
+ }
+
+ // invalidate context
+ ctx->ctx = NULL;
+
+ /* cleanup context */
+ luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
+ /* remove it from registry */
+ lua_pushlightuserdata(L, p);
+ lua_pushnil(L);
+ lua_rawset(L, LUA_REGISTRYINDEX);
+
+ lua_settop(L, top);
+}
+
+/*
+** Register a normal function
+** Params: db, function name, number arguments, [ callback | step, finalize], user data
+** Returns: true on sucess
+**
+** Normal function:
+** Params: context, params
+**
+** Aggregate function:
+** Params of step: context, params
+** Params of finalize: context
+*/
+static int db_register_function(lua_State *L, int aggregate) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ const char *name;
+ int args;
+ int result;
+ sdb_func *func;
+
+ /* safety measure */
+ if (aggregate) aggregate = 1;
+
+ name = luaL_checkstring(L, 2);
+ args = luaL_checkint(L, 3);
+ luaL_checktype(L, 4, LUA_TFUNCTION);
+ if (aggregate) luaL_checktype(L, 5, LUA_TFUNCTION);
+
+ /* maybe an alternative way to allocate memory should be used/avoided */
+ func = (sdb_func*)malloc(sizeof(sdb_func));
+ if (func == NULL) {
+ luaL_error(L, "out of memory");
+ }
+
+ result = sqlite3_create_function(
+ db->db, name, args, SQLITE_UTF8, func,
+ aggregate ? NULL : db_sql_normal_function,
+ aggregate ? db_sql_normal_function : NULL,
+ aggregate ? db_sql_finalize_function : NULL
+ );
+
+ if (result == SQLITE_OK) {
+ /* safety measures for userdata field to be present in the stack */
+ lua_settop(L, 5 + aggregate);
+
+ /* save registered function in db function list */
+ func->db = db;
+ func->aggregate = aggregate;
+ func->next = db->func;
+ db->func = func;
+
+ /* save the setp/normal function callback */
+ lua_pushvalue(L, 4);
+ func->fn_step = luaL_ref(L, LUA_REGISTRYINDEX);
+ /* save user data */
+ lua_pushvalue(L, 5+aggregate);
+ func->udata = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ if (aggregate) {
+ lua_pushvalue(L, 5);
+ func->fn_finalize = luaL_ref(L, LUA_REGISTRYINDEX);
+ }
+ else
+ func->fn_finalize = LUA_NOREF;
+ }
+ else {
+ /* free allocated memory */
+ free(func);
+ }
+
+ lua_pushboolean(L, result == SQLITE_OK ? 1 : 0);
+ return 1;
+}
+
+static int db_create_function(lua_State *L) {
+ return db_register_function(L, 0);
+}
+
+static int db_create_aggregate(lua_State *L) {
+ return db_register_function(L, 1);
+}
+
+/* create_collation; contributed by Thomas Lauer
+*/
+
+typedef struct {
+ lua_State *L;
+ int ref;
+} scc;
+
+static int collwrapper(scc *co,int l1,const void *p1,
+ int l2,const void *p2) {
+ int res=0;
+ lua_State *L=co->L;
+ lua_rawgeti(L,LUA_REGISTRYINDEX,co->ref);
+ lua_pushlstring(L,p1,l1);
+ lua_pushlstring(L,p2,l2);
+ if (lua_pcall(L,2,1,0)==0) res=(int)lua_tonumber(L,-1);
+ lua_pop(L,1);
+ return res;
+}
+
+static void collfree(scc *co) {
+ if (co) {
+ luaL_unref(co->L,LUA_REGISTRYINDEX,co->ref);
+ free(co);
+ }
+}
+
+static int db_create_collation(lua_State *L) {
+ sdb *db=lsqlite_checkdb(L,1);
+ const char *collname=luaL_checkstring(L,2);
+ scc *co=NULL;
+ int (*collfunc)(scc *,int,const void *,int,const void *)=NULL;
+ lua_settop(L,3); /* default args to nil, and exclude extras */
+ if (lua_isfunction(L,3)) collfunc=collwrapper;
+ else if (!lua_isnil(L,3))
+ luaL_error(L,"create_collation: function or nil expected");
+ if (collfunc != NULL) {
+ co=(scc *)malloc(sizeof(scc)); // userdata is a no-no as it
+ // will be garbage-collected
+ if (co) {
+ co->L=L;
+ /* lua_settop(L,3) above means we don't need: lua_pushvalue(L,3); */
+ co->ref=luaL_ref(L,LUA_REGISTRYINDEX);
+ }
+ else luaL_error(L,"create_collation: could not allocate callback");
+ }
+ sqlite3_create_collation_v2(db->db, collname, SQLITE_UTF8,
+ (void *)co,
+ (int(*)(void*,int,const void*,int,const void*))collfunc,
+ (void(*)(void*))collfree);
+ return 0;
+}
+
+/*
+** trace callback:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata, sql
+*/
+static void db_trace_callback(void *user, const char *sql) {
+ sdb *db = (sdb*)user;
+ lua_State *L = db->L;
+ int top = lua_gettop(L);
+
+ /* setup lua callback call */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, db->trace_cb); /* get callback */
+ lua_rawgeti(L, LUA_REGISTRYINDEX, db->trace_udata); /* get callback user data */
+ lua_pushstring(L, sql); /* traced sql statement */
+
+ /* call lua function */
+ lua_pcall(L, 2, 0, 0);
+ /* ignore any error generated by this function */
+
+ lua_settop(L, top);
+}
+
+static int db_trace(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+
+ if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
+ luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
+
+ db->trace_cb =
+ db->trace_udata = LUA_NOREF;
+
+ /* clear busy handler */
+ sqlite3_trace(db->db, NULL, NULL);
+ }
+ else {
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+
+ /* make sure we have an userdata field (even if nil) */
+ lua_settop(L, 3);
+
+ luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
+
+ db->trace_udata = luaL_ref(L, LUA_REGISTRYINDEX);
+ db->trace_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ /* set busy handler */
+ sqlite3_trace(db->db, db_trace_callback, db);
+ }
+
+ return 0;
+}
+
+
+#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK
+
+/*
+** progress handler:
+** Params: database, number of opcodes, callback function, userdata
+**
+** callback function:
+** Params: userdata
+** returns: 0 to return immediatly and return SQLITE_ABORT, non-zero to continue
+*/
+static int db_progress_callback(void *user) {
+ int result = 1; /* abort by default */
+ sdb *db = (sdb*)user;
+ lua_State *L = db->L;
+ int top = lua_gettop(L);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, db->progress_cb);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, db->progress_udata);
+
+ /* call lua function */
+ if (!lua_pcall(L, 1, 1, 0))
+ result = lua_toboolean(L, -1);
+
+ lua_settop(L, top);
+ return result;
+}
+
+static int db_progress_handler(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+
+ if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
+ luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
+
+ db->progress_cb =
+ db->progress_udata = LUA_NOREF;
+
+ /* clear busy handler */
+ sqlite3_progress_handler(db->db, 0, NULL, NULL);
+ }
+ else {
+ int nop = luaL_checkint(L, 2); /* number of opcodes */
+ luaL_checktype(L, 3, LUA_TFUNCTION);
+
+ /* make sure we have an userdata field (even if nil) */
+ lua_settop(L, 4);
+
+ luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
+
+ db->progress_udata = luaL_ref(L, LUA_REGISTRYINDEX);
+ db->progress_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ /* set progress callback */
+ sqlite3_progress_handler(db->db, nop, db_progress_callback, db);
+ }
+
+ return 0;
+}
+
+#else /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
+
+static int db_progress_handler(lua_State *L) {
+ lua_pushliteral(L, "progress callback support disabled at compile time");
+ lua_error(L);
+ return 0;
+}
+
+#endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
+
+/*
+** busy handler:
+** Params: database, callback function, userdata
+**
+** callback function:
+** Params: userdata, number of tries
+** returns: 0 to return immediatly and return SQLITE_BUSY, non-zero to try again
+*/
+static int db_busy_callback(void *user, int tries) {
+ int retry = 0; /* abort by default */
+ sdb *db = (sdb*)user;
+ lua_State *L = db->L;
+ int top = lua_gettop(L);
+
+ lua_rawgeti(L, LUA_REGISTRYINDEX, db->busy_cb);
+ lua_rawgeti(L, LUA_REGISTRYINDEX, db->busy_udata);
+ lua_pushnumber(L, tries);
+
+ /* call lua function */
+ if (!lua_pcall(L, 2, 1, 0))
+ retry = lua_toboolean(L, -1);
+
+ lua_settop(L, top);
+ return retry;
+}
+
+static int db_busy_handler(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+
+ if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
+
+ db->busy_cb =
+ db->busy_udata = LUA_NOREF;
+
+ /* clear busy handler */
+ sqlite3_busy_handler(db->db, NULL, NULL);
+ }
+ else {
+ luaL_checktype(L, 2, LUA_TFUNCTION);
+ /* make sure we have an userdata field (even if nil) */
+ lua_settop(L, 3);
+
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
+
+ db->busy_udata = luaL_ref(L, LUA_REGISTRYINDEX);
+ db->busy_cb = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ /* set busy handler */
+ sqlite3_busy_handler(db->db, db_busy_callback, db);
+ }
+
+ return 0;
+}
+
+static int db_busy_timeout(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ int timeout = luaL_checkint(L, 2);
+ sqlite3_busy_timeout(db->db, timeout);
+
+ /* if there was a timeout callback registered, it is now
+ ** invalid/useless. free any references we may have */
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
+ luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
+ db->busy_cb =
+ db->busy_udata = LUA_NOREF;
+
+ return 0;
+}
+
+/*
+** Params: db, sql, callback, user
+** returns: code [, errmsg]
+**
+** Callback:
+** Params: user, number of columns, values, names
+** Returns: 0 to continue, other value will cause abort
+*/
+static int db_exec_callback(void* user, int columns, char **data, char **names) {
+ int result = SQLITE_ABORT; /* abort by default */
+ sdb *db = (sdb*)user;
+ lua_State *L = db->L;
+ int n;
+
+ int top = lua_gettop(L);
+
+ lua_pushvalue(L, 3); /* function to call */
+ lua_pushvalue(L, 4); /* user data */
+ lua_pushnumber(L, columns); /* total number of rows in result */
+
+ /* column values */
+ lua_pushvalue(L, 6);
+ for (n = 0; n < columns;) {
+ lua_pushstring(L, data[n++]);
+ lua_rawseti(L, -2, n);
+ }
+
+ /* columns names */
+ lua_pushvalue(L, 5);
+ if (lua_isnil(L, -1)) {
+ lua_pop(L, 1);
+ lua_newtable(L);
+ lua_pushvalue(L, -1);
+ lua_replace(L, 5);
+ for (n = 0; n < columns;) {
+ lua_pushstring(L, names[n++]);
+ lua_rawseti(L, -2, n);
+ }
+ }
+
+ /* call lua function */
+ if (!lua_pcall(L, 4, 1, 0)) {
+ if (lua_isnumber(L, -1))
+ result = lua_tonumber(L, -1);
+ }
+
+ lua_settop(L, top);
+ return result;
+}
+
+static int db_exec(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ const char *sql = luaL_checkstring(L, 2);
+ int result;
+
+ if (!lua_isnoneornil(L, 3)) {
+ /* stack:
+ ** 3: callback function
+ ** 4: userdata
+ ** 5: column names
+ ** 6: reusable column values
+ */
+ luaL_checktype(L, 3, LUA_TFUNCTION);
+ lua_settop(L, 4); /* 'trap' userdata - nil extra parameters */
+ lua_pushnil(L); /* column names not known at this point */
+ lua_newtable(L); /* column values table */
+
+ result = sqlite3_exec(db->db, sql, db_exec_callback, db, NULL);
+ }
+ else {
+ /* no callbacks */
+ result = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
+ }
+
+ lua_pushnumber(L, result);
+ return 1;
+}
+
+/*
+** Params: db, sql
+** returns: code, compiled length or error message
+*/
+static int db_prepare(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ const char *sql = luaL_checkstring(L, 2);
+ int sql_len = lua_strlen(L, 2);
+ const char *sqltail;
+ sdb_vm *svm;
+ lua_settop(L,2); /* sql is on top of stack for call to newvm */
+ svm = newvm(L, db);
+
+ if (sqlite3_prepare(db->db, sql, sql_len, &svm->vm, &sqltail) != SQLITE_OK) {
+ cleanupvm(L, svm);
+
+ lua_pushnil(L);
+ lua_pushnumber(L, sqlite3_errcode(db->db));
+ return 2;
+ }
+
+ /* vm already in the stack */
+ lua_pushstring(L, sqltail);
+ return 2;
+}
+
+static int db_do_next_row(lua_State *L, int packed) {
+ int result;
+ sdb_vm *svm = lsqlite_checkvm(L, 1);
+ sqlite3_stmt *vm;
+ int columns;
+ int i;
+
+ result = stepvm(L, svm);
+ vm = svm->vm; /* stepvm may change svm->vm if re-prepare is needed */
+ svm->has_values = result == SQLITE_ROW ? 1 : 0;
+ svm->columns = columns = sqlite3_data_count(vm);
+
+ if (result == SQLITE_ROW) {
+ if (packed) {
+ lua_newtable(L);
+ if (packed == 1) {
+ for (i = 0; i < columns;) {
+ vm_push_column(L, vm, i);
+ lua_rawseti(L, -2, ++i);
+ }
+ }
+ else {
+ for (i = 0; i < columns; ++i) {
+ lua_pushstring(L, sqlite3_column_name(vm, i));
+ vm_push_column(L, vm, i);
+ lua_rawset(L, -3);
+ }
+ }
+ return 1;
+ }
+ else {
+ lua_checkstack(L, columns);
+ for (i = 0; i < columns; ++i)
+ vm_push_column(L, vm, i);
+ return svm->columns;
+ }
+ }
+
+ if (svm->temp) {
+ /* finalize and check for errors */
+ result = sqlite3_finalize(vm);
+ svm->vm = NULL;
+ cleanupvm(L, svm);
+ }
+ else if (result == SQLITE_DONE) {
+ result = sqlite3_reset(vm);
+ }
+
+ if (result != SQLITE_OK) {
+ lua_pushstring(L, sqlite3_errmsg(svm->db->db));
+ lua_error(L);
+ }
+ return 0;
+}
+
+static int db_next_row(lua_State *L) {
+ return db_do_next_row(L, 0);
+}
+
+static int db_next_packed_row(lua_State *L) {
+ return db_do_next_row(L, 1);
+}
+
+static int db_next_named_row(lua_State *L) {
+ return db_do_next_row(L, 2);
+}
+
+static int dbvm_do_rows(lua_State *L, int(*f)(lua_State *)) {
+ //sdb_vm *svm =
+ lsqlite_checkvm(L, 1);
+ lua_pushvalue(L,1);
+ lua_pushcfunction(L, f);
+ lua_insert(L, -2);
+ return 2;
+}
+
+static int dbvm_rows(lua_State *L) {
+ return dbvm_do_rows(L, db_next_packed_row);
+}
+
+static int dbvm_nrows(lua_State *L) {
+ return dbvm_do_rows(L, db_next_named_row);
+}
+
+static int dbvm_urows(lua_State *L) {
+ return dbvm_do_rows(L, db_next_row);
+}
+
+static int db_do_rows(lua_State *L, int(*f)(lua_State *)) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ const char *sql = luaL_checkstring(L, 2);
+ sdb_vm *svm;
+ lua_settop(L,2); /* sql is on top of stack for call to newvm */
+ svm = newvm(L, db);
+ svm->temp = 1;
+
+ if (sqlite3_prepare(db->db, sql, -1, &svm->vm, NULL) != SQLITE_OK) {
+ cleanupvm(L, svm);
+
+ lua_pushstring(L, sqlite3_errmsg(svm->db->db));
+ lua_error(L);
+ }
+
+ lua_pushcfunction(L, f);
+ lua_insert(L, -2);
+ return 2;
+}
+
+static int db_rows(lua_State *L) {
+ return db_do_rows(L, db_next_packed_row);
+}
+
+static int db_nrows(lua_State *L) {
+ return db_do_rows(L, db_next_named_row);
+}
+
+/* unpacked version of db:rows */
+static int db_urows(lua_State *L) {
+ return db_do_rows(L, db_next_row);
+}
+
+static int db_tostring(lua_State *L) {
+ char buff[32];
+ sdb *db = lsqlite_getdb(L, 1);
+ if (db->db == NULL)
+ strcpy(buff, "closed");
+ else
+ sprintf(buff, "%p", lua_touserdata(L, 1));
+ lua_pushfstring(L, "sqlite database (%s)", buff);
+ return 1;
+}
+
+static int db_close(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ lua_pushnumber(L, cleanupdb(L, db));
+ return 1;
+}
+
+static int db_close_vm(lua_State *L) {
+ sdb *db = lsqlite_checkdb(L, 1);
+ /* cleanup temporary only tables? */
+ int temp = lua_toboolean(L, 2);
+
+ /* free associated virtual machines */
+ lua_pushlightuserdata(L, db);
+ lua_rawget(L, LUA_REGISTRYINDEX);
+
+ /* close all used handles */
+ lua_pushnil(L);
+ while (lua_next(L, -2)) {
+ sdb_vm *svm = lua_touserdata(L, -2); /* key: vm; val: sql text */
+
+ if ((!temp || svm->temp) && svm->vm)
+ {
+ sqlite3_finalize(svm->vm);
+ svm->vm = NULL;
+ }
+
+ /* leave key in the stack */
+ lua_pop(L, 1);
+ }
+ return 0;
+}
+
+static int db_gc(lua_State *L) {
+ sdb *db = lsqlite_getdb(L, 1);
+ if (db->db != NULL) /* ignore closed databases */
+ cleanupdb(L, db);
+ return 0;
+}
+
+/*
+** =======================================================
+** General library functions
+** =======================================================
+*/
+
+static int lsqlite_version(lua_State *L) {
+ lua_pushstring(L, sqlite3_libversion());
+ return 1;
+}
+
+static int lsqlite_complete(lua_State *L) {
+ const char *sql = luaL_checkstring(L, 1);
+ lua_pushboolean(L, sqlite3_complete(sql));
+ return 1;
+}
+
+#ifndef WIN32
+static int lsqlite_temp_directory(lua_State *L) {
+ const char *oldtemp = sqlite3_temp_directory;
+
+ if (!lua_isnone(L, 1)) {
+ const char *temp = luaL_optstring(L, 1, NULL);
+ if (sqlite3_temp_directory) {
+ sqlite3_free((char*)sqlite3_temp_directory);
+ }
+ if (temp) {
+ sqlite3_temp_directory = sqlite3_mprintf("%s", temp);
+ }
+ else {
+ sqlite3_temp_directory = NULL;
+ }
+ }
+ lua_pushstring(L, oldtemp);
+ return 1;
+}
+#endif
+
+static int lsqlite_do_open(lua_State *L, const char *filename) {
+ sdb *db = newdb(L); /* create and leave in stack */
+
+ if (sqlite3_open(filename, &db->db) == SQLITE_OK) {
+ /* database handle already in the stack - return it */
+ return 1;
+ }
+
+ /* failed to open database */
+ lua_pushnil(L); /* push nil */
+ lua_pushnumber(L, sqlite3_errcode(db->db));
+ lua_pushstring(L, sqlite3_errmsg(db->db)); /* push error message */
+
+ /* clean things up */
+ cleanupdb(L, db);
+
+ /* return */
+ return 3;
+}
+
+static int lsqlite_open(lua_State *L) {
+ const char *filename = luaL_checkstring(L, 1);
+ return lsqlite_do_open(L, filename);
+}
+
+static int lsqlite_open_memory(lua_State *L) {
+ return lsqlite_do_open(L, ":memory:");
+}
+
+static int lsqlite_newindex(lua_State *L) {
+ lua_pushliteral(L, "attempt to change readonly table");
+ lua_error(L);
+ return 0;
+}
+
+/*
+** =======================================================
+** Register functions
+** =======================================================
+*/
+
+#define SC(s) { #s, SQLITE_ ## s },
+#define LSC(s) { #s, LSQLITE_ ## s },
+
+static const struct {
+ const char* name;
+ int value;
+} sqlite_constants[] = {
+ /* error codes */
+ SC(OK) SC(ERROR) SC(INTERNAL) SC(PERM)
+ SC(ABORT) SC(BUSY) SC(LOCKED) SC(NOMEM)
+ SC(READONLY) SC(INTERRUPT) SC(IOERR) SC(CORRUPT)
+ SC(NOTFOUND) SC(FULL) SC(CANTOPEN) SC(PROTOCOL)
+ SC(EMPTY) SC(SCHEMA) SC(TOOBIG) SC(CONSTRAINT)
+ SC(MISMATCH) SC(MISUSE) SC(NOLFS)
+ SC(FORMAT) SC(NOTADB)
+
+ /* sqlite_step specific return values */
+ SC(RANGE) SC(ROW) SC(DONE)
+
+ /* column types */
+ SC(INTEGER) SC(FLOAT) SC(TEXT) SC(BLOB)
+ SC(NULL)
+
+ /* terminator */
+ { NULL, 0 }
+};
+
+/* ======================================================= */
+
+static const luaL_reg dblib[] = {
+ {"isopen", db_isopen },
+ {"last_insert_rowid", db_last_insert_rowid },
+ {"changes", db_changes },
+ {"total_changes", db_total_changes },
+ {"errcode", db_errcode },
+ {"error_code", db_errcode },
+ {"errmsg", db_errmsg },
+ {"error_message", db_errmsg },
+ {"interrupt", db_interrupt },
+
+ {"create_function", db_create_function },
+ {"create_aggregate", db_create_aggregate },
+ {"create_collation", db_create_collation },
+
+ {"trace", db_trace },
+ {"progress_handler", db_progress_handler },
+ {"busy_timeout", db_busy_timeout },
+ {"busy_handler", db_busy_handler },
+
+ {"prepare", db_prepare },
+ {"rows", db_rows },
+ {"urows", db_urows },
+ {"nrows", db_nrows },
+
+ {"exec", db_exec },
+ {"execute", db_exec },
+ {"close", db_close },
+ {"close_vm", db_close_vm },
+
+ {"__tostring", db_tostring },
+ {"__gc", db_gc },
+
+ {NULL, NULL}
+};
+
+static const luaL_reg vmlib[] = {
+ {"isopen", dbvm_isopen },
+
+ {"step", dbvm_step },
+ {"reset", dbvm_reset },
+ {"finalize", dbvm_finalize },
+
+ {"columns", dbvm_columns },
+
+ {"bind", dbvm_bind },
+ {"bind_values", dbvm_bind_values },
+ {"bind_names", dbvm_bind_names },
+ {"bind_blob", dbvm_bind_blob },
+ {"bind_parameter_count",dbvm_bind_parameter_count},
+ {"bind_parameter_name", dbvm_bind_parameter_name},
+
+ {"get_value", dbvm_get_value },
+ {"get_values", dbvm_get_values },
+ {"get_name", dbvm_get_name },
+ {"get_names", dbvm_get_names },
+ {"get_type", dbvm_get_type },
+ {"get_types", dbvm_get_types },
+ {"get_uvalues", dbvm_get_uvalues },
+ {"get_unames", dbvm_get_unames },
+ {"get_utypes", dbvm_get_utypes },
+
+ {"get_named_values", dbvm_get_named_values },
+ {"get_named_types", dbvm_get_named_types },
+
+ {"rows", dbvm_rows },
+ {"urows", dbvm_urows },
+ {"nrows", dbvm_nrows },
+
+ /* compatibility names (added by request) */
+ {"idata", dbvm_get_values },
+ {"inames", dbvm_get_names },
+ {"itypes", dbvm_get_types },
+ {"data", dbvm_get_named_values },
+ {"type", dbvm_get_named_types },
+
+ {"__tostring", dbvm_tostring },
+ {"__gc", dbvm_gc },
+
+ { NULL, NULL }
+};
+
+static const luaL_reg ctxlib[] = {
+ {"user_data", lcontext_user_data },
+
+ {"get_aggregate_data", lcontext_get_aggregate_context },
+ {"set_aggregate_data", lcontext_set_aggregate_context },
+ {"aggregate_count", lcontext_aggregate_count },
+
+ {"result", lcontext_result },
+ {"result_null", lcontext_result_null },
+ {"result_number", lcontext_result_double },
+ {"result_double", lcontext_result_double },
+ {"result_int", lcontext_result_int },
+ {"result_text", lcontext_result_text },
+ {"result_blob", lcontext_result_blob },
+ {"result_error", lcontext_result_error },
+
+ {"__tostring", lcontext_tostring },
+ {NULL, NULL}
+};
+
+static const luaL_reg sqlitelib[] = {
+ {"version", lsqlite_version },
+ {"complete", lsqlite_complete },
+#ifndef WIN32
+ {"temp_directory", lsqlite_temp_directory },
+#endif
+ {"open", lsqlite_open },
+ {"open_memory", lsqlite_open_memory },
+
+ {"__newindex", lsqlite_newindex },
+ {NULL, NULL}
+};
+
+static void create_meta(lua_State *L, const char *name, const luaL_reg *lib) {
+ luaL_newmetatable(L, name);
+ lua_pushstring(L, "__index");
+ lua_pushvalue(L, -2); /* push metatable */
+ lua_rawset(L, -3); /* metatable.__index = metatable */
+
+ /* register metatable functions */
+ luaL_openlib(L, NULL, lib, 0);
+
+ /* remove metatable from stack */
+ lua_pop(L, 1);
+}
+
+LUALIB_API int luaopen_lsqlite3(lua_State *L) {
+ create_meta(L, sqlite_meta, dblib);
+ create_meta(L, sqlite_vm_meta, vmlib);
+ create_meta(L, sqlite_ctx_meta, ctxlib);
+
+ luaL_getmetatable(L, sqlite_ctx_meta);
+ sqlite_ctx_meta_ref = luaL_ref(L, LUA_REGISTRYINDEX);
+
+ /* register (local) sqlite metatable */
+ luaL_register(L, "sqlite3", sqlitelib);
+
+ {
+ int i = 0;
+ /* add constants to global table */
+ while (sqlite_constants[i].name) {
+ lua_pushstring(L, sqlite_constants[i].name);
+ lua_pushnumber(L, sqlite_constants[i].value);
+ lua_rawset(L, -3);
+ ++i;
+ }
+ }
+
+ /* set sqlite's metatable to itself - set as readonly (__newindex) */
+ lua_pushvalue(L, -1);
+ lua_setmetatable(L, -2);
+
+ return 1;
+}
diff --git a/3rdparty/lsqlite3/lsqlite3.def b/3rdparty/lsqlite3/lsqlite3.def
new file mode 100644
index 00000000000..b1c23c72dca
--- /dev/null
+++ b/3rdparty/lsqlite3/lsqlite3.def
@@ -0,0 +1,2 @@
+EXPORTS
+luaopen_lsqlite3
diff --git a/3rdparty/lsqlite3/lunit.lua b/3rdparty/lsqlite3/lunit.lua
new file mode 100644
index 00000000000..f5b996ad7fa
--- /dev/null
+++ b/3rdparty/lsqlite3/lunit.lua
@@ -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({...}, 1, name)
+ name = "Anonymous Testcase"
+ end
+
+ local tc = TestCase(name)
+ for index, test in ipairs({...}) 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
+
+
+
+
diff --git a/3rdparty/lsqlite3/test.lua b/3rdparty/lsqlite3/test.lua
new file mode 100644
index 00000000000..07938b7dfb0
--- /dev/null
+++ b/3rdparty/lsqlite3/test.lua
@@ -0,0 +1,153 @@
+require("lsqlite3")
+
+local width = 78
+local function line(pref, suff)
+ pref = pref or ''
+ suff = suff or ''
+ local len = width - 2 - string.len(pref) - string.len(suff)
+ print(pref .. string.rep('-', len) .. suff)
+end
+
+local db, vm
+local assert_, assert = assert, function (test)
+ if (not test) then
+ error(db:errmsg(), 2)
+ end
+end
+
+line(sqlite3.version())
+
+os.remove('test.db')
+db = sqlite3.open('test.db')
+
+line(nil, 'db:exec')
+db:exec('CREATE TABLE t(a, b)')
+
+line(nil, 'prepare')
+vm = db:prepare('insert into t values(?, :bork)')
+assert(vm, db:errmsg())
+assert(vm:bind_parameter_count() == 2)
+assert(vm:bind_values(2, 4) == sqlite3.OK)
+assert(vm:step() == sqlite3.DONE)
+assert(vm:reset() == sqlite3.OK)
+assert(vm:bind_names{ 'pork', bork = 'nono' } == sqlite3.OK)
+assert(vm:step() == sqlite3.DONE)
+assert(vm:reset() == sqlite3.OK)
+assert(vm:bind_names{ bork = 'sisi' } == sqlite3.OK)
+assert(vm:step() == sqlite3.DONE)
+assert(vm:reset() == sqlite3.OK)
+assert(vm:bind_names{ 1 } == sqlite3.OK)
+assert(vm:step() == sqlite3.DONE)
+assert(vm:finalize() == sqlite3.OK)
+
+line("select * from t", 'db:exec')
+
+assert(db:exec('select * from t', function (ud, ncols, values, names)
+ --table.setn(values, 2)
+ print(unpack(values))
+ return sqlite3.OK
+end) == sqlite3.OK)
+
+line("select * from t", 'db:prepare')
+
+vm = db:prepare('select * from t')
+assert(vm, db:errmsg())
+print(vm:get_unames())
+while (vm:step() == sqlite3.ROW) do
+ print(vm:get_uvalues())
+end
+assert(vm:finalize() == sqlite3.OK)
+
+
+
+line('udf', 'scalar')
+
+local function do_query(sql)
+ local r
+ local vm = db:prepare(sql)
+ assert(vm, db:errmsg())
+ print('====================================')
+ print(vm:get_unames())
+ print('------------------------------------')
+ r = vm:step()
+ while (r == sqlite3.ROW) do
+ print(vm:get_uvalues())
+ r = vm:step()
+ end
+ assert(r == sqlite3.DONE)
+ assert(vm:finalize() == sqlite3.OK)
+ print('====================================')
+end
+
+local function udf1_scalar(ctx, v)
+ local ud = ctx:user_data()
+ ud.r = (ud.r or '') .. tostring(v)
+ ctx:result_text(ud.r)
+end
+
+db:create_function('udf1', 1, udf1_scalar, { })
+do_query('select udf1(a) from t')
+
+
+line('udf', 'aggregate')
+
+local function udf2_aggregate(ctx, ...)
+ local ud = ctx:get_aggregate_data()
+ if (not ud) then
+ ud = {}
+ ctx:set_aggregate_data(ud)
+ end
+ ud.r = (ud.r or 0) + 2
+end
+
+local function udf2_aggregate_finalize(ctx, v)
+ local ud = ctx:get_aggregate_data()
+ ctx:result_number(ud and ud.r or 0)
+end
+
+db:create_aggregate('udf2', 1, udf2_aggregate, udf2_aggregate_finalize, { })
+do_query('select udf2(a) from t')
+
+if (true) then
+ line(nil, '100 insert exec')
+ db:exec('delete from t')
+ local t = os.time()
+ for i = 1, 100 do
+ db:exec('insert into t values('..i..', '..(i * 2 * -1^i)..')')
+ end
+ print('elapsed: '..(os.time() - t))
+ do_query('select count(*) from t')
+
+ line(nil, '100000 insert exec T')
+ db:exec('delete from t')
+ local t = os.time()
+ db:exec('begin')
+ for i = 1, 100000 do
+ db:exec('insert into t values('..i..', '..(i * 2 * -1^i)..')')
+ end
+ db:exec('commit')
+ print('elapsed: '..(os.time() - t))
+ do_query('select count(*) from t')
+
+ line(nil, '100000 insert prepare/bind T')
+ db:exec('delete from t')
+ local t = os.time()
+ local vm = db:prepare('insert into t values(?, ?)')
+ db:exec('begin')
+ for i = 1, 100000 do
+ vm:bind_values(i, i * 2 * -1^i)
+ vm:step()
+ vm:reset()
+ end
+ vm:finalize()
+ db:exec('commit')
+ print('elapsed: '..(os.time() - t))
+ do_query('select count(*) from t')
+
+end
+
+line(nil, "db:close")
+
+assert(db:close() == sqlite3.OK)
+
+line(sqlite3.version())
diff --git a/3rdparty/lsqlite3/tests-sqlite3.lua b/3rdparty/lsqlite3/tests-sqlite3.lua
new file mode 100644
index 00000000000..83787ca9c18
--- /dev/null
+++ b/3rdparty/lsqlite3/tests-sqlite3.lua
@@ -0,0 +1,587 @@
+
+--[[--------------------------------------------------------------------------
+
+ 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 "lsqlite3"
+
+require "lunit"
+
+lunit.setprivfenv()
+lunit.import "assertions"
+lunit.import "checks"
+
+
+
+
+
+
+-------------------------------
+-- Basic open and close test --
+-------------------------------
+
+lunit.wrap("open_memory", function()
+ local db = assert_userdata( sqlite3.open_memory() )
+ assert( db:close() )
+end)
+
+lunit.wrap("open", function()
+ local filename = "/tmp/__lua-sqlite3-20040906135849." .. os.time()
+ local db = assert_userdata( 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 )
+--e assert_function( db.irows )
+ assert_function( db.rows )
+--e assert_function( db.cols )
+--e assert_function( db.first_irow )
+--e assert_function( db.first_row )
+--e 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()
+--e- assert( self.stmt:close() )
+ assert( self.stmt:finalize() ) --e+
+ assert( self.db:close() )
+end
+
+function stmt_funcs:test()
+ local stmt = self.stmt
+--e assert_function( stmt.close )
+ assert_function( stmt.reset )
+--e assert_function( stmt.exec )
+ assert_function( stmt.bind )
+--e assert_function( stmt.irows )
+--e assert_function( stmt.rows )
+--e assert_function( stmt.cols )
+--e assert_function( stmt.first_irow )
+--e assert_function( stmt.first_row )
+--e assert_function( stmt.first_cols )
+--e assert_function( stmt.column_names )
+--e assert_function( stmt.column_decltypes )
+--e assert_function( stmt.column_count )
+--e +
+ assert_function( stmt.isopen )
+ assert_function( stmt.step )
+ assert_function( stmt.reset )
+ assert_function( stmt.finalize )
+ assert_function( stmt.columns )
+ assert_function( stmt.bind )
+ assert_function( stmt.bind_values )
+ assert_function( stmt.bind_names )
+ assert_function( stmt.bind_blob )
+ assert_function( stmt.bind_parameter_count )
+ assert_function( stmt.bind_parameter_name )
+ assert_function( stmt.get_value )
+ assert_function( stmt.get_values )
+ assert_function( stmt.get_name )
+ assert_function( stmt.get_names )
+ assert_function( stmt.get_type )
+ assert_function( stmt.get_types )
+ assert_function( stmt.get_uvalues )
+ assert_function( stmt.get_unames )
+ assert_function( stmt.get_utypes )
+ assert_function( stmt.get_named_values )
+ assert_function( stmt.get_named_types )
+ assert_function( stmt.idata )
+ assert_function( stmt.inames )
+ assert_function( stmt.itypes )
+ assert_function( stmt.data )
+ assert_function( stmt.type )
+--e +
+end
+
+
+
+------------------
+-- Tests basics --
+------------------
+
+local basics = lunit.TestCase("Basics")
+
+function basics:setup()
+ self.db = assert_userdata( sqlite3.open_memory() )
+end
+
+function basics:teardown()
+ assert_number( self.db:close() )
+end
+
+function basics:create_table()
+ assert_number( self.db:exec("CREATE TABLE test (id, name)") )
+end
+
+function basics:drop_table()
+ assert_number( self.db:exec("DROP TABLE test") )
+end
+
+function basics:insert(id, name)
+ assert_number( self.db:exec("INSERT INTO test VALUES ("..id..", '"..name.."')") )
+end
+
+function basics:update(id, name)
+ assert_number( 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_userdata( sqlite3.open_memory() )
+ assert_number( db:exec("CREATE TABLE test (id INTEGER, name TEXT)") )
+ local stmt = assert_userdata( db:prepare("SELECT * FROM test") )
+
+ assert_equal(2, stmt:columns(), "Wrong number of columns." )
+
+ local names = assert_table( stmt:get_names() )
+ assert_equal(2, #(names), "Wrong number of names.")
+ assert_equal("id", names[1] )
+ assert_equal("name", names[2] )
+
+ local types = assert_table( stmt:get_types() )
+ assert_equal(2, #(types), "Wrong number of declaration types.")
+ assert_equal("INTEGER", types[1] )
+ assert_equal("TEXT", types[2] )
+
+ assert_equal( sqlite3.OK, stmt:finalize() )
+ assert_equal( sqlite3.OK, db:close() )
+end)
+
+
+
+---------------------
+-- Statement Tests --
+---------------------
+
+st = lunit.TestCase("Statement Tests")
+
+function st:setup()
+ self.db = assert( sqlite3.open_memory() )
+ assert_equal( sqlite3.OK, self.db:exec("CREATE TABLE test (id, name)") )
+ assert_equal( sqlite3.OK, self.db:exec("INSERT INTO test VALUES (1, 'Hello World')") )
+ assert_equal( sqlite3.OK, self.db:exec("INSERT INTO test VALUES (2, 'Hello Lua')") )
+ assert_equal( sqlite3.OK, self.db:exec("INSERT INTO test VALUES (3, 'Hello sqlite3')") )
+end
+
+function st:teardown()
+ assert_equal( sqlite3.OK, 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:rows() do
+ i = i + 1
+ assert( i <= #(expected), "Too many rows." )
+ assert_equal(2, #(row), "Two result column expected.")
+ assert_equal(i, row[1], "Wrong 'id'.")
+ assert_equal(expected[i], row[2], "Wrong 'name'.")
+ end
+ assert_equal( #(expected), i, "Too few rows." )
+ assert_number( stmt:finalize() )
+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_userdata( self.db:prepare("INSERT INTO test VALUES (?, ?)") )
+ assert_number( stmt:bind_values(0, "Test") )
+ assert_error(function() stmt:bind_values("To few") end)
+ assert_error(function() stmt:bind_values(0, "Test", "To many") end)
+end
+
+function st:test_questionmark()
+ local stmt = assert_userdata( self.db:prepare("INSERT INTO test VALUES (?, ?)") )
+ assert_number( stmt:bind_values(4, "Good morning") )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
+ assert_number( stmt:bind_values(5, "Foo Bar") )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
+ assert_number( stmt:finalize() )
+end
+
+--[===[
+function st:test_questionmark_multi()
+ local stmt = assert_userdata( self.db:prepare([[
+ INSERT INTO test VALUES (?, ?); INSERT INTO test VALUES (?, ?) ]]))
+ assert( stmt:bind_values(5, "Foo Bar", 4, "Good morning") )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
+ assert_number( stmt:finalize() )
+end
+]===]
+
+function st:test_identifiers()
+ local stmt = assert_userdata( self.db:prepare("INSERT INTO test VALUES (:id, :name)") )
+ assert_number( stmt:bind_values(4, "Good morning") )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
+ assert_number( stmt:bind_values(5, "Foo Bar") )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
+ assert_number( stmt:finalize() )
+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_values(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_userdata( self.db:prepare({"name", "id"}, "INSERT INTO test VALUES (:id, $name)") )
+ local stmt = assert_userdata( self.db:prepare("INSERT INTO test VALUES (:id, $name)") )
+ assert_number( stmt:bind_names({name="Good morning", id=4}) )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
+ assert_number( stmt:bind_names({name="Foo Bar", id=5}) )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
+ assert_number( stmt:finalize() )
+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_values("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_userdata( self.db:prepare("INSERT INTO test VALUES (:id, :name)") )
+ assert_number( stmt:bind_names({name="Good morning", id=4}) )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
+ assert_number( stmt:bind_names({name="Foo Bar", id=5}) )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning", "Foo Bar" }
+ assert_number( stmt:finalize() )
+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_values("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_values("Good morning", 4) )
+ assert_table( stmt:exec() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Good morning" }
+ assert_table( stmt:bind_values("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_values("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_userdata( self.db:prepare("INSERT INTO test VALUES (:id, :name)") )
+ local args = { }
+ args.id = 5
+ args.name = "Hello girls"
+ assert( stmt:bind_names(args) )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ args.id = 4
+ args.name = "Hello boys"
+ assert( stmt:bind_names(args) )
+ assert_number( stmt:step() )
+ assert_number( stmt:reset() )
+ self:check_content{ "Hello World", "Hello Lua", "Hello sqlite3", "Hello boys", "Hello girls" }
+ assert_number( stmt:finalize() )
+end
+
+
+
+--------------------------------
+-- Tests binding of arguments --
+--------------------------------
+
+b = lunit.TestCase("Binding Tests")
+
+function b:setup()
+ self.db = assert( sqlite3.open_memory() )
+ assert_number( self.db:exec("CREATE TABLE test (id, name, u, v, w, x, y, z)") )
+end
+
+function b:teardown()
+ assert_number( self.db:close() )
+end
+
+function b:test_auto_parameter_names()
+ local stmt = assert_userdata( self.db:prepare("INSERT INTO test VALUES(:a, $b, :a2, :b2, $a, :b, $a3, $b3)") )
+ local parameters = assert_number( stmt:bind_parameter_count() )
+ assert_equal( 8, parameters )
+ assert_equal( ":a", stmt:bind_parameter_name(1) )
+ assert_equal( "$b", stmt:bind_parameter_name(2) )
+ assert_equal( ":a2", stmt:bind_parameter_name(3) )
+ assert_equal( ":b2", stmt:bind_parameter_name(4) )
+ assert_equal( "$a", stmt:bind_parameter_name(5) )
+ assert_equal( ":b", stmt:bind_parameter_name(6) )
+ assert_equal( "$a3", stmt:bind_parameter_name(7) )
+ assert_equal( "$b3", stmt:bind_parameter_name(8) )
+end
+
+function b:test_auto_parameter_names()
+ local stmt = assert_userdata( self.db:prepare("INSERT INTO test VALUES($a, $b, $a2, $b2, $a, $b, $a3, $b3)") )
+ local parameters = assert_number( stmt:bind_parameter_count() )
+ assert_equal( 6, parameters )
+ assert_equal( "$a", stmt:bind_parameter_name(1) )
+ assert_equal( "$b", stmt:bind_parameter_name(2) )
+ assert_equal( "$a2", stmt:bind_parameter_name(3) )
+ assert_equal( "$b2", stmt:bind_parameter_name(4) )
+ assert_equal( "$a3", stmt:bind_parameter_name(5) )
+ assert_equal( "$b3", stmt:bind_parameter_name(6) )
+end
+
+function b:test_no_parameter_names_1()
+ local stmt = assert_userdata( self.db:prepare([[ SELECT * FROM test ]]))
+ local parameters = assert_number( stmt:bind_parameter_count() )
+ assert_equal( 0, (parameters) )
+end
+
+function b:test_no_parameter_names_2()
+ local stmt = assert_userdata( self.db:prepare([[ INSERT INTO test VALUES(?, ?, ?, ?, ?, ?, ?, ?) ]]))
+ local parameters = assert_number( stmt:bind_parameter_count() )
+ assert_equal( 8, (parameters) )
+ assert_nil( stmt:bind_parameter_name(1) )
+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_number( self.db:close() )
+end
+
+--[===[
+function bug:test_1()
+ self.db:exec("CREATE TABLE test (id INTEGER PRIMARY KEY, value TEXT)")
+
+ local query = assert_userdata( self.db:prepare("SELECT id FROM test WHERE value=?") )
+
+ assert_table ( query:bind_values("1") )
+ assert_nil ( query:first_cols() )
+ assert_table ( query:bind_values("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:create_function("test_nils", 5, function(arg1, arg2, arg3, arg4, arg5)
+ check(arg1, arg2, arg3, arg4, arg5)
+ end, {})
+
+ assert_number( self.db:exec([[ SELECT test_nils(1, 2, NULL, 4, NULL) ]]) )
+
+ for arg1, arg2, arg3, arg4, arg5 in self.db:urows([[ SELECT 1, 2, NULL, 4, NULL ]])
+ do check(arg1, arg2, arg3, arg4, arg5)
+ end
+
+ for row in self.db:rows([[ SELECT 1, 2, NULL, 4, NULL ]])
+ do assert_table( row )
+ check(row[1], row[2], row[3], row[4], row[5])
+ end
+end
+
+----------------------------
+-- Test for collation fun --
+----------------------------
+
+colla = lunit.TestCase("Collation Tests")
+
+function colla:setup()
+ local function collate(s1,s2)
+ -- if p then print("collation callback: ",s1,s2) end
+ s1=s1:lower()
+ s2=s2:lower()
+ if s1==s2 then return 0
+ elseif s1<s2 then return -1
+ else return 1 end
+ end
+ self.db = assert( sqlite3.open_memory() )
+ assert_nil(self.db:create_collation('CINSENS',collate))
+ self.db:exec[[
+ CREATE TABLE test(id INTEGER PRIMARY KEY,content COLLATE CINSENS);
+ INSERT INTO test VALUES(NULL,'hello world');
+ INSERT INTO test VALUES(NULL,'Buenos dias');
+ INSERT INTO test VALUES(NULL,'HELLO WORLD');
+ INSERT INTO test VALUES(NULL,'Guten Tag');
+ INSERT INTO test VALUES(NULL,'HeLlO WoRlD');
+ INSERT INTO test VALUES(NULL,'Bye for now');
+ ]]
+end
+
+function colla:teardown()
+ assert_number( self.db:close() )
+end
+
+function colla:test()
+ --for row in db:nrows('SELECT * FROM test') do
+ -- print(row.id,row.content)
+ --end
+ local n = 0
+ for row in self.db:nrows('SELECT * FROM test WHERE content="hElLo wOrLd"') do
+ -- print(row.id,row.content)
+ assert_equal (row.content:lower(), "hello world")
+ n = n + 1
+ end
+ assert_equal (n, 3)
+end
+
+lunit.run()
diff --git a/src/lib/lib.mak b/src/lib/lib.mak
index 645a227eaee..4e68961b922 100644
--- a/src/lib/lib.mak
+++ b/src/lib/lib.mak
@@ -513,7 +513,7 @@ LUAOBJS = \
$(LIBOBJ)/lua/ltablib.o \
$(LIBOBJ)/lua/loadlib.o \
$(LIBOBJ)/lua/linit.o \
- $(LIBOBJ)/lua/lib/lsqlite3.o \
+ $(LIBOBJ)/lua/lsqlite3/lsqlite3.o \
$(OBJ)/liblua.a: $(LUAOBJS)
@@ -530,6 +530,10 @@ $(LIBOBJ)/lua/%.o: $(LIBSRC)/lua/%.c | $(OSPREBUILD)
@echo Compiling $<...
$(CC) $(CDEFS) $(CCOMFLAGS) $(CONLYFLAGS) -DLUA_COMPAT_ALL $(LUA_FLAGS) -c $< -o $@
+$(LIBOBJ)/lua/lsqlite3/%.o: $(3RDPARTY)/lsqlite3/%.c | $(OSPREBUILD)
+ @echo Compiling $<...
+ $(CC) $(CDEFS) $(CCOMFLAGS) $(CONLYFLAGS) -DLUA_COMPAT_ALL $(LUA_FLAGS) -c $< -o $@
+
#-------------------------------------------------
# web library objects
#-------------------------------------------------
diff --git a/src/lib/lua/lib/lsqlite3.c b/src/lib/lua/lib/lsqlite3.c
deleted file mode 100644
index 34f4ca573f0..00000000000
--- a/src/lib/lua/lib/lsqlite3.c
+++ /dev/null
@@ -1,2157 +0,0 @@
-/************************************************************************
-* lsqlite3 *
-* Copyright (C) 2002-2013 Tiago Dionizio, Doug Currie *
-* All rights reserved. *
-* Author : Tiago Dionizio <tiago.dionizio@ist.utl.pt> *
-* Author : Doug Currie <doug.currie@alum.mit.edu> *
-* Library : lsqlite3 - a SQLite 3 database binding for Lua 5 *
-* *
-* 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. *
-************************************************************************/
-
-#include <stdlib.h>
-#include <string.h>
-#include <assert.h>
-
-#define LUA_LIB
-#include "lua/lua.h"
-#include "lua/lauxlib.h"
-
-#if LUA_VERSION_NUM > 501
-//
-// Lua 5.2
-//
-//#define lua_strlen lua_rawlen
-// luaL_typerror always used with arg at ndx == NULL
-#define luaL_typerror(L,ndx,str) luaL_error(L,"bad argument %d (%s expected, got nil)",ndx,str)
-// luaL_register used once, so below expansion is OK for this case
-//#define luaL_register(L,name,reg) lua_newtable(L);luaL_setfuncs(L,reg,0)
-// luaL_openlib always used with name == NULL
-#define luaL_openlib(L,name,reg,nup) luaL_setfuncs(L,reg,nup)
-#endif
-
-#include "sqlite3/sqlite3.h"
-
-/* compile time features */
-#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK)
- #define SQLITE_OMIT_PROGRESS_CALLBACK 0
-#endif
-#if !defined(LSQLITE_OMIT_UPDATE_HOOK)
- #define LSQLITE_OMIT_UPDATE_HOOK 0
-#endif
-
-typedef struct sdb sdb;
-typedef struct sdb_vm sdb_vm;
-typedef struct sdb_func sdb_func;
-
-/* to use as C user data so i know what function sqlite is calling */
-struct sdb_func {
- /* references to associated lua values */
- int fn_step;
- int fn_finalize;
- int udata;
-
- sdb *db;
- char aggregate;
-
- sdb_func *next;
-};
-
-/* information about database */
-struct sdb {
- /* associated lua state */
- lua_State *L;
- /* sqlite database handle */
- sqlite3 *db;
-
- /* sql functions stack usage */
- sdb_func *func; /* top SQL function being called */
-
- /* references */
- int busy_cb; /* busy callback */
- int busy_udata;
-
- int progress_cb; /* progress handler */
- int progress_udata;
-
- int trace_cb; /* trace callback */
- int trace_udata;
-
-#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
-
- int update_hook_cb; /* update_hook callback */
- int update_hook_udata;
-
- int commit_hook_cb; /* commit_hook callback */
- int commit_hook_udata;
-
- int rollback_hook_cb; /* rollback_hook callback */
- int rollback_hook_udata;
-
-#endif
-};
-
-static const char *sqlite_meta = ":sqlite3";
-static const char *sqlite_vm_meta = ":sqlite3:vm";
-static const char *sqlite_ctx_meta = ":sqlite3:ctx";
-static int sqlite_ctx_meta_ref;
-
-/*
-** =======================================================
-** Database Virtual Machine Operations
-** =======================================================
-*/
-
-static void vm_push_column(lua_State *L, sqlite3_stmt *vm, int idx) {
- switch (sqlite3_column_type(vm, idx)) {
- case SQLITE_INTEGER:
- {
- sqlite_int64 i64 = sqlite3_column_int64(vm, idx);
- lua_Number n = (lua_Number)i64;
- if (n == i64)
- lua_pushnumber(L, n);
- else
- lua_pushlstring(L, (const char*)sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
- }
- break;
- case SQLITE_FLOAT:
- lua_pushnumber(L, sqlite3_column_double(vm, idx));
- break;
- case SQLITE_TEXT:
- lua_pushlstring(L, (const char*)sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
- break;
- case SQLITE_BLOB:
- lua_pushlstring(L, (const char*)sqlite3_column_blob(vm, idx), sqlite3_column_bytes(vm, idx));
- break;
- case SQLITE_NULL:
- lua_pushnil(L);
- break;
- default:
- lua_pushnil(L);
- break;
- }
-}
-
-/* virtual machine information */
-struct sdb_vm {
- sdb *db; /* associated database handle */
- sqlite3_stmt *vm; /* virtual machine */
-
- /* sqlite3_step info */
- int columns; /* number of columns in result */
- char has_values; /* true when step succeeds */
-
- char temp; /* temporary vm used in db:rows */
-};
-
-/* called with sql text on the lua stack */
-static sdb_vm *newvm(lua_State *L, sdb *db) {
- sdb_vm *svm = (sdb_vm*)lua_newuserdata(L, sizeof(sdb_vm));
-
- luaL_getmetatable(L, sqlite_vm_meta);
- lua_setmetatable(L, -2); /* set metatable */
-
- svm->db = db;
- svm->columns = 0;
- svm->has_values = 0;
- svm->vm = NULL;
- svm->temp = 0;
-
- /* add an entry on the database table: svm -> sql text */
- lua_pushlightuserdata(L, db);
- lua_rawget(L, LUA_REGISTRYINDEX);
- lua_pushlightuserdata(L, svm);
- lua_pushvalue(L, -4); /* the sql text */
- lua_rawset(L, -3);
- lua_pop(L, 1);
-
- return svm;
-}
-
-static int cleanupvm(lua_State *L, sdb_vm *svm) {
- /* remove entry in database table - no harm if not present in the table */
- lua_pushlightuserdata(L, svm->db);
- lua_rawget(L, LUA_REGISTRYINDEX);
- lua_pushlightuserdata(L, svm);
- lua_pushnil(L);
- lua_rawset(L, -3);
- lua_pop(L, 1);
-
- svm->columns = 0;
- svm->has_values = 0;
-
- if (!svm->vm) return 0;
-
- lua_pushnumber(L, sqlite3_finalize(svm->vm));
- svm->vm = NULL;
- return 1;
-}
-
-static int stepvm(lua_State *L, sdb_vm *svm) {
- // MAME: fixed Visual Studio compiler warning lsqlite3.c(235) : warning C4701: potentially uninitialized local variable 'result' used
- int result = 0;
- int loop_limit = 3;
- while ( loop_limit-- ) {
- result = sqlite3_step(svm->vm);
- if ( result==SQLITE_ERROR ) {
- result = sqlite3_reset (svm->vm);
- }
- if ( result==SQLITE_SCHEMA ) {
- sqlite3_stmt *vn;
- const char *sql;
- /* recover sql text */
- lua_pushlightuserdata(L, svm->db);
- lua_rawget(L, LUA_REGISTRYINDEX);
- lua_pushlightuserdata(L, svm);
- lua_rawget(L, -2); /* sql text */
- sql = luaL_checkstring(L, -1);
- /* re-prepare */
- result = sqlite3_prepare(svm->db->db, sql, -1, &vn, NULL);
- if (result != SQLITE_OK) break;
- sqlite3_transfer_bindings(svm->vm, vn);
- sqlite3_finalize(svm->vm);
- svm->vm = vn;
- lua_pop(L,2);
- } else {
- break;
- }
- }
- return result;
-}
-
-static sdb_vm *lsqlite_getvm(lua_State *L, int index) {
- sdb_vm *svm = (sdb_vm*)luaL_checkudata(L, index, sqlite_vm_meta);
- if (svm == NULL) luaL_argerror(L, index, "bad sqlite virtual machine");
- return svm;
-}
-
-static sdb_vm *lsqlite_checkvm(lua_State *L, int index) {
- sdb_vm *svm = lsqlite_getvm(L, index);
- if (svm->vm == NULL) luaL_argerror(L, index, "attempt to use closed sqlite virtual machine");
- return svm;
-}
-
-static int dbvm_isopen(lua_State *L) {
- sdb_vm *svm = lsqlite_getvm(L, 1);
- lua_pushboolean(L, svm->vm != NULL ? 1 : 0);
- return 1;
-}
-
-static int dbvm_tostring(lua_State *L) {
- char buff[39];
- sdb_vm *svm = lsqlite_getvm(L, 1);
- if (svm->vm == NULL)
- strcpy(buff, "closed");
- else
- sprintf(buff, "%p", svm);
- lua_pushfstring(L, "sqlite virtual machine (%s)", buff);
- return 1;
-}
-
-static int dbvm_gc(lua_State *L) {
- sdb_vm *svm = lsqlite_getvm(L, 1);
- if (svm->vm != NULL) /* ignore closed vms */
- cleanupvm(L, svm);
- return 0;
-}
-
-static int dbvm_step(lua_State *L) {
- int result;
- sdb_vm *svm = lsqlite_checkvm(L, 1);
-
- result = stepvm(L, svm);
- svm->has_values = result == SQLITE_ROW ? 1 : 0;
- svm->columns = sqlite3_data_count(svm->vm);
-
- lua_pushnumber(L, result);
- return 1;
-}
-
-static int dbvm_finalize(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- return cleanupvm(L, svm);
-}
-
-static int dbvm_reset(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_reset(svm->vm);
- lua_pushnumber(L, sqlite3_errcode(svm->db->db));
- return 1;
-}
-
-static void dbvm_check_contents(lua_State *L, sdb_vm *svm) {
- if (!svm->has_values) {
- luaL_error(L, "misuse of function");
- }
-}
-
-static void dbvm_check_index(lua_State *L, sdb_vm *svm, int index) {
- if (index < 0 || index >= svm->columns) {
- luaL_error(L, "index out of range [0..%d]", svm->columns - 1);
- }
-}
-
-static void dbvm_check_bind_index(lua_State *L, sdb_vm *svm, int index) {
- if (index < 1 || index > sqlite3_bind_parameter_count(svm->vm)) {
- luaL_error(L, "bind index out of range [1..%d]", sqlite3_bind_parameter_count(svm->vm));
- }
-}
-
-/*
-** =======================================================
-** Virtual Machine - generic info
-** =======================================================
-*/
-static int dbvm_columns(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- lua_pushnumber(L, sqlite3_column_count(svm->vm));
- return 1;
-}
-
-/*
-** =======================================================
-** Virtual Machine - getters
-** =======================================================
-*/
-
-static int dbvm_get_value(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checkint(L, 2);
- dbvm_check_contents(L, svm);
- dbvm_check_index(L, svm, index);
- vm_push_column(L, svm->vm, index);
- return 1;
-}
-
-static int dbvm_get_name(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checknumber(L, 2);
- dbvm_check_index(L, svm, index);
- lua_pushstring(L, sqlite3_column_name(svm->vm, index));
- return 1;
-}
-
-static int dbvm_get_type(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checknumber(L, 2);
- dbvm_check_index(L, svm, index);
- lua_pushstring(L, sqlite3_column_decltype(svm->vm, index));
- return 1;
-}
-
-static int dbvm_get_values(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = svm->columns;
- int n;
- dbvm_check_contents(L, svm);
-
- lua_newtable(L);
- for (n = 0; n < columns;) {
- vm_push_column(L, vm, n++);
- lua_rawseti(L, -2, n);
- }
- return 1;
-}
-
-static int dbvm_get_names(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
-
- lua_newtable(L);
- for (n = 0; n < columns;) {
- lua_pushstring(L, sqlite3_column_name(vm, n++));
- lua_rawseti(L, -2, n);
- }
- return 1;
-}
-
-static int dbvm_get_types(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
-
- lua_newtable(L);
- for (n = 0; n < columns;) {
- lua_pushstring(L, sqlite3_column_decltype(vm, n++));
- lua_rawseti(L, -2, n);
- }
- return 1;
-}
-
-static int dbvm_get_uvalues(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = svm->columns;
- int n;
- dbvm_check_contents(L, svm);
-
- lua_checkstack(L, columns);
- for (n = 0; n < columns; ++n)
- vm_push_column(L, vm, n);
- return columns;
-}
-
-static int dbvm_get_unames(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
-
- lua_checkstack(L, columns);
- for (n = 0; n < columns; ++n)
- lua_pushstring(L, sqlite3_column_name(vm, n));
- return columns;
-}
-
-static int dbvm_get_utypes(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
- int n;
-
- lua_checkstack(L, columns);
- for (n = 0; n < columns; ++n)
- lua_pushstring(L, sqlite3_column_decltype(vm, n));
- return columns;
-}
-
-static int dbvm_get_named_values(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = svm->columns;
- int n;
- dbvm_check_contents(L, svm);
-
- lua_newtable(L);
- for (n = 0; n < columns; ++n) {
- lua_pushstring(L, sqlite3_column_name(vm, n));
- vm_push_column(L, vm, n);
- lua_rawset(L, -3);
- }
- return 1;
-}
-
-static int dbvm_get_named_types(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int columns = sqlite3_column_count(vm);
- int n;
-
- lua_newtable(L);
- for (n = 0; n < columns; ++n) {
- lua_pushstring(L, sqlite3_column_name(vm, n));
- lua_pushstring(L, sqlite3_column_decltype(vm, n));
- lua_rawset(L, -3);
- }
- return 1;
-}
-
-/*
-** =======================================================
-** Virtual Machine - Bind
-** =======================================================
-*/
-
-static int dbvm_bind_index(lua_State *L, sqlite3_stmt *vm, int index, int lindex) {
- switch (lua_type(L, lindex)) {
- case LUA_TSTRING:
- return sqlite3_bind_text(vm, index, lua_tostring(L, lindex), lua_strlen(L, lindex), SQLITE_TRANSIENT);
- case LUA_TNUMBER:
- return sqlite3_bind_double(vm, index, lua_tonumber(L, lindex));
- case LUA_TBOOLEAN:
- return sqlite3_bind_int(vm, index, lua_toboolean(L, lindex) ? 1 : 0);
- case LUA_TNONE:
- case LUA_TNIL:
- return sqlite3_bind_null(vm, index);
- default:
- luaL_error(L, "index (%d) - invalid data type for bind (%s)", index, lua_typename(L, lua_type(L, lindex)));
- return SQLITE_MISUSE; /*!*/
- }
-}
-
-
-static int dbvm_bind_parameter_count(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- lua_pushnumber(L, sqlite3_bind_parameter_count(svm->vm));
- return 1;
-}
-
-static int dbvm_bind_parameter_name(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checknumber(L, 2);
- dbvm_check_bind_index(L, svm, index);
- lua_pushstring(L, sqlite3_bind_parameter_name(svm->vm, index));
- return 1;
-}
-
-static int dbvm_bind(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int index = luaL_checkint(L, 2);
- int result;
-
- dbvm_check_bind_index(L, svm, index);
- result = dbvm_bind_index(L, vm, index, 3);
-
- lua_pushnumber(L, result);
- return 1;
-}
-
-static int dbvm_bind_blob(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- int index = luaL_checkint(L, 2);
- const char *value = luaL_checkstring(L, 3);
- int len = lua_strlen(L, 3);
-
- lua_pushnumber(L, sqlite3_bind_blob(svm->vm, index, value, len, SQLITE_TRANSIENT));
- return 1;
-}
-
-static int dbvm_bind_values(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int top = lua_gettop(L);
- int result, n;
-
- if (top - 1 != sqlite3_bind_parameter_count(vm))
- luaL_error(L,
- "incorrect number of parameters to bind (%d given, %d to bind)",
- top - 1,
- sqlite3_bind_parameter_count(vm)
- );
-
- for (n = 2; n <= top; ++n) {
- if ((result = dbvm_bind_index(L, vm, n - 1, n)) != SQLITE_OK) {
- lua_pushnumber(L, result);
- return 1;
- }
- }
-
- lua_pushnumber(L, SQLITE_OK);
- return 1;
-}
-
-static int dbvm_bind_names(lua_State *L) {
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm = svm->vm;
- int count = sqlite3_bind_parameter_count(vm);
- const char *name;
- int result, n;
- luaL_checktype(L, 2, LUA_TTABLE);
-
- for (n = 1; n <= count; ++n) {
- name = sqlite3_bind_parameter_name(vm, n);
- if (name && (name[0] == ':' || name[0] == '$')) {
- lua_pushstring(L, ++name);
- lua_gettable(L, 2);
- result = dbvm_bind_index(L, vm, n, -1);
- lua_pop(L, 1);
- }
- else {
- lua_pushnumber(L, n);
- lua_gettable(L, 2);
- result = dbvm_bind_index(L, vm, n, -1);
- lua_pop(L, 1);
- }
-
- if (result != SQLITE_OK) {
- lua_pushnumber(L, result);
- return 1;
- }
- }
-
- lua_pushnumber(L, SQLITE_OK);
- return 1;
-}
-
-/*
-** =======================================================
-** Database (internal management)
-** =======================================================
-*/
-
-/*
-** When creating database handles, always creates a `closed' database handle
-** before opening the actual database; so, if there is a memory error, the
-** database is not left opened.
-**
-** Creates a new 'table' and leaves it in the stack
-*/
-static sdb *newdb (lua_State *L) {
- sdb *db = (sdb*)lua_newuserdata(L, sizeof(sdb));
- db->L = L;
- db->db = NULL; /* database handle is currently `closed' */
- db->func = NULL;
-
- db->busy_cb =
- db->busy_udata =
- db->progress_cb =
- db->progress_udata =
- db->trace_cb =
- db->trace_udata =
-#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- db->update_hook_cb =
- db->update_hook_udata =
- db->commit_hook_cb =
- db->commit_hook_udata =
- db->rollback_hook_cb =
- db->rollback_hook_udata =
-#endif
- LUA_NOREF;
-
- luaL_getmetatable(L, sqlite_meta);
- lua_setmetatable(L, -2); /* set metatable */
-
- /* to keep track of 'open' virtual machines */
- lua_pushlightuserdata(L, db);
- lua_newtable(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
-
- return db;
-}
-
-static int cleanupdb(lua_State *L, sdb *db) {
- sdb_func *func;
- sdb_func *func_next;
- int top;
- int result;
-
- /* free associated virtual machines */
- lua_pushlightuserdata(L, db);
- lua_rawget(L, LUA_REGISTRYINDEX);
-
- /* close all used handles */
- top = lua_gettop(L);
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- sdb_vm *svm = (sdb_vm *)lua_touserdata(L, -2); /* key: vm; val: sql text */
- cleanupvm(L, svm);
-
- lua_settop(L, top);
- lua_pushnil(L);
- }
-
- lua_pop(L, 1); /* pop vm table */
-
- /* remove entry in lua registry table */
- lua_pushlightuserdata(L, db);
- lua_pushnil(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
-
- /* 'free' all references */
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
-#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
-#endif
-
- /* close database */
- result = sqlite3_close(db->db);
- db->db = NULL;
-
- /* free associated memory with created functions */
- func = db->func;
- while (func) {
- func_next = func->next;
- luaL_unref(L, LUA_REGISTRYINDEX, func->fn_step);
- luaL_unref(L, LUA_REGISTRYINDEX, func->fn_finalize);
- luaL_unref(L, LUA_REGISTRYINDEX, func->udata);
- free(func);
- func = func_next;
- }
- db->func = NULL;
- return result;
-}
-
-static sdb *lsqlite_getdb(lua_State *L, int index) {
- sdb *db = (sdb*)luaL_checkudata(L, index, sqlite_meta);
- if (db == NULL) luaL_typerror(L, index, "sqlite database");
- return db;
-}
-
-static sdb *lsqlite_checkdb(lua_State *L, int index) {
- sdb *db = lsqlite_getdb(L, index);
- if (db->db == NULL) luaL_argerror(L, index, "attempt to use closed sqlite database");
- return db;
-}
-
-
-/*
-** =======================================================
-** User Defined Functions - Context Methods
-** =======================================================
-*/
-typedef struct {
- sqlite3_context *ctx;
- int ud;
-} lcontext;
-
-static lcontext *lsqlite_make_context(lua_State *L) {
- lcontext *ctx = (lcontext*)lua_newuserdata(L, sizeof(lcontext));
- lua_rawgeti(L, LUA_REGISTRYINDEX, sqlite_ctx_meta_ref);
- lua_setmetatable(L, -2);
- ctx->ctx = NULL;
- ctx->ud = LUA_NOREF;
- return ctx;
-}
-
-static lcontext *lsqlite_getcontext(lua_State *L, int index) {
- lcontext *ctx = (lcontext*)luaL_checkudata(L, index, sqlite_ctx_meta);
- if (ctx == NULL) luaL_typerror(L, index, "sqlite context");
- return ctx;
-}
-
-static lcontext *lsqlite_checkcontext(lua_State *L, int index) {
- lcontext *ctx = lsqlite_getcontext(L, index);
- if (ctx->ctx == NULL) luaL_argerror(L, index, "invalid sqlite context");
- return ctx;
-}
-
-static int lcontext_tostring(lua_State *L) {
- char buff[39];
- lcontext *ctx = lsqlite_getcontext(L, 1);
- if (ctx->ctx == NULL)
- strcpy(buff, "closed");
- else
- sprintf(buff, "%p", ctx->ctx);
- lua_pushfstring(L, "sqlite function context (%s)", buff);
- return 1;
-}
-
-static void lcontext_check_aggregate(lua_State *L, lcontext *ctx) {
- sdb_func *func = (sdb_func*)sqlite3_user_data(ctx->ctx);
- if (!func->aggregate) {
- luaL_error(L, "attempt to call aggregate method from scalar function");
- }
-}
-
-static int lcontext_user_data(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- sdb_func *func = (sdb_func*)sqlite3_user_data(ctx->ctx);
- lua_rawgeti(L, LUA_REGISTRYINDEX, func->udata);
- return 1;
-}
-
-static int lcontext_get_aggregate_context(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- lcontext_check_aggregate(L, ctx);
- lua_rawgeti(L, LUA_REGISTRYINDEX, ctx->ud);
- return 1;
-}
-
-static int lcontext_set_aggregate_context(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- lcontext_check_aggregate(L, ctx);
- lua_settop(L, 2);
- luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
- ctx->ud = luaL_ref(L, LUA_REGISTRYINDEX);
- return 0;
-}
-
-static int lcontext_aggregate_count(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- lcontext_check_aggregate(L, ctx);
- lua_pushnumber(L, sqlite3_aggregate_count(ctx->ctx));
- return 1;
-}
-
-#if 0
-void *sqlite3_get_auxdata(sqlite3_context*, int);
-void sqlite3_set_auxdata(sqlite3_context*, int, void*, void (*)(void*));
-#endif
-
-static int lcontext_result(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- switch (lua_type(L, 2)) {
- case LUA_TNUMBER:
- sqlite3_result_double(ctx->ctx, luaL_checknumber(L, 2));
- break;
- case LUA_TSTRING:
- sqlite3_result_text(ctx->ctx, luaL_checkstring(L, 2), lua_strlen(L, 2), SQLITE_TRANSIENT);
- break;
- case LUA_TNIL:
- case LUA_TNONE:
- sqlite3_result_null(ctx->ctx);
- break;
- default:
- luaL_error(L, "invalid result type %s", lua_typename(L, 2));
- break;
- }
-
- return 0;
-}
-
-static int lcontext_result_blob(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- const char *blob = luaL_checkstring(L, 2);
- int size = lua_strlen(L, 2);
- sqlite3_result_blob(ctx->ctx, (const void*)blob, size, SQLITE_TRANSIENT);
- return 0;
-}
-
-static int lcontext_result_double(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- double d = luaL_checknumber(L, 2);
- sqlite3_result_double(ctx->ctx, d);
- return 0;
-}
-
-static int lcontext_result_error(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- const char *err = luaL_checkstring(L, 2);
- int size = lua_strlen(L, 2);
- sqlite3_result_error(ctx->ctx, err, size);
- return 0;
-}
-
-static int lcontext_result_int(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- int i = luaL_checkint(L, 2);
- sqlite3_result_int(ctx->ctx, i);
- return 0;
-}
-
-static int lcontext_result_null(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- sqlite3_result_null(ctx->ctx);
- return 0;
-}
-
-static int lcontext_result_text(lua_State *L) {
- lcontext *ctx = lsqlite_checkcontext(L, 1);
- const char *text = luaL_checkstring(L, 2);
- int size = lua_strlen(L, 2);
- sqlite3_result_text(ctx->ctx, text, size, SQLITE_TRANSIENT);
- return 0;
-}
-
-/*
-** =======================================================
-** Database Methods
-** =======================================================
-*/
-
-static int db_isopen(lua_State *L) {
- sdb *db = lsqlite_getdb(L, 1);
- lua_pushboolean(L, db->db != NULL ? 1 : 0);
- return 1;
-}
-
-static int db_last_insert_rowid(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- /* conversion warning: int64 -> luaNumber */
- sqlite_int64 rowid = sqlite3_last_insert_rowid(db->db);
- lua_Number n = (lua_Number)rowid;
- if (n == rowid)
- lua_pushnumber(L, n);
- else
- lua_pushfstring(L, "%ll", rowid);
- return 1;
-}
-
-static int db_changes(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushnumber(L, sqlite3_changes(db->db));
- return 1;
-}
-
-static int db_total_changes(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushnumber(L, sqlite3_total_changes(db->db));
- return 1;
-}
-
-static int db_errcode(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushnumber(L, sqlite3_errcode(db->db));
- return 1;
-}
-
-static int db_errmsg(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushstring(L, sqlite3_errmsg(db->db));
- return 1;
-}
-
-static int db_interrupt(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- sqlite3_interrupt(db->db);
- return 0;
-}
-
-/*
-** Registering SQL functions:
-*/
-
-static void db_push_value(lua_State *L, sqlite3_value *value) {
- switch (sqlite3_value_type(value)) {
- case SQLITE_TEXT:
- lua_pushlstring(L, (const char*)sqlite3_value_text(value), sqlite3_value_bytes(value));
- break;
-
- case SQLITE_INTEGER:
- {
- sqlite_int64 i64 = sqlite3_value_int64(value);
- lua_Number n = (lua_Number)i64;
- if (n == i64)
- lua_pushnumber(L, n);
- else
- lua_pushlstring(L, (const char*)sqlite3_value_text(value), sqlite3_value_bytes(value));
- }
- break;
-
- case SQLITE_FLOAT:
- lua_pushnumber(L, sqlite3_value_double(value));
- break;
-
- case SQLITE_BLOB:
- lua_pushlstring(L, (const char*)sqlite3_value_blob(value), sqlite3_value_bytes(value));
- break;
-
- case SQLITE_NULL:
- lua_pushnil(L);
- break;
-
- default:
- /* things done properly (SQLite + Lua SQLite)
- ** this should never happen */
- lua_pushnil(L);
- break;
- }
-}
-
-/*
-** callback functions used when calling registered sql functions
-*/
-
-/* scalar function to be called
-** callback params: context, values... */
-static void db_sql_normal_function(sqlite3_context *context, int argc, sqlite3_value **argv) {
- sdb_func *func = (sdb_func*)sqlite3_user_data(context);
- lua_State *L = func->db->L;
- int n;
- lcontext *ctx;
-
- int top = lua_gettop(L);
-
- /* ensure there is enough space in the stack */
- lua_checkstack(L, argc + 3);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_step); /* function to call */
-
- if (!func->aggregate) {
- ctx = lsqlite_make_context(L); /* push context - used to set results */
- }
- else {
- /* reuse context userdata value */
- void *p = sqlite3_aggregate_context(context, 1);
- /* i think it is OK to use assume that using a light user data
- ** as an entry on LUA REGISTRY table will be unique */
- lua_pushlightuserdata(L, p);
- lua_rawget(L, LUA_REGISTRYINDEX); /* context table */
-
- if (lua_isnil(L, -1)) { /* not yet created? */
- lua_pop(L, 1);
- ctx = lsqlite_make_context(L);
- lua_pushlightuserdata(L, p);
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
- else
- ctx = lsqlite_getcontext(L, -1);
- }
-
- /* push params */
- for (n = 0; n < argc; ++n) {
- db_push_value(L, argv[n]);
- }
-
- /* set context */
- ctx->ctx = context;
-
- if (lua_pcall(L, argc + 1, 0, 0)) {
- const char *errmsg = lua_tostring(L, -1);
- int size = lua_strlen(L, -1);
- sqlite3_result_error(context, errmsg, size);
- }
-
- /* invalidate context */
- ctx->ctx = NULL;
-
- if (!func->aggregate) {
- luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
- }
-
- lua_settop(L, top);
-}
-
-static void db_sql_finalize_function(sqlite3_context *context) {
- sdb_func *func = (sdb_func*)sqlite3_user_data(context);
- lua_State *L = func->db->L;
- void *p = sqlite3_aggregate_context(context, 1); /* minimal mem usage */
- lcontext *ctx;
- int top = lua_gettop(L);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_finalize); /* function to call */
-
- /* i think it is OK to use assume that using a light user data
- ** as an entry on LUA REGISTRY table will be unique */
- lua_pushlightuserdata(L, p);
- lua_rawget(L, LUA_REGISTRYINDEX); /* context table */
-
- if (lua_isnil(L, -1)) { /* not yet created? - shouldn't happen in finalize function */
- lua_pop(L, 1);
- ctx = lsqlite_make_context(L);
- lua_pushlightuserdata(L, p);
- lua_pushvalue(L, -2);
- lua_rawset(L, LUA_REGISTRYINDEX);
- }
- else
- ctx = lsqlite_getcontext(L, -1);
-
- /* set context */
- ctx->ctx = context;
-
- if (lua_pcall(L, 1, 0, 0)) {
- sqlite3_result_error(context, lua_tostring(L, -1), -1);
- }
-
- /* invalidate context */
- ctx->ctx = NULL;
-
- /* cleanup context */
- luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
- /* remove it from registry */
- lua_pushlightuserdata(L, p);
- lua_pushnil(L);
- lua_rawset(L, LUA_REGISTRYINDEX);
-
- lua_settop(L, top);
-}
-
-/*
-** Register a normal function
-** Params: db, function name, number arguments, [ callback | step, finalize], user data
-** Returns: true on sucess
-**
-** Normal function:
-** Params: context, params
-**
-** Aggregate function:
-** Params of step: context, params
-** Params of finalize: context
-*/
-static int db_register_function(lua_State *L, int aggregate) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *name;
- int args;
- int result;
- sdb_func *func;
-
- /* safety measure */
- if (aggregate) aggregate = 1;
-
- name = luaL_checkstring(L, 2);
- args = luaL_checkint(L, 3);
- luaL_checktype(L, 4, LUA_TFUNCTION);
- if (aggregate) luaL_checktype(L, 5, LUA_TFUNCTION);
-
- /* maybe an alternative way to allocate memory should be used/avoided */
- func = (sdb_func*)malloc(sizeof(sdb_func));
- if (func == NULL) {
- luaL_error(L, "out of memory");
- }
-
- result = sqlite3_create_function(
- db->db, name, args, SQLITE_UTF8, func,
- aggregate ? NULL : db_sql_normal_function,
- aggregate ? db_sql_normal_function : NULL,
- aggregate ? db_sql_finalize_function : NULL
- );
-
- if (result == SQLITE_OK) {
- /* safety measures for userdata field to be present in the stack */
- lua_settop(L, 5 + aggregate);
-
- /* save registered function in db function list */
- func->db = db;
- func->aggregate = aggregate;
- func->next = db->func;
- db->func = func;
-
- /* save the setp/normal function callback */
- lua_pushvalue(L, 4);
- func->fn_step = luaL_ref(L, LUA_REGISTRYINDEX);
- /* save user data */
- lua_pushvalue(L, 5+aggregate);
- func->udata = luaL_ref(L, LUA_REGISTRYINDEX);
-
- if (aggregate) {
- lua_pushvalue(L, 5);
- func->fn_finalize = luaL_ref(L, LUA_REGISTRYINDEX);
- }
- else
- func->fn_finalize = LUA_NOREF;
- }
- else {
- /* free allocated memory */
- free(func);
- }
-
- lua_pushboolean(L, result == SQLITE_OK ? 1 : 0);
- return 1;
-}
-
-static int db_create_function(lua_State *L) {
- return db_register_function(L, 0);
-}
-
-static int db_create_aggregate(lua_State *L) {
- return db_register_function(L, 1);
-}
-
-/* create_collation; contributed by Thomas Lauer
-*/
-
-typedef struct {
- lua_State *L;
- int ref;
-} scc;
-
-static int collwrapper(scc *co,int l1,const void *p1,
- int l2,const void *p2) {
- int res=0;
- lua_State *L=co->L;
- lua_rawgeti(L,LUA_REGISTRYINDEX,co->ref);
- lua_pushlstring(L,(const char*)p1,l1);
- lua_pushlstring(L,(const char*)p2,l2);
- if (lua_pcall(L,2,1,0)==0) res=lua_tonumber(L,-1);
- lua_pop(L,1);
- return res;
-}
-
-static void collfree(scc *co) {
- if (co) {
- luaL_unref(co->L,LUA_REGISTRYINDEX,co->ref);
- free(co);
- }
-}
-
-static int db_create_collation(lua_State *L) {
- sdb *db=lsqlite_checkdb(L,1);
- const char *collname=luaL_checkstring(L,2);
- scc *co=NULL;
- int (*collfunc)(scc *,int,const void *,int,const void *)=NULL;
- lua_settop(L,3); /* default args to nil, and exclude extras */
- if (lua_isfunction(L,3)) collfunc=collwrapper;
- else if (!lua_isnil(L,3))
- luaL_error(L,"create_collation: function or nil expected");
- if (collfunc != NULL) {
- co=(scc *)malloc(sizeof(scc)); /* userdata is a no-no as it
- will be garbage-collected */
- if (co) {
- co->L=L;
- /* lua_settop(L,3) above means we don't need: lua_pushvalue(L,3); */
- co->ref=luaL_ref(L,LUA_REGISTRYINDEX);
- }
- else luaL_error(L,"create_collation: could not allocate callback");
- }
- sqlite3_create_collation_v2(db->db, collname, SQLITE_UTF8,
- (void *)co,
- (int(*)(void*,int,const void*,int,const void*))collfunc,
- (void(*)(void*))collfree);
- return 0;
-}
-
-/*
-** trace callback:
-** Params: database, callback function, userdata
-**
-** callback function:
-** Params: userdata, sql
-*/
-static void db_trace_callback(void *user, const char *sql) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
-
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->trace_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->trace_udata); /* get callback user data */
- lua_pushstring(L, sql); /* traced sql statement */
-
- /* call lua function */
- lua_pcall(L, 2, 0, 0);
- /* ignore any error generated by this function */
-
- lua_settop(L, top);
-}
-
-static int db_trace(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
-
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
-
- db->trace_cb =
- db->trace_udata = LUA_NOREF;
-
- /* clear trace handler */
- sqlite3_trace(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
-
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
-
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->trace_udata);
-
- db->trace_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->trace_cb = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* set trace handler */
- sqlite3_trace(db->db, db_trace_callback, db);
- }
-
- return 0;
-}
-
-#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
-
-/*
-** update_hook callback:
-** Params: database, callback function, userdata
-**
-** callback function:
-** Params: userdata, {one of SQLITE_INSERT, SQLITE_DELETE, or SQLITE_UPDATE},
-** database name, table name (containing the affected row), rowid of the row
-*/
-static void db_update_hook_callback(void *user, int op, char const *dbname, char const *tblname, sqlite3_int64 rowid) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- lua_Number n;
-
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->update_hook_udata); /* get callback user data */
- lua_pushnumber(L, (lua_Number )op);
- lua_pushstring(L, dbname); /* update_hook database name */
- lua_pushstring(L, tblname); /* update_hook database name */
- n = (lua_Number)rowid;
- if (n == rowid)
- lua_pushnumber(L, n);
- else
- lua_pushfstring(L, "%ll", rowid);
-
- /* call lua function */
- lua_pcall(L, 5, 0, 0);
- /* ignore any error generated by this function */
-
- lua_settop(L, top);
-}
-
-static int db_update_hook(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
-
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
-
- db->update_hook_cb =
- db->update_hook_udata = LUA_NOREF;
-
- /* clear update_hook handler */
- sqlite3_update_hook(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
-
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
-
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->update_hook_udata);
-
- db->update_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->update_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* set update_hook handler */
- sqlite3_update_hook(db->db, db_update_hook_callback, db);
- }
-
- return 0;
-}
-
-/*
-** commit_hook callback:
-** Params: database, callback function, userdata
-**
-** callback function:
-** Params: userdata
-** Returned value: Return false or nil to continue the COMMIT operation normally.
-** return true (non false, non nil), then the COMMIT is converted into a ROLLBACK.
-*/
-static int db_commit_hook_callback(void *user) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
- int rollback = 0;
-
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->commit_hook_udata); /* get callback user data */
-
- /* call lua function */
- if (!lua_pcall(L, 1, 1, 0))
- rollback = lua_toboolean(L, -1); /* use result if there was no error */
-
- lua_settop(L, top);
- return rollback;
-}
-
-static int db_commit_hook(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
-
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
-
- db->commit_hook_cb =
- db->commit_hook_udata = LUA_NOREF;
-
- /* clear commit_hook handler */
- sqlite3_commit_hook(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
-
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
-
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->commit_hook_udata);
-
- db->commit_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->commit_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* set commit_hook handler */
- sqlite3_commit_hook(db->db, db_commit_hook_callback, db);
- }
-
- return 0;
-}
-
-/*
-** rollback hook callback:
-** Params: database, callback function, userdata
-**
-** callback function:
-** Params: userdata
-*/
-static void db_rollback_hook_callback(void *user) {
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
-
- /* setup lua callback call */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_cb); /* get callback */
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->rollback_hook_udata); /* get callback user data */
-
- /* call lua function */
- lua_pcall(L, 1, 0, 0);
- /* ignore any error generated by this function */
-
- lua_settop(L, top);
-}
-
-static int db_rollback_hook(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
-
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
-
- db->rollback_hook_cb =
- db->rollback_hook_udata = LUA_NOREF;
-
- /* clear rollback_hook handler */
- sqlite3_rollback_hook(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
-
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
-
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->rollback_hook_udata);
-
- db->rollback_hook_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->rollback_hook_cb = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* set rollback_hook handler */
- sqlite3_rollback_hook(db->db, db_rollback_hook_callback, db);
- }
-
- return 0;
-}
-
-#endif /* #if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK */
-
-#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK
-
-/*
-** progress handler:
-** Params: database, number of opcodes, callback function, userdata
-**
-** callback function:
-** Params: userdata
-** returns: 0 to return immediatly and return SQLITE_ABORT, non-zero to continue
-*/
-static int db_progress_callback(void *user) {
- int result = 1; /* abort by default */
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->progress_cb);
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->progress_udata);
-
- /* call lua function */
- if (!lua_pcall(L, 1, 1, 0))
- result = lua_toboolean(L, -1);
-
- lua_settop(L, top);
- return result;
-}
-
-static int db_progress_handler(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
-
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
-
- db->progress_cb =
- db->progress_udata = LUA_NOREF;
-
- /* clear busy handler */
- sqlite3_progress_handler(db->db, 0, NULL, NULL);
- }
- else {
- int nop = luaL_checkint(L, 2); /* number of opcodes */
- luaL_checktype(L, 3, LUA_TFUNCTION);
-
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 4);
-
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->progress_udata);
-
- db->progress_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->progress_cb = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* set progress callback */
- sqlite3_progress_handler(db->db, nop, db_progress_callback, db);
- }
-
- return 0;
-}
-
-#else /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
-
-static int db_progress_handler(lua_State *L) {
- lua_pushliteral(L, "progress callback support disabled at compile time");
- lua_error(L);
- return 0;
-}
-
-#endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
-
-/*
-** busy handler:
-** Params: database, callback function, userdata
-**
-** callback function:
-** Params: userdata, number of tries
-** returns: 0 to return immediatly and return SQLITE_BUSY, non-zero to try again
-*/
-static int db_busy_callback(void *user, int tries) {
- int retry = 0; /* abort by default */
- sdb *db = (sdb*)user;
- lua_State *L = db->L;
- int top = lua_gettop(L);
-
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->busy_cb);
- lua_rawgeti(L, LUA_REGISTRYINDEX, db->busy_udata);
- lua_pushnumber(L, tries);
-
- /* call lua function */
- if (!lua_pcall(L, 2, 1, 0))
- retry = lua_toboolean(L, -1);
-
- lua_settop(L, top);
- return retry;
-}
-
-static int db_busy_handler(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
-
- if (lua_gettop(L) < 2 || lua_isnil(L, 2)) {
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
-
- db->busy_cb =
- db->busy_udata = LUA_NOREF;
-
- /* clear busy handler */
- sqlite3_busy_handler(db->db, NULL, NULL);
- }
- else {
- luaL_checktype(L, 2, LUA_TFUNCTION);
- /* make sure we have an userdata field (even if nil) */
- lua_settop(L, 3);
-
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
-
- db->busy_udata = luaL_ref(L, LUA_REGISTRYINDEX);
- db->busy_cb = luaL_ref(L, LUA_REGISTRYINDEX);
-
- /* set busy handler */
- sqlite3_busy_handler(db->db, db_busy_callback, db);
- }
-
- return 0;
-}
-
-static int db_busy_timeout(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- int timeout = luaL_checkint(L, 2);
- sqlite3_busy_timeout(db->db, timeout);
-
- /* if there was a timeout callback registered, it is now
- ** invalid/useless. free any references we may have */
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_cb);
- luaL_unref(L, LUA_REGISTRYINDEX, db->busy_udata);
- db->busy_cb =
- db->busy_udata = LUA_NOREF;
-
- return 0;
-}
-
-/*
-** Params: db, sql, callback, user
-** returns: code [, errmsg]
-**
-** Callback:
-** Params: user, number of columns, values, names
-** Returns: 0 to continue, other value will cause abort
-*/
-static int db_exec_callback(void* user, int columns, char **data, char **names) {
- int result = SQLITE_ABORT; /* abort by default */
- lua_State *L = (lua_State*)user;
- int n;
-
- int top = lua_gettop(L);
-
- lua_pushvalue(L, 3); /* function to call */
- lua_pushvalue(L, 4); /* user data */
- lua_pushnumber(L, columns); /* total number of rows in result */
-
- /* column values */
- lua_pushvalue(L, 6);
- for (n = 0; n < columns;) {
- lua_pushstring(L, data[n++]);
- lua_rawseti(L, -2, n);
- }
-
- /* columns names */
- lua_pushvalue(L, 5);
- if (lua_isnil(L, -1)) {
- lua_pop(L, 1);
- lua_newtable(L);
- lua_pushvalue(L, -1);
- lua_replace(L, 5);
- for (n = 0; n < columns;) {
- lua_pushstring(L, names[n++]);
- lua_rawseti(L, -2, n);
- }
- }
-
- /* call lua function */
- if (!lua_pcall(L, 4, 1, 0)) {
- if (lua_isnumber(L, -1))
- result = lua_tonumber(L, -1);
- }
-
- lua_settop(L, top);
- return result;
-}
-
-static int db_exec(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *sql = luaL_checkstring(L, 2);
- int result;
-
- if (!lua_isnoneornil(L, 3)) {
- /* stack:
- ** 3: callback function
- ** 4: userdata
- ** 5: column names
- ** 6: reusable column values
- */
- luaL_checktype(L, 3, LUA_TFUNCTION);
- lua_settop(L, 4); /* 'trap' userdata - nil extra parameters */
- lua_pushnil(L); /* column names not known at this point */
- lua_newtable(L); /* column values table */
-
- result = sqlite3_exec(db->db, sql, db_exec_callback, L, NULL);
- }
- else {
- /* no callbacks */
- result = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
- }
-
- lua_pushnumber(L, result);
- return 1;
-}
-
-/*
-** Params: db, sql
-** returns: code, compiled length or error message
-*/
-static int db_prepare(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *sql = luaL_checkstring(L, 2);
- int sql_len = lua_strlen(L, 2);
- const char *sqltail;
- sdb_vm *svm;
- lua_settop(L,2); /* sql is on top of stack for call to newvm */
- svm = newvm(L, db);
-
- if (sqlite3_prepare(db->db, sql, sql_len, &svm->vm, &sqltail) != SQLITE_OK) {
- cleanupvm(L, svm);
-
- lua_pushnil(L);
- lua_pushnumber(L, sqlite3_errcode(db->db));
- return 2;
- }
-
- /* vm already in the stack */
- lua_pushstring(L, sqltail);
- return 2;
-}
-
-static int db_do_next_row(lua_State *L, int packed) {
- int result;
- sdb_vm *svm = lsqlite_checkvm(L, 1);
- sqlite3_stmt *vm;
- int columns;
- int i;
-
- result = stepvm(L, svm);
- vm = svm->vm; /* stepvm may change svm->vm if re-prepare is needed */
- svm->has_values = result == SQLITE_ROW ? 1 : 0;
- svm->columns = columns = sqlite3_data_count(vm);
-
- if (result == SQLITE_ROW) {
- if (packed) {
- lua_newtable(L);
- if (packed == 1) {
- for (i = 0; i < columns;) {
- vm_push_column(L, vm, i);
- lua_rawseti(L, -2, ++i);
- }
- }
- else {
- for (i = 0; i < columns; ++i) {
- lua_pushstring(L, sqlite3_column_name(vm, i));
- vm_push_column(L, vm, i);
- lua_rawset(L, -3);
- }
- }
- return 1;
- }
- else {
- lua_checkstack(L, columns);
- for (i = 0; i < columns; ++i)
- vm_push_column(L, vm, i);
- return svm->columns;
- }
- }
-
- if (svm->temp) {
- /* finalize and check for errors */
- result = sqlite3_finalize(vm);
- svm->vm = NULL;
- cleanupvm(L, svm);
- }
- else if (result == SQLITE_DONE) {
- result = sqlite3_reset(vm);
- }
-
- if (result != SQLITE_OK) {
- lua_pushstring(L, sqlite3_errmsg(svm->db->db));
- lua_error(L);
- }
- return 0;
-}
-
-static int db_next_row(lua_State *L) {
- return db_do_next_row(L, 0);
-}
-
-static int db_next_packed_row(lua_State *L) {
- return db_do_next_row(L, 1);
-}
-
-static int db_next_named_row(lua_State *L) {
- return db_do_next_row(L, 2);
-}
-
-static int dbvm_do_rows(lua_State *L, int(*f)(lua_State *)) {
- /* sdb_vm *svm = */
- lsqlite_checkvm(L, 1);
- lua_pushvalue(L,1);
- lua_pushcfunction(L, f);
- lua_insert(L, -2);
- return 2;
-}
-
-static int dbvm_rows(lua_State *L) {
- return dbvm_do_rows(L, db_next_packed_row);
-}
-
-static int dbvm_nrows(lua_State *L) {
- return dbvm_do_rows(L, db_next_named_row);
-}
-
-static int dbvm_urows(lua_State *L) {
- return dbvm_do_rows(L, db_next_row);
-}
-
-static int db_do_rows(lua_State *L, int(*f)(lua_State *)) {
- sdb *db = lsqlite_checkdb(L, 1);
- const char *sql = luaL_checkstring(L, 2);
- sdb_vm *svm;
- lua_settop(L,2); /* sql is on top of stack for call to newvm */
- svm = newvm(L, db);
- svm->temp = 1;
-
- if (sqlite3_prepare(db->db, sql, -1, &svm->vm, NULL) != SQLITE_OK) {
- cleanupvm(L, svm);
-
- lua_pushstring(L, sqlite3_errmsg(svm->db->db));
- lua_error(L);
- }
-
- lua_pushcfunction(L, f);
- lua_insert(L, -2);
- return 2;
-}
-
-static int db_rows(lua_State *L) {
- return db_do_rows(L, db_next_packed_row);
-}
-
-static int db_nrows(lua_State *L) {
- return db_do_rows(L, db_next_named_row);
-}
-
-/* unpacked version of db:rows */
-static int db_urows(lua_State *L) {
- return db_do_rows(L, db_next_row);
-}
-
-static int db_tostring(lua_State *L) {
- char buff[32];
- sdb *db = lsqlite_getdb(L, 1);
- if (db->db == NULL)
- strcpy(buff, "closed");
- else
- sprintf(buff, "%p", lua_touserdata(L, 1));
- lua_pushfstring(L, "sqlite database (%s)", buff);
- return 1;
-}
-
-static int db_close(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- lua_pushnumber(L, cleanupdb(L, db));
- return 1;
-}
-
-static int db_close_vm(lua_State *L) {
- sdb *db = lsqlite_checkdb(L, 1);
- /* cleanup temporary only tables? */
- int temp = lua_toboolean(L, 2);
-
- /* free associated virtual machines */
- lua_pushlightuserdata(L, db);
- lua_rawget(L, LUA_REGISTRYINDEX);
-
- /* close all used handles */
- lua_pushnil(L);
- while (lua_next(L, -2)) {
- sdb_vm *svm = (sdb_vm *)lua_touserdata(L, -2); /* key: vm; val: sql text */
-
- if ((!temp || svm->temp) && svm->vm)
- {
- sqlite3_finalize(svm->vm);
- svm->vm = NULL;
- }
-
- /* leave key in the stack */
- lua_pop(L, 1);
- }
- return 0;
-}
-
-static int db_gc(lua_State *L) {
- sdb *db = lsqlite_getdb(L, 1);
- if (db->db != NULL) /* ignore closed databases */
- cleanupdb(L, db);
- return 0;
-}
-
-/*
-** =======================================================
-** General library functions
-** =======================================================
-*/
-
-static int lsqlite_version(lua_State *L) {
- lua_pushstring(L, sqlite3_libversion());
- return 1;
-}
-
-static int lsqlite_complete(lua_State *L) {
- const char *sql = luaL_checkstring(L, 1);
- lua_pushboolean(L, sqlite3_complete(sql));
- return 1;
-}
-
-#ifndef WIN32
-static int lsqlite_temp_directory(lua_State *L) {
- const char *oldtemp = sqlite3_temp_directory;
-
- if (!lua_isnone(L, 1)) {
- const char *temp = luaL_optstring(L, 1, NULL);
- if (sqlite3_temp_directory) {
- sqlite3_free((char*)sqlite3_temp_directory);
- }
- if (temp) {
- sqlite3_temp_directory = sqlite3_mprintf("%s", temp);
- }
- else {
- sqlite3_temp_directory = NULL;
- }
- }
- lua_pushstring(L, oldtemp);
- return 1;
-}
-#endif
-
-static int lsqlite_do_open(lua_State *L, const char *filename) {
- sdb *db = newdb(L); /* create and leave in stack */
-
- if (sqlite3_open(filename, &db->db) == SQLITE_OK) {
- /* database handle already in the stack - return it */
- return 1;
- }
-
- /* failed to open database */
- lua_pushnil(L); /* push nil */
- lua_pushnumber(L, sqlite3_errcode(db->db));
- lua_pushstring(L, sqlite3_errmsg(db->db)); /* push error message */
-
- /* clean things up */
- cleanupdb(L, db);
-
- /* return */
- return 3;
-}
-
-static int lsqlite_open(lua_State *L) {
- const char *filename = luaL_checkstring(L, 1);
- return lsqlite_do_open(L, filename);
-}
-
-static int lsqlite_open_memory(lua_State *L) {
- return lsqlite_do_open(L, ":memory:");
-}
-
-static int lsqlite_newindex(lua_State *L) {
- lua_pushliteral(L, "attempt to change readonly table");
- lua_error(L);
- return 0;
-}
-
-/*
-** =======================================================
-** Register functions
-** =======================================================
-*/
-
-#define SC(s) { #s, SQLITE_ ## s },
-#define LSC(s) { #s, LSQLITE_ ## s },
-
-static const struct {
- const char* name;
- int value;
-} sqlite_constants[] = {
- /* error codes */
- SC(OK) SC(ERROR) SC(INTERNAL) SC(PERM)
- SC(ABORT) SC(BUSY) SC(LOCKED) SC(NOMEM)
- SC(READONLY) SC(INTERRUPT) SC(IOERR) SC(CORRUPT)
- SC(NOTFOUND) SC(FULL) SC(CANTOPEN) SC(PROTOCOL)
- SC(EMPTY) SC(SCHEMA) SC(TOOBIG) SC(CONSTRAINT)
- SC(MISMATCH) SC(MISUSE) SC(NOLFS)
- SC(FORMAT) SC(NOTADB)
-
- /* sqlite_step specific return values */
- SC(RANGE) SC(ROW) SC(DONE)
-
- /* column types */
- SC(INTEGER) SC(FLOAT) SC(TEXT) SC(BLOB)
- SC(NULL)
-
- /* Authorizer Action Codes */
- SC(CREATE_INDEX )
- SC(CREATE_TABLE )
- SC(CREATE_TEMP_INDEX )
- SC(CREATE_TEMP_TABLE )
- SC(CREATE_TEMP_TRIGGER)
- SC(CREATE_TEMP_VIEW )
- SC(CREATE_TRIGGER )
- SC(CREATE_VIEW )
- SC(DELETE )
- SC(DROP_INDEX )
- SC(DROP_TABLE )
- SC(DROP_TEMP_INDEX )
- SC(DROP_TEMP_TABLE )
- SC(DROP_TEMP_TRIGGER )
- SC(DROP_TEMP_VIEW )
- SC(DROP_TRIGGER )
- SC(DROP_VIEW )
- SC(INSERT )
- SC(PRAGMA )
- SC(READ )
- SC(SELECT )
- SC(TRANSACTION )
- SC(UPDATE )
- SC(ATTACH )
- SC(DETACH )
- SC(ALTER_TABLE )
- SC(REINDEX )
- SC(ANALYZE )
- SC(CREATE_VTABLE )
- SC(DROP_VTABLE )
- SC(FUNCTION )
- SC(SAVEPOINT )
-
- /* terminator */
- { NULL, 0 }
-};
-
-/* ======================================================= */
-
-static const luaL_Reg dblib[] = {
- {"isopen", db_isopen },
- {"last_insert_rowid", db_last_insert_rowid },
- {"changes", db_changes },
- {"total_changes", db_total_changes },
- {"errcode", db_errcode },
- {"error_code", db_errcode },
- {"errmsg", db_errmsg },
- {"error_message", db_errmsg },
- {"interrupt", db_interrupt },
-
- {"create_function", db_create_function },
- {"create_aggregate", db_create_aggregate },
- {"create_collation", db_create_collation },
-
- {"trace", db_trace },
- {"progress_handler", db_progress_handler },
- {"busy_timeout", db_busy_timeout },
- {"busy_handler", db_busy_handler },
-#if !defined(LSQLITE_OMIT_UPDATE_HOOK) || !LSQLITE_OMIT_UPDATE_HOOK
- {"update_hook", db_update_hook },
- {"commit_hook", db_commit_hook },
- {"rollback_hook", db_rollback_hook },
-#endif
-
- {"prepare", db_prepare },
- {"rows", db_rows },
- {"urows", db_urows },
- {"nrows", db_nrows },
-
- {"exec", db_exec },
- {"execute", db_exec },
- {"close", db_close },
- {"close_vm", db_close_vm },
-
- {"__tostring", db_tostring },
- {"__gc", db_gc },
-
- {NULL, NULL}
-};
-
-static const luaL_Reg vmlib[] = {
- {"isopen", dbvm_isopen },
-
- {"step", dbvm_step },
- {"reset", dbvm_reset },
- {"finalize", dbvm_finalize },
-
- {"columns", dbvm_columns },
-
- {"bind", dbvm_bind },
- {"bind_values", dbvm_bind_values },
- {"bind_names", dbvm_bind_names },
- {"bind_blob", dbvm_bind_blob },
- {"bind_parameter_count",dbvm_bind_parameter_count},
- {"bind_parameter_name", dbvm_bind_parameter_name},
-
- {"get_value", dbvm_get_value },
- {"get_values", dbvm_get_values },
- {"get_name", dbvm_get_name },
- {"get_names", dbvm_get_names },
- {"get_type", dbvm_get_type },
- {"get_types", dbvm_get_types },
- {"get_uvalues", dbvm_get_uvalues },
- {"get_unames", dbvm_get_unames },
- {"get_utypes", dbvm_get_utypes },
-
- {"get_named_values", dbvm_get_named_values },
- {"get_named_types", dbvm_get_named_types },
-
- {"rows", dbvm_rows },
- {"urows", dbvm_urows },
- {"nrows", dbvm_nrows },
-
- /* compatibility names (added by request) */
- {"idata", dbvm_get_values },
- {"inames", dbvm_get_names },
- {"itypes", dbvm_get_types },
- {"data", dbvm_get_named_values },
- {"type", dbvm_get_named_types },
-
- {"__tostring", dbvm_tostring },
- {"__gc", dbvm_gc },
-
- { NULL, NULL }
-};
-
-static const luaL_Reg ctxlib[] = {
- {"user_data", lcontext_user_data },
-
- {"get_aggregate_data", lcontext_get_aggregate_context },
- {"set_aggregate_data", lcontext_set_aggregate_context },
- {"aggregate_count", lcontext_aggregate_count },
-
- {"result", lcontext_result },
- {"result_null", lcontext_result_null },
- {"result_number", lcontext_result_double },
- {"result_double", lcontext_result_double },
- {"result_int", lcontext_result_int },
- {"result_text", lcontext_result_text },
- {"result_blob", lcontext_result_blob },
- {"result_error", lcontext_result_error },
-
- {"__tostring", lcontext_tostring },
- {NULL, NULL}
-};
-
-static const luaL_Reg sqlitelib[] = {
- {"version", lsqlite_version },
- {"complete", lsqlite_complete },
-#ifndef WIN32
- {"temp_directory", lsqlite_temp_directory },
-#endif
- {"open", lsqlite_open },
- {"open_memory", lsqlite_open_memory },
-
- {"__newindex", lsqlite_newindex },
- {NULL, NULL}
-};
-
-static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
- luaL_newmetatable(L, name);
- lua_pushstring(L, "__index");
- lua_pushvalue(L, -2); /* push metatable */
- lua_rawset(L, -3); /* metatable.__index = metatable */
-
- /* register metatable functions */
- luaL_openlib(L, NULL, lib, 0);
-
- /* remove metatable from stack */
- lua_pop(L, 1);
-}
-
-static int luaopen_sqlite3 ( lua_State * L )
-{
- luaL_newlib(L, sqlitelib);
- return 1;
-}
-
-LUALIB_API int luaopen_lsqlite3(lua_State *L) {
- create_meta(L, sqlite_meta, dblib);
- create_meta(L, sqlite_vm_meta, vmlib);
- create_meta(L, sqlite_ctx_meta, ctxlib);
-
- luaL_getmetatable(L, sqlite_ctx_meta);
- sqlite_ctx_meta_ref = luaL_ref(L, LUA_REGISTRYINDEX);
- /* register (local) sqlite metatable */
- //luaL_register(L, "sqlite3", sqlitelib);
- luaL_requiref(L, "sqlite3", luaopen_sqlite3, 1);
- {
- int i = 0;
- /* add constants to global table */
- while (sqlite_constants[i].name) {
- lua_pushstring(L, sqlite_constants[i].name);
- lua_pushnumber(L, sqlite_constants[i].value);
- lua_rawset(L, -3);
- ++i;
- }
- }
- /* set sqlite's metatable to itself - set as readonly (__newindex) */
- lua_pushvalue(L, -1);
- lua_setmetatable(L, -2);
-
- return 1;
-}
diff --git a/src/lib/lua/lib/lualibs.h b/src/lib/lua/lib/lualibs.h
deleted file mode 100644
index 4038eddff5d..00000000000
--- a/src/lib/lua/lib/lualibs.h
+++ /dev/null
@@ -1,8 +0,0 @@
-#ifndef LUALIBS_H
-#define LUALIBS_H
-
-extern "C" {
- int luaopen_lsqlite3(lua_State *L);
-}
-
-#endif //LUALIBS_H