# HG changeset patch # User jbe # Date 1452044390 -3600 # Node ID 04172238d79baa1b7160991213e6684665e6ccf6 # Parent ad437022be901b5627b4dfb23cc98f6cdb87d3be Do not require "engine" field to be set for mondelefant.connect{...}; Fixed bugs in mondelefant.connect{...} that could have crashed Lua; Shortened Lua registry key for mondelefant library diff -r ad437022be90 -r 04172238d79b libraries/mondelefant/mondelefant_native.c --- a/libraries/mondelefant/mondelefant_native.c Mon Jan 04 00:48:47 2016 +0100 +++ b/libraries/mondelefant/mondelefant_native.c Wed Jan 06 02:39:50 2016 +0100 @@ -9,7 +9,7 @@ // NOTE: Comments with format "// " denote the Lua stack position // prefix for all Lua registry entries of this library: -#define MONDELEFANT_REGKEY "e449ba8d9a53d353_mondelefant_" +#define MONDELEFANT_REGKEY "mondelefant_" // registry key of module "mondelefant_native": #define MONDELEFANT_MODULE_REGKEY (MONDELEFANT_REGKEY "module") @@ -194,76 +194,63 @@ // "connect" function of library, which establishes a database connection // and returns a database connection handle: static int mondelefant_connect(lua_State *L) { - luaL_Buffer buf; // Lua string buffer to create 'conninfo' (see below) const char *conninfo; // string for PQconnectdb function PGconn *pgconn; // PGconn object as returned by PQconnectdb function mondelefant_conn_t *conn; // C-structure for userdata - // expect a table as first argument: - luaL_checktype(L, 1, LUA_TTABLE); - // if engine is anything but "postgresql", then raise error: - lua_settop(L, 1); - lua_getfield(L, 1, "engine"); // 2 - if (!lua_toboolean(L, 2)) { - return luaL_argerror(L, 1, "no database engine selected"); - } - lua_pushliteral(L, "postgresql"); // 3 - if (!lua_rawequal(L, 2, 3)) { - return luaL_argerror(L, 1, - "only database engine 'postgresql' is supported" - ); - } - // copy conninfo string for PQconnectdb function from argument table to - // stack position 2: - lua_settop(L, 1); - lua_getfield(L, 1, "conninfo"); // 2 - // if no conninfo string was found, then assemble one from the named - // options except "engine" option: - if (!lua_toboolean(L, 2)) { + // check if string is given as first argument: + if (lua_type(L, 1) != LUA_TSTRING) { + // expect a table as first argument if no string is given: + luaL_checktype(L, 1, LUA_TTABLE); + // copy conninfo string for PQconnectdb function from argument table to + // stack position 2: lua_settop(L, 1); - lua_pushnil(L); // slot for key at stack position 2 - lua_pushnil(L); // slot for value at stack position 3 - luaL_buffinit(L, &buf); - { + lua_getfield(L, 1, "conninfo"); // 2 + // check if conninfo is set: + if (!lua_isnil(L, 2)) { + // if yes, use that value but check its type: + luaL_argcheck(L, lua_type(L, 2) == LUA_TSTRING, 2, "\"conninfo\" value is not a string"); + } else { + // otherwise assemble conninfo string from the named options: + luaL_Buffer buf; int need_seperator = 0; + const char *value; + size_t value_len; + size_t value_pos = 0; + lua_settop(L, 1); + lua_pushnil(L); // slot for key at stack position 2 + lua_pushnil(L); // slot for value at stack position 3 + luaL_buffinit(L, &buf); while (lua_pushvalue(L, 2), lua_next(L, 1)) { + luaL_argcheck(L, lua_isstring(L, -2), 1, "key in table is not a string"); + luaL_argcheck(L, lua_isstring(L, -1), 1, "value in table is not a string"); + value = lua_tolstring(L, -1, &value_len); lua_replace(L, 3); + lua_pop(L, 1); lua_replace(L, 2); + if (need_seperator) luaL_addchar(&buf, ' '); // NOTE: numbers will be converted to strings automatically here, // but perhaps this will change in future versions of lua - luaL_argcheck(L, - lua_isstring(L, 2) && lua_isstring(L, 3), 1, "key is not a string" - ); lua_pushvalue(L, 2); - lua_pushliteral(L, "engine"); - if (!lua_rawequal(L, -2, -1)) { - const char *value; - size_t value_len; - size_t value_pos = 0; - lua_pop(L, 1); - if (need_seperator) luaL_addchar(&buf, ' '); - luaL_addvalue(&buf); - luaL_addchar(&buf, '='); - luaL_addchar(&buf, '\''); - value = lua_tolstring(L, 3, &value_len); - do { - char c; - c = value[value_pos++]; - if (c == '\'') luaL_addchar(&buf, '\\'); - luaL_addchar(&buf, c); - } while (value_pos < value_len); - luaL_addchar(&buf, '\''); - need_seperator = 1; - } else { - lua_pop(L, 1); - } + luaL_addvalue(&buf); + luaL_addchar(&buf, '='); + luaL_addchar(&buf, '\''); + do { + char c; + c = value[value_pos++]; + if (c == '\'') luaL_addchar(&buf, '\\'); + luaL_addchar(&buf, c); + } while (value_pos < value_len); + luaL_addchar(&buf, '\''); + need_seperator = 1; } + luaL_pushresult(&buf); } - luaL_pushresult(&buf); - lua_replace(L, 2); - lua_settop(L, 2); + // ensure that string is on stack position 1 which is the top of stack: + lua_replace(L, 1); + lua_settop(L, 1); } - // use conninfo string on stack position 2: - conninfo = lua_tostring(L, 2); + // use conninfo string on stack position 1: + conninfo = lua_tostring(L, 1); // call PQconnectdb function of libpq: pgconn = PQconnectdb(conninfo); // throw or return errors, if neccessary: @@ -273,18 +260,18 @@ ); } if (PQstatus(pgconn) != CONNECTION_OK) { - lua_pushnil(L); // 3 - mondelefant_push_first_line(L, PQerrorMessage(pgconn)); // 4 - lua_newtable(L); // 5 + lua_pushnil(L); // 2 + mondelefant_push_first_line(L, PQerrorMessage(pgconn)); // 3 + lua_newtable(L); // 4 lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_ERROROBJECT_MT_REGKEY ); - lua_setmetatable(L, 5); + lua_setmetatable(L, 4); lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION); - lua_setfield(L, 5, "code"); - lua_pushvalue(L, 4); - lua_setfield(L, 5, "message"); + lua_setfield(L, 4, "code"); + lua_pushvalue(L, 3); + lua_setfield(L, 4, "message"); PQfinish(pgconn); return 3; }