|
1 #include "dbd_oracle.h" |
|
2 |
|
3 /* |
|
4 * Converts SQLite types to Lua types |
|
5 */ |
|
6 static lua_push_type_t oracle_to_lua_push(unsigned int oracle_type, int null) { |
|
7 lua_push_type_t lua_type; |
|
8 |
|
9 if (null) |
|
10 return LUA_PUSH_NIL; |
|
11 |
|
12 switch(oracle_type) { |
|
13 case SQLT_NUM: |
|
14 case SQLT_FLT: |
|
15 lua_type = LUA_PUSH_NUMBER; |
|
16 break; |
|
17 case SQLT_INT: |
|
18 lua_type = LUA_PUSH_INTEGER; |
|
19 break; |
|
20 default: |
|
21 lua_type = LUA_PUSH_STRING; |
|
22 } |
|
23 |
|
24 return lua_type; |
|
25 } |
|
26 |
|
27 /* |
|
28 * success = statement:close() |
|
29 */ |
|
30 int statement_close(lua_State *L) { |
|
31 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); |
|
32 int ok = 0; |
|
33 |
|
34 if (statement->stmt) { |
|
35 int rc; |
|
36 |
|
37 rc = OCIHandleFree((dvoid *)statement->stmt, OCI_HTYPE_STMT); /* Free handles */ |
|
38 |
|
39 statement->stmt = NULL; |
|
40 } |
|
41 |
|
42 lua_pushboolean(L, ok); |
|
43 return 1; |
|
44 } |
|
45 |
|
46 /* |
|
47 * success,err = statement:execute(...) |
|
48 */ |
|
49 int statement_execute(lua_State *L) { |
|
50 int n = lua_gettop(L); |
|
51 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); |
|
52 int p; |
|
53 int errflag = 0; |
|
54 const char *errstr = NULL; |
|
55 int expected_params; |
|
56 int num_bind_params = n - 1; |
|
57 int num_columns; |
|
58 int rc; |
|
59 |
|
60 char errbuf[100]; |
|
61 int errcode; |
|
62 |
|
63 ub2 type; |
|
64 |
|
65 if (!statement->stmt) { |
|
66 lua_pushboolean(L, 0); |
|
67 lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); |
|
68 return 2; |
|
69 } |
|
70 |
|
71 for (p = 2; p <= n; p++) { |
|
72 int i = p - 1; |
|
73 int type = lua_type(L, p); |
|
74 char err[64]; |
|
75 const char *value; |
|
76 |
|
77 OCIBind *bnd = (OCIBind *)0; |
|
78 |
|
79 switch(type) { |
|
80 case LUA_TNIL: |
|
81 errflag = OCIBindByPos( |
|
82 statement->stmt, |
|
83 &bnd, |
|
84 statement->conn->err, |
|
85 i, |
|
86 NULL, |
|
87 0, |
|
88 SQLT_CHR, |
|
89 (dvoid *)0, |
|
90 (ub2 *)0, |
|
91 (ub2 *)0, |
|
92 (ub4)0, |
|
93 (ub4 *)0, |
|
94 OCI_DEFAULT); |
|
95 break; |
|
96 case LUA_TNUMBER: |
|
97 case LUA_TSTRING: |
|
98 case LUA_TBOOLEAN: |
|
99 value = lua_tostring(L, p); |
|
100 |
|
101 errflag = OCIBindByPos( |
|
102 statement->stmt, |
|
103 &bnd, |
|
104 statement->conn->err, |
|
105 i, |
|
106 value, |
|
107 strlen(value), |
|
108 SQLT_CHR, |
|
109 (dvoid *)0, |
|
110 (ub2 *)0, |
|
111 (ub2 *)0, |
|
112 (ub4)0, |
|
113 (ub4 *)0, |
|
114 (ub4)OCI_DEFAULT); |
|
115 break; |
|
116 default: |
|
117 /* |
|
118 * Unknown/unsupported value type |
|
119 */ |
|
120 errflag = 1; |
|
121 snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); |
|
122 errstr = err; |
|
123 } |
|
124 |
|
125 if (errflag) |
|
126 break; |
|
127 } |
|
128 |
|
129 if (errflag) { |
|
130 lua_pushboolean(L, 0); |
|
131 if (errstr) |
|
132 lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); |
|
133 else { |
|
134 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
135 |
|
136 lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); |
|
137 } |
|
138 |
|
139 return 2; |
|
140 } |
|
141 |
|
142 /* |
|
143 * statement type |
|
144 */ |
|
145 rc = OCIAttrGet( |
|
146 (dvoid *)statement->stmt, |
|
147 (ub4)OCI_HTYPE_STMT, |
|
148 (dvoid *)&type, |
|
149 (ub4 *)0, |
|
150 (ub4)OCI_ATTR_STMT_TYPE, |
|
151 statement->conn->err |
|
152 ); |
|
153 |
|
154 if (rc) { |
|
155 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
156 |
|
157 lua_pushboolean(L, 0); |
|
158 lua_pushfstring(L, "Error getting type: %s", errbuf); |
|
159 |
|
160 return 2; |
|
161 } |
|
162 |
|
163 /* |
|
164 * execute statement |
|
165 */ |
|
166 rc = OCIStmtExecute( |
|
167 statement->conn->svc, |
|
168 statement->stmt, |
|
169 statement->conn->err, |
|
170 type == OCI_STMT_SELECT ? 0 : 1, |
|
171 (ub4)0, |
|
172 (CONST OCISnapshot *)NULL, |
|
173 (OCISnapshot *)NULL, |
|
174 statement->conn->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT |
|
175 ); |
|
176 |
|
177 if (rc) { |
|
178 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
179 |
|
180 lua_pushboolean(L, 0); |
|
181 lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); |
|
182 |
|
183 return 2; |
|
184 } |
|
185 |
|
186 /* |
|
187 * get number of columns |
|
188 */ |
|
189 rc = OCIAttrGet( |
|
190 (dvoid *)statement->stmt, |
|
191 (ub4)OCI_HTYPE_STMT, |
|
192 (dvoid *)&num_columns, |
|
193 (ub4 *)0, |
|
194 (ub4)OCI_ATTR_PARAM_COUNT, |
|
195 statement->conn->err |
|
196 ); |
|
197 |
|
198 if (rc) { |
|
199 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
200 |
|
201 lua_pushboolean(L, 0); |
|
202 lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); |
|
203 |
|
204 return 2; |
|
205 } |
|
206 |
|
207 statement->num_columns = num_columns; |
|
208 |
|
209 lua_pushboolean(L, 1); |
|
210 return 1; |
|
211 } |
|
212 |
|
213 /* |
|
214 * must be called after an execute |
|
215 */ |
|
216 static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { |
|
217 int rc; |
|
218 sword status; |
|
219 int i; |
|
220 bindparams_t *bind; |
|
221 |
|
222 char errbuf[100]; |
|
223 int errcode; |
|
224 |
|
225 if (!statement->stmt) { |
|
226 luaL_error(L, DBI_ERR_FETCH_INVALID); |
|
227 return 0; |
|
228 } |
|
229 |
|
230 bind = (bindparams_t *)malloc(sizeof(bindparams_t) * statement->num_columns); |
|
231 memset(bind, 0, sizeof(bindparams_t) * statement->num_columns); |
|
232 |
|
233 for (i = 0; i < statement->num_columns; i++) { |
|
234 rc = OCIParamGet(statement->stmt, OCI_HTYPE_STMT, statement->conn->err, (dvoid **)&bind[i].param, i+1); |
|
235 if (rc) { |
|
236 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
237 luaL_error(L, "param get %s", errbuf); |
|
238 } |
|
239 |
|
240 rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].name), (ub4 *)&(bind[i].name_len), OCI_ATTR_NAME, statement->conn->err); |
|
241 if (rc) { |
|
242 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
243 luaL_error(L, "name get %s", errbuf); |
|
244 } |
|
245 |
|
246 rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].data_type), (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->conn->err); |
|
247 if (rc) { |
|
248 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
249 luaL_error(L, "datatype get %s", errbuf); |
|
250 } |
|
251 |
|
252 rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].max_len), 0, OCI_ATTR_DATA_SIZE, statement->conn->err); |
|
253 if (rc) { |
|
254 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); |
|
255 luaL_error(L, "datasize get %s", errbuf); |
|
256 } |
|
257 |
|
258 bind[i].data = calloc(bind[i].max_len+1, sizeof(char)); |
|
259 rc = OCIDefineByPos(statement->stmt, &bind[i].define, statement->conn->err, (ub4)i+1, bind[i].data, bind[i].max_len, SQLT_STR, (dvoid *)&(bind[i].null), (ub2 *)0, (ub2 *)0, (ub4)OCI_DEFAULT); |
|
260 if (rc) { |
|
261 OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); |
|
262 luaL_error(L, "define by pos %s", errbuf); |
|
263 } |
|
264 } |
|
265 |
|
266 status = OCIStmtFetch(statement->stmt, statement->conn->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT); |
|
267 |
|
268 if (status == OCI_NO_DATA) { |
|
269 /* No more rows */ |
|
270 lua_pushnil(L); |
|
271 return 1; |
|
272 } else if (status != OCI_SUCCESS) { |
|
273 OCIErrorGet((dvoid *)statement->conn->err, (ub4)1, (text *)NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); |
|
274 luaL_error(L, DBI_ERR_FETCH_FAILED, errbuf); |
|
275 } |
|
276 |
|
277 if (statement->num_columns) { |
|
278 int i; |
|
279 int d = 1; |
|
280 |
|
281 lua_newtable(L); |
|
282 |
|
283 for (i = 0; i < statement->num_columns; i++) { |
|
284 lua_push_type_t lua_push = oracle_to_lua_push(bind[i].data_type, bind[i].null); |
|
285 const char *name = strlower(bind[i].name); |
|
286 const char *data = bind[i].data; |
|
287 |
|
288 if (lua_push == LUA_PUSH_NIL) { |
|
289 if (named_columns) { |
|
290 LUA_PUSH_ATTRIB_NIL(name); |
|
291 } else { |
|
292 LUA_PUSH_ARRAY_NIL(d); |
|
293 } |
|
294 } else if (lua_push == LUA_PUSH_INTEGER) { |
|
295 int val = atoi(data); |
|
296 |
|
297 if (named_columns) { |
|
298 LUA_PUSH_ATTRIB_INT(name, val); |
|
299 } else { |
|
300 LUA_PUSH_ARRAY_INT(d, val); |
|
301 } |
|
302 } else if (lua_push == LUA_PUSH_NUMBER) { |
|
303 double val = strtod(data, NULL); |
|
304 |
|
305 if (named_columns) { |
|
306 LUA_PUSH_ATTRIB_FLOAT(name, val); |
|
307 } else { |
|
308 LUA_PUSH_ARRAY_FLOAT(d, val); |
|
309 } |
|
310 } else if (lua_push == LUA_PUSH_STRING) { |
|
311 if (named_columns) { |
|
312 LUA_PUSH_ATTRIB_STRING(name, data); |
|
313 } else { |
|
314 LUA_PUSH_ARRAY_STRING(d, data); |
|
315 } |
|
316 } else if (lua_push == LUA_PUSH_BOOLEAN) { |
|
317 int val = 1; |
|
318 |
|
319 if (named_columns) { |
|
320 LUA_PUSH_ATTRIB_BOOL(name, val); |
|
321 } else { |
|
322 LUA_PUSH_ARRAY_BOOL(d, val); |
|
323 } |
|
324 } else { |
|
325 luaL_error(L, DBI_ERR_UNKNOWN_PUSH); |
|
326 } |
|
327 } |
|
328 } else { |
|
329 /* |
|
330 * no columns returned by statement? |
|
331 */ |
|
332 lua_pushnil(L); |
|
333 } |
|
334 |
|
335 return 1; |
|
336 } |
|
337 |
|
338 static int next_iterator(lua_State *L) { |
|
339 statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_ORACLE_STATEMENT); |
|
340 int named_columns = lua_toboolean(L, lua_upvalueindex(2)); |
|
341 |
|
342 return statement_fetch_impl(L, statement, named_columns); |
|
343 } |
|
344 |
|
345 /* |
|
346 * table = statement:fetch(named_indexes) |
|
347 */ |
|
348 static int statement_fetch(lua_State *L) { |
|
349 statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); |
|
350 int named_columns = lua_toboolean(L, 2); |
|
351 |
|
352 return statement_fetch_impl(L, statement, named_columns); |
|
353 } |
|
354 |
|
355 /* |
|
356 * iterfunc = statement:rows(named_indexes) |
|
357 */ |
|
358 static int statement_rows(lua_State *L) { |
|
359 if (lua_gettop(L) == 1) { |
|
360 lua_pushvalue(L, 1); |
|
361 lua_pushboolean(L, 0); |
|
362 } else { |
|
363 lua_pushvalue(L, 1); |
|
364 lua_pushboolean(L, lua_toboolean(L, 2)); |
|
365 } |
|
366 |
|
367 lua_pushcclosure(L, next_iterator, 2); |
|
368 return 1; |
|
369 } |
|
370 |
|
371 /* |
|
372 * __gc |
|
373 */ |
|
374 static int statement_gc(lua_State *L) { |
|
375 /* always free the handle */ |
|
376 statement_close(L); |
|
377 |
|
378 return 0; |
|
379 } |
|
380 |
|
381 int dbd_oracle_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { |
|
382 int rc; |
|
383 statement_t *statement = NULL; |
|
384 OCIStmt *stmt; |
|
385 char *new_sql; |
|
386 |
|
387 /* |
|
388 * convert SQL string into a Oracle API compatible SQL statement |
|
389 */ |
|
390 new_sql = replace_placeholders(L, ':', sql_query); |
|
391 |
|
392 rc = OCIHandleAlloc((dvoid *)conn->oracle, (dvoid **)&stmt, OCI_HTYPE_STMT, 0, (dvoid **)0); |
|
393 rc = OCIStmtPrepare(stmt, conn->err, new_sql, strlen(new_sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT); |
|
394 |
|
395 free(new_sql); |
|
396 |
|
397 statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); |
|
398 statement->conn = conn; |
|
399 statement->stmt = stmt; |
|
400 statement->num_columns = 0; |
|
401 |
|
402 luaL_getmetatable(L, DBD_ORACLE_STATEMENT); |
|
403 lua_setmetatable(L, -2); |
|
404 |
|
405 return 1; |
|
406 } |
|
407 |
|
408 int dbd_oracle_statement(lua_State *L) { |
|
409 static const luaL_Reg statement_methods[] = { |
|
410 {"close", statement_close}, |
|
411 {"execute", statement_execute}, |
|
412 {"fetch", statement_fetch}, |
|
413 {"rows", statement_rows}, |
|
414 {NULL, NULL} |
|
415 }; |
|
416 |
|
417 static const luaL_Reg statement_class_methods[] = { |
|
418 {NULL, NULL} |
|
419 }; |
|
420 |
|
421 luaL_newmetatable(L, DBD_ORACLE_STATEMENT); |
|
422 luaL_register(L, 0, statement_methods); |
|
423 lua_pushvalue(L,-1); |
|
424 lua_setfield(L, -2, "__index"); |
|
425 |
|
426 lua_pushcfunction(L, statement_gc); |
|
427 lua_setfield(L, -2, "__gc"); |
|
428 |
|
429 luaL_register(L, DBD_ORACLE_STATEMENT, statement_class_methods); |
|
430 |
|
431 return 1; |
|
432 } |