webmcp

changeset 406:36f0d1d5ed7d

Further fixes in mondelefant.connect{...} (including proper handling of garbage collection in case of memory allocation errors); Code cleanup (use luaL_setmetatable, which is available since Lua 5.2)
author jbe
date Wed Jan 06 18:59:58 2016 +0100 (2016-01-06)
parents c5f9a1b2f225
children 0e641ac76647
files libraries/mondelefant/mondelefant_native.c
line diff
     1.1 --- a/libraries/mondelefant/mondelefant_native.c	Wed Jan 06 02:54:45 2016 +0100
     1.2 +++ b/libraries/mondelefant/mondelefant_native.c	Wed Jan 06 18:59:58 2016 +0100
     1.3 @@ -195,20 +195,16 @@
     1.4  // and returns a database connection handle:
     1.5  static int mondelefant_connect(lua_State *L) {
     1.6    const char *conninfo;  // string for PQconnectdb function
     1.7 -  PGconn *pgconn;  // PGconn object as returned by PQconnectdb function
     1.8    mondelefant_conn_t *conn;  // C-structure for userdata
     1.9    // check if string is given as first argument:
    1.10    if (lua_type(L, 1) != LUA_TSTRING) {
    1.11      // expect a table as first argument if no string is given:
    1.12      luaL_checktype(L, 1, LUA_TTABLE);
    1.13 -    // copy conninfo string for PQconnectdb function from argument table to
    1.14 -    // stack position 2:
    1.15 -    lua_settop(L, 1);
    1.16 -    lua_getfield(L, 1, "conninfo");  // 2
    1.17 -    // check if conninfo is set:
    1.18 -    if (!lua_isnil(L, 2)) {
    1.19 +    // extract conninfo string for PQconnectdb if possible:
    1.20 +    lua_getfield(L, 1, "conninfo");
    1.21 +    if (!lua_isnil(L, -1)) {
    1.22        // if yes, use that value but check its type:
    1.23 -      luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING, 2, "\"conninfo\" value is not a string");
    1.24 +      luaL_argcheck(L, lua_type(L, -1) == LUA_TSTRING, 1, "\"conninfo\" value is not a string");
    1.25      } else {
    1.26        // otherwise assemble conninfo string from the named options:
    1.27        luaL_Buffer buf;
    1.28 @@ -247,61 +243,59 @@
    1.29      }
    1.30      // ensure that string is on stack position 1 which is the top of stack:
    1.31      lua_replace(L, 1);
    1.32 -    lua_settop(L, 1);
    1.33    }
    1.34    // use conninfo string on stack position 1:
    1.35    conninfo = lua_tostring(L, 1);
    1.36 +  // create userdata on stack position 2:
    1.37 +  lua_settop(L, 1);
    1.38 +  conn = lua_newuserdata(L, sizeof(*conn));  // 2
    1.39    // call PQconnectdb function of libpq:
    1.40 -  pgconn = PQconnectdb(conninfo);
    1.41 -  // throw or return errors, if neccessary:
    1.42 -  if (!pgconn) {
    1.43 -    return luaL_error(L,
    1.44 -      "Error in libpq while creating 'PGconn' structure."
    1.45 -    );
    1.46 +  conn->pgconn = PQconnectdb(conninfo);
    1.47 +  // try emergency garbage collection on first failure:
    1.48 +  if (!conn->pgconn) {
    1.49 +    lua_gc(L, LUA_GCCOLLECT, 0);
    1.50 +    conn->pgconn = PQconnectdb(conninfo);
    1.51    }
    1.52 -  if (PQstatus(pgconn) != CONNECTION_OK) {
    1.53 -    lua_pushnil(L);  // 2
    1.54 -    mondelefant_push_first_line(L, PQerrorMessage(pgconn));  // 3
    1.55 -    lua_newtable(L);  // 4
    1.56 -    lua_getfield(L,
    1.57 -      LUA_REGISTRYINDEX,
    1.58 -      MONDELEFANT_ERROROBJECT_MT_REGKEY
    1.59 -    );
    1.60 -    lua_setmetatable(L, 4);
    1.61 +  // throw error in case of (unexpected) error of PQconnectdb call:
    1.62 +  if (!conn->pgconn) return luaL_error(L,
    1.63 +    "Error in libpq while creating 'PGconn' structure."
    1.64 +  );
    1.65 +  // set metatable for userdata (ensure PQfinish on unexpected error below):
    1.66 +  luaL_setmetatable(L, MONDELEFANT_CONN_MT_REGKEY);
    1.67 +  // check result of PQconnectdb call:
    1.68 +  if (PQstatus(conn->pgconn) != CONNECTION_OK) {
    1.69 +    lua_pushnil(L);  // 3
    1.70 +    mondelefant_push_first_line(L, PQerrorMessage(conn->pgconn));  // 4
    1.71 +    lua_newtable(L);  // 5
    1.72 +    luaL_setmetatable(L, MONDELEFANT_ERROROBJECT_MT_REGKEY);
    1.73      lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION);
    1.74 -    lua_setfield(L, 4, "code");
    1.75 -    lua_pushvalue(L, 3);
    1.76 -    lua_setfield(L, 4, "message");
    1.77 -    PQfinish(pgconn);
    1.78 +    lua_setfield(L, 5, "code");
    1.79 +    lua_pushvalue(L, 4);
    1.80 +    lua_setfield(L, 5, "message");
    1.81 +    // manual PQfinish (do not wait until garbage collection):
    1.82 +    PQfinish(conn->pgconn);
    1.83 +    conn->pgconn = NULL;
    1.84      return 3;
    1.85    }
    1.86 -  // create userdata:
    1.87 -  lua_settop(L, 0);
    1.88 -  conn = lua_newuserdata(L, sizeof(*conn));  // 1
    1.89 -  // set 'pgconn' in C-struct of userdata:
    1.90 -  conn->pgconn = pgconn;
    1.91    // set 'server_encoding' in C-struct of userdata:
    1.92    {
    1.93      const char *charset;
    1.94 -    charset = PQparameterStatus(pgconn, "server_encoding");
    1.95 +    charset = PQparameterStatus(conn->pgconn, "server_encoding");
    1.96      if (charset && !strcmp(charset, "UTF8")) {
    1.97        conn->server_encoding = MONDELEFANT_SERVER_ENCODING_UTF8;
    1.98      } else {
    1.99        conn->server_encoding = MONDELEFANT_SERVER_ENCODING_ASCII;
   1.100      }
   1.101    }
   1.102 -  // set meta-table of userdata:
   1.103 -  luaL_getmetatable(L, MONDELEFANT_CONN_MT_REGKEY);  // 2
   1.104 -  lua_setmetatable(L, 1);
   1.105    // create and associate userdata table:
   1.106    lua_newtable(L);
   1.107 -  lua_setuservalue(L, 1);
   1.108 +  lua_setuservalue(L, 2);
   1.109    // store key "fd" with file descriptor of connection:
   1.110 -  lua_pushinteger(L, PQsocket(pgconn));
   1.111 -  lua_setfield(L, 1, "fd");
   1.112 +  lua_pushinteger(L, PQsocket(conn->pgconn));
   1.113 +  lua_setfield(L, 2, "fd");
   1.114    // store key "engine" with value "postgresql" as connection specific data:
   1.115    lua_pushliteral(L, "postgresql");
   1.116 -  lua_setfield(L, 1, "engine");
   1.117 +  lua_setfield(L, 2, "engine");
   1.118    // return userdata:
   1.119    return 1;
   1.120  }
   1.121 @@ -458,11 +452,7 @@
   1.122        PGnotify *notify;
   1.123        if (!PQconsumeInput(conn->pgconn)) {
   1.124          lua_newtable(L);  // 2
   1.125 -        lua_getfield(L,
   1.126 -          LUA_REGISTRYINDEX,
   1.127 -          MONDELEFANT_ERROROBJECT_MT_REGKEY
   1.128 -        );
   1.129 -        lua_setmetatable(L, 2);
   1.130 +        luaL_setmetatable(L, MONDELEFANT_ERROROBJECT_MT_REGKEY);
   1.131          lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION);
   1.132          lua_setfield(L, 2, "code");
   1.133          mondelefant_push_first_line(L, PQerrorMessage(conn->pgconn));  // 3
   1.134 @@ -522,8 +512,7 @@
   1.135      lua_settop(L, 2);
   1.136    }
   1.137    // set meta-table for database result lists/objects:
   1.138 -  lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY);  // 3
   1.139 -  lua_setmetatable(L, 2);
   1.140 +  luaL_setmetatable(L, MONDELEFANT_RESULT_MT_REGKEY);
   1.141    // set "_connection" attribute to self:
   1.142    lua_pushvalue(L, 1);  // 3
   1.143    lua_setfield(L, 2, "_connection");
   1.144 @@ -547,8 +536,7 @@
   1.145      lua_settop(L, 2);
   1.146    }
   1.147    // set meta-table for database result lists/objects:
   1.148 -  lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY);  // 3
   1.149 -  lua_setmetatable(L, 2);
   1.150 +  luaL_setmetatable(L, MONDELEFANT_RESULT_MT_REGKEY);
   1.151    // set "_connection" attribute to self:
   1.152    lua_pushvalue(L, 1);  // 3
   1.153    lua_setfield(L, 2, "_connection");
   1.154 @@ -944,11 +932,7 @@
   1.155        const char *command;
   1.156        command = lua_tostring(L, 2);
   1.157        lua_newtable(L);  // 5
   1.158 -      lua_getfield(L,
   1.159 -        LUA_REGISTRYINDEX,
   1.160 -        MONDELEFANT_ERROROBJECT_MT_REGKEY
   1.161 -      );
   1.162 -      lua_setmetatable(L, 5);
   1.163 +      luaL_setmetatable(L, MONDELEFANT_ERROROBJECT_MT_REGKEY);
   1.164        lua_pushvalue(L, 1);
   1.165        lua_setfield(L, 5, "connection");
   1.166        lua_pushvalue(L, 2);
   1.167 @@ -1406,8 +1390,7 @@
   1.168      lua_settop(L, 1);
   1.169    }
   1.170    // set meta-table for database classes (models):
   1.171 -  lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CLASS_MT_REGKEY);  // 2
   1.172 -  lua_setmetatable(L, 1);
   1.173 +  luaL_setmetatable(L, MONDELEFANT_CLASS_MT_REGKEY);
   1.174    // check, if "prototype" attribute is not set:
   1.175    lua_pushliteral(L, "prototype");  // 2
   1.176    lua_rawget(L, 1);  // 2

Impressum / About Us