Переглянути джерело

Update to LuaSQLite 0.9.4

bel2125 7 роки тому
батько
коміт
1fcfdb2cde
1 змінених файлів з 224 додано та 32 видалено
  1. 224 32
      src/third_party/lsqlite3.c

+ 224 - 32
src/third_party/lsqlite3.c

@@ -1,10 +1,10 @@
 /************************************************************************
 * lsqlite3                                                              *
-* Copyright (C) 2002-2015 Tiago Dionizio, Doug Currie                   *
+* Copyright (C) 2002-2016 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          *
+* Library   : lsqlite3 - an 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       *
@@ -30,7 +30,9 @@
 #include <string.h>
 #include <assert.h>
 
-#include "civetweb_lua.h"
+#define LUA_LIB
+#include "lua.h"
+#include "lauxlib.h"
 
 #if LUA_VERSION_NUM > 501
 /*
@@ -61,10 +63,15 @@
 #if !defined(LSQLITE_OMIT_UPDATE_HOOK)
     #define LSQLITE_OMIT_UPDATE_HOOK 0
 #endif
-
+#if defined(LSQLITE_OMIT_OPEN_V2)
+    #define SQLITE3_OPEN(L,filename,flags) sqlite3_open(L,filename)
+#else
+    #define SQLITE3_OPEN(L,filename,flags) sqlite3_open_v2(L,filename,flags,NULL)
+#endif
 
 typedef struct sdb sdb;
 typedef struct sdb_vm sdb_vm;
+typedef struct sdb_bu sdb_bu;
 typedef struct sdb_func sdb_func;
 
 /* to use as C user data so i know what function sqlite is calling */
