dbd/mysql/statement.c

changeset 1
408291a6eb3e
child 2
c4f02fc67e5a
equal deleted inserted replaced
0:4ff31a4ea1fb 1:408291a6eb3e
1 #include "dbd_mysql.h"
2
3 static lua_push_type_t mysql_to_lua_push(unsigned int mysql_type) {
4 lua_push_type_t lua_type;
5
6 switch(mysql_type) {
7 case MYSQL_TYPE_NULL:
8 lua_type = LUA_PUSH_NIL;
9 break;
10
11 case MYSQL_TYPE_TINY:
12 case MYSQL_TYPE_SHORT:
13 case MYSQL_TYPE_LONG:
14 lua_type = LUA_PUSH_INTEGER;
15 break;
16
17 case MYSQL_TYPE_DOUBLE:
18 case MYSQL_TYPE_LONGLONG:
19 lua_type = LUA_PUSH_NUMBER;
20 break;
21
22 default:
23 lua_type = LUA_PUSH_STRING;
24 }
25
26 return lua_type;
27 }
28
29 static int statement_close(lua_State *L) {
30 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT);
31
32 if (statement->metadata) {
33 mysql_free_result(statement->metadata);
34 }
35
36 if (statement->stmt) {
37 mysql_stmt_close(statement->stmt);
38 }
39
40 return 1;
41 }
42
43 static int statement_execute(lua_State *L) {
44 int n = lua_gettop(L);
45 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT);
46 int num_bind_params = n - 1;
47
48 MYSQL_BIND *bind = NULL;
49 MYSQL_RES *metadata = NULL;
50
51 char *error_message = NULL;
52
53 int p;
54
55 bind = malloc(sizeof(MYSQL_BIND) * num_bind_params);
56 memset(bind, 0, sizeof(MYSQL_BIND) * num_bind_params);
57
58 for (p = 2; p <= n; p++) {
59 int type = lua_type(L, p);
60 int i = p - 2;
61
62 const char *str = NULL;
63 size_t str_len;
64
65 double num;
66
67 switch(type) {
68 case LUA_TNIL:
69 bind[i].buffer_type = MYSQL_TYPE_NULL;
70 bind[i].is_null = (my_bool*)1;
71 break;
72
73 case LUA_TNUMBER:
74 num = luaL_checknumber(L, p);
75
76 bind[i].buffer_type = MYSQL_TYPE_DOUBLE;
77 bind[i].is_null = (my_bool*)0;
78 bind[i].buffer = (char *)&num;
79 bind[i].length = 0;
80 break;
81
82 case LUA_TSTRING:
83 str = luaL_checklstring(L, p, &str_len);
84
85 bind[i].buffer_type = MYSQL_TYPE_STRING;
86 bind[i].is_null = (my_bool*)0;
87 bind[i].buffer = (char *)str;
88 bind[i].length = &str_len;
89 break;
90
91 default:
92 error_message = "Binding unknown or unsupported type";
93 goto cleanup;
94 }
95 }
96
97 if (mysql_stmt_bind_param(statement->stmt, bind)) {
98 error_message = "Error binding statement parameters: %s";
99 goto cleanup;
100 }
101
102 if (mysql_stmt_execute(statement->stmt)) {
103 error_message = "Error executing statement: %s";
104 goto cleanup;
105 }
106
107 metadata = mysql_stmt_result_metadata(statement->stmt);
108
109 cleanup:
110 if (bind)
111 free(bind);
112
113 if (error_message) {
114 luaL_error(L, error_message, mysql_stmt_error(statement->stmt));
115 return 0;
116 }
117
118 statement->metadata = metadata;
119
120 return 1;
121 }
122
123 static int statement_fetch_impl(lua_State *L, int named_columns) {
124 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT);
125 int column_count;
126 MYSQL_BIND *bind = NULL;
127 const char *error_message = NULL;
128
129 if (!statement->stmt) {
130 luaL_error(L, "fetch called before execute");
131 lua_pushnil(L);
132 return 1;
133 }
134
135 if (!statement->metadata) {
136 lua_pushnil(L);
137 return 1;
138 }
139
140 column_count = mysql_num_fields(statement->metadata);
141
142 if (column_count > 0) {
143 int i;
144 MYSQL_FIELD *fields;
145
146 bind = malloc(sizeof(MYSQL_BIND) * column_count);
147 memset(bind, 0, sizeof(MYSQL_BIND) * column_count);
148
149 fields = mysql_fetch_fields(statement->metadata);
150
151 for (i = 0; i < column_count; i++) {
152 unsigned int length = fields[i].length;
153
154 char *buffer = (char *)malloc(length);
155 memset(buffer, 0, length);
156
157 bind[i].buffer_type = fields[i].type;
158 bind[i].buffer = buffer;
159 bind[i].buffer_length = length;
160 }
161
162 if (mysql_stmt_bind_result(statement->stmt, bind)) {
163 error_message = "Error binding results: %s";
164 goto cleanup;
165 }
166
167 if (!mysql_stmt_fetch(statement->stmt)) {
168 int d = 1;
169
170 lua_newtable(L);
171 for (i = 0; i < column_count; i++) {
172 lua_push_type_t lua_push = mysql_to_lua_push(fields[i].type);
173 const char *name = fields[i].name;
174
175 if (lua_push == LUA_PUSH_NIL) {
176 if (named_columns) {
177 LUA_PUSH_ATTRIB_NIL(name);
178 } else {
179 LUA_PUSH_ARRAY_NIL(d);
180 }
181 } else if (lua_push == LUA_PUSH_INTEGER) {
182 if (named_columns) {
183 LUA_PUSH_ATTRIB_INT(name, *(int *)(bind[i].buffer));
184 } else {
185 LUA_PUSH_ARRAY_INT(d, *(int *)(bind[i].buffer));
186 }
187 } else if (lua_push == LUA_PUSH_NUMBER) {
188 if (named_columns) {
189 LUA_PUSH_ATTRIB_FLOAT(name, *(double *)(bind[i].buffer));
190 } else {
191 LUA_PUSH_ARRAY_FLOAT(d, *(double *)(bind[i].buffer));
192 }
193 } else if (lua_push == LUA_PUSH_STRING) {
194 if (named_columns) {
195 LUA_PUSH_ATTRIB_STRING(name, bind[i].buffer);
196 } else {
197 LUA_PUSH_ARRAY_STRING(d, bind[i].buffer);
198 }
199 } else if (lua_push == LUA_PUSH_BOOLEAN) {
200 if (named_columns) {
201 LUA_PUSH_ATTRIB_BOOL(name, *(int *)(bind[i].buffer));
202 } else {
203 LUA_PUSH_ARRAY_BOOL(d, *(int *)(bind[i].buffer));
204 }
205 } else {
206 luaL_error(L, "Unknown push type in result set");
207 }
208 }
209 } else {
210 lua_pushnil(L);
211 }
212 }
213
214 cleanup:
215 if (bind) {
216 int i;
217
218 for (i = 0; i < column_count; i++) {
219 free(bind[i].buffer);
220 }
221
222 free(bind);
223 }
224
225 if (error_message) {
226 luaL_error(L, error_message, mysql_stmt_error(statement->stmt));
227 return 0;
228 }
229
230 return 1;
231 }
232
233
234 static int statement_fetch(lua_State *L) {
235 return statement_fetch_impl(L, 0);
236 }
237
238 static int statement_fetchtable(lua_State *L) {
239 return statement_fetch_impl(L, 1);
240 }
241
242 static int statement_gc(lua_State *L) {
243 /* always free the handle */
244 statement_close(L);
245
246 return 0;
247 }
248
249
250 static const luaL_Reg statement_methods[] = {
251 {"close", statement_close},
252 {"execute", statement_execute},
253 {"fetch", statement_fetch},
254 {"fetchtable", statement_fetchtable},
255 {NULL, NULL}
256 };
257
258 static const luaL_Reg statement_class_methods[] = {
259 {NULL, NULL}
260 };
261
262 int dbd_mysql_statement_create(lua_State *L, connection_t *conn, const char *sql_query) {
263 unsigned long sql_len = strlen(sql_query);
264
265 statement_t *statement = NULL;
266
267 MYSQL_STMT *stmt = mysql_stmt_init(conn->mysql);
268
269 if (!stmt) {
270 luaL_error(L, "Error allocating statement handle: %s", mysql_error(conn->mysql));
271 return 0;
272 }
273
274 if (mysql_stmt_prepare(stmt, sql_query, sql_len)) {
275 luaL_error(L, "Error preparing statement handle: %s", mysql_stmt_error(stmt));
276 return 0;
277 }
278
279 statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t));
280 statement->mysql = conn->mysql;
281 statement->stmt = stmt;
282 statement->metadata = NULL;
283
284 luaL_getmetatable(L, DBD_MYSQL_STATEMENT);
285 lua_setmetatable(L, -2);
286
287 return 1;
288 }
289
290 int dbd_mysql_statement(lua_State *L) {
291 luaL_newmetatable(L, DBD_MYSQL_STATEMENT);
292 luaL_register(L, 0, statement_methods);
293 lua_pushvalue(L,-1);
294 lua_setfield(L, -2, "__index");
295
296 lua_pushcfunction(L, statement_gc);
297 lua_setfield(L, -2, "__gc");
298
299 luaL_register(L, DBD_MYSQL_STATEMENT, statement_class_methods);
300
301 return 1;
302 }

mercurial