webmcp
diff libraries/mondelefant/mondelefant_native.c @ 397:46ba2168693a
Improved error handling in mondelefant_native.c; Fixed bug in error handling when PQsendQuery returned 0
author | jbe |
---|---|
date | Thu Dec 10 17:23:51 2015 +0100 (2015-12-10) |
parents | 762ab1e87702 |
children | ac9a4e1885da |
line diff
1.1 --- a/libraries/mondelefant/mondelefant_native.c Wed Dec 09 21:16:24 2015 +0100 1.2 +++ b/libraries/mondelefant/mondelefant_native.c Thu Dec 10 17:23:51 2015 +0100 1.3 @@ -179,17 +179,16 @@ 1.4 1.5 // pushing first line of a string on Lua's stack (without trailing CR/LF): 1.6 static void mondelefant_push_first_line(lua_State *L, const char *str) { 1.7 - char *str2; 1.8 size_t i = 0; 1.9 if (!str) abort(); // should not happen 1.10 - str2 = strdup(str); 1.11 while (1) { 1.12 - char c = str2[i]; 1.13 - if (c == '\n' || c == '\r' || c == 0) { str2[i] = 0; break; } 1.14 + char c = str[i]; 1.15 + if (c == '\n' || c == '\r' || c == 0) { 1.16 + lua_pushlstring(L, str, i); 1.17 + return; 1.18 + } 1.19 i++; 1.20 - }; 1.21 - lua_pushstring(L, str2); 1.22 - free(str2); 1.23 + } 1.24 } 1.25 1.26 // "connect" function of library, which establishes a database connection 1.27 @@ -199,16 +198,18 @@ 1.28 const char *conninfo; // string for PQconnectdb function 1.29 PGconn *pgconn; // PGconn object as returned by PQconnectdb function 1.30 mondelefant_conn_t *conn; // C-structure for userdata 1.31 + // expect a table as first argument: 1.32 + luaL_checktype(L, 1, LUA_TTABLE); 1.33 // if engine is anything but "postgresql", then raise error: 1.34 lua_settop(L, 1); 1.35 lua_getfield(L, 1, "engine"); // 2 1.36 if (!lua_toboolean(L, 2)) { 1.37 - return luaL_error(L, "No database engine selected."); 1.38 + return luaL_argerror(L, 1, "no database engine selected"); 1.39 } 1.40 lua_pushliteral(L, "postgresql"); // 3 1.41 if (!lua_rawequal(L, 2, 3)) { 1.42 - return luaL_error(L, 1.43 - "Only database engine 'postgresql' is supported." 1.44 + return luaL_argerror(L, 1, 1.45 + "only database engine 'postgresql' is supported" 1.46 ); 1.47 } 1.48 // copy conninfo string for PQconnectdb function from argument table to 1.49 @@ -230,7 +231,7 @@ 1.50 // NOTE: numbers will be converted to strings automatically here, 1.51 // but perhaps this will change in future versions of lua 1.52 luaL_argcheck(L, 1.53 - lua_isstring(L, 2) && lua_isstring(L, 3), 1, "non-string contained" 1.54 + lua_isstring(L, 2) && lua_isstring(L, 3), 1, "key is not a string" 1.55 ); 1.56 lua_pushvalue(L, 2); 1.57 lua_pushliteral(L, "engine"); 1.58 @@ -265,24 +266,25 @@ 1.59 conninfo = lua_tostring(L, 2); 1.60 // call PQconnectdb function of libpq: 1.61 pgconn = PQconnectdb(conninfo); 1.62 - // throw errors, if neccessary: 1.63 + // throw or return errors, if neccessary: 1.64 if (!pgconn) { 1.65 return luaL_error(L, 1.66 "Error in libpq while creating 'PGconn' structure." 1.67 ); 1.68 } 1.69 if (PQstatus(pgconn) != CONNECTION_OK) { 1.70 - const char *errmsg; 1.71 - lua_pushnil(L); 1.72 - errmsg = PQerrorMessage(pgconn); 1.73 - if (errmsg) { 1.74 - mondelefant_push_first_line(L, errmsg); 1.75 - } else { 1.76 - lua_pushliteral(L, 1.77 - "Error while connecting to database, but no error message given." 1.78 - ); 1.79 - } 1.80 + lua_pushnil(L); // 3 1.81 + mondelefant_push_first_line(L, PQerrorMessage(pgconn)); // 4 1.82 + lua_newtable(L); // 5 1.83 + lua_getfield(L, 1.84 + LUA_REGISTRYINDEX, 1.85 + MONDELEFANT_ERROROBJECT_MT_REGKEY 1.86 + ); 1.87 + lua_setmetatable(L, 5); 1.88 lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION); 1.89 + lua_setfield(L, 5, "code"); 1.90 + lua_pushvalue(L, 4); 1.91 + lua_setfield(L, 5, "message"); 1.92 PQfinish(pgconn); 1.93 return 3; 1.94 } 1.95 @@ -390,11 +392,10 @@ 1.96 // method "close" of database handles: 1.97 static int mondelefant_conn_close(lua_State *L) { 1.98 mondelefant_conn_t *conn; 1.99 - lua_settop(L, 1); 1.100 conn = mondelefant_get_conn(L, 1); 1.101 PQfinish(conn->pgconn); 1.102 conn->pgconn = NULL; 1.103 - lua_pushnil(L); // 2 1.104 + lua_pushnil(L); 1.105 lua_setfield(L, 1, "fd"); // set "fd" attribute to nil 1.106 return 0; 1.107 } 1.108 @@ -402,7 +403,6 @@ 1.109 // method "is_okay" of database handles: 1.110 static int mondelefant_conn_is_ok(lua_State *L) { 1.111 mondelefant_conn_t *conn; 1.112 - lua_settop(L, 1); 1.113 conn = mondelefant_get_conn(L, 1); 1.114 lua_pushboolean(L, PQstatus(conn->pgconn) == CONNECTION_OK); 1.115 return 1; 1.116 @@ -411,7 +411,6 @@ 1.117 // method "get_transaction_status" of database handles: 1.118 static int mondelefant_conn_get_transaction_status(lua_State *L) { 1.119 mondelefant_conn_t *conn; 1.120 - lua_settop(L, 1); 1.121 conn = mondelefant_get_conn(L, 1); 1.122 switch (PQtransactionStatus(conn->pgconn)) { 1.123 case PQTRANS_IDLE: 1.124 @@ -432,8 +431,8 @@ 1.125 return 1; 1.126 } 1.127 1.128 -// method "wait" of database handles: 1.129 -static int mondelefant_conn_wait(lua_State *L) { 1.130 +// method "try_wait" of database handles: 1.131 +static int mondelefant_conn_try_wait(lua_State *L) { 1.132 mondelefant_conn_t *conn; 1.133 int infinite, nonblock = 0; 1.134 struct timespec wakeup; 1.135 @@ -461,6 +460,7 @@ 1.136 luaL_argcheck(L, 0, 2, "not a valid timeout"); 1.137 } 1.138 } 1.139 + lua_settop(L, 1); 1.140 if (!nonblock) { 1.141 fd = PQsocket(conn->pgconn); 1.142 FD_ZERO(&fds); 1.143 @@ -470,17 +470,26 @@ 1.144 { 1.145 PGnotify *notify; 1.146 if (!PQconsumeInput(conn->pgconn)) { 1.147 - lua_pushnil(L); 1.148 - mondelefant_push_first_line(L, PQerrorMessage(conn->pgconn)); 1.149 - return 2; 1.150 + lua_newtable(L); // 2 1.151 + lua_getfield(L, 1.152 + LUA_REGISTRYINDEX, 1.153 + MONDELEFANT_ERROROBJECT_MT_REGKEY 1.154 + ); 1.155 + lua_setmetatable(L, 2); 1.156 + lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION); 1.157 + lua_setfield(L, 2, "code"); 1.158 + mondelefant_push_first_line(L, PQerrorMessage(conn->pgconn)); // 3 1.159 + lua_setfield(L, 2, "message"); 1.160 + return 1; 1.161 } 1.162 notify = PQnotifies(conn->pgconn); 1.163 if (notify) { 1.164 + lua_pushnil(L); 1.165 lua_pushstring(L, notify->relname); 1.166 lua_pushstring(L, notify->extra); 1.167 lua_pushinteger(L, notify->be_pid); 1.168 PQfreemem(notify); 1.169 - return 3; 1.170 + return 4; 1.171 } 1.172 } 1.173 if (infinite) { 1.174 @@ -508,21 +517,22 @@ 1.175 select(fd+1, &fds, NULL, NULL, &timeout); 1.176 } 1.177 } 1.178 - lua_pushboolean(L, 0); 1.179 - if (nonblock) lua_pushliteral(L, "No notification pending"); 1.180 - else lua_pushliteral(L, "Timeout while waiting for notification"); 1.181 + lua_pushnil(L); 1.182 + lua_pushnil(L); 1.183 return 2; 1.184 } 1.185 1.186 // method "create_list" of database handles: 1.187 static int mondelefant_conn_create_list(lua_State *L) { 1.188 // ensure that first argument is a database connection: 1.189 - lua_settop(L, 2); 1.190 luaL_checkudata(L, 1, MONDELEFANT_CONN_MT_REGKEY); 1.191 // if no second argument is given, use an empty table: 1.192 - if (!lua_toboolean(L, 2)) { 1.193 - lua_newtable(L); 1.194 - lua_replace(L, 2); // new result at stack position 2 1.195 + if (lua_isnoneornil(L, 2)) { 1.196 + lua_settop(L, 1); 1.197 + lua_newtable(L); // 2 1.198 + } else { 1.199 + luaL_checktype(L, 2, LUA_TTABLE); 1.200 + lua_settop(L, 2); 1.201 } 1.202 // set meta-table for database result lists/objects: 1.203 lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY); // 3 1.204 @@ -540,14 +550,16 @@ 1.205 // method "create_object" of database handles: 1.206 static int mondelefant_conn_create_object(lua_State *L) { 1.207 // ensure that first argument is a database connection: 1.208 - lua_settop(L, 2); 1.209 luaL_checkudata(L, 1, MONDELEFANT_CONN_MT_REGKEY); 1.210 // if no second argument is given, use an empty table: 1.211 - if (!lua_toboolean(L, 2)) { 1.212 - lua_newtable(L); 1.213 - lua_replace(L, 2); // new result at stack position 2 1.214 + if (lua_isnoneornil(L, 2)) { 1.215 + lua_settop(L, 1); 1.216 + lua_newtable(L); // 2 1.217 + } else { 1.218 + luaL_checktype(L, 2, LUA_TTABLE); 1.219 + lua_settop(L, 2); 1.220 } 1.221 - // set meta-table for database result lists/objects: 1.222 + // set meta-table for database result lists/objects: 1.223 lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY); // 3 1.224 lua_setmetatable(L, 2); 1.225 // set "_connection" attribute to self: 1.226 @@ -575,7 +587,6 @@ 1.227 char *output; 1.228 size_t output_len; 1.229 // get 'conn' attribute of C-struct of database connection: 1.230 - lua_settop(L, 2); 1.231 conn = mondelefant_get_conn(L, 1); 1.232 // get second argument, which must be a string: 1.233 input = luaL_checklstring(L, 2, &input_len); 1.234 @@ -613,7 +624,6 @@ 1.235 size_t output_len; 1.236 luaL_Buffer buf; 1.237 // get 'conn' attribute of C-struct of database connection: 1.238 - lua_settop(L, 2); 1.239 conn = mondelefant_get_conn(L, 1); 1.240 // get second argument, which must be a string: 1.241 input = luaL_checklstring(L, 2, &input_len); 1.242 @@ -645,11 +655,10 @@ 1.243 size_t template_pos = 0; 1.244 luaL_Buffer buf; 1.245 // get 'conn' attribute of C-struct of database connection: 1.246 - lua_settop(L, 2); 1.247 conn = mondelefant_get_conn(L, 1); 1.248 // if second argument is a string, return this string: 1.249 - if (lua_isstring(L, 2)) { 1.250 - lua_tostring(L, 2); 1.251 + if (lua_type(L, 2) == LUA_TSTRING) { 1.252 + lua_settop(L, 2); 1.253 return 1; 1.254 } 1.255 // if second argument has __tostring meta-method, 1.256 @@ -657,6 +666,8 @@ 1.257 if (luaL_callmeta(L, 2, "__tostring")) return 1; 1.258 // otherwise, require that second argument is a table: 1.259 luaL_checktype(L, 2, LUA_TTABLE); 1.260 + // set stack top: 1.261 + lua_settop(L, 2); 1.262 // get first element of table, which must be a string: 1.263 lua_rawgeti(L, 2, 1); // 3 1.264 luaL_argcheck(L, 1.265 @@ -904,7 +915,7 @@ 1.266 } else if (!strcmp(modestr, "opt_object")) { 1.267 mode = MONDELEFANT_QUERY_MODE_OPT_OBJECT; 1.268 } else { 1.269 - return luaL_error(L, "Unknown query mode specified."); 1.270 + return luaL_argerror(L, mode_idx, "unknown query mode"); 1.271 } 1.272 } 1.273 modes[command_idx] = mode; 1.274 @@ -961,110 +972,117 @@ 1.275 lua_setmetatable(L, 5); 1.276 lua_pushvalue(L, 1); 1.277 lua_setfield(L, 5, "connection"); 1.278 - lua_pushinteger(L, command_idx + 1); 1.279 - lua_setfield(L, 5, "command_number"); 1.280 lua_pushvalue(L, 2); 1.281 lua_setfield(L, 5, "sql_command"); 1.282 - if (!res) { 1.283 - lua_pushliteral(L, MONDELEFANT_ERRCODE_RESULTCOUNT_LOW); 1.284 - lua_setfield(L, 5, "code"); 1.285 - lua_pushliteral(L, "Received too few database result sets."); 1.286 - lua_setfield(L, 5, "message"); 1.287 - } else if (command_idx >= command_count) { 1.288 - lua_pushliteral(L, MONDELEFANT_ERRCODE_RESULTCOUNT_HIGH); 1.289 + if (!sent_success) { 1.290 + lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION); 1.291 lua_setfield(L, 5, "code"); 1.292 - lua_pushliteral(L, "Received too many database result sets."); 1.293 - lua_setfield(L, 5, "message"); 1.294 - } else if ( 1.295 - pgstatus != PGRES_TUPLES_OK && pgstatus != PGRES_COMMAND_OK 1.296 - ) { 1.297 - const char *sqlstate; 1.298 - const char *errmsg; 1.299 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SEVERITY)); 1.300 - lua_setfield(L, 5, "pg_severity"); 1.301 - sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); 1.302 - if (sqlstate) { 1.303 - lua_pushstring(L, sqlstate); 1.304 - lua_setfield(L, 5, "pg_sqlstate"); 1.305 - lua_pushstring(L, mondelefant_translate_errcode(sqlstate)); 1.306 - lua_setfield(L, 5, "code"); 1.307 - } else { 1.308 - lua_pushliteral(L, MONDELEFANT_ERRCODE_UNKNOWN); 1.309 - lua_setfield(L, 5, "code"); 1.310 - } 1.311 - errmsg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); 1.312 - if (errmsg) { 1.313 - mondelefant_push_first_line(L, errmsg); 1.314 - lua_setfield(L, 5, "message"); 1.315 - lua_pushstring(L, errmsg); 1.316 - lua_setfield(L, 5, "pg_message_primary"); 1.317 - } else { 1.318 - lua_pushliteral(L, 1.319 - "Error while fetching result, but no error message given." 1.320 - ); 1.321 - lua_setfield(L, 5, "message"); 1.322 - } 1.323 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL)); 1.324 - lua_setfield(L, 5, "pg_message_detail"); 1.325 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_MESSAGE_HINT)); 1.326 - lua_setfield(L, 5, "pg_message_hint"); 1.327 - // NOTE: "position" and "pg_internal_position" are recalculated to 1.328 - // byte offsets, as Lua 5.1 is not Unicode aware. 1.329 - { 1.330 - char *tmp; 1.331 - tmp = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION); 1.332 - if (tmp) { 1.333 - int pos; 1.334 - pos = atoi(tmp) - 1; 1.335 - if (conn->server_encoding == MONDELEFANT_SERVER_ENCODING_UTF8) { 1.336 - pos = utf8_position_to_byte(command, pos); 1.337 - } 1.338 - lua_pushinteger(L, pos + 1); 1.339 - lua_setfield(L, 5, "position"); 1.340 - } 1.341 - } 1.342 - { 1.343 - const char *internal_query; 1.344 - internal_query = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); 1.345 - lua_pushstring(L, internal_query); 1.346 - lua_setfield(L, 5, "pg_internal_query"); 1.347 - char *tmp; 1.348 - tmp = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION); 1.349 - if (tmp) { 1.350 - int pos; 1.351 - pos = atoi(tmp) - 1; 1.352 - if (conn->server_encoding == MONDELEFANT_SERVER_ENCODING_UTF8) { 1.353 - pos = utf8_position_to_byte(internal_query, pos); 1.354 - } 1.355 - lua_pushinteger(L, pos + 1); 1.356 - lua_setfield(L, 5, "pg_internal_position"); 1.357 - } 1.358 - } 1.359 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_CONTEXT)); 1.360 - lua_setfield(L, 5, "pg_context"); 1.361 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_FILE)); 1.362 - lua_setfield(L, 5, "pg_source_file"); 1.363 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_LINE)); 1.364 - lua_setfield(L, 5, "pg_source_line"); 1.365 - lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION)); 1.366 - lua_setfield(L, 5, "pg_source_function"); 1.367 - } else if (rows < 1 && mode == MONDELEFANT_QUERY_MODE_OBJECT) { 1.368 - lua_pushliteral(L, MONDELEFANT_ERRCODE_QUERY1_NO_ROWS); 1.369 - lua_setfield(L, 5, "code"); 1.370 - lua_pushliteral(L, "Expected one row, but got empty set."); 1.371 - lua_setfield(L, 5, "message"); 1.372 - } else if (rows > 1 && mode != MONDELEFANT_QUERY_MODE_LIST) { 1.373 - lua_pushliteral(L, MONDELEFANT_ERRCODE_QUERY1_MULTIPLE_ROWS); 1.374 - lua_setfield(L, 5, "code"); 1.375 - lua_pushliteral(L, "Got more than one result row."); 1.376 + mondelefant_push_first_line(L, PQerrorMessage(conn->pgconn)); 1.377 lua_setfield(L, 5, "message"); 1.378 } else { 1.379 - // should not happen 1.380 - abort(); 1.381 - } 1.382 - if (res) { 1.383 - PQclear(res); 1.384 - while ((res = PQgetResult(conn->pgconn))) PQclear(res); 1.385 + lua_pushinteger(L, command_idx + 1); 1.386 + lua_setfield(L, 5, "command_number"); 1.387 + if (!res) { 1.388 + lua_pushliteral(L, MONDELEFANT_ERRCODE_RESULTCOUNT_LOW); 1.389 + lua_setfield(L, 5, "code"); 1.390 + lua_pushliteral(L, "Received too few database result sets."); 1.391 + lua_setfield(L, 5, "message"); 1.392 + } else if (command_idx >= command_count) { 1.393 + lua_pushliteral(L, MONDELEFANT_ERRCODE_RESULTCOUNT_HIGH); 1.394 + lua_setfield(L, 5, "code"); 1.395 + lua_pushliteral(L, "Received too many database result sets."); 1.396 + lua_setfield(L, 5, "message"); 1.397 + } else if ( 1.398 + pgstatus != PGRES_TUPLES_OK && pgstatus != PGRES_COMMAND_OK 1.399 + ) { 1.400 + const char *sqlstate; 1.401 + const char *errmsg; 1.402 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SEVERITY)); 1.403 + lua_setfield(L, 5, "pg_severity"); 1.404 + sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); 1.405 + if (sqlstate) { 1.406 + lua_pushstring(L, sqlstate); 1.407 + lua_setfield(L, 5, "pg_sqlstate"); 1.408 + lua_pushstring(L, mondelefant_translate_errcode(sqlstate)); 1.409 + lua_setfield(L, 5, "code"); 1.410 + } else { 1.411 + lua_pushliteral(L, MONDELEFANT_ERRCODE_UNKNOWN); 1.412 + lua_setfield(L, 5, "code"); 1.413 + } 1.414 + errmsg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); 1.415 + if (errmsg) { 1.416 + mondelefant_push_first_line(L, errmsg); 1.417 + lua_setfield(L, 5, "message"); 1.418 + lua_pushstring(L, errmsg); 1.419 + lua_setfield(L, 5, "pg_message_primary"); 1.420 + } else { 1.421 + lua_pushliteral(L, 1.422 + "Error while fetching result, but no error message given." 1.423 + ); 1.424 + lua_setfield(L, 5, "message"); 1.425 + } 1.426 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL)); 1.427 + lua_setfield(L, 5, "pg_message_detail"); 1.428 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_MESSAGE_HINT)); 1.429 + lua_setfield(L, 5, "pg_message_hint"); 1.430 + // NOTE: "position" and "pg_internal_position" are recalculated to 1.431 + // byte offsets, as Lua 5.2 is not Unicode aware. 1.432 + { 1.433 + char *tmp; 1.434 + tmp = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION); 1.435 + if (tmp) { 1.436 + int pos; 1.437 + pos = atoi(tmp) - 1; 1.438 + if (conn->server_encoding == MONDELEFANT_SERVER_ENCODING_UTF8) { 1.439 + pos = utf8_position_to_byte(command, pos); 1.440 + } 1.441 + lua_pushinteger(L, pos + 1); 1.442 + lua_setfield(L, 5, "position"); 1.443 + } 1.444 + } 1.445 + { 1.446 + const char *internal_query; 1.447 + internal_query = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); 1.448 + lua_pushstring(L, internal_query); 1.449 + lua_setfield(L, 5, "pg_internal_query"); 1.450 + char *tmp; 1.451 + tmp = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION); 1.452 + if (tmp) { 1.453 + int pos; 1.454 + pos = atoi(tmp) - 1; 1.455 + if (conn->server_encoding == MONDELEFANT_SERVER_ENCODING_UTF8) { 1.456 + pos = utf8_position_to_byte(internal_query, pos); 1.457 + } 1.458 + lua_pushinteger(L, pos + 1); 1.459 + lua_setfield(L, 5, "pg_internal_position"); 1.460 + } 1.461 + } 1.462 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_CONTEXT)); 1.463 + lua_setfield(L, 5, "pg_context"); 1.464 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_FILE)); 1.465 + lua_setfield(L, 5, "pg_source_file"); 1.466 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_LINE)); 1.467 + lua_setfield(L, 5, "pg_source_line"); 1.468 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION)); 1.469 + lua_setfield(L, 5, "pg_source_function"); 1.470 + } else if (rows < 1 && mode == MONDELEFANT_QUERY_MODE_OBJECT) { 1.471 + lua_pushliteral(L, MONDELEFANT_ERRCODE_QUERY1_NO_ROWS); 1.472 + lua_setfield(L, 5, "code"); 1.473 + lua_pushliteral(L, "Expected one row, but got empty set."); 1.474 + lua_setfield(L, 5, "message"); 1.475 + } else if (rows > 1 && mode != MONDELEFANT_QUERY_MODE_LIST) { 1.476 + lua_pushliteral(L, MONDELEFANT_ERRCODE_QUERY1_MULTIPLE_ROWS); 1.477 + lua_setfield(L, 5, "code"); 1.478 + lua_pushliteral(L, "Got more than one result row."); 1.479 + lua_setfield(L, 5, "message"); 1.480 + } else { 1.481 + // should not happen 1.482 + abort(); 1.483 + } 1.484 + if (res) { 1.485 + PQclear(res); 1.486 + while ((res = PQgetResult(conn->pgconn))) PQclear(res); 1.487 + } 1.488 } 1.489 if (lua_toboolean(L, 3)) { 1.490 lua_pushvalue(L, 3); 1.491 @@ -1312,43 +1330,45 @@ 1.492 return command_count+1; 1.493 } 1.494 1.495 -// method "escalate" of error objects: 1.496 -static int mondelefant_errorobject_escalate(lua_State *L) { 1.497 - // check, if we may throw an error object instead of an error string: 1.498 - lua_settop(L, 1); 1.499 - lua_getfield(L, 1, "connection"); // 2 1.500 - lua_getfield(L, 2, "error_objects"); // 3 1.501 - if (lua_toboolean(L, 3)) { 1.502 - // throw error object: 1.503 +// method "is_kind_of" of error objects: 1.504 +static int mondelefant_errorobject_is_kind_of(lua_State *L) { 1.505 + const char *errclass; 1.506 + luaL_checktype(L, 1, LUA_TTABLE); 1.507 + errclass = luaL_checkstring(L, 2); 1.508 + lua_settop(L, 2); 1.509 + lua_getfield(L, 1, "code"); // 3 1.510 + luaL_argcheck(L, 1.511 + lua_type(L, 3) == LUA_TSTRING, 1.512 + 1, 1.513 + "field 'code' of error object is not a string" 1.514 + ); 1.515 + lua_pushboolean(L, 1.516 + mondelefant_check_error_class(lua_tostring(L, 3), errclass) 1.517 + ); 1.518 + return 1; 1.519 +} 1.520 + 1.521 +// method "wait" of database handles: 1.522 +static int mondelefant_conn_wait(lua_State *L) { 1.523 + int argc; 1.524 + // count number of arguments: 1.525 + argc = lua_gettop(L); 1.526 + // insert "try_wait" function/method at stack position 1: 1.527 + lua_pushcfunction(L, mondelefant_conn_try_wait); 1.528 + lua_insert(L, 1); 1.529 + // call "try_wait" method: 1.530 + lua_call(L, argc, LUA_MULTRET); // results (with error) starting at index 1 1.531 + // check, if error occurred: 1.532 + if (lua_toboolean(L, 1)) { 1.533 + // raise error 1.534 lua_settop(L, 1); 1.535 return lua_error(L); 1.536 } else { 1.537 - // throw error string: 1.538 - lua_getfield(L, 1, "message"); // 4 1.539 - if (lua_isnil(L, 4)) { 1.540 - return luaL_error(L, "No error message given for escalation."); 1.541 - } 1.542 - return lua_error(L); 1.543 + // return everything but nil error object: 1.544 + return lua_gettop(L) - 1; 1.545 } 1.546 } 1.547 1.548 -// method "is_kind_of" of error objects: 1.549 -static int mondelefant_errorobject_is_kind_of(lua_State *L) { 1.550 - lua_settop(L, 2); 1.551 - lua_getfield(L, 1, "code"); // 3 1.552 - if (lua_isstring(L, 3)) { 1.553 - lua_pushboolean(L, 1.554 - mondelefant_check_error_class( 1.555 - lua_tostring(L, 3), luaL_checkstring(L, 2) 1.556 - ) 1.557 - ); 1.558 - } else { 1.559 - // only happens for errors where code is not set 1.560 - lua_pushboolean(L, 0); 1.561 - } 1.562 - return 1; 1.563 -} 1.564 - 1.565 // method "query" of database handles: 1.566 static int mondelefant_conn_query(lua_State *L) { 1.567 int argc; 1.568 @@ -1361,11 +1381,9 @@ 1.569 lua_call(L, argc, LUA_MULTRET); // results (with error) starting at index 1 1.570 // check, if error occurred: 1.571 if (lua_toboolean(L, 1)) { 1.572 - // invoke escalate method of error object: 1.573 - lua_pushcfunction(L, mondelefant_errorobject_escalate); 1.574 - lua_pushvalue(L, 1); 1.575 - lua_call(L, 1, 0); // will raise an error 1.576 - return 0; // should not be executed 1.577 + // raise error 1.578 + lua_settop(L, 1); 1.579 + return lua_error(L); 1.580 } else { 1.581 // return everything but nil error object: 1.582 return lua_gettop(L) - 1; 1.583 @@ -1420,11 +1438,13 @@ 1.584 1.585 // library function "new_class": 1.586 static int mondelefant_new_class(lua_State *L) { 1.587 - // use first argument as template or create new table: 1.588 - lua_settop(L, 1); 1.589 - if (!lua_toboolean(L, 1)) { 1.590 + // if no argument is given, use an empty table: 1.591 + if (lua_isnoneornil(L, 1)) { 1.592 lua_settop(L, 0); 1.593 lua_newtable(L); // 1 1.594 + } else { 1.595 + luaL_checktype(L, 1, LUA_TTABLE); 1.596 + lua_settop(L, 1); 1.597 } 1.598 // set meta-table for database classes (models): 1.599 lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CLASS_MT_REGKEY); // 2 1.600 @@ -1843,6 +1863,7 @@ 1.601 {"close", mondelefant_conn_close}, 1.602 {"is_ok", mondelefant_conn_is_ok}, 1.603 {"get_transaction_status", mondelefant_conn_get_transaction_status}, 1.604 + {"try_wait", mondelefant_conn_try_wait}, 1.605 {"wait", mondelefant_conn_wait}, 1.606 {"create_list", mondelefant_conn_create_list}, 1.607 {"create_object", mondelefant_conn_create_object}, 1.608 @@ -1861,7 +1882,7 @@ 1.609 1.610 // registration information for methods of error objects: 1.611 static const struct luaL_Reg mondelefant_errorobject_methods[] = { 1.612 - {"escalate", mondelefant_errorobject_escalate}, 1.613 + {"escalate", lua_error}, 1.614 {"is_kind_of", mondelefant_errorobject_is_kind_of}, 1.615 {NULL, NULL} 1.616 };