@@ -116,6 +123,7 @@ struct sdb {
 
 static const char *sqlite_meta      = ":sqlite3";
 static const char *sqlite_vm_meta   = ":sqlite3:vm";
+static const char *sqlite_bu_meta   = ":sqlite3:bu";
 static const char *sqlite_ctx_meta  = ":sqlite3:ctx";
 static int sqlite_ctx_meta_ref;
 
@@ -190,7 +198,7 @@ struct sdb_vm {
 
 /* called with db,sql text on the lua stack */
 static sdb_vm *newvm(lua_State *L, sdb *db) {
-    sdb_vm *svm = (sdb_vm*)lua_newuserdata(L, sizeof(sdb_vm));
+    sdb_vm *svm = (sdb_vm*)lua_newuserdata(L, sizeof(sdb_vm)); /* db sql svm_ud -- */
 
     luaL_getmetatable(L, sqlite_vm_meta);
     lua_setmetatable(L, -2);        /* set metatable */
@@ -202,12 +210,12 @@ static sdb_vm *newvm(lua_State *L, sdb *db) {
     svm->temp = 0;
 
     /* add an entry on the database table: svm -> db to keep db live while svm is live */
-    lua_pushlightuserdata(L, db);
-    lua_rawget(L, LUA_REGISTRYINDEX);
-    lua_pushlightuserdata(L, svm);
-    lua_pushvalue(L, -5); /* the db for this vm */
-    lua_rawset(L, -3);
-    lua_pop(L, 1);
+    lua_pushlightuserdata(L, db);     /* db sql svm_ud db_lud -- */
+    lua_rawget(L, LUA_REGISTRYINDEX); /* db sql svm_ud reg[db_lud] -- */
+    lua_pushlightuserdata(L, svm);    /* db sql svm_ud reg[db_lud] svm_lud -- */
+    lua_pushvalue(L, -5);             /* db sql svm_ud reg[db_lud] svm_lud db -- */
+    lua_rawset(L, -3);                /* (reg[db_lud])[svm_lud] = db ; set the db for this vm */
+    lua_pop(L, 1);                    /* db sql svm_ud -- */
 
     return svm;
 }
@@ -371,7 +379,7 @@ static int dbvm_get_values(lua_State *L) {
     int n;
     dbvm_check_contents(L, svm);
 
-    lua_newtable(L);
+    lua_createtable(L, columns, 0);
     for (n = 0; n < columns;) {
         vm_push_column(L, vm, n++);
         lua_rawseti(L, -2, n);
@@ -385,7 +393,7 @@ static int dbvm_get_names(lua_State *L) {
     int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
     int n;
 
-    lua_newtable(L);
+    lua_createtable(L, columns, 0);
     for (n = 0; n < columns;) {
         lua_pushstring(L, sqlite3_column_name(vm, n++));
         lua_rawseti(L, -2, n);
@@ -399,7 +407,7 @@ static int dbvm_get_types(lua_State *L) {
     int columns = sqlite3_column_count(vm); /* valid as soon as statement prepared */
     int n;
 
-    lua_newtable(L);
+    lua_createtable(L, columns, 0);
     for (n = 0; n < columns;) {
         lua_pushstring(L, sqlite3_column_decltype(vm, n++));
         lua_rawseti(L, -2, n);
@@ -451,7 +459,7 @@ static int dbvm_get_named_values(lua_State *L) {
     int n;
     dbvm_check_contents(L, svm);
 
-    lua_newtable(L);
+    lua_createtable(L, 0, columns);
     for (n = 0; n < columns; ++n) {
         lua_pushstring(L, sqlite3_column_name(vm, n));
         vm_push_column(L, vm, n);
@@ -466,7 +474,7 @@ static int dbvm_get_named_types(lua_State *L) {
     int columns = sqlite3_column_count(vm);
     int n;
 
-    lua_newtable(L);
+    lua_createtable(L, 0, columns);
     for (n = 0; n < columns; ++n) {
         lua_pushstring(L, sqlite3_column_name(vm, n));
         lua_pushstring(L, sqlite3_column_decltype(vm, n));
@@ -922,6 +930,14 @@ static int db_interrupt(lua_State *L) {
     return 0;
 }
 
+static int db_db_filename(lua_State *L) {
+    sdb *db = lsqlite_checkdb(L, 1);
+    const char *db_name = luaL_checkstring(L, 2);
+    // sqlite3_db_filename may return NULL, in that case Lua pushes nil...
+    lua_pushstring(L, sqlite3_db_filename(db->db, db_name));
+    return 1;
+}
+
 /*
 ** Registering SQL functions:
 */
@@ -1535,6 +1551,122 @@ static int db_progress_handler(lua_State *L) {
 
 #endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
 
+/* Online Backup API */
+#if 0
+sqlite3_backup *sqlite3_backup_init(
+  sqlite3 *pDest,                        /* Destination database handle */
+  const char *zDestName,                 /* Destination database name */
+  sqlite3 *pSource,                      /* Source database handle */
+  const char *zSourceName                /* Source database name */
+);
+int sqlite3_backup_step(sqlite3_backup *p, int nPage);
+int sqlite3_backup_finish(sqlite3_backup *p);
+int sqlite3_backup_remaining(sqlite3_backup *p);
+int sqlite3_backup_pagecount(sqlite3_backup *p);
+#endif
+
+struct sdb_bu {
+    sqlite3_backup *bu;     /* backup structure */
+};
+
+static int cleanupbu(lua_State *L, sdb_bu *sbu) {
+
+    if (!sbu->bu) return 0; /* already finished */
+
+    /* remove table from registry */
+    lua_pushlightuserdata(L, sbu->bu);
+    lua_pushnil(L);
+    lua_rawset(L, LUA_REGISTRYINDEX);
+
+    lua_pushinteger(L, sqlite3_backup_finish(sbu->bu));
+    sbu->bu = NULL;
+
+    return 1;
+}
+
+static int lsqlite_backup_init(lua_State *L) {
+
+    sdb *target_db = lsqlite_checkdb(L, 1);
+    const char *target_nm = luaL_checkstring(L, 2);
+    sdb *source_db = lsqlite_checkdb(L, 3);
+    const char *source_nm = luaL_checkstring(L, 4);
+
+    sqlite3_backup *bu = sqlite3_backup_init(target_db->db, target_nm, source_db->db, source_nm);
+
+    if (NULL != bu) {
+        sdb_bu *sbu = (sdb_bu*)lua_newuserdata(L, sizeof(sdb_bu));
+
+        luaL_getmetatable(L, sqlite_bu_meta);
+        lua_setmetatable(L, -2);        /* set metatable */
+        sbu->bu = bu;
+
+        /* create table from registry */
+        /* to prevent referenced databases from being garbage collected while bu is live */
+        lua_pushlightuserdata(L, bu);
+        lua_createtable(L, 2, 0);
+        /* add source and target dbs to table at indices 1 and 2 */
+        lua_pushvalue(L, 1); /* target db */
+        lua_rawseti(L, -2, 1);
+        lua_pushvalue(L, 3); /* source db */
+        lua_rawseti(L, -2, 2);
+        /* put table in registry with key lightuserdata bu */
+        lua_rawset(L, LUA_REGISTRYINDEX);
+
+        return 1;
+    }
+    else {
+        return 0;
+    }
+}
+
+static sdb_bu *lsqlite_getbu(lua_State *L, int index) {
+    sdb_bu *sbu = (sdb_bu*)luaL_checkudata(L, index, sqlite_bu_meta);
+    if (sbu == NULL) luaL_typerror(L, index, "sqlite database backup");
+    return sbu;
+}
+
+static sdb_bu *lsqlite_checkbu(lua_State *L, int index) {
+    sdb_bu *sbu = lsqlite_getbu(L, index);
+    if (sbu->bu == NULL) luaL_argerror(L, index, "attempt to use closed sqlite database backup");
+    return sbu;
+}
+
+static int dbbu_gc(lua_State *L) {
+    sdb_bu *sbu = lsqlite_getbu(L, 1);
+    if (sbu->bu != NULL) {
+        cleanupbu(L, sbu);
+        lua_pop(L, 1);
+    }
+    /* else ignore if already finished */
+    return 0;
+}
+
+static int dbbu_step(lua_State *L) {
+    sdb_bu *sbu = lsqlite_checkbu(L, 1);
+    int nPage = luaL_checkint(L, 2);
+    lua_pushinteger(L, sqlite3_backup_step(sbu->bu, nPage));
+    return 1;
+}
+
+static int dbbu_remaining(lua_State *L) {
+    sdb_bu *sbu = lsqlite_checkbu(L, 1);
+    lua_pushinteger(L, sqlite3_backup_remaining(sbu->bu));
+    return 1;
+}
+
+static int dbbu_pagecount(lua_State *L) {
+    sdb_bu *sbu = lsqlite_checkbu(L, 1);
+    lua_pushinteger(L, sqlite3_backup_pagecount(sbu->bu));
+    return 1;
+}
+
+static int dbbu_finish(lua_State *L) {
+    sdb_bu *sbu = lsqlite_checkbu(L, 1);
+    return cleanupbu(L, sbu);
+}
+
+/* end of Online Backup API */
+
 /*
 ** busy handler:
 ** Params: database, callback function, userdata
@@ -1637,7 +1769,7 @@ static int db_exec_callback(void* user, int columns, char **data, char **names)
     lua_pushvalue(L, 5);
     if (lua_isnil(L, -1)) {
         lua_pop(L, 1);
-        lua_newtable(L);
+        lua_createtable(L, columns, 0);
         lua_pushvalue(L, -1);
         lua_replace(L, 5);
         for (n = 0; n < columns;) {
@@ -1730,14 +1862,15 @@ static int db_do_next_row(lua_State *L, int packed) {
 
     if (result == SQLITE_ROW) {
         if (packed) {
-            lua_newtable(L);
             if (packed == 1) {
+                lua_createtable(L, columns, 0);
                 for (i = 0; i < columns;) {
                     vm_push_column(L, vm, i);
                     lua_rawseti(L, -2, ++i);
                 }
             }
             else {
+                lua_createtable(L, 0, columns);
                 for (i = 0; i < columns; ++i) {
                     lua_pushstring(L, sqlite3_column_name(vm, i));
                     vm_push_column(L, vm, i);
@@ -1880,6 +2013,17 @@ static int db_close_vm(lua_State *L) {
     return 0;
 }
 
+/* From: Wolfgang Oertl
+When using lsqlite3 in a multithreaded environment, each thread has a separate Lua 
+environment, but full userdata structures can't be passed from one thread to another.
+This is possible with lightuserdata, however. See: lsqlite_open_ptr().
+*/
+static int db_get_ptr(lua_State *L) {
+    sdb *db = lsqlite_checkdb(L, 1);
+    lua_pushlightuserdata(L, db->db);
+    return 1;
+}
+
 static int db_gc(lua_State *L) {
     sdb *db = lsqlite_getdb(L, 1);
     if (db->db != NULL)  /* ignore closed databases */
@@ -1904,7 +2048,7 @@ static int lsqlite_complete(lua_State *L) {
     return 1;
 }
 
-#ifndef WIN32
+#ifndef _WIN32
 static int lsqlite_temp_directory(lua_State *L) {
     const char *oldtemp = sqlite3_temp_directory;
 
@@ -1925,10 +2069,10 @@ static int lsqlite_temp_directory(lua_State *L) {
 }
 #endif
 
-static int lsqlite_do_open(lua_State *L, const char *filename) {
+static int lsqlite_do_open(lua_State *L, const char *filename, int flags) {
     sdb *db = newdb(L); /* create and leave in stack */
 
-    if (sqlite3_open(filename, &db->db) == SQLITE_OK) {
+    if (SQLITE3_OPEN(filename, &db->db, flags) == SQLITE_OK) {
         /* database handle already in the stack - return it */
         return 1;
     }
@@ -1947,11 +2091,36 @@ static int lsqlite_do_open(lua_State *L, const char *filename) {
 
 static int lsqlite_open(lua_State *L) {
     const char *filename = luaL_checkstring(L, 1);
-    return lsqlite_do_open(L, filename);
+    int flags = luaL_optinteger(L, 2, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+    return lsqlite_do_open(L, filename, flags);
 }
 
 static int lsqlite_open_memory(lua_State *L) {
-    return lsqlite_do_open(L, ":memory:");
+    return lsqlite_do_open(L, ":memory:", SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE);
+}
+
+/* From: Wolfgang Oertl
+When using lsqlite3 in a multithreaded environment, each thread has a separate Lua 
+environment, but full userdata structures can't be passed from one thread to another.
+This is possible with lightuserdata, however. See: db_get_ptr().
+*/
+static int lsqlite_open_ptr(lua_State *L) {
+    sqlite3 *db_ptr;
+    sdb *db;
+    int rc;
+
+    luaL_checktype(L, 1, LUA_TLIGHTUSERDATA);
+    db_ptr = lua_touserdata(L, 1);
+    /* This is the only API function that runs sqlite3SafetyCheck regardless of
+     * SQLITE_ENABLE_API_ARMOR and does almost nothing (without an SQL
+     * statement) */
+    rc = sqlite3_exec(db_ptr, NULL, NULL, NULL, NULL);
+    if (rc != SQLITE_OK)
+        luaL_argerror(L, 1, "not a valid SQLite3 pointer");
+
+    db = newdb(L); /* create and leave in stack */
+    db->db = db_ptr;
+    return 1;
 }
 
 static int lsqlite_newindex(lua_State *L) {
@@ -2035,6 +2204,17 @@ static const struct {
     SC(FUNCTION           )
     SC(SAVEPOINT          )
 
+    /* file open flags */
+    SC(OPEN_READONLY)
+    SC(OPEN_READWRITE)
+    SC(OPEN_CREATE)
+    SC(OPEN_URI)
+    SC(OPEN_MEMORY)
+    SC(OPEN_NOMUTEX)
+    SC(OPEN_FULLMUTEX)
+    SC(OPEN_SHAREDCACHE)
+    SC(OPEN_PRIVATECACHE)
+    
     /* terminator */
     { NULL, 0 }
 };
@@ -2051,6 +2231,7 @@ static const luaL_Reg dblib[] = {
     {"errmsg",              db_errmsg               },
     {"error_message",       db_errmsg               },
     {"interrupt",           db_interrupt            },
+    {"db_filename",         db_db_filename          },
 
     {"create_function",     db_create_function      },
     {"create_aggregate",    db_create_aggregate     },
@@ -2076,6 +2257,7 @@ static const luaL_Reg dblib[] = {
     {"execute",             db_exec                 },
     {"close",               db_close                },
     {"close_vm",            db_close_vm             },
+    {"get_ptr",             db_get_ptr              },
 
     {"__tostring",          db_tostring             },
     {"__gc",                db_gc                   },
@@ -2151,15 +2333,30 @@ static const luaL_Reg ctxlib[] = {
     {NULL, NULL}
 };
 
+static const luaL_Reg dbbulib[] = {
+
+    {"step",        dbbu_step       },
+    {"remaining",   dbbu_remaining  },
+    {"pagecount",   dbbu_pagecount  },
+    {"finish",      dbbu_finish     },
+
+//  {"__tostring",  dbbu_tostring   },
+    {"__gc",        dbbu_gc         },
+    {NULL, NULL}
+};
+
 static const luaL_Reg sqlitelib[] = {
     {"lversion",        lsqlite_lversion        },
     {"version",         lsqlite_version         },
     {"complete",        lsqlite_complete        },
-#ifndef WIN32
+#ifndef _WIN32
     {"temp_directory",  lsqlite_temp_directory  },
 #endif
     {"open",            lsqlite_open            },
     {"open_memory",     lsqlite_open_memory     },
+    {"open_ptr",        lsqlite_open_ptr        },
+
+    {"backup_init",     lsqlite_backup_init     },
 
     {"__newindex",      lsqlite_newindex        },
     {NULL, NULL}
@@ -2178,22 +2375,17 @@ static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
     lua_pop(L, 1);
 }
 
-static int luaopen_sqlitelib (lua_State *L) {
-    luaL_newlibtable(L, sqlitelib);
-    luaL_setfuncs(L, sqlitelib, 0);
-    return 1;
-}
-
 LUALIB_API int luaopen_lsqlite3(lua_State *L) {
     create_meta(L, sqlite_meta, dblib);
     create_meta(L, sqlite_vm_meta, vmlib);
+    create_meta(L, sqlite_bu_meta, dbbulib);
     create_meta(L, sqlite_ctx_meta, ctxlib);
 
     luaL_getmetatable(L, sqlite_ctx_meta);
     sqlite_ctx_meta_ref = luaL_ref(L, LUA_REGISTRYINDEX);
 
-    /* register global sqlite3 library */
-    luaL_requiref(L, "sqlite3", luaopen_sqlitelib, 1);
+    /* register (local) sqlite metatable */
+    luaL_register(L, "sqlite3", sqlitelib);
 
     {
         int i = 0;