dbd/oracle/statement.c

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
 * Fetch metadata from the database
29
 */
30
 
31
static void statement_fetch_metadata(lua_State *L, statement_t *statement) {
32
    bindparams_t *bind;
33
    int i;
34
 
35
    char errbuf[100];
36
    int errcode;
37
    int rc;
38
 
39
    if (statement->metadata)
40
	return;
41
 
42
    statement->bind = (bindparams_t *)malloc(sizeof(bindparams_t) * statement->num_columns);
43
    memset(statement->bind, 0, sizeof(bindparams_t) * statement->num_columns);
44
    bind = statement->bind;
45
 
46
    for (i = 0; i < statement->num_columns; i++) {
47
	rc = OCIParamGet(statement->stmt, OCI_HTYPE_STMT, statement->conn->err, (dvoid **)&bind[i].param, i+1);
48
	if (rc) {
49
	    OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
50
	    luaL_error(L, "param get %s", errbuf);
51
	}
52
 
53
	rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].name), (ub4 *)&(bind[i].name_len), OCI_ATTR_NAME, statement->conn->err);
54
	if (rc) {
55
	    OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
56
	    luaL_error(L, "name get %s", errbuf);
57
	}
58
 
59
	rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].data_type), (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->conn->err);
60
	if (rc) {
61
	    OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
62
	    luaL_error(L, "datatype get %s", errbuf);
63
	}
64
 
65
	rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].max_len), 0, OCI_ATTR_DATA_SIZE, statement->conn->err);
66
	if (rc) {
67
	    OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
68
	    luaL_error(L, "datasize get %s", errbuf);
69
	}
70
 
71
	bind[i].data = calloc(bind[i].max_len+1, sizeof(char));
72
	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);
73
	if (rc) {
74
	    OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
75
	    luaL_error(L, "define by pos %s", errbuf);
76
	}
77
    }
78
 
79
    statement->metadata = 1;
80
}
81
 
82
 
83
/*
84
 * num_affected_rows = statement:affected()
85
 */
86
static int statement_affected(lua_State *L) {
87
    statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT);
88
    int affected;
89
    int rc; 
90
 
91
    if (!statement->stmt) {
92
        luaL_error(L, DBI_ERR_INVALID_STATEMENT);
93
    }
94
 
95
    /* 
96
     * get number of affected rows 
97
     */
98
    rc = OCIAttrGet(
99
	(dvoid *)statement->stmt, 
100
	(ub4)OCI_HTYPE_STMT,
101
        (dvoid *)&affected, 
102
	(ub4 *)0, 
103
	(ub4)OCI_ATTR_ROW_COUNT,
104
        statement->conn->err
105
    );
106
 
107
    lua_pushinteger(L, affected);
108
 
109
    return 1;
110
}
111
 
112
/*
113
 * success = statement:close()
114
 */
115
int statement_close(lua_State *L) {
116
    statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT);
117
    int ok = 0;
118
 
119
    if (statement->stmt) {
120
	int rc;
121
 
122
	rc = OCIHandleFree((dvoid *)statement->stmt, OCI_HTYPE_STMT);    /* Free handles */	
123
 
124
	statement->stmt = NULL;
125
    }
126
 
127
    if (statement->bind) {
128
	free(statement->bind);
129
	statement->bind = NULL;
130
    }
131
 
132
    lua_pushboolean(L, ok);
133
    return 1;
134
}
135
 
136
/*
137
 *  column_names = statement:columns()
138
 */
139
static int statement_columns(lua_State *L) {
140
    statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT);
141
    int rc;
142
 
143
    bindparams_t *bind;
144
 
145
    char errbuf[100];
146
    int errcode;
147
 
148
    int i;
149
    int d = 1;
150
 
151
    if (!statement->stmt) {
152
        luaL_error(L, DBI_ERR_INVALID_STATEMENT);
153
        return 0;
154
    }
155
 
156
    statement_fetch_metadata(L, statement);    
157
 
158
    lua_newtable(L);
