diff options
author | 2015-01-10 14:50:15 +0100 | |
---|---|---|
committer | 2015-01-10 14:50:15 +0100 | |
commit | 001b907d02cc15414b396625549c5d09faf1a223 (patch) | |
tree | 2f910e652e1d34ae29e103c2c0a3189dd277131b | |
parent | b8e52b09c37877bf301ca64e76db3131010c5fb6 (diff) |
added lsqlite3 full source
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("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</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<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,"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')</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 <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. * + ************************************************************************/</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 |