LuaSQLite3

Check-in [ded1fb4786]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix db_exec_callback to be thread safe. Add rockspec. Cleanup; see HISTORY.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ded1fb4786204353f65dcacb418a95fbb9d1ef56
User & Date: e@ecd9bf9a-ecc1-ed47-8102-3ce978d4cc14 2010-03-05 01:51:00
Context
2011-01-10
22:27
Add changes from Ronny Dierckx check-in: a2e54aefb5 user: e@ecd9bf9a-ecc1-ed47-8102-3ce978d4cc14 tags: trunk
2010-03-05
01:51
Fix db_exec_callback to be thread safe. Add rockspec. Cleanup; see HISTORY. check-in: ded1fb4786 user: e@ecd9bf9a-ecc1-ed47-8102-3ce978d4cc14 tags: trunk
2007-08-17
21:42
Add collation support, tests, and doco from Thomas Lauer Convert doco to POD format Test with SQLite 3.4.2 Add html target to Makefile for converting POD doco Update HISTORY and README check-in: 7666e33cec user: e@ecd9bf9a-ecc1-ed47-8102-3ce978d4cc14 tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to HISTORY.































1
2
3
4
5
6
7






























2007-August-15 e

Version "0.6-devel"

Since the "0.5-devel" release of this Lua library...

Tested with SQLite 3.4.2
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
2010-February-14

Version "0.7-devel"

Since the "0.6-devel" release of this Lua library...

Made db_exec_callback thread safe.
Thanks to Grant Robinson.

Bug fix in dbvm_bind_index error message.
Thanks to Dirk Feytons.

Added a few casts and changed a few comments to ANSI C style.
Thanks to Corey Stup.

Note that Thomas Lauer has a patch referenced on LuaForge
to make collations thread safe(r). This issue is still 
under investigation: the patch has wide ranging affect
and to me it appears unsafe wrt GC. The whole issue of 
thread references in callbacks deserves thorough review.
A new design that places referenced values in the upvalues
of the callback function (rather than in the registry of 
the function defining thread) would be preferable. It may
also make sense to keep thread references in a shared 
environment of the library's functions, and/or require
all callbacks to be defined in the main lua state (so 
they the state is guaranteed to outlive other threads).

-=-

2007-August-15 e

Version "0.6-devel"

Since the "0.5-devel" release of this Lua library...

Tested with SQLite 3.4.2

Changes to Makefile.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

22
23
24
25
26
27
28
29
30
31
32
33





34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50

51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
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
|






<
<
<
<
<
<







|
>
|
<
|
|
<
<
<
<




>
>
>
>
>









|





|
|
>











|













|
|
|



|
|
|
|
|











|








1
2
3
4
5
6
7






8
9
10
11
12
13
14
15
16
17

18
19




20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
# 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)






  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
  LUALIB=
  SQLITE3INC= -I$(BASE)/include
  SQLITE3LIB= -L$(BASE)/lib -lsqlite3

#  Windows' LUALIB is the same as the Lua executable's directory...
#  LUALIB= -L$(BASE)/bin -llua51




  #
  POD2HTML= perl -x -S doc/pod2html.pl
endif

LUAEXE= lua

INSTALL= install -p
INSTALLPATH= $(LUAEXE) installpath.lua

TMP=./tmp
DISTDIR=./archive

# OS detection
#
SHFLAGS=-shared
UNAME= $(shell uname)
ifeq "$(UNAME)" "Linux"
  _SO=so
  SHFLAGS=-shared -fPIC
endif
ifneq "" "$(findstring BSD,$(UNAME))"
  _SO=so
endif
ifeq "$(UNAME)" "Darwin"
  _SO=so
  SHFLAGS=-fPIC -arch i686 -arch x86_64
  SOFLAGS=-dynamiclib -single_module -undefined dynamic_lookup -arch i686 -arch x86_64
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 -fomit-frame-pointer $(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) $(SOFLAGS) -o $@ $(OBJS) $(LIBS)

