LuaSQLite3

Check-in [be6de29e8f]
Login

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

Overview
Comment:Add Online Backup API.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: be6de29e8fb1e597b8517aae7128a542275e76a7
User & Date: e 2016-11-03 04:32:34
References
2016-11-03
16:15 Closed ticket [aea4b6254f]: Add online backup API support plus 5 other changes artifact: a26ededb9c user: e
Context
2016-11-03
16:13
Add GC test for Online Backup API. check-in: 1c355fc530 user: e tags: trunk
04:32
Add Online Backup API. check-in: be6de29e8f user: e tags: trunk
2016-11-02
17:38
Implement suggested lua_createtable() performance improvement from Egil in ticket [0439ca1556]. check-in: a56548c06d user: e tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to lsqlite3.c.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
63
64
65
66
67
68
69

70
71
72
73
74
75
76
...
114
115
116
117
118
119
120

121
122
123
124
125
126
127
...
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
....
1533
1534
1535
1536
1537
1538
1539















































































































1540
1541
1542
1543
1544
1545
1546
....
2149
2150
2151
2152
2153
2154
2155












2156
2157
2158
2159
2160
2161
2162
2163
2164
2165


2166
2167
2168
2169
2170
2171
2172
....
2180
2181
2182
2183
2184
2185
2186

2187
2188
2189
2190
2191
2192
2193
/************************************************************************
* lsqlite3                                                              *
* Copyright (C) 2002-2015 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 *
................................................................................
#if !defined(LSQLITE_OMIT_UPDATE_HOOK)
    #define LSQLITE_OMIT_UPDATE_HOOK 0
#endif


typedef struct sdb sdb;
typedef struct sdb_vm sdb_vm;

typedef struct sdb_func sdb_func;

/* to use as C user data so i know what function sqlite is calling */
struct sdb_func {
    /* references to associated lua values */
    int fn_step;
    int fn_finalize;
................................................................................
    int rollback_hook_udata;

#endif
};

static const char *sqlite_meta      = ":sqlite3";
static const char *sqlite_vm_meta   = ":sqlite3:vm";

static const char *sqlite_ctx_meta  = ":sqlite3:ctx";
static int sqlite_ctx_meta_ref;

/* Lua 5.3 introduced an integer type, but depending on the implementation, it could be 32 
** or 64 bits (or something else?). This helper macro tries to do "the right thing."
*/

................................................................................
    char has_values;        /* true when step succeeds */

    char temp;              /* temporary vm used in db:rows */
};

/* 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));

    luaL_getmetatable(L, sqlite_vm_meta);
    lua_setmetatable(L, -2);        /* set metatable */

    svm->db = db;
    svm->columns = 0;
    svm->has_values = 0;
    svm->vm = NULL;
    svm->temp = 0;

    /* add an entry on the database table: svm -> 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);

    return svm;
}

static int cleanupvm(lua_State *L, sdb_vm *svm) {

    /* remove entry in database table - no harm if not present in the table */
................................................................................
    lua_pushliteral(L, "progress callback support disabled at compile time");
    lua_error(L);
    return 0;
}

#endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */
















































































































/*
** busy handler:
** Params: database, callback function, userdata
**
** callback function:
** Params: userdata, number of tries
** returns: 0 to return immediatly and return SQLITE_BUSY, non-zero to try again
................................................................................
    {"result_text",             lcontext_result_text            },
    {"result_blob",             lcontext_result_blob            },
    {"result_error",            lcontext_result_error           },

    {"__tostring",              lcontext_tostring               },
    {NULL, NULL}
};













static const luaL_Reg sqlitelib[] = {
    {"lversion",        lsqlite_lversion        },
    {"version",         lsqlite_version         },
    {"complete",        lsqlite_complete        },
#ifndef WIN32
    {"temp_directory",  lsqlite_temp_directory  },
#endif
    {"open",            lsqlite_open            },
    {"open_memory",     lsqlite_open_memory     },



    {"__newindex",      lsqlite_newindex        },
    {NULL, NULL}
};

static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
    luaL_newmetatable(L, name);
................................................................................
    /* remove metatable from stack */
    lua_pop(L, 1);
}

LUALIB_API int luaopen_lsqlite3(lua_State *L) {
    create_meta(L, sqlite_meta, dblib);
    create_meta(L, sqlite_vm_meta, vmlib);

    create_meta(L, sqlite_ctx_meta, ctxlib);

    luaL_getmetatable(L, sqlite_ctx_meta);
    sqlite_ctx_meta_ref = luaL_ref(L, LUA_REGISTRYINDEX);

    /* register (local) sqlite metatable */
    luaL_register(L, "sqlite3", sqlitelib);


|



|







 







>







 







>







 







|











|
|
|
|
|
|







 







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>
>










>
>







 







>







1
2
3
4
5
6
7
8
9
10
11
12
13
14
..
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
...
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
...
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
....
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
....
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
....
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
/************************************************************************
* lsqlite3                                                              *
* 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 - 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       *
* "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 *
................................................................................
#if !defined(LSQLITE_OMIT_UPDATE_HOOK)
    #define LSQLITE_OMIT_UPDATE_HOOK 0
#endif


typedef struct sdb sdb;
typedef struct sdb_vm sdb_vm;
typedef struct sdb_bu sdb_bu;
typedef struct sdb_func sdb_func;

/* to use as C user data so i know what function sqlite is calling */
struct sdb_func {
    /* references to associated lua values */
    int fn_step;
    int fn_finalize;
................................................................................
    int rollback_hook_udata;

#endif
};

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;

/* Lua 5.3 introduced an integer type, but depending on the implementation, it could be 32 
** or 64 bits (or something else?). This helper macro tries to do "the right thing."
*/

................................................................................
    char has_values;        /* true when step succeeds */

    char temp;              /* temporary vm used in db:rows */
};

