Import to git
commit
1ea37c5271
|
@ -0,0 +1,24 @@
|
|||
# Copyright (C) 2007-2009 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(dist.cmake)
|
||||
|
||||
# Find SQLite3
|
||||
FIND_PACKAGE(SQLite3 REQUIRED)
|
||||
INCLUDE_DIRECTORIES (${SQLITE3_INCLUDE_DIRS})
|
||||
|
||||
# Create lsqlite module
|
||||
ADD_LUA_MODULE(lsqlite3 lsqlite3.c lsqlite3.def)
|
||||
TARGET_LINK_LIBRARIES(lsqlite3 ${SQLITE3_LIBRARIES})
|
||||
|
||||
# install lsqlite
|
||||
INSTALL(TARGETS lsqlite3 DESTINATION ${INSTALL_CMOD})
|
||||
INSTALL(FILES HISTORY README DESTINATION ${INSTALL_DATA})
|
||||
INSTALL(DIRECTORY doc/ DESTINATION ${INSTALL_DOC})
|
||||
INSTALL(FILES lunit.lua test.lua tests-sqlite3.lua DESTINATION ${INSTALL_TEST})
|
||||
INSTALL(DIRECTORY examples/ DESTINATION ${INSTALL_EXAMPLE})
|
|
@ -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 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)
|
|
@ -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
|
||||
************************************************************************/
|
|
@ -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
|
|
@ -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/
|
|
@ -0,0 +1,130 @@
|
|||
# LuaDist CMake utility library.
|
||||
# Provides variables and utility functions common to LuaDist CMake builds.
|
||||
#
|
||||
# Copyright (C) 2007-2010 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.
|
||||
|
||||
# Few convinence settings
|
||||
SET (CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true)
|
||||
SET (CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_MODULE_PATH})
|
||||
|
||||
# Where to install module parts:
|
||||
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_LMOD share/lua/lmod CACHE PATH "Directory to install Lua modules.")
|
||||
set(INSTALL_CMOD share/lua/cmod CACHE PATH "Directory to install Lua binary modules.")
|
||||
set(INSTALL_DATA share/${PROJECT_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")
|
||||
|
||||
|
||||
# In MSVC, prevent warnings that can occur when using standard libraries.
|
||||
if(MSVC)
|
||||
add_definitions(-D_CRT_SECURE_NO_WARNINGS)
|
||||
endif(MSVC)
|
||||
|
||||
# Adds Lua shared library module target `_target`.
|
||||
# Additional sources to build the module are listed after `_target`.
|
||||
macro(add_lua_module _target)
|
||||
find_package(Lua51 REQUIRED)
|
||||
include_directories(${LUA_INCLUDE_DIR}) #2DO: somehow apply only to _target?
|
||||
|
||||
add_library(${_target} MODULE ${ARGN})
|
||||
set_target_properties(${_target} PROPERTIES PREFIX "")
|
||||
target_link_libraries(${_target} ${LUA_LIBRARY})
|
||||
|
||||
IF(WIN32)
|
||||
set_target_properties(${_target} PROPERTIES LINK_FLAGS "-Wl,--enable-auto-import")
|
||||
ENDIF()
|
||||
|
||||
endmacro(add_lua_module)
|
||||
|
||||
# Runs Lua script `_testfile` under CTest tester.
|
||||
# Optional argument `_testcurrentdir` 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}.
|
||||
# Under LuaDist, set test=true in config.lua to enable testing.
|
||||
macro(add_lua_test _testfile)
|
||||
include(CTest)
|
||||
if(BUILD_TESTING)
|
||||
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.
|
||||
set(TESTWRAPPER ${CMAKE_CURRENT_BINARY_DIR}/${TESTFILENAME})
|
||||
set(TESTWRAPPERSOURCE
|
||||
"package.path = '${CMAKE_CURRENT_BINARY_DIR}/?.lua\;${CMAKE_CURRENT_SOURCE_DIR}/?.lua\;' .. package.path
|
||||
package.cpath = '${CMAKE_CURRENT_BINARY_DIR}/?.so\;${CMAKE_CURRENT_BINARY_DIR}/?.dll\;' .. package.cpath
|
||||
return dofile '${TESTFILEABS}'
|
||||
" )
|
||||
if(${ARGC} GREATER 1)
|
||||
set(_testcurrentdir ${ARGV1})
|
||||
get_filename_component(TESTCURRENTDIRABS ${_testcurrentdir} ABSOLUTE)
|
||||
set(TESTWRAPPERSOURCE
|
||||
"require 'lfs'
|
||||
lfs.chdir('${TESTCURRENTDIRABS}')
|
||||
${TESTWRAPPERSOURCE}")
|
||||
endif()
|
||||
FILE(WRITE ${TESTWRAPPER} ${TESTWRAPPERSOURCE})
|
||||
|
||||
add_test(${TESTFILEBASE} ${LUA} ${TESTWRAPPER})
|
||||
endif(BUILD_TESTING)
|
||||
|
||||
# see also http://gdcm.svn.sourceforge.net/viewvc/gdcm/Sandbox/CMakeModules/UsePythonTest.cmake
|
||||
endmacro(add_lua_test)
|
||||
|
||||
# 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(add_lua_bin2c)
|
|
@ -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"
|
||||
}
|
|
@ -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>
|
|
@ -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. *
|
||||
************************************************************************/
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
#!perl
|
||||
|
||||
use Pod::Html;
|
||||
|
||||
pod2html @ARGV;
|
||||
|
||||
__END__
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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()
|
|
@ -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
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,2 @@
|
|||
EXPORTS
|
||||
luaopen_lsqlite3
|
|
@ -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
|
||||
|
||||
|
||||
|
||||
|
|
@ -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())
|
|
@ -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()
|
Loading…
Reference in New Issue