159
    for (i = 0; i < statement->num_columns; i++) {
160
	const char *name = strlower(statement->bind[i].name);
161
 
162
	LUA_PUSH_ARRAY_STRING(d, name);
163
    }
164
 
165
    return 1;
166
}
167
 
168
 
169
/*
170
 * success,err = statement:execute(...)
171
 */
172
int statement_execute(lua_State *L) {
173
    int n = lua_gettop(L);
174
    statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT);
175
    int p;
176
    int errflag = 0;
177
    const char *errstr = NULL;
178
    int num_columns;
179
    int rc;
180
 
181
    char errbuf[100];
182
    int errcode;
183
 
184
    ub2 type;
185
 
186
    if (!statement->stmt) {
187
	lua_pushboolean(L, 0);
188
	lua_pushstring(L, DBI_ERR_EXECUTE_INVALID);
189
	return 2;
190
    }
191
 
192
    for (p = 2; p <= n; p++) {
193
	int i = p - 1;
194
	int type = lua_type(L, p);
195
	char err[64];
196
	const char *value;
197
 
198
	OCIBind *bnd = (OCIBind *)0;
199
 
200
	switch(type) {
201
	case LUA_TNIL:
202
	    errflag = OCIBindByPos(
203
		statement->stmt, 
204
		&bnd, 
205
		statement->conn->err, 
206
		i, 
207
		NULL, 
208
		0, 
209
		SQLT_CHR, 
210
		(dvoid *)0, 
211
		(ub2 *)0, 
212
		(ub2 *)0, 
213
		(ub4)0, 
214
		(ub4 *)0,
215
		OCI_DEFAULT);
216
	    break;
217
	case LUA_TNUMBER:
218
	case LUA_TSTRING:
219
	case LUA_TBOOLEAN:
220
	    value = lua_tostring(L, p);
221
 
222
	    errflag = OCIBindByPos(
223
		statement->stmt, 
224
		&bnd, 
225
		statement->conn->err, 
226
		i, 
227
		value, 
228
		strlen(value), 
229
		SQLT_CHR, 
230
		(dvoid *)0, 
231
		(ub2 *)0, 
232
		(ub2 *)0, 
233
		(ub4)0, 
234
		(ub4 *)0,
235
		(ub4)OCI_DEFAULT);
236
	    break;
237
	default:
238
	    /*
239
	     * Unknown/unsupported value type
240
	     */
241
	    errflag = 1;
242
            snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type));
243
            errstr = err;
244
	}
245
 
246
	if (errflag)
247
	    break;
248
    }   
249
 
250
    if (errflag) {
251
	lua_pushboolean(L, 0);
252
	if (errstr)
253
	    lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr);
254
	else {
255
	    OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
256
 
257
	    lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf);
258
	}
259
    
260
	return 2;
261
    }
262
 
263
    /* 
264
     * statement type 
265
     */
266
    rc = OCIAttrGet(
267
	(dvoid *)statement->stmt, 
268
	(ub4)OCI_HTYPE_STMT, 
269
	(dvoid *)&type, 
270
	(ub4 *)0, 
271
	(ub4)OCI_ATTR_STMT_TYPE, 
272
	statement->conn->err
273
    );
274
 
275
    if (rc) {
276
	OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
277
 
278
	lua_pushboolean(L, 0);
279
	lua_pushfstring(L, "Error getting type: %s", errbuf);
280
 
281
	return 2;
282
    }
283
 
284
    /*
285
     * execute statement
286
     */
287
    rc = OCIStmtExecute(
288
	statement->conn->svc, 
289
	statement->stmt, 
290
	statement->conn->err, 
291
	type == OCI_STMT_SELECT ? 0 : 1, 
292
	(ub4)0, 
293
	(CONST OCISnapshot *)NULL, 
294
	(OCISnapshot *)NULL, 
295
	statement->conn->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT
296
    );
297
 
298
    if (rc) {
299
	OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
300
 
301
	lua_pushboolean(L, 0);
302
	lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf);
303
 
304
	return 2;
305
    }
306
 
307
    /* 
308
     * get number of columns 
309
     */
