|
1 #include "dbd_sqlite3.h" |
|
2 |
|
3 static lua_push_type_t sqlite_to_lua_push(unsigned int sqlite_type) { |
|
4 lua_push_type_t lua_type; |
|
5 |
|
6 switch(sqlite_type) { |
|
7 case SQLITE_NULL: |
|
8 lua_type = LUA_PUSH_NIL; |
|
9 break; |
|
10 |
|
11 case SQLITE_INTEGER: |
|
12 lua_type = LUA_PUSH_INTEGER; |
|
13 break; |
|
14 |
|
15 case SQLITE_FLOAT: |
|
16 lua_type = LUA_PUSH_NUMBER; |
|
17 break; |
|
18 |
|
19 default: |
|
20 lua_type = LUA_PUSH_STRING; |
|
21 } |
|
22 |
|
23 return lua_type; |
|
24 } |
|
25 |
|
26 static int step(statement_t *statement) { |
|
27 int res = sqlite3_step(statement->stmt); |
|
28 |
|
29 if (res == SQLITE_DONE) { |
|
30 statement->more_data = 0; |
|
31 return 1; |
|
32 } else if (res == SQLITE_ROW) { |
|
33 statement->more_data = 1; |
|
34 return 1; |
|
35 } |
|
36 |
|
37 return 0; |
|
38 } |
|
39 |
|
40 static int statement_close(lua_State *L) { |
|
41 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); |
|
42 int ok = 0; |
|
43 |
|
44 if (statement->stmt) { |
|
45 if (sqlite3_finalize(statement->stmt) == SQLITE_OK) { |
|
46 ok = 1; |
|
47 } |
|
48 } |
|
49 |
|
50 lua_pushboolean(L, ok); |
|
51 |
|
52 return 1; |
|
53 } |
|
54 |
|
55 static int statement_execute(lua_State *L) { |
|
56 int n = lua_gettop(L); |
|
57 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); |
|
58 int p; |
|
59 |
|
60 if (sqlite3_reset(statement->stmt) != SQLITE_OK) { |
|
61 lua_pushboolean(L, 0); |
|
62 return 1; |
|
63 } |
|
64 |
|
65 for (p = 2; p <= n; p++) { |
|
66 int i = p - 1; |
|
67 |
|
68 if (lua_isnil(L, p)) { |
|
69 if (sqlite3_bind_null(statement->stmt, i) != SQLITE_OK) { |
|
70 luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite)); |
|
71 } |
|
72 } else if (lua_isnumber(L, p)) { |
|
73 if (sqlite3_bind_double(statement->stmt, i, luaL_checknumber(L, p)) != SQLITE_OK) { |
|
74 luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite)); |
|
75 } |
|
76 } else if (lua_isstring(L, p)) { |
|
77 if (sqlite3_bind_text(statement->stmt, i, luaL_checkstring(L, p), -1, SQLITE_STATIC) != SQLITE_OK) { |
|
78 luaL_error(L, "Failed to execute statement: %s", sqlite3_errmsg(statement->sqlite)); |
|
79 } |
|
80 } |
|
81 } |
|
82 |
|
83 lua_pushboolean(L, step(statement)); |
|
84 return 1; |
|
85 } |
|
86 |
|
87 static int statement_fetch_impl(lua_State *L, int named_columns) { |
|
88 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_SQLITE_STATEMENT); |
|
89 int num_columns; |
|
90 |
|
91 if (!statement->more_data) { |
|
92 lua_pushnil(L); |
|
93 return 1; |
|
94 } |
|
95 |
|
96 num_columns = sqlite3_column_count(statement->stmt); |
|
97 |
|
98 if (num_columns) { |
|
99 int i; |
|
100 int d = 1; |
|
101 |
|
102 lua_newtable(L); |
|
103 |
|
104 for (i = 0; i < num_columns; i++) { |
|
105 lua_push_type_t lua_push = sqlite_to_lua_push(sqlite3_column_type(statement->stmt, i)); |
|
106 const char *name = sqlite3_column_name(statement->stmt, i); |
|
107 |
|
108 if (lua_push == LUA_PUSH_NIL) { |
|
109 if (named_columns) { |
|
110 LUA_PUSH_ATTRIB_NIL(name); |
|
111 } else { |
|
112 LUA_PUSH_ARRAY_NIL(d); |
|
113 } |
|
114 } else if (lua_push == LUA_PUSH_INTEGER) { |
|
115 int val = sqlite3_column_int(statement->stmt, i); |
|
116 |
|
117 if (named_columns) { |
|
118 LUA_PUSH_ATTRIB_INT(name, val); |
|
119 } else { |
|
120 LUA_PUSH_ARRAY_INT(d, val); |
|
121 } |
|
122 } else if (lua_push == LUA_PUSH_NUMBER) { |
|
123 double val = sqlite3_column_double(statement->stmt, i); |
|
124 |
|
125 if (named_columns) { |
|
126 LUA_PUSH_ATTRIB_FLOAT(name, val); |
|
127 } else { |
|
128 LUA_PUSH_ARRAY_FLOAT(d, val); |
|
129 } |
|
130 } else if (lua_push == LUA_PUSH_STRING) { |
|
131 const char *val = (const char *)sqlite3_column_text(statement->stmt, i); |
|
132 |
|
133 if (named_columns) { |
|
134 LUA_PUSH_ATTRIB_STRING(name, val); |
|
135 } else { |
|
136 LUA_PUSH_ARRAY_STRING(d, val); |
|
137 } |
|
138 } else if (lua_push == LUA_PUSH_BOOLEAN) { |
|
139 int val = sqlite3_column_int(statement->stmt, i); |
|
140 |
|
141 if (named_columns) { |
|
142 LUA_PUSH_ATTRIB_BOOL(name, val); |
|
143 } else { |
|
144 LUA_PUSH_ARRAY_BOOL(d, val); |
|
145 } |
|
146 } else { |
|
147 luaL_error(L, "Unknown push type in result set"); |
|
148 } |
|
149 } |
|
150 } |
|
151 |
|
152 if (step(statement) == 0) { |
|
153 if (sqlite3_reset(statement->stmt) != SQLITE_OK) { |
|
154 luaL_error(L, "Failed to fetch statement: %s", sqlite3_errmsg(statement->sqlite)); |
|
155 } |
|
156 } |
|
157 |
|
158 return 1; |
|
159 } |
|
160 |
|
161 |
|
162 static int statement_fetch(lua_State *L) { |
|
163 return statement_fetch_impl(L, 0); |
|
164 } |
|
165 |
|
166 static int statement_fetchtable(lua_State *L) { |
|
167 return statement_fetch_impl(L, 1); |
|
168 } |
|
169 |
|
170 static int statement_gc(lua_State *L) { |
|
171 /* always free the handle */ |
|
172 statement_close(L); |
|
173 |
|
174 return 0; |
|
175 } |
|
176 |
|
177 |
|
178 static const luaL_Reg statement_methods[] = { |
|
179 {"close", statement_close}, |
|
180 {"execute", statement_execute}, |
|
181 {"fetch", statement_fetch}, |
|
182 {"fetchtable", statement_fetchtable}, |
|
183 {NULL, NULL} |
|
184 }; |
|
185 |
|
186 static const luaL_Reg statement_class_methods[] = { |
|
187 {NULL, NULL} |
|
188 }; |
|
189 |
|
190 int dbd_sqlite3_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { |
|
191 statement_t *statement = NULL; |
|
192 |
|
193 statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); |
|
194 statement->sqlite = conn->sqlite; |
|
195 statement->stmt = NULL; |
|
196 statement->more_data = 0; |
|
197 |
|
198 if (sqlite3_prepare_v2(statement->sqlite, sql_query, strlen(sql_query), &statement->stmt, NULL) != SQLITE_OK) { |
|
199 luaL_error(L, "Failed to prepare statement: %s", sqlite3_errmsg(statement->sqlite)); |
|
200 lua_pushnil(L); |
|
201 return 1; |
|
202 } |
|
203 |
|
204 luaL_getmetatable(L, DBD_SQLITE_STATEMENT); |
|
205 lua_setmetatable(L, -2); |
|
206 |
|
207 return 1; |
|
208 } |
|
209 |
|
210 int dbd_sqlite3_statement(lua_State *L) { |
|
211 luaL_newmetatable(L, DBD_SQLITE_STATEMENT); |
|
212 luaL_register(L, 0, statement_methods); |
|
213 lua_pushvalue(L,-1); |
|
214 lua_setfield(L, -2, "__index"); |
|
215 |
|
216 lua_pushcfunction(L, statement_gc); |
|
217 lua_setfield(L, -2, "__gc"); |
|
218 |
|
219 luaL_register(L, DBD_SQLITE_STATEMENT, statement_class_methods); |
|
220 |
|
221 return 1; |
|
222 } |