1
4
5# include "luametatex.h"
6# include "lmtoptional.h"
7
8typedef struct sqlite3_instance sqlite3_instance;
9
10# define SQLITELIB_METATABLE "luatex.sqlitelib"
11
12typedef struct sqlitelib_data {
13
14 sqlite3_instance *db;
15} sqlitelib_data ;
16
17typedef struct sqlitelib_state_info {
18
19 int initialized;
20 int padding;
21
22 int (*sqlite3_initialize) (
23 void
24 );
25
26 int (*sqlite3_open) (
27 const char *filename,
28 sqlite3_instance **ppDb
29 );
30
31 int (*sqlite3_close) (
32 sqlite3_instance *
33 );
34
35 int (*sqlite3_exec) (
36 sqlite3_instance *,
37 const char *sql,
38 int (*callback)(void*, int, char**, char**),
39 void *,
40 char **errmsg
41 );
42
43 const char * (*sqlite3_errmsg) (
44 sqlite3_instance *
45 );
46
47} sqlitelib_state_info;
48
49static sqlitelib_state_info sqlitelib_state = {
50
51 .initialized = 0,
52 .padding = 0,
53
54 .sqlite3_initialize = NULL,
55 .sqlite3_open = NULL,
56 .sqlite3_close = NULL,
57 .sqlite3_exec = NULL,
58 .sqlite3_errmsg = NULL,
59
60};
61
62static int sqlitelib_initialize(lua_State * L)
63{
64 if (! sqlitelib_state.initialized) {
65 const char *filename = lua_tostring(L, 1);
66 if (filename) {
67
68 lmt_library lib = lmt_library_load(filename);
69
70 sqlitelib_state.sqlite3_initialize = lmt_library_find(lib, "sqlite3_initialize");
71 sqlitelib_state.sqlite3_open = lmt_library_find(lib, "sqlite3_open");
72 sqlitelib_state.sqlite3_close = lmt_library_find(lib, "sqlite3_close");
73 sqlitelib_state.sqlite3_exec = lmt_library_find(lib, "sqlite3_exec");
74 sqlitelib_state.sqlite3_errmsg = lmt_library_find(lib, "sqlite3_errmsg");
75
76 sqlitelib_state.initialized = lmt_library_okay(lib);
77 }
78 if (sqlitelib_state.initialized) {
79 sqlitelib_state.sqlite3_initialize();
80 }
81 }
82 lua_pushboolean(L, sqlitelib_state.initialized);
83 return 1;
84}
85
86static int sqlitelib_open(lua_State * L)
87{
88 if (sqlitelib_state.initialized) {
89 const char *filename = lua_tostring(L, 1);
90 if (filename != NULL) {
91 sqlitelib_data *data = lua_newuserdatauv(L, sizeof(data), 0);
92 if (! sqlitelib_state.sqlite3_open(filename, &(data->db))) {
93 luaL_getmetatable(L, SQLITELIB_METATABLE);
94 lua_setmetatable(L, -2);
95 return 1;
96 }
97 }
98 }
99 return 0;
100}
101
102static int sqlitelib_close(lua_State * L)
103{
104 if (sqlitelib_state.initialized) {
105 sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE);
106 if (data != NULL) {
107 sqlitelib_state.sqlite3_close(data->db);
108 data->db = NULL;
109 }
110 }
111 return 0;
112}
113
114
115
116static int rows_done = 0;
117
118static int sqlitelib_callback(void * L, int nofcolumns, char **values, char **fields)
119{
120 lua_pushvalue(L, -1);
121 lua_pushinteger(L, nofcolumns);
122 if (nofcolumns > 0 && values != NULL) {
123 lua_createtable(L, nofcolumns, 0);
124 for (int i = 0; i < nofcolumns; i++) {
125 lua_pushstring(L, values[i]);
126 lua_rawseti(L, -2, (lua_Integer)i + 1);
127 }
128 if (! rows_done && fields != NULL) {
129 lua_createtable(L, nofcolumns, 0);
130 for (int i = 0; i < nofcolumns; i++) {
131 lua_pushstring(L, fields[i]);
132 lua_rawseti(L, -2, (lua_Integer)i + 1);
133 }
134 lua_call(L, 3, 0);
135 } else {
136 lua_call(L, 2, 0);
137 }
138 } else {
139 lua_call(L, 1, 0);
140 }
141 ++rows_done;
142 return 0;
143}
144
145
146
147static int sqlitelib_execute(lua_State * L)
148{
149 if (sqlitelib_state.initialized && ! rows_done) {
150 sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE);
151 if (data != NULL) {
152 const char *query = lua_tostring(L, 2);
153 if (query != NULL) {
154 int result = 0;
155 rows_done = 0;
156 if (lua_isfunction(L, 3)) {
157 result = sqlitelib_state.sqlite3_exec(data->db, query, &sqlitelib_callback, L, NULL);
158 } else {
159 result = sqlitelib_state.sqlite3_exec(data->db, query, NULL, NULL, NULL);
160 }
161 rows_done = 0;
162 lua_pushboolean(L, ! result);
163 return 1;
164 }
165 }
166 }
167 lua_pushboolean(L, 0);
168 return 1;
169}
170
171static int sqlitelib_getmessage(lua_State * L)
172{
173 if (sqlitelib_state.initialized) {
174 sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE);
175 if (data != NULL) {
176 lua_pushstring(L, sqlitelib_state.sqlite3_errmsg(data->db));
177 return 1;
178 }
179 }
180 return 0;
181}
182
183
184
185static int sqlitelib_free(lua_State * L)
186{
187 return sqlitelib_close(L);
188}
189
190
191
192static int sqlitelib_tostring(lua_State * L)
193{
194 if (sqlitelib_state.initialized) {
195 sqlitelib_data * data = luaL_checkudata(L, 1, SQLITELIB_METATABLE);
196 if (data != NULL) {
197 (void) lua_pushfstring(L, "<sqlitelib-instance %p>", data);
198 } else {
199 lua_pushnil(L);
200 }
201 return 1;
202 } else {
203 return 0;
204 }
205}
206
207static const struct luaL_Reg sqlitelib_metatable[] = {
208 { "__tostring", sqlitelib_tostring },
209 { "__gc", sqlitelib_free },
210 { NULL, NULL },
211};
212
213static struct luaL_Reg sqlitelib_function_list[] = {
214 { "initialize", sqlitelib_initialize },
215 { "open", sqlitelib_open },
216 { "close", sqlitelib_close },
217 { "execute", sqlitelib_execute },
218 { "getmessage", sqlitelib_getmessage },
219 { NULL, NULL },
220};
221
222int luaopen_sqlite(lua_State * L)
223{
224 luaL_newmetatable(L, SQLITELIB_METATABLE);
225 luaL_setfuncs(L, sqlitelib_metatable, 0);
226 lmt_library_register(L, "sqlite", sqlitelib_function_list);
227 return 0;
228}
229 |