1 #include "dbd_db2.h"
2 #include "db2_common.h"
3 
4 #define BIND_BUFFER_SIZE    1024
5 
6 static lua_push_type_t db2_to_lua_push(unsigned int db2_type) {
7     lua_push_type_t lua_type;
8 
9     switch(db2_type) {
10 	case SQL_BOOLEAN:
11 	    lua_type = LUA_PUSH_BOOLEAN;
12 	case SQL_SMALLINT:
13 	case SQL_INTEGER:
14 	    lua_type = LUA_PUSH_INTEGER;
15 	    break;
16 	case SQL_FLOAT:
17 	case SQL_REAL:
18 	case SQL_DOUBLE:
19 	case SQL_DECIMAL:
20 	    lua_type = LUA_PUSH_NUMBER;
21 	    break;
22 	    break;
23 	default:
24 	    lua_type = LUA_PUSH_STRING;
25     }
26 
27     return lua_type;
28 }
29 
30 /*
31  * num_affected_rows = statement:affected()
32  */
33 static int statement_affected(lua_State *L) {
34     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT);
35     SQLINTEGER affected;
36 
37     if (!statement->stmt) {
38         luaL_error(L, DBI_ERR_INVALID_STATEMENT);
39     }
40 
41     (void)SQLRowCount(statement->stmt, &affected);
42 
43     lua_pushinteger(L, affected);
44 
45     return 1;
46 }
47 
48 /*
49  * free cursor and associated memory
STR2REAL(const std::string & s)50  */
51 static void free_cursor(statement_t *statement) {
52     if (statement->cursor_open) {
53 	SQLFreeStmt(statement->stmt, SQL_CLOSE);
54 	statement->cursor_open = 0;
55     }
56 }
57 
58 /*
59  * success = statement:close()
60  */
61 static int statement_close(lua_State *L) {
62     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT);
63 
64     free_cursor(statement);
65 
66     if (statement->resultset) {
67 	free(statement->resultset);
68 	statement->resultset = NULL;
69     }
70 
JSONUIDecoderJSONUIDecoder71     if (statement->parambuf) {
72 	free(statement->parambuf);
73 	statement->parambuf = NULL;
74     }
75 
76     statement->num_result_columns = 0;
77 
78     if (statement->stmt) {
79 	SQLFreeHandle(SQL_HANDLE_STMT, statement->stmt);
80 	statement->stmt = SQL_NULL_HSTMT;
81     }
82 
83     return 0;
84 }
85 
86 /*
87  *  column_names = statement:columns()
88  */
89 static int statement_columns(lua_State *L) {
90     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT);
91 
92     int i;
93     int d;
94 
95     if (!statement->resultset) {
96 	lua_pushnil(L);
97 	return 1;
98     }
99 
100     d = 1;
101     lua_newtable(L);
102     for (i = 0; i < statement->num_result_columns; i++) {
103 	const char *name = dbd_strlower((char *)statement->resultset[i].name);
104 	LUA_PUSH_ARRAY_STRING(d, name);
105     }
106 
107     return 1;
108 }
109 
110 /*
111  * success = statement:execute(...)
112  */
113 static int statement_execute(lua_State *L) {
114     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT);
115     int n = lua_gettop(L);
~JSONUIDecoderJSONUIDecoder116     int p;
117     int errflag = 0;
118     const char *errstr = NULL;
119     SQLRETURN rc = SQL_SUCCESS;
120     unsigned char *buffer = statement->parambuf;
121     int offset = 0;
122 
123     SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1];
124 
125     if (!statement->stmt) {
metadataJSONUIDecoder126 	lua_pushboolean(L, 0);
127 	lua_pushstring(L, DBI_ERR_EXECUTE_INVALID);
128 	return 2;
129     }
130 
131     /* If the cursor is open from a previous execute, close it */
132     free_cursor(statement);
133 
buildUserInterfaceJSONUIDecoder134     if (statement->num_params != n-1) {
135         /*
136 	 * SQLExecute does not handle this condition,
137  	 * and the client library will fill unset params
138 	 * with NULLs
139 	 */
140 	lua_pushboolean(L, 0);
141         lua_pushfstring(L, DBI_ERR_PARAM_MISCOUNT, statement->num_params, n-1);
142 	return 2;
143     }
144 
145     for (p = 2; p <= n; p++) {
146 	int i = p - 1;
147 	int type = lua_type(L, p);
148 	char err[64];
149 	const char *str = NULL;
150 	size_t len = 0;
151 	double *num;
152 	int *boolean;
153 	const static SQLLEN nullvalue = SQL_NULL_DATA;
154 
155 	switch(type) {
156 	case LUA_TNIL:
157 	    rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)0, 0, (SQLPOINTER)&nullvalue);
158 	    errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO;
159 	    break;
160 	case LUA_TNUMBER:
161 	    num = (double *)(buffer + offset);
162 	    *num = lua_tonumber(L, p);
163 	    offset += sizeof(double);
164 	    rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_DOUBLE, SQL_DECIMAL, 10, 0, (SQLPOINTER)num, 0, NULL);
165 	    errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO;
166 	    break;
167 	case LUA_TSTRING:
168 	    str = lua_tolstring(L, p, &len);
169 	    rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_CHAR, SQL_VARCHAR, 0, 0, (SQLPOINTER)str, len, NULL);
170 	    errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO;
171 	    break;
172 	case LUA_TBOOLEAN:
173 	    boolean = (int *)(buffer + offset);
174 	    *boolean = lua_toboolean(L, p);
175 	    offset += sizeof(int);
176 	    rc = SQLBindParameter(statement->stmt, i, SQL_PARAM_INPUT, SQL_C_LONG, SQL_INTEGER, 0, 0, (SQLPOINTER)boolean, len, NULL);
177 	    errflag = rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO;
178 	    break;
179 	default:
180 	    /*
181 	     * Unknown/unsupported value type
182 	     */
183 	    errflag = 1;
184             snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type));
185             errstr = err;
186 	}
187 
188 	if (errflag)
189 	    break;
190     }
191 
192     if (errflag) {
193 	lua_pushboolean(L, 0);
194 
195 	if (errstr) {
196 	    lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr);
197 	} else {
198 	    db2_stmt_diag(statement->stmt, message, sizeof(message));
199 	    lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, message);
200 	}
201 
202 	return 2;
203     }
204 
205     rc = SQLExecute(statement->stmt);
206     if (rc != SQL_SUCCESS) {
207 	db2_stmt_diag(statement->stmt, message, sizeof(message));
208 	lua_pushnil(L);
209 	lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, message);
210 	return 2;
211     }
212 
213     statement->cursor_open = 1;
214 
215     lua_pushboolean(L, 1);
216     return 1;
217 }
218 
219 
220 
221 /*
222  * must be called after an execute
223  */
224 static int statement_fetch_impl(lua_State *L, statement_t *statement,
225 				int named_columns) {
226     int i;
227     int d;
228 
229     SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1];
230     SQLRETURN rc;
231 
232     if (!statement->cursor_open)
233 	goto nodata;
234 
proxy_dsp(const string & json)235     /* fetch each row, and display */
236     rc = SQLFetch(statement->stmt);
237     if (rc == SQL_NO_DATA_FOUND) {
238 	free_cursor(statement);
239 	goto nodata;
240     }
proxy_dsp(dsp * dsp)241 
242     if (rc != SQL_SUCCESS) {
243 	db2_stmt_diag(statement->stmt, message, sizeof(message));
244         luaL_error(L, DBI_ERR_FETCH_FAILED, message);
245     }
246 
247     d = 1;
248     lua_newtable(L);
249     for (i = 0; i < statement->num_result_columns; i++) {
~proxy_dsp()250 	resultset_t *rs = &statement->resultset[i];
251 	SQLCHAR *name = rs->name;
252 	lua_push_type_t lua_type = rs->lua_type;
253 	resultset_data_t *data = &(rs->data);
254 
getNumInputs()255 	if (rs->actual_len == SQL_NULL_DATA)
256 	    lua_type = LUA_PUSH_NIL;
257 
buildUserInterface(UI * ui)258 	if (named_columns)
259 	    lua_pushstring(L, (const char *)name);
260 
init(int samplingRate)261 	switch (lua_type) {
262 	    case LUA_PUSH_NIL:
263 		lua_pushnil(L);
264 		break;
265 	    case LUA_PUSH_INTEGER:
266 		lua_pushinteger(L, data->integer);
267 		break;
268 	    case LUA_PUSH_NUMBER:
269 		lua_pushnumber(L, data->number);
270 		break;
271 	    case LUA_PUSH_BOOLEAN:
272 		lua_pushboolean(L, data->boolean);
273 		break;
274 	    case LUA_PUSH_STRING:
275 		lua_pushstring(L, (const char *)data->str);
276 		break;
277 	    default:
278 		luaL_error(L, DBI_ERR_UNKNOWN_PUSH);
279 	}
280 
281 	if (named_columns)
282 	    lua_rawset(L, -3);
283 	else {
284 	    lua_rawseti(L, -2, d);
285 	    d++;
286 	}
287     }
288 
289     return 1;
290 nodata:
291     lua_pushnil(L);
292     return 1;
293 }
294 
295 
296 static int next_iterator(lua_State *L) {
297     statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_DB2_STATEMENT);
298     int named_columns = lua_toboolean(L, lua_upvalueindex(2));
299 
300     return statement_fetch_impl(L, statement, named_columns);
301 }
302 
303 /*
304  * table = statement:fetch(named_indexes)
305  */
306 static int statement_fetch(lua_State *L) {
307     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT);
308     int named_columns = lua_toboolean(L, 2);
309 
310     return statement_fetch_impl(L, statement, named_columns);
311 }
312 
313 /*
314  * num_rows = statement:rowcount()
315  */
316 static int statement_rowcount(lua_State *L) {
317     luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_DB2_STATEMENT, "rowcount");
318 
319     return 0;
320 }
321 
322 /*
323  * iterfunc = statement:rows(named_indexes)
324  */
325 static int statement_rows(lua_State *L) {
326     if (lua_gettop(L) == 1) {
327         lua_pushvalue(L, 1);
328         lua_pushboolean(L, 0);
329     } else {
330         lua_pushvalue(L, 1);
331         lua_pushboolean(L, lua_toboolean(L, 2));
332     }
333 
334     lua_pushcclosure(L, next_iterator, 2);
335     return 1;
336 }
337 
338 /*
339  * __gc
340  */
341 static int statement_gc(lua_State *L) {
342     /* always free the handle */
343     statement_close(L);
344 
345     return 0;
346 }
347 
348 /*
349  * __tostring
350  */
351 static int statement_tostring(lua_State *L) {
352     statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_DB2_STATEMENT);
353 
354     lua_pushfstring(L, "%s: %p", DBD_DB2_STATEMENT, statement);
355 
356     return 1;
357 }
358 
359 int dbd_db2_statement_create(lua_State *L, connection_t *conn, const char *sql_query) {
360     SQLRETURN rc = SQL_SUCCESS;
361     statement_t *statement = NULL;
362     SQLHANDLE stmt;
363     SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1];
364     SQLCHAR *buffer = NULL;
365     int buflen;
366     SQLSMALLINT sqlctype;
367     SQLPOINTER dataptr;
368     int datalen;
369 
370     resultset_t *resultset = NULL;
371     int i;
372 
373     rc = SQLAllocHandle(SQL_HANDLE_STMT, conn->db2, &stmt);
374     if (rc != SQL_SUCCESS) {
375 	db2_dbc_diag(conn->db2, message, sizeof(message));
376         lua_pushnil(L);
377         lua_pushfstring(L, DBI_ERR_ALLOC_STATEMENT, message);
378         return 2;
379     }
380 
381     /*
382      * turn off deferred prepare
383      * statements will be sent to the server at prepare time,
384      * and therefore we can catch errors now rather
385      * than at execute time
386      */
387     rc = SQLSetStmtAttr(stmt,SQL_ATTR_DEFERRED_PREPARE,(SQLPOINTER)SQL_DEFERRED_PREPARE_OFF,0);
388 
389     rc = SQLPrepare(stmt, (SQLCHAR *)sql_query, SQL_NTS);
390     if (rc != SQL_SUCCESS) {
391 	db2_stmt_diag(stmt, message, sizeof(message));
392 	lua_pushnil(L);
393 	lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, message);
394 	return 2;
395     }
396 
397     statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t));
398     statement->stmt = stmt;
399     statement->db2 = conn->db2;
400     statement->resultset = NULL;
401     statement->cursor_open = 0;
402     statement->num_params = 0;
403     statement->parambuf = NULL;
404 
405     /*
406      * identify the number of input parameters
407      */
408     rc = SQLNumParams(stmt, &statement->num_params);
409     if (rc != SQL_SUCCESS) {
410 	db2_stmt_diag(stmt, message, sizeof(message));
411         lua_pushboolean(L, 0);
412         lua_pushfstring(L, DBI_ERR_PREP_STATEMENT, message);
413         return 2;
414     }
415     if (statement->num_params > 0) {
416         statement->parambuf = (unsigned char *)malloc(sizeof(double) *
417 						      statement->num_params);
418     }
419 
420     /*
421      * identify the number of output columns
422      */
423     rc = SQLNumResultCols(stmt, &statement->num_result_columns);
424 
425     if (statement->num_result_columns > 0) {
426 	resultset = (resultset_t *)malloc(sizeof(resultset_t) *
427 					  statement->num_result_columns);
428 	memset(resultset, 0, sizeof(resultset_t) *
429 			     statement->num_result_columns);
430 
431 	buflen = 0;
432 	for (i = 0; i < statement->num_result_columns; i++) {
433 	    /*
434 	     * return a set of attributes for a column
435 	     */
436 	    rc = SQLDescribeCol(stmt,
437                         (SQLSMALLINT)(i + 1),
438                         resultset[i].name,
439                         sizeof(resultset[i].name),
440                         &resultset[i].name_len,
441                         &resultset[i].type,
442                         &resultset[i].size,
443                         &resultset[i].scale,
444                         NULL);
445 
446 	    if (rc != SQL_SUCCESS) {
447 		db2_stmt_diag(stmt, message, sizeof(message));
448 		lua_pushnil(L);
449 		lua_pushfstring(L, DBI_ERR_DESC_RESULT, message);
450 		return 2;
451 	    }
452 
453 	    resultset[i].lua_type = db2_to_lua_push(resultset[i].type);
454 	    if (resultset[i].lua_type == LUA_PUSH_STRING)
455 		buflen += (resultset[i].size + 1 + 3) & ~3;
456 	}
457 
458 	if (buflen > 0)
459 	    buffer = malloc(buflen);
460 
461 	for (i = 0; i < statement->num_result_columns; i++) {
462 	    switch (resultset[i].lua_type) {
463 		case LUA_PUSH_INTEGER:
464 		    sqlctype = SQL_C_LONG;
465 		    dataptr = &resultset[i].data.integer;
466 		    datalen = 0;
467 		    break;
468 		case LUA_PUSH_NUMBER:
469 		    sqlctype = SQL_C_DOUBLE;
470 		    dataptr = &resultset[i].data.number;
471 		    datalen = 0;
472 		    break;
473 		default:
474 		    sqlctype = SQL_C_CHAR;
475 		    resultset[i].data.str = buffer;
476 		    dataptr = buffer;
477 		    datalen = resultset[i].size + 1;
478 		    buffer += (datalen + 3) & ~3;
479 		    break;
480 	    }
481 
482 	    rc = SQLBindCol(stmt,
483                        (SQLSMALLINT)(i + 1),
484                        sqlctype,
485                        dataptr,
486 		       datalen,
487                        &resultset[i].actual_len);
488 
489 	    if (rc != SQL_SUCCESS) {
490 		db2_stmt_diag(stmt, message, sizeof(message));
491 		lua_pushnil(L);
492 		lua_pushfstring(L, DBI_ERR_ALLOC_RESULT, message);
493 		return 2;
494 	    }
495 	}
496 
497 	statement->resultset = resultset;
498     }
499     luaL_getmetatable(L, DBD_DB2_STATEMENT);
500     lua_setmetatable(L, -2);
501 
502     return 1;
503 }
504 
505 int dbd_db2_statement(lua_State *L) {
506     static const luaL_Reg statement_methods[] = {
507 	{"affected", statement_affected},
508 	{"close", statement_close},
509 	{"columns", statement_columns},
510 	{"execute", statement_execute},
511 	{"fetch", statement_fetch},
512 	{"rowcount", statement_rowcount},
513 	{"rows", statement_rows},
514 	{NULL, NULL}
515     };
516 
517     static const luaL_Reg statement_class_methods[] = {
518 	{NULL, NULL}
519     };
520 
521     dbd_register(L, DBD_DB2_STATEMENT,
522 		 statement_methods, statement_class_methods,
523 		 statement_gc, statement_tostring);
524 
525     return 1;
526 }
527