Fri, 21 May 2010 23:00:13 +0000
* Add new MySQL types
* Fix memory leak in the MySQL handler
* Add new 'Drivers' method to the DBI class
1 | 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: | |
33 | 12 | case MYSQL_TYPE_YEAR: |
1 | 13 | case MYSQL_TYPE_SHORT: |
14 | case MYSQL_TYPE_LONG: | |
15 | lua_type = LUA_PUSH_INTEGER; | |
16 | break; | |
17 | ||
18 | case MYSQL_TYPE_DOUBLE: | |
19 | case MYSQL_TYPE_LONGLONG: | |
20 | lua_type = LUA_PUSH_NUMBER; | |
21 | break; | |
22 | ||
23 | default: | |
24 | lua_type = LUA_PUSH_STRING; | |
25 | } | |
26 | ||
27 | return lua_type; | |
28 | } | |
29 | ||
33 | 30 | static size_t mysql_buffer_size(MYSQL_FIELD *field) { |
31 | unsigned int mysql_type = field->type; | |
32 | size_t size = 0; | |
33 | ||
34 | switch (mysql_type) { | |
35 | case MYSQL_TYPE_TINY: | |
36 | 36 | size = 1; |
33 | 37 | break; |
38 | case MYSQL_TYPE_YEAR: | |
39 | case MYSQL_TYPE_SHORT: | |
36 | 40 | size = 2; |
33 | 41 | break; |
42 | case MYSQL_TYPE_INT24: | |
43 | size = 4; | |
44 | break; | |
45 | case MYSQL_TYPE_LONG: | |
46 | size = 4; | |
47 | break; | |
48 | case MYSQL_TYPE_LONGLONG: | |
49 | size = 8; | |
50 | break; | |
51 | case MYSQL_TYPE_FLOAT: | |
52 | size = 4; | |
53 | break; | |
54 | case MYSQL_TYPE_DOUBLE: | |
55 | size = 8; | |
56 | break; | |
57 | case MYSQL_TYPE_TIME: | |
58 | case MYSQL_TYPE_DATE: | |
59 | case MYSQL_TYPE_DATETIME: | |
60 | case MYSQL_TYPE_TIMESTAMP: | |
61 | size = sizeof(MYSQL_TIME); | |
62 | break; | |
63 | default: | |
64 | size = field->length; | |
65 | } | |
66 | ||
67 | return size; | |
68 | } | |
69 | ||
2 | 70 | /* |
21
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
71 | * num_affected_rows = statement:affected() |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
72 | */ |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
73 | static int statement_affected(lua_State *L) { |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
74 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
75 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
76 | if (!statement->stmt) { |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
77 | luaL_error(L, DBI_ERR_INVALID_STATEMENT); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
78 | } |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
79 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
80 | lua_pushinteger(L, mysql_stmt_affected_rows(statement->stmt)); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
81 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
82 | return 1; |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
83 | } |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
84 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
85 | /* |
2 | 86 | * success = statement:close() |
87 | */ | |
1 | 88 | static int statement_close(lua_State *L) { |
89 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); | |
90 | ||
91 | if (statement->metadata) { | |
92 | mysql_free_result(statement->metadata); | |
3 | 93 | statement->metadata = NULL; |
1 | 94 | } |
95 | ||
96 | if (statement->stmt) { | |
3 | 97 | mysql_stmt_close(statement->stmt); |
98 | statement->stmt = NULL; | |
1 | 99 | } |
100 | ||
3 | 101 | lua_pushboolean(L, 1); |
1 | 102 | return 1; |
103 | } | |
104 | ||
2 | 105 | /* |
30
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
106 | * column_names = statement:columns() |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
107 | */ |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
108 | static int statement_columns(lua_State *L) { |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
109 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
110 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
111 | MYSQL_FIELD *fields; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
112 | int i; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
113 | int num_columns; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
114 | int d = 1; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
115 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
116 | if (!statement->stmt) { |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
117 | luaL_error(L, DBI_ERR_INVALID_STATEMENT); |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
118 | return 0; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
119 | } |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
120 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
121 | fields = mysql_fetch_fields(statement->metadata); |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
122 | num_columns = mysql_num_fields(statement->metadata); |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
123 | lua_newtable(L); |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
124 | for (i = 0; i < num_columns; i++) { |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
125 | const char *name = fields[i].name; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
126 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
127 | LUA_PUSH_ARRAY_STRING(d, name); |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
128 | } |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
129 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
130 | return 1; |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
131 | } |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
132 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
133 | |
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
134 | /* |
3 | 135 | * success,err = statement:execute(...) |
2 | 136 | */ |
1 | 137 | static int statement_execute(lua_State *L) { |
138 | int n = lua_gettop(L); | |
139 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); | |
140 | int num_bind_params = n - 1; | |
3 | 141 | int expected_params; |
14 | 142 | |
25 | 143 | unsigned char *buffer = NULL; |
14 | 144 | int offset = 0; |
1 | 145 | |
146 | MYSQL_BIND *bind = NULL; | |
147 | MYSQL_RES *metadata = NULL; | |
148 | ||
149 | char *error_message = NULL; | |
10 | 150 | char *errstr = NULL; |
1 | 151 | |
152 | int p; | |
153 | ||
36 | 154 | if (statement->metadata) { |
155 | /* | |
156 | * free existing metadata from any previous executions | |
157 | */ | |
158 | mysql_free_result(statement->metadata); | |
159 | statement->metadata = NULL; | |
160 | } | |
161 | ||
3 | 162 | if (!statement->stmt) { |
163 | lua_pushboolean(L, 0); | |
4 | 164 | lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); |
3 | 165 | return 2; |
166 | } | |
167 | ||
168 | expected_params = mysql_stmt_param_count(statement->stmt); | |
169 | ||
170 | if (expected_params != num_bind_params) { | |
171 | /* | |
10 | 172 | * mysql_stmt_bind_param does not handle this condition, |
3 | 173 | * and the client library will segfault if these do no match |
174 | */ | |
175 | lua_pushboolean(L, 0); | |
4 | 176 | lua_pushfstring(L, DBI_ERR_PARAM_MISCOUNT, expected_params, num_bind_params); |
3 | 177 | return 2; |
178 | } | |
179 | ||
26 | 180 | if (num_bind_params > 0) { |
25 | 181 | bind = malloc(sizeof(MYSQL_BIND) * num_bind_params); |
182 | if (bind == NULL) { | |
183 | luaL_error(L, "Could not alloc bind params\n"); | |
184 | } | |
185 | ||
26 | 186 | buffer = (unsigned char *)malloc(num_bind_params * sizeof(double)); |
25 | 187 | memset(bind, 0, sizeof(MYSQL_BIND) * num_bind_params); |
23
a4825c3e65e9
Bugfix: memory corruption possible after reallocs. Using a static buffer instead. Will need to check for overflows on static buffer.
nrich@ii.net
parents:
21
diff
changeset
|
188 | } |
a4825c3e65e9
Bugfix: memory corruption possible after reallocs. Using a static buffer instead. Will need to check for overflows on static buffer.
nrich@ii.net
parents:
21
diff
changeset
|
189 | |
1 | 190 | for (p = 2; p <= n; p++) { |
191 | int type = lua_type(L, p); | |
192 | int i = p - 2; | |
193 | ||
194 | const char *str = NULL; | |
7
4480ae002881
Bugfix - the size of strings for bind params pointed to the same memory
nrich@ii.net
parents:
6
diff
changeset
|
195 | size_t *str_len = NULL; |
6
22046b996150
Fixed bug: double bind params were using the same variables memory space so they were all being set to the same number.
nrich@ii.net
parents:
4
diff
changeset
|
196 | double *num = NULL; |
9 | 197 | int *boolean = NULL; |
10 | 198 | char err[64]; |
1 | 199 | |
200 | switch(type) { | |
201 | case LUA_TNIL: | |
202 | bind[i].buffer_type = MYSQL_TYPE_NULL; | |
203 | bind[i].is_null = (my_bool*)1; | |
204 | break; | |
205 | ||
9 | 206 | case LUA_TBOOLEAN: |
26 | 207 | boolean = (int *)(buffer + offset); |
14 | 208 | offset += sizeof(int); |
9 | 209 | *boolean = lua_toboolean(L, p); |
14 | 210 | |
9 | 211 | bind[i].buffer_type = MYSQL_TYPE_LONG; |
212 | bind[i].is_null = (my_bool*)0; | |
213 | bind[i].buffer = (char *)boolean; | |
214 | bind[i].length = 0; | |
215 | break; | |
216 | ||
1 | 217 | case LUA_TNUMBER: |
6
22046b996150
Fixed bug: double bind params were using the same variables memory space so they were all being set to the same number.
nrich@ii.net
parents:
4
diff
changeset
|
218 | /* |
22046b996150
Fixed bug: double bind params were using the same variables memory space so they were all being set to the same number.
nrich@ii.net
parents:
4
diff
changeset
|
219 | * num needs to be it's own |
22046b996150
Fixed bug: double bind params were using the same variables memory space so they were all being set to the same number.
nrich@ii.net
parents:
4
diff
changeset
|
220 | * memory here |
22046b996150
Fixed bug: double bind params were using the same variables memory space so they were all being set to the same number.
nrich@ii.net
parents:
4
diff
changeset
|
221 | */ |
26 | 222 | num = (double *)(buffer + offset); |
14 | 223 | offset += sizeof(double); |
9 | 224 | *num = lua_tonumber(L, p); |
1 | 225 | |
226 | bind[i].buffer_type = MYSQL_TYPE_DOUBLE; | |
227 | bind[i].is_null = (my_bool*)0; | |
6
22046b996150
Fixed bug: double bind params were using the same variables memory space so they were all being set to the same number.
nrich@ii.net
parents:
4
diff
changeset
|
228 | bind[i].buffer = (char *)num; |
1 | 229 | bind[i].length = 0; |
230 | break; | |
231 | ||
232 | case LUA_TSTRING: | |
26 | 233 | str_len = (size_t *)(buffer + offset); |
14 | 234 | offset += sizeof(size_t); |
9 | 235 | str = lua_tolstring(L, p, str_len); |
1 | 236 | |
237 | bind[i].buffer_type = MYSQL_TYPE_STRING; | |
238 | bind[i].is_null = (my_bool*)0; | |
239 | bind[i].buffer = (char *)str; | |
7
4480ae002881
Bugfix - the size of strings for bind params pointed to the same memory
nrich@ii.net
parents:
6
diff
changeset
|
240 | bind[i].length = str_len; |
1 | 241 | break; |
242 | ||
243 | default: | |
10 | 244 | snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); |
245 | errstr = err; | |
246 | error_message = DBI_ERR_BINDING_PARAMS; | |
1 | 247 | goto cleanup; |
248 | } | |
249 | } | |
250 | ||
251 | if (mysql_stmt_bind_param(statement->stmt, bind)) { | |
4 | 252 | error_message = DBI_ERR_BINDING_PARAMS; |
1 | 253 | goto cleanup; |
254 | } | |
255 | ||
256 | if (mysql_stmt_execute(statement->stmt)) { | |
4 | 257 | error_message = DBI_ERR_BINDING_EXEC; |
1 | 258 | goto cleanup; |
259 | } | |
260 | ||
261 | metadata = mysql_stmt_result_metadata(statement->stmt); | |
262 | ||
21
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
263 | if (metadata) { |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
264 | mysql_stmt_store_result(statement->stmt); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
265 | } |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
266 | |
1 | 267 | cleanup: |
23
a4825c3e65e9
Bugfix: memory corruption possible after reallocs. Using a static buffer instead. Will need to check for overflows on static buffer.
nrich@ii.net
parents:
21
diff
changeset
|
268 | if (bind) { |
1 | 269 | free(bind); |
23
a4825c3e65e9
Bugfix: memory corruption possible after reallocs. Using a static buffer instead. Will need to check for overflows on static buffer.
nrich@ii.net
parents:
21
diff
changeset
|
270 | } |
1 | 271 | |
25 | 272 | if (buffer) { |
273 | free(buffer); | |
274 | } | |
275 | ||
1 | 276 | if (error_message) { |
3 | 277 | lua_pushboolean(L, 0); |
10 | 278 | lua_pushfstring(L, error_message, errstr ? errstr : mysql_stmt_error(statement->stmt)); |
3 | 279 | return 2; |
1 | 280 | } |
281 | ||
282 | statement->metadata = metadata; | |
283 | ||
3 | 284 | lua_pushboolean(L, 1); |
1 | 285 | return 1; |
286 | } | |
287 | ||
11
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
288 | static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { |
1 | 289 | int column_count; |
290 | MYSQL_BIND *bind = NULL; | |
291 | const char *error_message = NULL; | |
292 | ||
293 | if (!statement->stmt) { | |
4 | 294 | luaL_error(L, DBI_ERR_FETCH_INVALID); |
3 | 295 | return 0; |
296 | } | |
297 | ||
298 | if (!statement->metadata) { | |
4 | 299 | luaL_error(L, DBI_ERR_FETCH_NO_EXECUTE); |
3 | 300 | return 0; |
1 | 301 | } |
302 | ||
303 | column_count = mysql_num_fields(statement->metadata); | |
304 | ||
305 | if (column_count > 0) { | |
306 | int i; | |
307 | MYSQL_FIELD *fields; | |
308 | ||
309 | bind = malloc(sizeof(MYSQL_BIND) * column_count); | |
310 | memset(bind, 0, sizeof(MYSQL_BIND) * column_count); | |
311 | ||
312 | fields = mysql_fetch_fields(statement->metadata); | |
313 | ||
314 | for (i = 0; i < column_count; i++) { | |
33 | 315 | unsigned int length = mysql_buffer_size(&fields[i]); |
1 | 316 | char *buffer = (char *)malloc(length); |
317 | memset(buffer, 0, length); | |
318 | ||
319 | bind[i].buffer_type = fields[i].type; | |
320 | bind[i].buffer = buffer; | |
321 | bind[i].buffer_length = length; | |
322 | } | |
323 | ||
324 | if (mysql_stmt_bind_result(statement->stmt, bind)) { | |
4 | 325 | error_message = DBI_ERR_BINDING_RESULTS; |
1 | 326 | goto cleanup; |
327 | } | |
328 | ||
329 | if (!mysql_stmt_fetch(statement->stmt)) { | |
330 | int d = 1; | |
331 | ||
332 | lua_newtable(L); | |
333 | for (i = 0; i < column_count; i++) { | |
334 | lua_push_type_t lua_push = mysql_to_lua_push(fields[i].type); | |
335 | const char *name = fields[i].name; | |
336 | ||
337 | if (lua_push == LUA_PUSH_NIL) { | |
338 | if (named_columns) { | |
339 | LUA_PUSH_ATTRIB_NIL(name); | |
340 | } else { | |
341 | LUA_PUSH_ARRAY_NIL(d); | |
342 | } | |
343 | } else if (lua_push == LUA_PUSH_INTEGER) { | |
36 | 344 | if (fields[i].type == MYSQL_TYPE_YEAR || fields[i].type == MYSQL_TYPE_SHORT) { |
345 | if (named_columns) { | |
346 | LUA_PUSH_ATTRIB_INT(name, *(short *)(bind[i].buffer)); | |
347 | } else { | |
348 | LUA_PUSH_ARRAY_INT(d, *(short *)(bind[i].buffer)); | |
349 | } | |
350 | } else if (fields[i].type == MYSQL_TYPE_TINY) { | |
351 | if (named_columns) { | |
352 | LUA_PUSH_ATTRIB_INT(name, (int)*(char *)(bind[i].buffer)); | |
353 | } else { | |
354 | LUA_PUSH_ARRAY_INT(d, (int)*(char *)(bind[i].buffer)); | |
355 | } | |
1 | 356 | } else { |
36 | 357 | if (named_columns) { |
358 | LUA_PUSH_ATTRIB_INT(name, *(int *)(bind[i].buffer)); | |
359 | } else { | |
360 | LUA_PUSH_ARRAY_INT(d, *(int *)(bind[i].buffer)); | |
361 | } | |
1 | 362 | } |
363 | } else if (lua_push == LUA_PUSH_NUMBER) { | |
364 | if (named_columns) { | |
365 | LUA_PUSH_ATTRIB_FLOAT(name, *(double *)(bind[i].buffer)); | |
366 | } else { | |
367 | LUA_PUSH_ARRAY_FLOAT(d, *(double *)(bind[i].buffer)); | |
368 | } | |
369 | } else if (lua_push == LUA_PUSH_STRING) { | |
33 | 370 | |
371 | if (fields[i].type == MYSQL_TYPE_TIMESTAMP || fields[i].type == MYSQL_TYPE_DATETIME) { | |
372 | char str[20]; | |
373 | struct st_mysql_time *t = bind[i].buffer; | |
374 | ||
375 | snprintf(str, 20, "%d-%02d-%02d %02d:%02d:%02d", t->year, t->month, t->day, t->hour, t->minute, t->second); | |
376 | ||
377 | if (named_columns) { | |
378 | LUA_PUSH_ATTRIB_STRING(name, str); | |
379 | } else { | |
380 | LUA_PUSH_ARRAY_STRING(d, str); | |
381 | } | |
382 | } else if (fields[i].type == MYSQL_TYPE_TIME) { | |
383 | char str[9]; | |
384 | struct st_mysql_time *t = bind[i].buffer; | |
385 | ||
386 | snprintf(str, 9, "%02d:%02d:%02d", t->hour, t->minute, t->second); | |
387 | ||
388 | if (named_columns) { | |
389 | LUA_PUSH_ATTRIB_STRING(name, str); | |
390 | } else { | |
391 | LUA_PUSH_ARRAY_STRING(d, str); | |
392 | } | |
393 | } else if (fields[i].type == MYSQL_TYPE_DATE) { | |
394 | char str[20]; | |
395 | struct st_mysql_time *t = bind[i].buffer; | |
396 | ||
397 | snprintf(str, 11, "%d-%02d-%02d", t->year, t->month, t->day); | |
398 | ||
399 | if (named_columns) { | |
400 | LUA_PUSH_ATTRIB_STRING(name, str); | |
401 | } else { | |
402 | LUA_PUSH_ARRAY_STRING(d, str); | |
403 | } | |
404 | ||
1 | 405 | } else { |
33 | 406 | if (named_columns) { |
407 | LUA_PUSH_ATTRIB_STRING(name, bind[i].buffer); | |
408 | } else { | |
409 | LUA_PUSH_ARRAY_STRING(d, bind[i].buffer); | |
410 | } | |
1 | 411 | } |
412 | } else if (lua_push == LUA_PUSH_BOOLEAN) { | |
413 | if (named_columns) { | |
414 | LUA_PUSH_ATTRIB_BOOL(name, *(int *)(bind[i].buffer)); | |
415 | } else { | |
416 | LUA_PUSH_ARRAY_BOOL(d, *(int *)(bind[i].buffer)); | |
417 | } | |
418 | } else { | |
4 | 419 | luaL_error(L, DBI_ERR_UNKNOWN_PUSH); |
1 | 420 | } |
421 | } | |
422 | } else { | |
423 | lua_pushnil(L); | |
424 | } | |
425 | } | |
426 | ||
427 | cleanup: | |
428 | if (bind) { | |
429 | int i; | |
430 | ||
431 | for (i = 0; i < column_count; i++) { | |
432 | free(bind[i].buffer); | |
433 | } | |
434 | ||
435 | free(bind); | |
436 | } | |
437 | ||
438 | if (error_message) { | |
439 | luaL_error(L, error_message, mysql_stmt_error(statement->stmt)); | |
440 | return 0; | |
441 | } | |
442 | ||
443 | return 1; | |
444 | } | |
445 | ||
11
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
446 | static int next_iterator(lua_State *L) { |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
447 | statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_MYSQL_STATEMENT); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
448 | int named_columns = lua_toboolean(L, lua_upvalueindex(2)); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
449 | |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
450 | return statement_fetch_impl(L, statement, named_columns); |
1 | 451 | } |
452 | ||
2 | 453 | /* |
12
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
454 | * table = statement:fetch(named_indexes) |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
455 | */ |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
456 | static int statement_fetch(lua_State *L) { |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
457 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
458 | int named_columns = lua_toboolean(L, 2); |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
459 | |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
460 | return statement_fetch_impl(L, statement, named_columns); |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
461 | } |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
462 | |
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
463 | /* |
21
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
464 | * num_rows = statement:rowcount() |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
465 | */ |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
466 | static int statement_rowcount(lua_State *L) { |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
467 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
468 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
469 | if (!statement->stmt) { |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
470 | luaL_error(L, DBI_ERR_INVALID_STATEMENT); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
471 | } |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
472 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
473 | lua_pushinteger(L, mysql_stmt_num_rows(statement->stmt)); |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
474 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
475 | return 1; |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
476 | } |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
477 | |
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
478 | /* |
12
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
479 | * iterfunc = statement:rows(named_indexes) |
2 | 480 | */ |
12
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
481 | static int statement_rows(lua_State *L) { |
11
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
482 | if (lua_gettop(L) == 1) { |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
483 | lua_pushvalue(L, 1); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
484 | lua_pushboolean(L, 0); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
485 | } else { |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
486 | lua_pushvalue(L, 1); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
487 | lua_pushboolean(L, lua_toboolean(L, 2)); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
488 | } |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
489 | |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
490 | lua_pushcclosure(L, next_iterator, 2); |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
491 | return 1; |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
492 | } |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
493 | |
b3e05e361f46
Bugfix: PSQL array returns were not being indexed properly.
nrich@ii.net
parents:
10
diff
changeset
|
494 | /* |
2 | 495 | * __gc |
496 | */ | |
1 | 497 | static int statement_gc(lua_State *L) { |
498 | /* always free the handle */ | |
499 | statement_close(L); | |
500 | ||
501 | return 0; | |
502 | } | |
503 | ||
32
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
504 | /* |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
505 | * __tostring |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
506 | */ |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
507 | static int statement_tostring(lua_State *L) { |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
508 | statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_MYSQL_STATEMENT); |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
509 | |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
510 | lua_pushfstring(L, "%s: %p", DBD_MYSQL_STATEMENT, statement); |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
511 | |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
512 | return 1; |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
513 | } |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
514 | |
1 | 515 | int dbd_mysql_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { |
516 | unsigned long sql_len = strlen(sql_query); | |
517 | ||
518 | statement_t *statement = NULL; | |
519 | ||
520 | MYSQL_STMT *stmt = mysql_stmt_init(conn->mysql); | |
521 | ||
522 | if (!stmt) { | |
3 | 523 | lua_pushnil(L); |
4 | 524 | lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, mysql_error(conn->mysql)); |
3 | 525 | return 2; |
1 | 526 | } |
527 | ||
528 | if (mysql_stmt_prepare(stmt, sql_query, sql_len)) { | |
3 | 529 | lua_pushnil(L); |
4 | 530 | lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, mysql_stmt_error(stmt)); |
3 | 531 | return 2; |
1 | 532 | } |
533 | ||
534 | statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); | |
535 | statement->mysql = conn->mysql; | |
536 | statement->stmt = stmt; | |
537 | statement->metadata = NULL; | |
538 | ||
33 | 539 | /* |
540 | mysql_stmt_attr_set(stmt, STMT_ATTR_UPDATE_MAX_LENGTH, (my_bool*)0); | |
541 | */ | |
542 | ||
1 | 543 | luaL_getmetatable(L, DBD_MYSQL_STATEMENT); |
544 | lua_setmetatable(L, -2); | |
545 | ||
546 | return 1; | |
547 | } | |
548 | ||
549 | int dbd_mysql_statement(lua_State *L) { | |
2 | 550 | static const luaL_Reg statement_methods[] = { |
21
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
551 | {"affected", statement_affected}, |
2 | 552 | {"close", statement_close}, |
30
8599f34c139b
Add 'columns' method to statement handles to retrieve column names from a result set
nrich@ii.net
parents:
26
diff
changeset
|
553 | {"columns", statement_columns}, |
2 | 554 | {"execute", statement_execute}, |
555 | {"fetch", statement_fetch}, | |
21
7956401a0c5e
Added the statement:affected() and statement:rowcount() methods.
nrich@ii.net
parents:
14
diff
changeset
|
556 | {"rowcount", statement_rowcount}, |
12
014ba3ab3903
Renamed statement:fetch() to statement:rows(), and statement:row() to statement:fetch(). The API reads better this way.
nrich@ii.net
parents:
11
diff
changeset
|
557 | {"rows", statement_rows}, |
2 | 558 | {NULL, NULL} |
559 | }; | |
560 | ||
561 | static const luaL_Reg statement_class_methods[] = { | |
562 | {NULL, NULL} | |
563 | }; | |
564 | ||
1 | 565 | luaL_newmetatable(L, DBD_MYSQL_STATEMENT); |
566 | luaL_register(L, 0, statement_methods); | |
567 | lua_pushvalue(L,-1); | |
568 | lua_setfield(L, -2, "__index"); | |
569 | ||
570 | lua_pushcfunction(L, statement_gc); | |
571 | lua_setfield(L, -2, "__gc"); | |
572 | ||
32
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
573 | lua_pushcfunction(L, statement_tostring); |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
574 | lua_setfield(L, -2, "__tostring"); |
03ed0ca09837
Add __tostring method to connection and statement objects.
nrich@ii.net
parents:
30
diff
changeset
|
575 | |
1 | 576 | luaL_register(L, DBD_MYSQL_STATEMENT, statement_class_methods); |
577 | ||
578 | return 1; | |
579 | } |