310
    rc = OCIAttrGet(
311
	(dvoid *)statement->stmt, 
312
	(ub4)OCI_HTYPE_STMT,
313
        (dvoid *)&num_columns, 
314
	(ub4 *)0, 
315
	(ub4)OCI_ATTR_PARAM_COUNT,
316
        statement->conn->err
317
    );
318
 
319
    if (rc) {
320
	OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR);
321
 
322
	lua_pushboolean(L, 0);
323
	lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf);
324
 
325
	return 2;
326
    }
327
 
328
    statement->num_columns = num_columns;
329
 
330
    lua_pushboolean(L, 1);
331
    return 1;
332
}
333
 
334
/*
335
 * must be called after an execute
336
 */
337
static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) {
338
    int rc;
339
    sword status;
340
    int i;
341
    bindparams_t *bind;
342
 
343
    char errbuf[100];
344
    int errcode;
345
 
346
    if (!statement->stmt) {
347
	luaL_error(L, DBI_ERR_FETCH_INVALID);
348
	return 0;
349
    }
350
 
351
    statement_fetch_metadata(L, statement);    
352
    bind = statement->bind;
353
 
354
    status = OCIStmtFetch(statement->stmt, statement->conn->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT);
355
 
356
    if (status == OCI_NO_DATA) {
357
	/* No more rows */
358
        lua_pushnil(L);
359
        return 1;
360
    } else if (status != OCI_SUCCESS) {
361
	OCIErrorGet((dvoid *)statement->conn->err, (ub4)1, (text *)NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR);
362
	luaL_error(L, DBI_ERR_FETCH_FAILED, errbuf);
363
    }
364
 
365
    if (statement->num_columns) {
366
	int i;
367
	int d = 1;
368
 
369
	lua_newtable(L);
370
 
371
	for (i = 0; i < statement->num_columns; i++) {
372
	    lua_push_type_t lua_push = oracle_to_lua_push(bind[i].data_type, bind[i].null);
373
	    const char *name = strlower(bind[i].name);
374
	    const char *data = bind[i].data;
375
 
376
	    if (lua_push == LUA_PUSH_NIL) {
377
                if (named_columns) {
378
                    LUA_PUSH_ATTRIB_NIL(name);
379
                } else {
380
                    LUA_PUSH_ARRAY_NIL(d);
381
                }
382
            } else if (lua_push == LUA_PUSH_INTEGER) {
383
		int val = atoi(data);
384
 
385
                if (named_columns) {
386
                    LUA_PUSH_ATTRIB_INT(name, val);
387
                } else {
388
                    LUA_PUSH_ARRAY_INT(d, val);
389
                }
390
            } else if (lua_push == LUA_PUSH_NUMBER) {
391
		double val = strtod(data, NULL);
392
 
393
                if (named_columns) {
394
                    LUA_PUSH_ATTRIB_FLOAT(name, val);
395
                } else {
396
                    LUA_PUSH_ARRAY_FLOAT(d, val);
397
                }
398
            } else if (lua_push == LUA_PUSH_STRING) {
399
                if (named_columns) {
400
                    LUA_PUSH_ATTRIB_STRING(name, data);
401
                } else {
402
                    LUA_PUSH_ARRAY_STRING(d, data);
403
                }
404
            } else if (lua_push == LUA_PUSH_BOOLEAN) {
405
		int val = atoi(data);
406
 
407
                if (named_columns) {
408
                    LUA_PUSH_ATTRIB_BOOL(name, val);
409
                } else {
410
                    LUA_PUSH_ARRAY_BOOL(d, val);
411
                }
412
            } else {
413
                luaL_error(L, DBI_ERR_UNKNOWN_PUSH);
414
            }
415
	}
416
    } else {
417
	/* 
418
         * no columns returned by statement?
419
         */ 
420
	lua_pushnil(L);
421
    }
422
 
423
    return 1;    
424
}
425
 
426
static int next_iterator(lua_State *L) {
427
    statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_ORACLE_STATEMENT);