install: $(T)
	$(INSTALL) $< `$(INSTALLPATH) $(MYLIB)`

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 . $(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

Added installpath.lua.





























>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
-- Script to find the install path for a C module. Public domain.

if not arg or not arg[1] then
  io.write("Usage: lua installpath.lua modulename\n")
  os.exit(1)
end
for p in string.gfind(package.cpath, "[^;]+") do
  if string.sub(p, 1, 1) ~= "." then
    local p2 = string.gsub(arg[1], "%.", string.sub(package.config, 1, 1))
    io.write(string.gsub(p, "%?", p2), "\n")
    return
  end
end
error("no suitable installation path found")

Added lsqlite3-0.7-1.rockspec.











































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
package = "lsqlite3"
version = "0.7-1"
source = {
    url = "http://luaforge.net/frs/download.php/2565/lsqlite3-7.tar.gz"
}
description = {
    summary = "A binding for Lua to the SQLite3 database library",
    detailed = [[
        lsqlite3 is a thin wrapper around the public domain SQLite3 database engine. 
        The lsqlite3 module supports the creation and manipulation of SQLite3 databases. 
        After a require('lsqlite3') the exported functions are called with prefix sqlite3. 
        However, most sqlite3 functions are called via an object-oriented interface to 
        either database or SQL statement objects.
    ]],
    license = "MIT/X11",
    homepage = "http://luaforge.net/projects/luasqlite/"
}
dependencies = {
    "lua >= 5.1"
}
external_dependencies = {
    SQLITE = {
        header = "sqlite3.h"
    }
}
build = {
    type = "builtin",
    modules = {
        lsqlite3 = {
            sources = { "lsqlite3.c" },
            libraries = { "sqlite3" },
            incdirs = { "$(SQLITE_INCDIR)" },
            libdirs = { "$(SQLITE_LIBDIR)" }
        }
    },
	copy_directories = { 'doc', 'examples' }
}

Changes to lsqlite3.c.

26
27
28
29
30
31
32

33
34
35
36
37
38
39
..
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
...
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
...
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
...
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
....
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
....
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
....
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
....
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                *
************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <assert.h>


#include "lua.h"
#include "lauxlib.h"

#include "sqlite3.h"

/* compile time features */
#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK)
................................................................................
        case SQLITE_INTEGER:
            {
                sqlite_int64 i64 = sqlite3_column_int64(vm, idx);
                lua_Number n = (lua_Number)i64;
                if (n == i64)
                    lua_pushnumber(L, n);
                else
                    lua_pushlstring(L, sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
            }
            break;
        case SQLITE_FLOAT:
            lua_pushnumber(L, sqlite3_column_double(vm, idx));
            break;
        case SQLITE_TEXT:
            lua_pushlstring(L, sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
            break;
        case SQLITE_BLOB:
            lua_pushlstring(L, sqlite3_column_blob(vm, idx), sqlite3_column_bytes(vm, idx));
            break;
        case SQLITE_NULL:
            lua_pushnil(L);
            break;
................................................................................
        case LUA_TNONE:
        case LUA_TNIL:
        /* allow boolean values so i have a way to know which
        ** values were actually not set */
        case LUA_TBOOLEAN:
            return sqlite3_bind_null(vm, index);
        default:
            luaL_error(L, "index (%d) - invalid data type for bind (%s)", index, lua_typename(L, lindex));
            return SQLITE_MISUSE; /*!*/
    }
}


static int dbvm_bind_parameter_count(lua_State *L) {
    sdb_vm *svm = lsqlite_checkvm(L, 1);
................................................................................
/*
** Registering SQL functions:
*/

static void db_push_value(lua_State *L, sqlite3_value *value) {
    switch (sqlite3_value_type(value)) {
        case SQLITE_TEXT:
            lua_pushlstring(L, sqlite3_value_text(value), sqlite3_value_bytes(value));
            break;

        case SQLITE_INTEGER:
            {
                sqlite_int64 i64 = sqlite3_value_int64(value);
                lua_Number n = (lua_Number)i64;
                if (n == i64)
                    lua_pushnumber(L, n);
                else
                    lua_pushlstring(L, sqlite3_value_text(value), sqlite3_value_bytes(value));
            }
            break;

        case SQLITE_FLOAT:
            lua_pushnumber(L, sqlite3_value_double(value));
            break;

................................................................................

    lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_step);   /* function to call */

    if (!func->aggregate) {
        ctx = lsqlite_make_context(L); /* push context - used to set results */
    }
    else {
        // reuse context userdata value

        void *p = sqlite3_aggregate_context(context, 1);
        /* i think it is OK to use assume that using a light user data
        ** as an entry on LUA REGISTRY table will be unique */
        lua_pushlightuserdata(L, p);
        lua_rawget(L, LUA_REGISTRYINDEX);       /* context table */

        if (lua_isnil(L, -1)) { /* not yet created? */
................................................................................
    }

    /* push params */
    for (n = 0; n < argc; ++n) {
        db_push_value(L, argv[n]);
    }

    // set context
    ctx->ctx = context;

    if (lua_pcall(L, argc + 1, 0, 0)) {
        const char *errmsg = lua_tostring(L, -1);
        int size = lua_strlen(L, -1);
        sqlite3_result_error(context, errmsg, size);
    }

    // invalidate context
    ctx->ctx = NULL;

    if (!func->aggregate) {
        luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
    }

    lua_settop(L, top);
................................................................................
        lua_pushlightuserdata(L, p);
        lua_pushvalue(L, -2);
        lua_rawset(L, LUA_REGISTRYINDEX);
    }
    else
        ctx = lsqlite_getcontext(L, -1);

    // set context
    ctx->ctx = context;

    if (lua_pcall(L, 1, 0, 0)) {
        sqlite3_result_error(context, lua_tostring(L, -1), -1);
    }

    // invalidate context
    ctx->ctx = NULL;

    /* cleanup context */
    luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
    /* remove it from registry */
    lua_pushlightuserdata(L, p);
    lua_pushnil(L);
................................................................................
    scc *co=NULL;
    int (*collfunc)(scc *,int,const void *,int,const void *)=NULL;
    lua_settop(L,3); /* default args to nil, and exclude extras */
    if (lua_isfunction(L,3)) collfunc=collwrapper;
    else if (!lua_isnil(L,3))
        luaL_error(L,"create_collation: function or nil expected");
    if (collfunc != NULL) {
        co=(scc *)malloc(sizeof(scc)); // userdata is a no-no as it
                                         // will be garbage-collected
        if (co) {
            co->L=L;
            /* lua_settop(L,3) above means we don't need: lua_pushvalue(L,3); */
            co->ref=luaL_ref(L,LUA_REGISTRYINDEX);
        }
        else luaL_error(L,"create_collation: could not allocate callback");
    }
................................................................................
**
** Callback:
** Params: user, number of columns, values, names
** Returns: 0 to continue, other value will cause abort
*/
static int db_exec_callback(void* user, int columns, char **data, char **names) {
    int result = SQLITE_ABORT; /* abort by default */
    sdb *db = (sdb*)user;
    lua_State *L = db->L;
    int n;

    int top = lua_gettop(L);

    lua_pushvalue(L, 3); /* function to call */
    lua_pushvalue(L, 4); /* user data */
    lua_pushnumber(L, columns); /* total number of rows in result */
................................................................................
        **  6: reusable column values
        */
        luaL_checktype(L, 3, LUA_TFUNCTION);
        lua_settop(L, 4);   /* 'trap' userdata - nil extra parameters */
        lua_pushnil(L);     /* column names not known at this point */
        lua_newtable(L);    /* column values table */

        result = sqlite3_exec(db->db, sql, db_exec_callback, db, NULL);
    }
    else {
        /* no callbacks */
        result = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
    }

    lua_pushnumber(L, result);
................................................................................
}

static int db_next_named_row(lua_State *L) {
    return db_do_next_row(L, 2);
}

static int dbvm_do_rows(lua_State *L, int(*f)(lua_State *)) {
    //sdb_vm *svm = 
    lsqlite_checkvm(L, 1);
    lua_pushvalue(L,1);
    lua_pushcfunction(L, f);
    lua_insert(L, -2);
    return 2;
}








>







 







|






|







 







|







 







|









|







 







|
<







 







|








|







 







|






|







 







|
|







 







<
|







 







|







 







|







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
...
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
...
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
...
922
923
924
925
926
927
928
929

930
931
932
933
934
935
936
...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
...
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
....
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
....
1351
1352
1353
1354
1355
1356
1357

1358
1359
1360
1361
1362
1363
1364
1365
....
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
....
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                *
************************************************************************/

#include <stdlib.h>
#include <string.h>
#include <assert.h>

#define LUA_LIB
#include "lua.h"
#include "lauxlib.h"

#include "sqlite3.h"

/* compile time features */
#if !defined(SQLITE_OMIT_PROGRESS_CALLBACK)
................................................................................
        case SQLITE_INTEGER:
            {
                sqlite_int64 i64 = sqlite3_column_int64(vm, idx);
                lua_Number n = (lua_Number)i64;
                if (n == i64)
                    lua_pushnumber(L, n);
                else
                    lua_pushlstring(L, (const char*)sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
            }
            break;
        case SQLITE_FLOAT:
            lua_pushnumber(L, sqlite3_column_double(vm, idx));
            break;
        case SQLITE_TEXT:
            lua_pushlstring(L, (const char*)sqlite3_column_text(vm, idx), sqlite3_column_bytes(vm, idx));
            break;
        case SQLITE_BLOB:
            lua_pushlstring(L, sqlite3_column_blob(vm, idx), sqlite3_column_bytes(vm, idx));
            break;
        case SQLITE_NULL:
            lua_pushnil(L);
            break;
................................................................................
        case LUA_TNONE:
        case LUA_TNIL:
        /* allow boolean values so i have a way to know which
        ** values were actually not set */
        case LUA_TBOOLEAN:
            return sqlite3_bind_null(vm, index);
        default:
            luaL_error(L, "index (%d) - invalid data type for bind (%s)", index, lua_typename(L, lua_type(L, lindex)));
            return SQLITE_MISUSE; /*!*/
    }
}


static int dbvm_bind_parameter_count(lua_State *L) {
    sdb_vm *svm = lsqlite_checkvm(L, 1);
................................................................................
/*
** Registering SQL functions:
*/

static void db_push_value(lua_State *L, sqlite3_value *value) {
    switch (sqlite3_value_type(value)) {
        case SQLITE_TEXT:
            lua_pushlstring(L, (const char*)sqlite3_value_text(value), sqlite3_value_bytes(value));
            break;

        case SQLITE_INTEGER:
            {
                sqlite_int64 i64 = sqlite3_value_int64(value);
                lua_Number n = (lua_Number)i64;
                if (n == i64)
                    lua_pushnumber(L, n);
                else
                    lua_pushlstring(L, (const char*)sqlite3_value_text(value), sqlite3_value_bytes(value));
            }
            break;

        case SQLITE_FLOAT:
            lua_pushnumber(L, sqlite3_value_double(value));
            break;

................................................................................

    lua_rawgeti(L, LUA_REGISTRYINDEX, func->fn_step);   /* function to call */

    if (!func->aggregate) {
        ctx = lsqlite_make_context(L); /* push context - used to set results */
    }
    else {
        /* reuse context userdata value */

        void *p = sqlite3_aggregate_context(context, 1);
        /* i think it is OK to use assume that using a light user data
        ** as an entry on LUA REGISTRY table will be unique */
        lua_pushlightuserdata(L, p);
        lua_rawget(L, LUA_REGISTRYINDEX);       /* context table */

        if (lua_isnil(L, -1)) { /* not yet created? */
................................................................................
    }

    /* push params */
    for (n = 0; n < argc; ++n) {
        db_push_value(L, argv[n]);
    }

    /* set context */
    ctx->ctx = context;

    if (lua_pcall(L, argc + 1, 0, 0)) {
        const char *errmsg = lua_tostring(L, -1);
        int size = lua_strlen(L, -1);
        sqlite3_result_error(context, errmsg, size);
    }

    /* invalidate context */
    ctx->ctx = NULL;

    if (!func->aggregate) {
        luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
    }

    lua_settop(L, top);
................................................................................
        lua_pushlightuserdata(L, p);
        lua_pushvalue(L, -2);
        lua_rawset(L, LUA_REGISTRYINDEX);
    }
    else
        ctx = lsqlite_getcontext(L, -1);

    /* set context */
    ctx->ctx = context;

    if (lua_pcall(L, 1, 0, 0)) {
        sqlite3_result_error(context, lua_tostring(L, -1), -1);
    }

    /* invalidate context */
    ctx->ctx = NULL;

    /* cleanup context */
    luaL_unref(L, LUA_REGISTRYINDEX, ctx->ud);
    /* remove it from registry */
    lua_pushlightuserdata(L, p);
    lua_pushnil(L);
................................................................................
    scc *co=NULL;
    int (*collfunc)(scc *,int,const void *,int,const void *)=NULL;
    lua_settop(L,3); /* default args to nil, and exclude extras */
    if (lua_isfunction(L,3)) collfunc=collwrapper;
    else if (!lua_isnil(L,3))
        luaL_error(L,"create_collation: function or nil expected");
    if (collfunc != NULL) {
        co=(scc *)malloc(sizeof(scc)); /* userdata is a no-no as it
                                          will be garbage-collected */
        if (co) {
            co->L=L;
            /* lua_settop(L,3) above means we don't need: lua_pushvalue(L,3); */
            co->ref=luaL_ref(L,LUA_REGISTRYINDEX);
        }
        else luaL_error(L,"create_collation: could not allocate callback");
    }
................................................................................
**
** Callback:
** Params: user, number of columns, values, names
** Returns: 0 to continue, other value will cause abort
*/
static int db_exec_callback(void* user, int columns, char **data, char **names) {
    int result = SQLITE_ABORT; /* abort by default */

    lua_State *L = (lua_State*)user;
    int n;

    int top = lua_gettop(L);

    lua_pushvalue(L, 3); /* function to call */
    lua_pushvalue(L, 4); /* user data */
    lua_pushnumber(L, columns); /* total number of rows in result */
................................................................................
        **  6: reusable column values
        */
        luaL_checktype(L, 3, LUA_TFUNCTION);
        lua_settop(L, 4);   /* 'trap' userdata - nil extra parameters */
        lua_pushnil(L);     /* column names not known at this point */
        lua_newtable(L);    /* column values table */

        result = sqlite3_exec(db->db, sql, db_exec_callback, L, NULL);
    }
    else {
        /* no callbacks */
        result = sqlite3_exec(db->db, sql, NULL, NULL, NULL);
    }

    lua_pushnumber(L, result);
................................................................................
}

static int db_next_named_row(lua_State *L) {
    return db_do_next_row(L, 2);
}

static int dbvm_do_rows(lua_State *L, int(*f)(lua_State *)) {
    /* sdb_vm *svm =  */
    lsqlite_checkvm(L, 1);
    lua_pushvalue(L,1);
    lua_pushcfunction(L, f);
    lua_insert(L, -2);
    return 2;
}