Fri, 24 Dec 2010 00:34:04 +0000
Make calling autocommit with the same value as set a NOOP to suppress a warning from the DB
#include "dbd_postgresql.h" int dbd_postgresql_statement_create(lua_State *L, connection_t *conn, const char *sql_query); static int run(connection_t *conn, const char *command) { PGresult *result = PQexec(conn->postgresql, command); ExecStatusType status; if (!result) return 1; status = PQresultStatus(result); PQclear(result); if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK) return 1; return 0; } static int commit(connection_t *conn) { return run(conn, "COMMIT"); } static int begin(connection_t *conn) { return run(conn, "BEGIN"); } static int rollback(connection_t *conn) { return run(conn, "ROLLBACK"); } /* * connection = DBD.PostgreSQL.New(dbname, user, password, host, port) */ static int connection_new(lua_State *L) { int n = lua_gettop(L); connection_t *conn = NULL; const char *host = NULL; const char *user = NULL; const char *password = NULL; const char *db = NULL; const char *port = NULL; const char *options = NULL; /* TODO always NULL */ const char *tty = NULL; /* TODO always NULL */ char portbuf[18]; /* db, user, password, host, port */ switch (n) { case 5: if (lua_isnil(L, 5) == 0) { int pport = luaL_checkint(L, 5); if (pport >= 1 && pport <= 65535) { snprintf(portbuf, sizeof(portbuf), "%d", pport); port = portbuf; } else { luaL_error(L, DBI_ERR_INVALID_PORT, pport); } } case 4: if (lua_isnil(L, 4) == 0) host = luaL_checkstring(L, 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)); conn->postgresql = PQsetdbLogin(host, port, options, tty, db, user, password); conn->statement_id = 0; conn->autocommit = 0; begin(conn); if (PQstatus(conn->postgresql) != CONNECTION_OK) { lua_pushnil(L); lua_pushfstring(L, DBI_ERR_CONNECTION_FAILED, PQerrorMessage(conn->postgresql)); return 2; } luaL_getmetatable(L, DBD_POSTGRESQL_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_POSTGRESQL_CONNECTION); int on = lua_toboolean(L, 2); int err = 0; if (conn->postgresql) { if (on != conn->autocommit) { if (on) err = rollback(conn); else err = begin(conn); } conn->autocommit = on; } 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_POSTGRESQL_CONNECTION); int disconnect = 0; if (conn->postgresql) { /* * if autocommit is turned off, we probably * want to rollback any outstanding transactions. */ if (!conn->autocommit) rollback(conn); PQfinish(conn->postgresql); disconnect = 1; conn->postgresql = NULL; } 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_POSTGRESQL_CONNECTION); int err = 0; if (conn->postgresql) { commit(conn); if (!conn->autocommit) err = begin(conn); else err = 1; } 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_POSTGRESQL_CONNECTION); int ok = 0; if (conn->postgresql) { ConnStatusType status = PQstatus(conn->postgresql); if (status == CONNECTION_OK) 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_POSTGRESQL_CONNECTION); if (conn->postgresql) { return dbd_postgresql_statement_create(L, conn, luaL_checkstring(L, 2)); } lua_pushnil(L); lua_pushstring(L, DBI_ERR_DB_UNAVAILABLE); return 2; } /* * quoted = connection:quote(str) */ static int connection_quote(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); size_t len; const char *from = luaL_checklstring(L, 2, &len); char *to = (char *)calloc(len*2+1, sizeof(char)); int err = 0; int quoted_len; if (!conn->postgresql) { luaL_error(L, DBI_ERR_DB_UNAVAILABLE); } quoted_len = PQescapeStringConn(conn->postgresql, to, from, len, &err); if (err) { free(to); luaL_error(L, DBI_ERR_QUOTING_STR, PQerrorMessage(conn->postgresql)); } lua_pushlstring(L, to, quoted_len); free(to); return 1; } /* * success = connection:rollback() */ static int connection_rollback(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); int err = 0; if (conn->postgresql) { rollback(conn); if (!conn->autocommit) err = begin(conn); else err = 1; } lua_pushboolean(L, !err); return 1; } /* * __gc */ static int connection_gc(lua_State *L) { /* always close the connection */ connection_close(L); return 0; } /* * __tostring */ static int connection_tostring(lua_State *L) { connection_t *conn = (connection_t *)luaL_checkudata(L, 1, DBD_POSTGRESQL_CONNECTION); lua_pushfstring(L, "%s: %p", DBD_POSTGRESQL_CONNECTION, conn); return 1; } int dbd_postgresql_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}, {"quote", connection_quote}, {"rollback", connection_rollback}, {NULL, NULL} }; static const luaL_Reg connection_class_methods[] = { {"New", connection_new}, {NULL, NULL} }; luaL_newmetatable(L, DBD_POSTGRESQL_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"); lua_pushcfunction(L, connection_tostring); lua_setfield(L, -2, "__tostring"); luaL_register(L, DBD_POSTGRESQL_CONNECTION, connection_class_methods); return 1; }