/* 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)); /* db sql svm_ud -- */

    luaL_getmetatable(L, sqlite_vm_meta);
    lua_setmetatable(L, -2);        /* set metatable */

    svm->db = db;
    svm->columns = 0;
    svm->has_values = 0;
    svm->vm = NULL;
    svm->temp = 0;

    /* add an entry on the database table: svm -> db to keep db live while svm is live */
    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;
}

static int cleanupvm(lua_State *L, sdb_vm *svm) {

    /* remove entry in database table - no harm if not present in the table */
................................................................................
    lua_pushliteral(L, "progress callback support disabled at compile time");
    lua_error(L);
    return 0;
}

#endif /* #if !defined(SQLITE_OMIT_PROGRESS_CALLBACK) || !SQLITE_OMIT_PROGRESS_CALLBACK */

/* 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);

    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;
}

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
**
** callback function:
** Params: userdata, number of tries
** returns: 0 to return immediatly and return SQLITE_BUSY, non-zero to try again
................................................................................
    {"result_text",             lcontext_result_text            },
    {"result_blob",             lcontext_result_blob            },
    {"result_error",            lcontext_result_error           },

    {"__tostring",              lcontext_tostring               },
    {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
    {"temp_directory",  lsqlite_temp_directory  },
#endif
    {"open",            lsqlite_open            },
    {"open_memory",     lsqlite_open_memory     },

    {"backup_init",     lsqlite_backup_init     },

    {"__newindex",      lsqlite_newindex        },
    {NULL, NULL}
};

static void create_meta(lua_State *L, const char *name, const luaL_Reg *lib) {
    luaL_newmetatable(L, name);
................................................................................
    /* remove metatable from stack */
    lua_pop(L, 1);
}

LUALIB_API int luaopen_lsqlite3(lua_State *L) {
    create_meta(L, sqlite_meta, dblib);
    create_meta(L, sqlite_vm_meta, vmlib);
    create_meta(L, sqlite_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 (local) sqlite metatable */
    luaL_register(L, "sqlite3", sqlitelib);

Changes to test/tests-sqlite3.lua.

1062
1063
1064
1065
1066
1067
1068
1069
1070






























































1071
1072
      assert_equal (row.val,'Lua\0')
      assert_equal (#row.val, 4)
    end
    for row in db:nrows("SELECT name as val FROM test WHERE id = 3") do
      assert_equal (row.val, 'Hello\0SQLite\0')
      assert_equal (#row.val, 13)
    end
end































































lunit.main(arg)










>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>


1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
      assert_equal (row.val,'Lua\0')
      assert_equal (#row.val, 4)
    end
    for row in db:nrows("SELECT name as val FROM test WHERE id = 3") do
      assert_equal (row.val, 'Hello\0SQLite\0')
      assert_equal (#row.val, 13)
    end
end

-------------------------------------
--   Tests for Online Backup API   --
-------------------------------------

local db_bu = lunit_TestCase("Online Backup API")

function db_bu.setup()
  db_bu.db_src = assert( sqlite3.open_memory() )
  assert_equal( sqlite3.OK, db_bu.db_src:exec("CREATE TABLE test (id, name text)") )
  assert_equal( sqlite3.OK, db_bu.db_src:exec("INSERT INTO test VALUES (1, 'Hello World')") )
  assert_equal( sqlite3.OK, db_bu.db_src:exec("INSERT INTO test VALUES (2, 'Hello Lua')") )
  assert_equal( sqlite3.OK, db_bu.db_src:exec("INSERT INTO test VALUES (3, 'Hello SQLite')") )
  db_bu.filename = "/tmp/__lua-sqlite3-20161102233049." .. os.time()
  db_bu.db_tgt = assert_userdata( sqlite3.open(db_bu.filename) )
end

function db_bu.teardown()
  assert( db_bu.db_src:close() )
  assert( db_bu.db_tgt:close() )
  os.remove(db_bu.filename)
end

function db_bu.test()

  assert_function( sqlite3.backup_init )

  local bu = assert_userdata( sqlite3.backup_init(db_bu.db_tgt, 'main', db_bu.db_src, 'main') )

  assert_function ( bu.step )
  assert_function ( bu.remaining )
  assert_function ( bu.pagecount )
  assert_function ( bu.finish )

  if true then
    bu = nil
    collectgarbage()
    collectgarbage()
  else
    bu:finish()
  end

  bu = assert_userdata( sqlite3.backup_init(db_bu.db_tgt, 'main', db_bu.db_src, 'main') )

  assert_equal( sqlite3.DONE, bu:step(-1) )
  assert_equal( sqlite3.OK, bu:finish() )
  bu = nil

  local db = db_bu.db_tgt
  for row in db:nrows("SELECT id as val FROM test WHERE name='Hello World'") do
    assert_equal (row.val, 1)
  end
  for row in db:nrows("SELECT substr(name,7,3) as val FROM test WHERE id = 2") do
    assert_equal (row.val,'Lua')
    assert_equal (#row.val, 3)
  end
  for row in db:nrows("SELECT name as val FROM test WHERE id = 3") do
    assert_equal (row.val, 'Hello SQLite')
    assert_equal (#row.val, 12)
  end

end

lunit.main(arg)