--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dbd/db2/connection.c Fri Dec 05 07:41:15 2008 +0000 @@ -0,0 +1,251 @@ +#include "dbd_db2.h" + +int dbd_db2_statement_create(lua_State *L, connection_t *conn, const char *sql_query); + +static int commit(connection_t *conn) { + SQLRETURN rc = SQL_SUCCESS; + + rc = SQLEndTran(SQL_HANDLE_DBC, conn->db2, SQL_COMMIT); + + return rc != SQL_SUCCESS; +} + +static int rollback(connection_t *conn) { + SQLRETURN rc = SQL_SUCCESS; + + rc = SQLEndTran(SQL_HANDLE_DBC, conn->db2, SQL_ROLLBACK); + + return rc != SQL_SUCCESS; +} + + +/* + * connection = DBD.DB2.New(dbname, user, password, host, port) + */ +static int connection_new(lua_State *L) { + int n = lua_gettop(L); + connection_t *conn = NULL; + SQLRETURN rc = SQL_SUCCESS; + + const char *user = NULL; + const char *password = NULL; + const char *db = NULL; + + SQLCHAR message[SQL_MAX_MESSAGE_LENGTH + 1]; + SQLCHAR sqlstate[SQL_SQLSTATE_SIZE + 1]; + SQLINTEGER sqlcode; + SQLSMALLINT length; + + /* db, user, password, host, port */ + switch(n) { + case 5: + case 4: + case 3: + if (lua_isnil(L, 3) == 0) + password = luaL_checkstring(L, 3); + case 2: + if (lua_isnil(L, 2) == 0) + user = luaL_checkstring(L, 2); + case 1: + /* + * db is the only mandatory parameter + */ + db = luaL_checkstring(L, 1); + } + + conn = (connection_t *)lua_newuserdata(L, sizeof(connection_t)); + + /* allocate an environment handle */ + rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &conn->env); + if (rc != SQL_SUCCESS) { + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot allocate environment handle"); + return 2; + } + + /* set attribute to enable application to run as ODBC 3.0 application */ + rc = SQLSetEnvAttr(conn->env, SQL_ATTR_ODBC_VERSION, (void *)SQL_OV_ODBC3, 0); + if (rc != SQL_SUCCESS) { + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot set ODBC version attribute"); + return 2; + } + + /* allocate a database connection handle */ + rc = SQLAllocHandle(SQL_HANDLE_DBC, conn->env, &conn->db2); + if (rc != SQL_SUCCESS) { + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot allocate database handle"); + return 2; + } + + /* set AUTOCOMMIT off */ + rc = SQLSetConnectAttr(conn->db2, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)SQL_AUTOCOMMIT_OFF, SQL_NTS); + if (rc != SQL_SUCCESS) { + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, "Cannot turn off autocommit"); + return 2; + } + + /* connect to the database */ + rc = SQLConnect(conn->db2, (SQLCHAR *)db, SQL_NTS, (SQLCHAR *)user, SQL_NTS, (SQLCHAR *)password, SQL_NTS); + if (rc != SQL_SUCCESS) { + SQLGetDiagRec(SQL_HANDLE_DBC, conn->db2, 1, sqlstate, &sqlcode, message, SQL_MAX_MESSAGE_LENGTH + 1, &length); + + lua_pushnil(L); + lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, message); + return 2; + } + + luaL_getmetatable(L, DBD_DB2_CONNECTION); + lua_setmetatable(L, -2); + + return 1; +} + +/* + * success = connection:autocommit(on) + */ +static int connection_autocommit(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); + int on = lua_toboolean(L, 2); + int err = 0; + + if (conn->db2) { + int onval = on ? SQL_AUTOCOMMIT_ON : SQL_AUTOCOMMIT_OFF; + + SQLRETURN rc = SQLSetConnectAttr(conn->db2, SQL_ATTR_AUTOCOMMIT, (SQLPOINTER)onval, SQL_NTS); + + err = rc != SQL_SUCCESS; + } + + lua_pushboolean(L, !err); + return 1; +} + +/* + * success = connection:close() + */ +static int connection_close(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); + int disconnect = 0; + + if (conn->db2) { + SQLRETURN rc = SQL_SUCCESS; + + rollback(conn); + + /* disconnect from the database */ + rc = SQLDisconnect(conn->db2); + + /* free connection handle */ + rc = SQLFreeHandle(SQL_HANDLE_DBC, conn->db2); + + /* free environment handle */ + rc = SQLFreeHandle(SQL_HANDLE_ENV, conn->env); + + conn->db2 = 0; + } + + lua_pushboolean(L, disconnect); + return 1; +} + +/* + * success = connection:commit() + */ +static int connection_commit(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); + int err = 1; + + if (conn->db2) { + err = commit(conn); + } + + lua_pushboolean(L, !err); + return 1; +} + +/* + * ok = connection:ping() + */ +static int connection_ping(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); + int ok = 0; + + if (conn->db2) { + ok = 1; + } + + lua_pushboolean(L, ok); + return 1; +} + +/* + * statement = connection:prepare(sql_string) + */ +static int connection_prepare(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); + + if (conn->db2) { + return dbd_db2_statement_create(L, conn, luaL_checkstring(L, 2)); + } + + lua_pushnil(L); + lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); + return 2; +} + +/* + * success = connection:rollback() + */ +static int connection_rollback(lua_State *L) { + connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_DB2_CONNECTION); + int err = 1; + + if (conn->db2) { + err = rollback(conn); + } + + lua_pushboolean(L, !err); + return 1; +} + +/* + * __gc + */ +static int connection_gc(lua_State *L) { + /* always close the connection */ + connection_close(L); + + return 0; +} + +int dbd_db2_connection(lua_State *L) { + static const luaL_Reg connection_methods[] = { + {"autocommit", connection_autocommit}, + {"close", connection_close}, + {"commit", connection_commit}, + {"ping", connection_ping}, + {"prepare", connection_prepare}, + {"rollback", connection_rollback}, + {NULL, NULL} + }; + + static const luaL_Reg connection_class_methods[] = { + {"New", connection_new}, + {NULL, NULL} + }; + + luaL_newmetatable(L, DBD_DB2_CONNECTION); + luaL_register(L, 0, connection_methods); + lua_pushvalue(L,-1); + lua_setfield(L, -2, "__index"); + + lua_pushcfunction(L, connection_gc); + lua_setfield(L, -2, "__gc"); + + luaL_register(L, DBD_DB2_CONNECTION, connection_class_methods); + + return 1; +}