428
    int named_columns = lua_toboolean(L, lua_upvalueindex(2));
429
 
430
    return statement_fetch_impl(L, statement, named_columns);
431
}
432
 
433
/*
434
 * table = statement:fetch(named_indexes)
435
 */
436
static int statement_fetch(lua_State *L) {
437
    statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT);
438
    int named_columns = lua_toboolean(L, 2);
439
 
440
    return statement_fetch_impl(L, statement, named_columns);
441
}
442
 
443
/*
444
 * num_rows = statement:rowcount()
445
 */
446
static int statement_rowcount(lua_State *L) {
447
    luaL_error(L, DBI_ERR_NOT_IMPLEMENTED, DBD_ORACLE_STATEMENT, "rowcount");
448
 
449
    return 0;
450
}
451
 
452
/*
453
 * iterfunc = statement:rows(named_indexes)
454
 */
455
static int statement_rows(lua_State *L) {
456
    if (lua_gettop(L) == 1) {
457
        lua_pushvalue(L, 1);
458
        lua_pushboolean(L, 0);
459
    } else {
460
        lua_pushvalue(L, 1);
461
        lua_pushboolean(L, lua_toboolean(L, 2));
462
    }
463
 
464
    lua_pushcclosure(L, next_iterator, 2);
465
    return 1;
466
}
467
 
468
/*
469
 * __gc
470
 */
471
static int statement_gc(lua_State *L) {
472
    /* always free the handle */
473
    statement_close(L);
474
 
475
    return 0;
476
}
477
 
478
/*
479
 * __tostring
480
 */
481
static int statement_tostring(lua_State *L) {
482
    statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT);
483
 
484
    lua_pushfstring(L, "%s: %p", DBD_ORACLE_STATEMENT, statement);
485
 
486
    return 1;
487
}
488
 
489
int dbd_oracle_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { 
490
    int rc;
491
    statement_t *statement = NULL;
492
    OCIStmt *stmt;
493
    char *new_sql;
494
 
495
    /*
496
     * convert SQL string into a Oracle API compatible SQL statement
497
     */
498
    new_sql = replace_placeholders(L, ':', sql_query);
499
 
500
    rc = OCIHandleAlloc((dvoid *)conn->oracle, (dvoid **)&stmt, OCI_HTYPE_STMT, 0, (dvoid **)0);
501
    rc = OCIStmtPrepare(stmt, conn->err, new_sql, strlen(new_sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT);
502
 
503
    free(new_sql);
504
 
505
    statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t));
506
    statement->conn = conn;
507
    statement->stmt = stmt;
508
    statement->num_columns = 0;
509
    statement->bind = NULL;
510
    statement->metadata = 0;
511
 
512
    luaL_getmetatable(L, DBD_ORACLE_STATEMENT);
513
    lua_setmetatable(L, -2);
514
 
515
    return 1;
516
} 
517
 
518
int dbd_oracle_statement(lua_State *L) {
519
    static const luaL_Reg statement_methods[] = {
520
	{"affected", statement_affected},
521
	{"close", statement_close},
522
	{"columns", statement_columns},
523
	{"execute", statement_execute},
524
	{"fetch", statement_fetch},
525
	{"rowcount", statement_rowcount},
526
	{"rows", statement_rows},
527
	{NULL, NULL}
528
    };
529
 
530
    static const luaL_Reg statement_class_methods[] = {
531
	{NULL, NULL}
532
    };
533
 
534
    luaL_newmetatable(L, DBD_ORACLE_STATEMENT);
535
    luaL_register(L, 0, statement_methods);
536
    lua_pushvalue(L,-1);
537
    lua_setfield(L, -2, "__index");
538
 
539
    lua_pushcfunction(L, statement_gc);
540
    lua_setfield(L, -2, "__gc");
541
 
542
    lua_pushcfunction(L, statement_tostring);
543
    lua_setfield(L, -2, "__tostring");
544
 
545
    luaL_register(L, DBD_ORACLE_STATEMENT, statement_class_methods);
546
 
547
    return 1;    
548
}