--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbd/oracle/statement.c Sat Dec 06 00:32:37 2008 +0000 @@ -0,0 +1,432 @@ +#include "dbd_oracle.h" + +/* + * Converts SQLite types to Lua types + */ +static lua_push_type_t oracle_to_lua_push(unsigned int oracle_type, int null) { + lua_push_type_t lua_type; + + if (null) + return LUA_PUSH_NIL; + + switch(oracle_type) { + case SQLT_NUM: + case SQLT_FLT: + lua_type = LUA_PUSH_NUMBER; + break; + case SQLT_INT: + lua_type = LUA_PUSH_INTEGER; + break; + default: + lua_type = LUA_PUSH_STRING; + } + + return lua_type; +} + +/* + * success = statement:close() + */ +int statement_close(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); + int ok = 0; + + if (statement->stmt) { + int rc; + + rc = OCIHandleFree((dvoid *)statement->stmt, OCI_HTYPE_STMT); /* Free handles */ + + statement->stmt = NULL; + } + + lua_pushboolean(L, ok); + return 1; +} + +/* + * success,err = statement:execute(...) + */ +int statement_execute(lua_State *L) { + int n = lua_gettop(L); + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); + int p; + int errflag = 0; + const char *errstr = NULL; + int expected_params; + int num_bind_params = n - 1; + int num_columns; + int rc; + + char errbuf[100]; + int errcode; + + ub2 type; + + if (!statement->stmt) { + lua_pushboolean(L, 0); + lua_pushstring(L, DBI_ERR_EXECUTE_INVALID); + return 2; + } + + for (p = 2; p <= n; p++) { + int i = p - 1; + int type = lua_type(L, p); + char err[64]; + const char *value; + + OCIBind *bnd = (OCIBind *)0; + + switch(type) { + case LUA_TNIL: + errflag = OCIBindByPos( + statement->stmt, + &bnd, + statement->conn->err, + i, + NULL, + 0, + SQLT_CHR, + (dvoid *)0, + (ub2 *)0, + (ub2 *)0, + (ub4)0, + (ub4 *)0, + OCI_DEFAULT); + break; + case LUA_TNUMBER: + case LUA_TSTRING: + case LUA_TBOOLEAN: + value = lua_tostring(L, p); + + errflag = OCIBindByPos( + statement->stmt, + &bnd, + statement->conn->err, + i, + value, + strlen(value), + SQLT_CHR, + (dvoid *)0, + (ub2 *)0, + (ub2 *)0, + (ub4)0, + (ub4 *)0, + (ub4)OCI_DEFAULT); + break; + default: + /* + * Unknown/unsupported value type + */ + errflag = 1; + snprintf(err, sizeof(err)-1, DBI_ERR_BINDING_TYPE_ERR, lua_typename(L, type)); + errstr = err; + } + + if (errflag) + break; + } + + if (errflag) { + lua_pushboolean(L, 0); + if (errstr) + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errstr); + else { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); + } + + return 2; + } + + /* + * statement type + */ + rc = OCIAttrGet( + (dvoid *)statement->stmt, + (ub4)OCI_HTYPE_STMT, + (dvoid *)&type, + (ub4 *)0, + (ub4)OCI_ATTR_STMT_TYPE, + statement->conn->err + ); + + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + + lua_pushboolean(L, 0); + lua_pushfstring(L, "Error getting type: %s", errbuf); + + return 2; + } + + /* + * execute statement + */ + rc = OCIStmtExecute( + statement->conn->svc, + statement->stmt, + statement->conn->err, + type == OCI_STMT_SELECT ? 0 : 1, + (ub4)0, + (CONST OCISnapshot *)NULL, + (OCISnapshot *)NULL, + statement->conn->autocommit ? OCI_COMMIT_ON_SUCCESS : OCI_DEFAULT + ); + + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + + lua_pushboolean(L, 0); + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); + + return 2; + } + + /* + * get number of columns + */ + rc = OCIAttrGet( + (dvoid *)statement->stmt, + (ub4)OCI_HTYPE_STMT, + (dvoid *)&num_columns, + (ub4 *)0, + (ub4)OCI_ATTR_PARAM_COUNT, + statement->conn->err + ); + + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + + lua_pushboolean(L, 0); + lua_pushfstring(L, DBI_ERR_BINDING_PARAMS, errbuf); + + return 2; + } + + statement->num_columns = num_columns; + + lua_pushboolean(L, 1); + return 1; +} + +/* + * must be called after an execute + */ +static int statement_fetch_impl(lua_State *L, statement_t *statement, int named_columns) { + int rc; + sword status; + int i; + bindparams_t *bind; + + char errbuf[100]; + int errcode; + + if (!statement->stmt) { + luaL_error(L, DBI_ERR_FETCH_INVALID); + return 0; + } + + bind = (bindparams_t *)malloc(sizeof(bindparams_t) * statement->num_columns); + memset(bind, 0, sizeof(bindparams_t) * statement->num_columns); + + for (i = 0; i < statement->num_columns; i++) { + rc = OCIParamGet(statement->stmt, OCI_HTYPE_STMT, statement->conn->err, (dvoid **)&bind[i].param, i+1); + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + luaL_error(L, "param get %s", errbuf); + } + + rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].name), (ub4 *)&(bind[i].name_len), OCI_ATTR_NAME, statement->conn->err); + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + luaL_error(L, "name get %s", errbuf); + } + + rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].data_type), (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->conn->err); + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + luaL_error(L, "datatype get %s", errbuf); + } + + rc = OCIAttrGet(bind[i].param, OCI_DTYPE_PARAM, (dvoid *)&(bind[i].max_len), 0, OCI_ATTR_DATA_SIZE, statement->conn->err); + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4) sizeof(errbuf), OCI_HTYPE_ERROR); + luaL_error(L, "datasize get %s", errbuf); + } + + bind[i].data = calloc(bind[i].max_len+1, sizeof(char)); + 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); + if (rc) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4) 1, (text *) NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + luaL_error(L, "define by pos %s", errbuf); + } + } + + status = OCIStmtFetch(statement->stmt, statement->conn->err, 1, OCI_FETCH_NEXT, OCI_DEFAULT); + + if (status == OCI_NO_DATA) { + /* No more rows */ + lua_pushnil(L); + return 1; + } else if (status != OCI_SUCCESS) { + OCIErrorGet((dvoid *)statement->conn->err, (ub4)1, (text *)NULL, &errcode, errbuf, (ub4)sizeof(errbuf), OCI_HTYPE_ERROR); + luaL_error(L, DBI_ERR_FETCH_FAILED, errbuf); + } + + if (statement->num_columns) { + int i; + int d = 1; + + lua_newtable(L); + + for (i = 0; i < statement->num_columns; i++) { + lua_push_type_t lua_push = oracle_to_lua_push(bind[i].data_type, bind[i].null); + const char *name = strlower(bind[i].name); + const char *data = bind[i].data; + + if (lua_push == LUA_PUSH_NIL) { + if (named_columns) { + LUA_PUSH_ATTRIB_NIL(name); + } else { + LUA_PUSH_ARRAY_NIL(d); + } + } else if (lua_push == LUA_PUSH_INTEGER) { + int val = atoi(data); + + if (named_columns) { + LUA_PUSH_ATTRIB_INT(name, val); + } else { + LUA_PUSH_ARRAY_INT(d, val); + } + } else if (lua_push == LUA_PUSH_NUMBER) { + double val = strtod(data, NULL); + + if (named_columns) { + LUA_PUSH_ATTRIB_FLOAT(name, val); + } else { + LUA_PUSH_ARRAY_FLOAT(d, val); + } + } else if (lua_push == LUA_PUSH_STRING) { + if (named_columns) { + LUA_PUSH_ATTRIB_STRING(name, data); + } else { + LUA_PUSH_ARRAY_STRING(d, data); + } + } else if (lua_push == LUA_PUSH_BOOLEAN) { + int val = 1; + + if (named_columns) { + LUA_PUSH_ATTRIB_BOOL(name, val); + } else { + LUA_PUSH_ARRAY_BOOL(d, val); + } + } else { + luaL_error(L, DBI_ERR_UNKNOWN_PUSH); + } + } + } else { + /* + * no columns returned by statement? + */ + lua_pushnil(L); + } + + return 1; +} + +static int next_iterator(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, lua_upvalueindex(1), DBD_ORACLE_STATEMENT); + int named_columns = lua_toboolean(L, lua_upvalueindex(2)); + + return statement_fetch_impl(L, statement, named_columns); +} + +/* + * table = statement:fetch(named_indexes) + */ +static int statement_fetch(lua_State *L) { + statement_t *statement = (statement_t *)luaL_checkudata(L, 1, DBD_ORACLE_STATEMENT); + int named_columns = lua_toboolean(L, 2); + + return statement_fetch_impl(L, statement, named_columns); +} + +/* + * iterfunc = statement:rows(named_indexes) + */ +static int statement_rows(lua_State *L) { + if (lua_gettop(L) == 1) { + lua_pushvalue(L, 1); + lua_pushboolean(L, 0); + } else { + lua_pushvalue(L, 1); + lua_pushboolean(L, lua_toboolean(L, 2)); + } + + lua_pushcclosure(L, next_iterator, 2); + return 1; +} + +/* + * __gc + */ +static int statement_gc(lua_State *L) { + /* always free the handle */ + statement_close(L); + + return 0; +} + +int dbd_oracle_statement_create(lua_State *L, connection_t *conn, const char *sql_query) { + int rc; + statement_t *statement = NULL; + OCIStmt *stmt; + char *new_sql; + + /* + * convert SQL string into a Oracle API compatible SQL statement + */ + new_sql = replace_placeholders(L, ':', sql_query); + + rc = OCIHandleAlloc((dvoid *)conn->oracle, (dvoid **)&stmt, OCI_HTYPE_STMT, 0, (dvoid **)0); + rc = OCIStmtPrepare(stmt, conn->err, new_sql, strlen(new_sql), (ub4)OCI_NTV_SYNTAX, (ub4)OCI_DEFAULT); + + free(new_sql); + + statement = (statement_t *)lua_newuserdata(L, sizeof(statement_t)); + statement->conn = conn; + statement->stmt = stmt; + statement->num_columns = 0; + + luaL_getmetatable(L, DBD_ORACLE_STATEMENT); + lua_setmetatable(L, -2); + + return 1; +} + +int dbd_oracle_statement(lua_State *L) { + static const luaL_Reg statement_methods[] = { + {"close", statement_close}, + {"execute", statement_execute}, + {"fetch", statement_fetch}, + {"rows", statement_rows}, + {NULL, NULL} + }; + + static const luaL_Reg statement_class_methods[] = { + {NULL, NULL} + }; + + luaL_newmetatable(L, DBD_ORACLE_STATEMENT); + luaL_register(L, 0, statement_methods); + lua_pushvalue(L,-1); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, statement_gc); + lua_setfield(L, -2, "__gc"); + + luaL_register(L, DBD_ORACLE_STATEMENT, statement_class_methods); + + return 1; +}