webmcp
diff libraries/mondelefant/mondelefant_native.c @ 0:9fdfb27f8e67
Version 1.0.0
author | jbe/bsw |
---|---|
date | Sun Oct 25 12:00:00 2009 +0100 (2009-10-25) |
parents | |
children | 3a6fe8663b26 |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libraries/mondelefant/mondelefant_native.c Sun Oct 25 12:00:00 2009 +0100 1.3 @@ -0,0 +1,1558 @@ 1.4 +#include <lua.h> 1.5 +#include <lauxlib.h> 1.6 +#include <libpq-fe.h> 1.7 +#include <postgres.h> 1.8 +#include <catalog/pg_type.h> 1.9 +#include <stdint.h> 1.10 + 1.11 +#define MONDELEFANT_REGKEY "e449ba8d9a53d353_mondelefant" 1.12 + 1.13 +#define MONDELEFANT_MODULE_REGKEY (MONDELEFANT_REGKEY "_module") 1.14 +#define MONDELEFANT_CONN_MT_REGKEY (MONDELEFANT_REGKEY "_connection") 1.15 +#define MONDELEFANT_CONN_DATA_REGKEY (MONDELEFANT_REGKEY "_connection_data") 1.16 +#define MONDELEFANT_RESULT_MT_REGKEY (MONDELEFANT_REGKEY "_result") 1.17 +#define MONDELEFANT_ERROROBJECT_MT_REGKEY (MONDELEFANT_REGKEY "_errorobject") 1.18 +#define MONDELEFANT_CLASS_MT_REGKEY (MONDELEFANT_REGKEY "_class") 1.19 +#define MONDELEFANT_CLASS_PROTO_REGKEY (MONDELEFANT_REGKEY "_class_proto") 1.20 + 1.21 +#define MONDELEFANT_SERVER_ENCODING_ASCII 0 1.22 +#define MONDELEFANT_SERVER_ENCODING_UTF8 1 1.23 + 1.24 +typedef struct { 1.25 + PGconn *pgconn; 1.26 + int server_encoding; 1.27 +} mondelefant_conn_t; 1.28 + 1.29 +static size_t utf8_position_to_byte(const char *str, size_t utf8pos) { 1.30 + size_t bytepos; 1.31 + for (bytepos = 0; utf8pos > 0; bytepos++) { 1.32 + uint8_t c; 1.33 + c = ((const uint8_t *)str)[bytepos]; 1.34 + if (!c) break; 1.35 + if (c <= 0x7f || c >= 0xc0) utf8pos--; 1.36 + } 1.37 + return bytepos; 1.38 +} 1.39 + 1.40 +#define MONDELEFANT_POSTGRESQL_BINARY_OID ((Oid)17) 1.41 + 1.42 +static const char *mondelefant_oid_to_typestr(Oid oid) { 1.43 + switch (oid) { 1.44 + case 16: return "bool"; 1.45 + case 17: return "bytea"; 1.46 + case 18: return "char"; 1.47 + case 19: return "name"; 1.48 + case 20: return "int8"; 1.49 + case 21: return "int2"; 1.50 + case 23: return "int4"; 1.51 + case 25: return "text"; 1.52 + case 26: return "oid"; 1.53 + case 27: return "tid"; 1.54 + case 28: return "xid"; 1.55 + case 29: return "cid"; 1.56 + case 600: return "point"; 1.57 + case 601: return "lseg"; 1.58 + case 602: return "path"; 1.59 + case 603: return "box"; 1.60 + case 604: return "polygon"; 1.61 + case 628: return "line"; 1.62 + case 700: return "float4"; 1.63 + case 701: return "float8"; 1.64 + case 705: return "unknown"; 1.65 + case 718: return "circle"; 1.66 + case 790: return "money"; 1.67 + case 829: return "macaddr"; 1.68 + case 869: return "inet"; 1.69 + case 650: return "cidr"; 1.70 + case 1042: return "bpchar"; 1.71 + case 1043: return "varchar"; 1.72 + case 1082: return "date"; 1.73 + case 1083: return "time"; 1.74 + case 1114: return "timestamp"; 1.75 + case 1184: return "timestamptz"; 1.76 + case 1186: return "interval"; 1.77 + case 1266: return "timetz"; 1.78 + case 1560: return "bit"; 1.79 + case 1562: return "varbit"; 1.80 + case 1700: return "numeric"; 1.81 + default: return NULL; 1.82 + } 1.83 +} 1.84 + 1.85 +#define mondelefant_errcode_item(incode, outcode) \ 1.86 + if (!strncmp(pgcode, (incode), strlen(incode))) return outcode; else 1.87 + 1.88 +#define MONDELEFANT_ERRCODE_UNKNOWN "unknown" 1.89 +#define MONDELEFANT_ERRCODE_CONNECTION "ConnectionException" 1.90 +#define MONDELEFANT_ERRCODE_RESULTCOUNT_LOW "WrongResultSetCount.ResultSetMissing" 1.91 +#define MONDELEFANT_ERRCODE_RESULTCOUNT_HIGH "WrongResultSetCount.TooManyResults" 1.92 +#define MONDELEFANT_ERRCODE_QUERY1_NO_ROWS "NoData.OneRowExpected" 1.93 +#define MONDELEFANT_ERRCODE_QUERY1_MULTIPLE_ROWS "CardinalityViolation.OneRowExpected" 1.94 + 1.95 +static const char *mondelefant_translate_errcode(const char *pgcode) { 1.96 + if (!pgcode) abort(); // should not happen 1.97 + mondelefant_errcode_item("02", "NoData") 1.98 + mondelefant_errcode_item("03", "SqlStatementNotYetComplete") 1.99 + mondelefant_errcode_item("08", "ConnectionException") 1.100 + mondelefant_errcode_item("09", "TriggeredActionException") 1.101 + mondelefant_errcode_item("0A", "FeatureNotSupported") 1.102 + mondelefant_errcode_item("0B", "InvalidTransactionInitiation") 1.103 + mondelefant_errcode_item("0F", "LocatorException") 1.104 + mondelefant_errcode_item("0L", "InvalidGrantor") 1.105 + mondelefant_errcode_item("0P", "InvalidRoleSpecification") 1.106 + mondelefant_errcode_item("21", "CardinalityViolation") 1.107 + mondelefant_errcode_item("22", "DataException") 1.108 + mondelefant_errcode_item("23001", "IntegrityConstraintViolation.RestrictViolation") 1.109 + mondelefant_errcode_item("23502", "IntegrityConstraintViolation.NotNullViolation") 1.110 + mondelefant_errcode_item("23503", "IntegrityConstraintViolation.ForeignKeyViolation") 1.111 + mondelefant_errcode_item("23505", "IntegrityConstraintViolation.UniqueViolation") 1.112 + mondelefant_errcode_item("23514", "IntegrityConstraintViolation.CheckViolation") 1.113 + mondelefant_errcode_item("23", "IntegrityConstraintViolation") 1.114 + mondelefant_errcode_item("24", "InvalidCursorState") 1.115 + mondelefant_errcode_item("25", "InvalidTransactionState") 1.116 + mondelefant_errcode_item("26", "InvalidSqlStatementName") 1.117 + mondelefant_errcode_item("27", "TriggeredDataChangeViolation") 1.118 + mondelefant_errcode_item("28", "InvalidAuthorizationSpecification") 1.119 + mondelefant_errcode_item("2B", "DependentPrivilegeDescriptorsStillExist") 1.120 + mondelefant_errcode_item("2D", "InvalidTransactionTermination") 1.121 + mondelefant_errcode_item("2F", "SqlRoutineException") 1.122 + mondelefant_errcode_item("34", "InvalidCursorName") 1.123 + mondelefant_errcode_item("38", "ExternalRoutineException") 1.124 + mondelefant_errcode_item("39", "ExternalRoutineInvocationException") 1.125 + mondelefant_errcode_item("3B", "SavepointException") 1.126 + mondelefant_errcode_item("3D", "InvalidCatalogName") 1.127 + mondelefant_errcode_item("3F", "InvalidSchemaName") 1.128 + mondelefant_errcode_item("40", "TransactionRollback") 1.129 + mondelefant_errcode_item("42", "SyntaxErrorOrAccessRuleViolation") 1.130 + mondelefant_errcode_item("44", "WithCheckOptionViolation") 1.131 + mondelefant_errcode_item("53", "InsufficientResources") 1.132 + mondelefant_errcode_item("54", "ProgramLimitExceeded") 1.133 + mondelefant_errcode_item("55", "ObjectNotInPrerequisiteState") 1.134 + mondelefant_errcode_item("57", "OperatorIntervention") 1.135 + mondelefant_errcode_item("58", "SystemError") 1.136 + mondelefant_errcode_item("F0", "ConfigurationFileError") 1.137 + mondelefant_errcode_item("P0", "PlpgsqlError") 1.138 + mondelefant_errcode_item("XX", "InternalError") 1.139 + return "unknown"; 1.140 +} 1.141 + 1.142 +static int mondelefant_check_error_class( 1.143 + const char *errcode, const char *errclass 1.144 +) { 1.145 + size_t i = 0; 1.146 + while (1) { 1.147 + if (errclass[i] == 0) { 1.148 + if (errcode[i] == 0 || errcode[i] == '.') return 1; 1.149 + else return 0; 1.150 + } 1.151 + if (errcode[i] != errclass[i]) return 0; 1.152 + i++; 1.153 + } 1.154 +} 1.155 + 1.156 +static void mondelefant_push_first_line(lua_State *L, const char *str) { 1.157 + char *str2; 1.158 + size_t i = 0; 1.159 + if (!str) abort(); // should not happen 1.160 + str2 = strdup(str); 1.161 + while (1) { 1.162 + char c = str2[i]; 1.163 + if (c == '\n' || c == '\r' || c == 0) { str2[i] = 0; break; } 1.164 + i++; 1.165 + }; 1.166 + lua_pushstring(L, str2); 1.167 + free(str2); 1.168 +} 1.169 + 1.170 +static int mondelefant_connect(lua_State *L) { 1.171 + luaL_Buffer buf; 1.172 + const char *conninfo; 1.173 + PGconn *pgconn; 1.174 + mondelefant_conn_t *conn; 1.175 + lua_settop(L, 1); 1.176 + lua_getfield(L, 1, "engine"); // 2 1.177 + if (!lua_toboolean(L, 2)) { 1.178 + return luaL_error(L, "No database engine selected."); 1.179 + } 1.180 + lua_pushliteral(L, "postgresql"); // 3 1.181 + if (!lua_rawequal(L, 2, 3)) { 1.182 + return luaL_error(L, 1.183 + "Only database engine 'postgresql' is supported." 1.184 + ); 1.185 + } 1.186 + lua_settop(L, 1); 1.187 + lua_pushnil(L); // slot for key at stack position 2 1.188 + lua_pushnil(L); // slot for value at stack position 3 1.189 + luaL_buffinit(L, &buf); 1.190 + { 1.191 + int need_seperator = 0; 1.192 + while (lua_pushvalue(L, 2), lua_next(L, 1)) { 1.193 + lua_replace(L, 3); 1.194 + lua_replace(L, 2); 1.195 + // NOTE: numbers will be converted to strings automatically here, 1.196 + // but perhaps this will change in future versions of lua 1.197 + luaL_argcheck(L, 1.198 + lua_isstring(L, 2) && lua_isstring(L, 3), 1, "non-string contained" 1.199 + ); 1.200 + lua_pushvalue(L, 2); 1.201 + lua_pushliteral(L, "engine"); 1.202 + if (!lua_rawequal(L, -2, -1)) { 1.203 + const char *value; 1.204 + size_t value_len; 1.205 + size_t value_pos = 0; 1.206 + lua_pop(L, 1); 1.207 + if (need_seperator) luaL_addchar(&buf, ' '); 1.208 + luaL_addvalue(&buf); 1.209 + luaL_addchar(&buf, '='); 1.210 + luaL_addchar(&buf, '\''); 1.211 + value = lua_tolstring(L, 3, &value_len); 1.212 + do { 1.213 + char c; 1.214 + c = value[value_pos++]; 1.215 + if (c == '\'') luaL_addchar(&buf, '\\'); 1.216 + luaL_addchar(&buf, c); 1.217 + } while (value_pos < value_len); 1.218 + luaL_addchar(&buf, '\''); 1.219 + need_seperator = 1; 1.220 + } else { 1.221 + lua_pop(L, 1); 1.222 + } 1.223 + } 1.224 + } 1.225 + luaL_pushresult(&buf); 1.226 + lua_replace(L, 2); 1.227 + lua_settop(L, 2); 1.228 + conninfo = lua_tostring(L, 2); 1.229 + pgconn = PQconnectdb(conninfo); 1.230 + if (!pgconn) { 1.231 + return luaL_error(L, 1.232 + "Error in libpq while creating 'PGconn' structure." 1.233 + ); 1.234 + } 1.235 + if (PQstatus(pgconn) != CONNECTION_OK) { 1.236 + const char *errmsg; 1.237 + lua_pushnil(L); 1.238 + errmsg = PQerrorMessage(pgconn); 1.239 + if (errmsg) { 1.240 + mondelefant_push_first_line(L, errmsg); 1.241 + } else { 1.242 + lua_pushliteral(L, 1.243 + "Error while connecting to database, but no error message given." 1.244 + ); 1.245 + } 1.246 + lua_pushliteral(L, MONDELEFANT_ERRCODE_CONNECTION); 1.247 + PQfinish(pgconn); 1.248 + return 3; 1.249 + } 1.250 + lua_settop(L, 0); 1.251 + conn = lua_newuserdata(L, sizeof(*conn)); // 1 1.252 + conn->pgconn = pgconn; 1.253 + { 1.254 + const char *charset; 1.255 + charset = PQparameterStatus(pgconn, "server_encoding"); 1.256 + if (charset && !strcmp(charset, "UTF8")) { 1.257 + conn->server_encoding = MONDELEFANT_SERVER_ENCODING_UTF8; 1.258 + } else { 1.259 + conn->server_encoding = MONDELEFANT_SERVER_ENCODING_ASCII; 1.260 + } 1.261 + } 1.262 + 1.263 + luaL_getmetatable(L, MONDELEFANT_CONN_MT_REGKEY); // 2 1.264 + lua_setmetatable(L, 1); 1.265 + 1.266 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CONN_DATA_REGKEY); // 2 1.267 + lua_pushvalue(L, 1); // 3 1.268 + lua_newtable(L); // 4 1.269 + lua_settable(L, 2); 1.270 + lua_settop(L, 1); 1.271 + 1.272 + lua_pushliteral(L, "postgresql"); 1.273 + lua_setfield(L, 1, "engine"); 1.274 + return 1; 1.275 +} 1.276 + 1.277 +static mondelefant_conn_t *mondelefant_get_conn(lua_State *L, int index) { 1.278 + mondelefant_conn_t *conn; 1.279 + conn = luaL_checkudata(L, index, MONDELEFANT_CONN_MT_REGKEY); 1.280 + if (!conn->pgconn) { 1.281 + luaL_error(L, "PostgreSQL connection has been closed."); 1.282 + return NULL; 1.283 + } 1.284 + return conn; 1.285 +} 1.286 + 1.287 +static int mondelefant_conn_index(lua_State *L) { 1.288 + lua_settop(L, 2); 1.289 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CONN_DATA_REGKEY); // 3 1.290 + lua_pushvalue(L, 1); // 4 1.291 + lua_gettable(L, 3); // 4 1.292 + lua_remove(L, 3); // connection specific data-table at stack position 3 1.293 + lua_pushvalue(L, 2); // 4 1.294 + lua_gettable(L, 3); // 4 1.295 + if (!lua_isnil(L, 4)) return 1; 1.296 + lua_settop(L, 3); 1.297 + lua_getfield(L, 3, "prototype"); // 4 1.298 + if (lua_toboolean(L, 4)) { 1.299 + lua_pushvalue(L, 2); // 5 1.300 + lua_gettable(L, 4); // 5 1.301 + if (!lua_isnil(L, 5)) return 1; 1.302 + } 1.303 + lua_settop(L, 2); 1.304 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_MODULE_REGKEY); // 3 1.305 + lua_getfield(L, 3, "postgresql_connection_prototype"); // 4 1.306 + if (lua_toboolean(L, 4)) { 1.307 + lua_pushvalue(L, 2); // 5 1.308 + lua_gettable(L, 4); // 5 1.309 + if (!lua_isnil(L, 5)) return 1; 1.310 + } 1.311 + lua_settop(L, 3); 1.312 + lua_getfield(L, 3, "connection_prototype"); // 4 1.313 + if (lua_toboolean(L, 4)) { 1.314 + lua_pushvalue(L, 2); // 5 1.315 + lua_gettable(L, 4); // 5 1.316 + if (!lua_isnil(L, 5)) return 1; 1.317 + } 1.318 + return 0; 1.319 +} 1.320 + 1.321 +static int mondelefant_conn_newindex(lua_State *L) { 1.322 + lua_settop(L, 3); 1.323 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CONN_DATA_REGKEY); // 4 1.324 + lua_pushvalue(L, 1); // 5 1.325 + lua_gettable(L, 4); // 5 1.326 + lua_remove(L, 4); // connection specific data-table at stack position 4 1.327 + lua_pushvalue(L, 2); 1.328 + lua_pushvalue(L, 3); 1.329 + lua_settable(L, 4); 1.330 + return 0; 1.331 +} 1.332 + 1.333 +static int mondelefant_conn_free(lua_State *L) { 1.334 + mondelefant_conn_t *conn; 1.335 + conn = luaL_checkudata(L, 1, MONDELEFANT_CONN_MT_REGKEY); 1.336 + if (conn->pgconn) PQfinish(conn->pgconn); 1.337 + conn->pgconn = NULL; 1.338 + return 0; 1.339 +} 1.340 + 1.341 +static int mondelefant_conn_close(lua_State *L) { 1.342 + mondelefant_conn_t *conn; 1.343 + lua_settop(L, 1); 1.344 + conn = mondelefant_get_conn(L, 1); 1.345 + PQfinish(conn->pgconn); 1.346 + conn->pgconn = NULL; 1.347 + return 0; 1.348 +} 1.349 + 1.350 +static int mondelefant_conn_is_ok(lua_State *L) { 1.351 + mondelefant_conn_t *conn; 1.352 + lua_settop(L, 1); 1.353 + conn = mondelefant_get_conn(L, 1); 1.354 + lua_pushboolean(L, PQstatus(conn->pgconn) == CONNECTION_OK); 1.355 + return 1; 1.356 +} 1.357 + 1.358 +static int mondelefant_conn_get_transaction_status(lua_State *L) { 1.359 + mondelefant_conn_t *conn; 1.360 + lua_settop(L, 1); 1.361 + conn = mondelefant_get_conn(L, 1); 1.362 + switch (PQtransactionStatus(conn->pgconn)) { 1.363 + case PQTRANS_IDLE: 1.364 + lua_pushliteral(L, "idle"); 1.365 + break; 1.366 + case PQTRANS_ACTIVE: 1.367 + lua_pushliteral(L, "active"); 1.368 + break; 1.369 + case PQTRANS_INTRANS: 1.370 + lua_pushliteral(L, "intrans"); 1.371 + break; 1.372 + case PQTRANS_INERROR: 1.373 + lua_pushliteral(L, "inerror"); 1.374 + break; 1.375 + default: 1.376 + lua_pushliteral(L, "unknown"); 1.377 + } 1.378 + return 1; 1.379 +} 1.380 + 1.381 +static int mondelefant_conn_create_list(lua_State *L) { 1.382 + lua_settop(L, 2); 1.383 + luaL_checkudata(L, 1, MONDELEFANT_CONN_MT_REGKEY); 1.384 + if (!lua_toboolean(L, 2)) { 1.385 + lua_newtable(L); 1.386 + lua_replace(L, 2); // new result at stack position 2 1.387 + } 1.388 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY); // 3 1.389 + lua_setmetatable(L, 2); 1.390 + lua_pushvalue(L, 1); // 3 1.391 + lua_setfield(L, 2, "_connection"); 1.392 + lua_pushliteral(L, "list"); // 3 1.393 + lua_setfield(L, 2, "_type"); 1.394 + return 1; 1.395 +} 1.396 + 1.397 +static int mondelefant_conn_create_object(lua_State *L) { 1.398 + lua_settop(L, 2); 1.399 + luaL_checkudata(L, 1, MONDELEFANT_CONN_MT_REGKEY); 1.400 + if (!lua_toboolean(L, 2)) { 1.401 + lua_newtable(L); 1.402 + lua_replace(L, 2); // new result at stack position 2 1.403 + } 1.404 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY); // 3 1.405 + lua_setmetatable(L, 2); 1.406 + lua_pushvalue(L, 1); // 3 1.407 + lua_setfield(L, 2, "_connection"); 1.408 + lua_pushliteral(L, "object"); // 3 1.409 + lua_setfield(L, 2, "_type"); // "object" or "list" 1.410 + lua_newtable(L); // 3 1.411 + lua_setfield(L, 2, "_data"); 1.412 + lua_newtable(L); // 3 1.413 + lua_setfield(L, 2, "_dirty"); 1.414 + lua_newtable(L); // 3 1.415 + lua_setfield(L, 2, "_ref"); // nil=no info, false=nil, else table 1.416 + return 1; 1.417 +} 1.418 + 1.419 +static int mondelefant_conn_quote_string(lua_State *L) { 1.420 + mondelefant_conn_t *conn; 1.421 + const char *input; 1.422 + size_t input_len; 1.423 + char *output; 1.424 + size_t output_len; 1.425 + lua_settop(L, 2); 1.426 + conn = mondelefant_get_conn(L, 1); 1.427 + input = luaL_checklstring(L, 2, &input_len); 1.428 + if (input_len > (SIZE_MAX / sizeof(char) - 3) / 2) { 1.429 + return luaL_error(L, "String to be escaped is too long."); 1.430 + } 1.431 + output = malloc((2 * input_len + 3) * sizeof(char)); 1.432 + if (!output) { 1.433 + return luaL_error(L, "Could not allocate memory for string quoting."); 1.434 + } 1.435 + output[0] = '\''; 1.436 + output_len = PQescapeStringConn( 1.437 + conn->pgconn, output + 1, input, input_len, NULL 1.438 + ); 1.439 + output[output_len + 1] = '\''; 1.440 + output[output_len + 2] = 0; 1.441 + lua_pushlstring(L, output, output_len + 2); 1.442 + free(output); 1.443 + return 1; 1.444 +} 1.445 + 1.446 +static int mondelefant_conn_quote_binary(lua_State *L) { 1.447 + mondelefant_conn_t *conn; 1.448 + const char *input; 1.449 + size_t input_len; 1.450 + char *output; 1.451 + size_t output_len; 1.452 + luaL_Buffer buf; 1.453 + lua_settop(L, 2); 1.454 + conn = mondelefant_get_conn(L, 1); 1.455 + input = luaL_checklstring(L, 2, &input_len); 1.456 + output = (char *)PQescapeByteaConn( 1.457 + conn->pgconn, (const unsigned char *)input, input_len, &output_len 1.458 + ); 1.459 + if (!output) { 1.460 + return luaL_error(L, "Could not allocate memory for binary quoting."); 1.461 + } 1.462 + luaL_buffinit(L, &buf); 1.463 + luaL_addchar(&buf, '\''); 1.464 + luaL_addlstring(&buf, output, output_len - 1); 1.465 + luaL_addchar(&buf, '\''); 1.466 + luaL_pushresult(&buf); 1.467 + PQfreemem(output); 1.468 + return 1; 1.469 +} 1.470 + 1.471 +static int mondelefant_conn_assemble_command(lua_State *L) { 1.472 + mondelefant_conn_t *conn; 1.473 + int paramidx = 2; 1.474 + const char *template; 1.475 + size_t template_pos = 0; 1.476 + luaL_Buffer buf; 1.477 + lua_settop(L, 2); 1.478 + conn = mondelefant_get_conn(L, 1); 1.479 + if (lua_isstring(L, 2)) { 1.480 + lua_tostring(L, 2); 1.481 + return 1; 1.482 + } 1.483 + // extra feature for objects with __tostring meta-method: 1.484 + if (luaL_callmeta(L, 2, "__tostring")) return 1; 1.485 + luaL_checktype(L, 2, LUA_TTABLE); 1.486 + lua_rawgeti(L, 2, 1); // 3 1.487 + luaL_argcheck(L, 1.488 + lua_isstring(L, 3), 1.489 + 2, 1.490 + "First entry of SQL command structure is not a string." 1.491 + ); 1.492 + template = lua_tostring(L, 3); 1.493 + lua_pushliteral(L, "input_converter"); // 4 1.494 + lua_gettable(L, 1); // input_converter at stack position 4 1.495 + lua_pushnil(L); // free space at stack position 5 1.496 + lua_pushnil(L); // free space at stack position 6 1.497 + luaL_buffinit(L, &buf); 1.498 + while (1) { 1.499 + char c; 1.500 + c = template[template_pos++]; 1.501 + if (!c) break; 1.502 + if (c == '?' || c == '$') { 1.503 + if (template[template_pos] == c) { 1.504 + template_pos++; 1.505 + luaL_addchar(&buf, c); 1.506 + } else { 1.507 + luaL_Buffer keybuf; 1.508 + int subcmd; 1.509 + subcmd = (c == '$'); 1.510 + luaL_buffinit(L, &keybuf); 1.511 + while (1) { 1.512 + c = template[template_pos]; 1.513 + if ( 1.514 + (c < 'A' || c > 'Z') && 1.515 + (c < 'a' || c > 'z') && 1.516 + (c < '0' || c > '9') && 1.517 + (c != '_') 1.518 + ) break; 1.519 + luaL_addchar(&keybuf, c); 1.520 + template_pos++; 1.521 + } 1.522 + luaL_pushresult(&keybuf); 1.523 + if (lua_objlen(L, -1)) { 1.524 + lua_pushvalue(L, -1); // save key on stack 1.525 + lua_gettable(L, 2); // fetch value 1.526 + } else { 1.527 + lua_pop(L, 1); 1.528 + lua_pushnil(L); // put nil on key position 1.529 + lua_rawgeti(L, 2, paramidx++); // fetch value 1.530 + } 1.531 + // stack: ..., <buffer>, key, pre-value 1.532 + if (subcmd) { 1.533 + size_t i; 1.534 + size_t count; 1.535 + lua_replace(L, 5); // sub-structure at stack position 5 1.536 + lua_pop(L, 1); // drop stored key 1.537 + // stack: ..., <buffer> 1.538 + luaL_argcheck(L, 1.539 + !lua_isnil(L, 5), 1.540 + 2, 1.541 + "SQL sub-structure not found." 1.542 + ); 1.543 + luaL_argcheck(L, 1.544 + lua_type(L, 5) == LUA_TTABLE, 1.545 + 2, 1.546 + "SQL sub-structure must be a table." 1.547 + ); 1.548 + // stack: ..., <buffer> 1.549 + lua_getfield(L, 5, "sep"); 1.550 + lua_replace(L, 6); // seperator at stack position 6 1.551 + if (lua_isnil(L, 6)) { 1.552 + lua_pushstring(L, ", "); 1.553 + lua_replace(L, 6); 1.554 + } else { 1.555 + luaL_argcheck(L, 1.556 + lua_isstring(L, 6), 1.557 + 2, 1.558 + "Seperator of SQL sub-structure has to be a string." 1.559 + ); 1.560 + } 1.561 + count = lua_objlen(L, 5); 1.562 + for (i = 0; i < count; i++) { 1.563 + if (i) { 1.564 + lua_pushvalue(L, 6); 1.565 + luaL_addvalue(&buf); 1.566 + } 1.567 + lua_pushcfunction(L, mondelefant_conn_assemble_command); 1.568 + lua_pushvalue(L, 1); 1.569 + lua_rawgeti(L, 5, i+1); 1.570 + lua_call(L, 2, 1); 1.571 + luaL_addvalue(&buf); 1.572 + } 1.573 + } else { 1.574 + if (lua_toboolean(L, 4)) { 1.575 + // call input_converter with connection handle, value and info 1.576 + lua_pushvalue(L, 4); 1.577 + lua_pushvalue(L, 1); 1.578 + lua_pushvalue(L, -3); 1.579 + lua_newtable(L); 1.580 + lua_pushvalue(L, -6); 1.581 + lua_setfield(L, -2, "field_name"); 1.582 + lua_call(L, 3, 1); 1.583 + // stack: ..., <buffer>, key, pre-value, final-value 1.584 + lua_remove(L, -2); 1.585 + lua_remove(L, -2); 1.586 + // stack: ..., <buffer>, final-value 1.587 + if (!lua_isstring(L, -1)) { 1.588 + return luaL_error(L, "input_converter returned non-string."); 1.589 + } 1.590 + } else { 1.591 + lua_remove(L, -2); 1.592 + // stack: ..., <buffer>, pre-value 1.593 + if (lua_isnil(L, -1)) { 1.594 + lua_pushliteral(L, "NULL"); 1.595 + } else if (lua_type(L, -1) == LUA_TBOOLEAN) { 1.596 + lua_pushstring(L, lua_toboolean(L, -1) ? "TRUE" : "FALSE"); 1.597 + } else if (lua_isstring(L, -1)) { 1.598 + // NOTE: In this version of lua a number will be converted 1.599 + lua_tostring(L, -1); 1.600 + lua_pushcfunction(L, mondelefant_conn_quote_string); 1.601 + lua_pushvalue(L, 1); 1.602 + lua_pushvalue(L, -3); 1.603 + lua_call(L, 2, 1); 1.604 + } else { 1.605 + return luaL_error(L, 1.606 + "Unable to convert SQL value due to unknown type " 1.607 + "or missing input_converter." 1.608 + ); 1.609 + } 1.610 + // stack: ..., <buffer>, pre-value, final-value 1.611 + lua_remove(L, -2); 1.612 + // stack: ..., <buffer>, final-value 1.613 + } 1.614 + luaL_addvalue(&buf); 1.615 + } 1.616 + } 1.617 + } else { 1.618 + luaL_addchar(&buf, c); 1.619 + } 1.620 + } 1.621 + luaL_pushresult(&buf); 1.622 + return 1; 1.623 +} 1.624 + 1.625 +#define MONDELEFANT_MAX_COMMAND_COUNT 64 1.626 +#define MONDELEFANT_MAX_COLUMN_COUNT 1024 1.627 +#define MONDELEFANT_QUERY_MODE_LIST 1 1.628 +#define MONDELEFANT_QUERY_MODE_OBJECT 2 1.629 +#define MONDELEFANT_QUERY_MODE_OPT_OBJECT 3 1.630 + 1.631 +static int mondelefant_conn_try_query(lua_State *L) { 1.632 + mondelefant_conn_t *conn; 1.633 + int command_count; 1.634 + int command_idx; 1.635 + int modes[MONDELEFANT_MAX_COMMAND_COUNT]; 1.636 + luaL_Buffer buf; 1.637 + int sent_success; 1.638 + PGresult *res; 1.639 + int rows, cols, row, col; 1.640 + conn = mondelefant_get_conn(L, 1); 1.641 + command_count = lua_gettop(L) / 2; 1.642 + lua_pushnil(L); // needed, if last mode was omitted 1.643 + if (command_count > MONDELEFANT_MAX_COMMAND_COUNT) { 1.644 + return luaL_error(L, "Exceeded maximum command count in one query."); 1.645 + } 1.646 + luaL_buffinit(L, &buf); 1.647 + for (command_idx = 0; command_idx < command_count; command_idx++) { 1.648 + int mode; 1.649 + int mode_idx; // stack index of mode string 1.650 + if (command_idx) luaL_addchar(&buf, ' '); 1.651 + lua_pushcfunction(L, mondelefant_conn_assemble_command); 1.652 + lua_pushvalue(L, 1); 1.653 + lua_pushvalue(L, 2 + 2 * command_idx); 1.654 + lua_call(L, 2, 1); 1.655 + luaL_addvalue(&buf); 1.656 + luaL_addchar(&buf, ';'); 1.657 + mode_idx = 3 + 2 * command_idx; 1.658 + if (lua_isnil(L, mode_idx)) { 1.659 + mode = MONDELEFANT_QUERY_MODE_LIST; 1.660 + } else { 1.661 + const char *modestr; 1.662 + modestr = luaL_checkstring(L, mode_idx); 1.663 + if (!strcmp(modestr, "list")) { 1.664 + mode = MONDELEFANT_QUERY_MODE_LIST; 1.665 + } else if (!strcmp(modestr, "object")) { 1.666 + mode = MONDELEFANT_QUERY_MODE_OBJECT; 1.667 + } else if (!strcmp(modestr, "opt_object")) { 1.668 + mode = MONDELEFANT_QUERY_MODE_OPT_OBJECT; 1.669 + } else { 1.670 + return luaL_error(L, "Unknown query mode specified."); 1.671 + } 1.672 + } 1.673 + modes[command_idx] = mode; 1.674 + } 1.675 + luaL_pushresult(&buf); // stack position unknown 1.676 + lua_replace(L, 2); // SQL command string to stack position 2 1.677 + lua_settop(L, 2); 1.678 + lua_getfield(L, 1, "sql_tracer"); // tracer at stack position 3 1.679 + if (lua_toboolean(L, 3)) { 1.680 + lua_pushvalue(L, 1); // 4 1.681 + lua_pushvalue(L, 2); // 5 1.682 + lua_call(L, 2, 1); // trace callback at stack position 3 1.683 + } 1.684 + sent_success = PQsendQuery(conn->pgconn, lua_tostring(L, 2)); 1.685 + lua_newtable(L); // results in table at stack position 4 1.686 + for (command_idx = 0; ; command_idx++) { 1.687 + int mode; 1.688 + char binary[MONDELEFANT_MAX_COLUMN_COUNT]; 1.689 + ExecStatusType pgstatus; 1.690 + mode = modes[command_idx]; 1.691 + if (sent_success) { 1.692 + res = PQgetResult(conn->pgconn); 1.693 + if (command_idx >= command_count && !res) break; 1.694 + if (res) { 1.695 + pgstatus = PQresultStatus(res); 1.696 + rows = PQntuples(res); 1.697 + cols = PQnfields(res); 1.698 + } 1.699 + } 1.700 + if ( 1.701 + !sent_success || command_idx >= command_count || !res || 1.702 + (pgstatus != PGRES_TUPLES_OK && pgstatus != PGRES_COMMAND_OK) || 1.703 + (rows < 1 && mode == MONDELEFANT_QUERY_MODE_OBJECT) || 1.704 + (rows > 1 && mode != MONDELEFANT_QUERY_MODE_LIST) 1.705 + ) { 1.706 + const char *command; 1.707 + command = lua_tostring(L, 2); 1.708 + lua_newtable(L); // 5 1.709 + lua_getfield(L, 1.710 + LUA_REGISTRYINDEX, 1.711 + MONDELEFANT_ERROROBJECT_MT_REGKEY 1.712 + ); 1.713 + lua_setmetatable(L, 5); 1.714 + lua_pushvalue(L, 1); 1.715 + lua_setfield(L, 5, "connection"); 1.716 + lua_pushinteger(L, command_idx + 1); 1.717 + lua_setfield(L, 5, "command_number"); 1.718 + lua_pushvalue(L, 2); 1.719 + lua_setfield(L, 5, "sql_command"); 1.720 + if (!res) { 1.721 + lua_pushliteral(L, MONDELEFANT_ERRCODE_RESULTCOUNT_LOW); 1.722 + lua_setfield(L, 5, "code"); 1.723 + lua_pushliteral(L, "Received too few database result sets."); 1.724 + lua_setfield(L, 5, "message"); 1.725 + } else if (command_idx >= command_count) { 1.726 + lua_pushliteral(L, MONDELEFANT_ERRCODE_RESULTCOUNT_HIGH); 1.727 + lua_setfield(L, 5, "code"); 1.728 + lua_pushliteral(L, "Received too many database result sets."); 1.729 + lua_setfield(L, 5, "message"); 1.730 + } else if ( 1.731 + pgstatus != PGRES_TUPLES_OK && pgstatus != PGRES_COMMAND_OK 1.732 + ) { 1.733 + const char *sqlstate; 1.734 + const char *errmsg; 1.735 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SEVERITY)); 1.736 + lua_setfield(L, 5, "pg_severity"); 1.737 + sqlstate = PQresultErrorField(res, PG_DIAG_SQLSTATE); 1.738 + if (sqlstate) { 1.739 + lua_pushstring(L, sqlstate); 1.740 + lua_setfield(L, 5, "pg_sqlstate"); 1.741 + lua_pushstring(L, mondelefant_translate_errcode(sqlstate)); 1.742 + lua_setfield(L, 5, "code"); 1.743 + } else { 1.744 + lua_pushliteral(L, MONDELEFANT_ERRCODE_UNKNOWN); 1.745 + lua_setfield(L, 5, "code"); 1.746 + } 1.747 + errmsg = PQresultErrorField(res, PG_DIAG_MESSAGE_PRIMARY); 1.748 + if (errmsg) { 1.749 + mondelefant_push_first_line(L, errmsg); 1.750 + lua_setfield(L, 5, "message"); 1.751 + lua_pushstring(L, errmsg); 1.752 + lua_setfield(L, 5, "pg_message_primary"); 1.753 + } else { 1.754 + lua_pushliteral(L, 1.755 + "Error while fetching result, but no error message given." 1.756 + ); 1.757 + lua_setfield(L, 5, "message"); 1.758 + } 1.759 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_MESSAGE_DETAIL)); 1.760 + lua_setfield(L, 5, "pg_message_detail"); 1.761 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_MESSAGE_HINT)); 1.762 + lua_setfield(L, 5, "pg_message_hint"); 1.763 + // NOTE: "position" and "pg_internal_position" are recalculated to 1.764 + // byte offsets, as Lua 5.1 is not Unicode aware. 1.765 + { 1.766 + char *tmp; 1.767 + tmp = PQresultErrorField(res, PG_DIAG_STATEMENT_POSITION); 1.768 + if (tmp) { 1.769 + int pos; 1.770 + pos = atoi(tmp) - 1; 1.771 + if (conn->server_encoding == MONDELEFANT_SERVER_ENCODING_UTF8) { 1.772 + pos = utf8_position_to_byte(command, pos); 1.773 + } 1.774 + lua_pushinteger(L, pos + 1); 1.775 + lua_setfield(L, 5, "position"); 1.776 + } 1.777 + } 1.778 + { 1.779 + const char *internal_query; 1.780 + internal_query = PQresultErrorField(res, PG_DIAG_INTERNAL_QUERY); 1.781 + lua_pushstring(L, internal_query); 1.782 + lua_setfield(L, 5, "pg_internal_query"); 1.783 + char *tmp; 1.784 + tmp = PQresultErrorField(res, PG_DIAG_INTERNAL_POSITION); 1.785 + if (tmp) { 1.786 + int pos; 1.787 + pos = atoi(tmp) - 1; 1.788 + if (conn->server_encoding == MONDELEFANT_SERVER_ENCODING_UTF8) { 1.789 + pos = utf8_position_to_byte(internal_query, pos); 1.790 + } 1.791 + lua_pushinteger(L, pos + 1); 1.792 + lua_setfield(L, 5, "pg_internal_position"); 1.793 + } 1.794 + } 1.795 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_CONTEXT)); 1.796 + lua_setfield(L, 5, "pg_context"); 1.797 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_FILE)); 1.798 + lua_setfield(L, 5, "pg_source_file"); 1.799 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_LINE)); 1.800 + lua_setfield(L, 5, "pg_source_line"); 1.801 + lua_pushstring(L, PQresultErrorField(res, PG_DIAG_SOURCE_FUNCTION)); 1.802 + lua_setfield(L, 5, "pg_source_function"); 1.803 + } else if (rows < 1 && mode == MONDELEFANT_QUERY_MODE_OBJECT) { 1.804 + lua_pushliteral(L, MONDELEFANT_ERRCODE_QUERY1_NO_ROWS); 1.805 + lua_setfield(L, 5, "code"); 1.806 + lua_pushliteral(L, "Expected one row, but got empty set."); 1.807 + lua_setfield(L, 5, "message"); 1.808 + } else if (rows > 1 && mode != MONDELEFANT_QUERY_MODE_LIST) { 1.809 + lua_pushliteral(L, MONDELEFANT_ERRCODE_QUERY1_MULTIPLE_ROWS); 1.810 + lua_setfield(L, 5, "code"); 1.811 + lua_pushliteral(L, "Got more than one result row."); 1.812 + lua_setfield(L, 5, "message"); 1.813 + } else { 1.814 + // should not happen 1.815 + abort(); 1.816 + } 1.817 + if (res) { 1.818 + PQclear(res); 1.819 + while ((res = PQgetResult(conn->pgconn))) PQclear(res); 1.820 + } 1.821 + if (lua_toboolean(L, 3)) { 1.822 + lua_pushvalue(L, 3); 1.823 + lua_pushvalue(L, 5); 1.824 + lua_call(L, 1, 0); 1.825 + } 1.826 + return 1; 1.827 + } 1.828 + rows = PQntuples(res); 1.829 + cols = PQnfields(res); 1.830 + if (modes[command_idx] == MONDELEFANT_QUERY_MODE_LIST) { 1.831 + lua_pushcfunction(L, mondelefant_conn_create_list); // 5 1.832 + lua_pushvalue(L, 1); // 6 1.833 + lua_call(L, 1, 1); // 5 1.834 + } else { 1.835 + lua_pushcfunction(L, mondelefant_conn_create_object); // 5 1.836 + lua_pushvalue(L, 1); // 6 1.837 + lua_call(L, 1, 1); // 5 1.838 + } 1.839 + lua_newtable(L); // column_info at atack position 6 1.840 + for (col = 0; col < cols; col++) { 1.841 + lua_newtable(L); // 7 1.842 + lua_pushstring(L, PQfname(res, col)); 1.843 + lua_setfield(L, 7, "field_name"); 1.844 + { 1.845 + Oid tmp; 1.846 + tmp = PQftable(res, col); 1.847 + if (tmp == InvalidOid) lua_pushnil(L); 1.848 + else lua_pushinteger(L, tmp); 1.849 + lua_setfield(L, 7, "table_oid"); 1.850 + } 1.851 + { 1.852 + int tmp; 1.853 + tmp = PQftablecol(res, col); 1.854 + if (tmp == 0) lua_pushnil(L); 1.855 + else lua_pushinteger(L, tmp); 1.856 + lua_setfield(L, 7, "table_column_number"); 1.857 + } 1.858 + { 1.859 + Oid tmp; 1.860 + tmp = PQftype(res, col); 1.861 + binary[col] = (tmp == MONDELEFANT_POSTGRESQL_BINARY_OID); 1.862 + lua_pushinteger(L, tmp); 1.863 + lua_setfield(L, 7, "type_oid"); 1.864 + lua_pushstring(L, mondelefant_oid_to_typestr(tmp)); 1.865 + lua_setfield(L, 7, "type"); 1.866 + } 1.867 + { 1.868 + int tmp; 1.869 + tmp = PQfmod(res, col); 1.870 + if (tmp == -1) lua_pushnil(L); 1.871 + else lua_pushinteger(L, tmp); 1.872 + lua_setfield(L, 7, "type_modifier"); 1.873 + } 1.874 + lua_rawseti(L, 6, col+1); 1.875 + } 1.876 + lua_setfield(L, 5, "_column_info"); // stack at position 5 with result 1.877 + { 1.878 + char *tmp; 1.879 + tmp = PQcmdTuples(res); 1.880 + if (tmp[0]) { 1.881 + lua_pushinteger(L, atoi(tmp)); 1.882 + lua_setfield(L, 5, "_rows_affected"); 1.883 + } 1.884 + } 1.885 + { 1.886 + Oid tmp; 1.887 + tmp = PQoidValue(res); 1.888 + if (tmp != InvalidOid) { 1.889 + lua_pushinteger(L, tmp); 1.890 + lua_setfield(L, 5, "_oid"); 1.891 + } 1.892 + } 1.893 + if (modes[command_idx] == MONDELEFANT_QUERY_MODE_LIST) { 1.894 + for (row = 0; row < rows; row++) { 1.895 + lua_pushcfunction(L, mondelefant_conn_create_object); // 6 1.896 + lua_pushvalue(L, 1); // 7 1.897 + lua_call(L, 1, 1); // 6 1.898 + for (col = 0; col < cols; col++) { 1.899 + if (PQgetisnull(res, row, col)) { 1.900 + lua_pushnil(L); 1.901 + } else if (binary[col]) { 1.902 + size_t binlen; 1.903 + char *binval; 1.904 + binval = (char *)PQunescapeBytea( 1.905 + (unsigned char *)PQgetvalue(res, row, col), &binlen 1.906 + ); 1.907 + if (!binval) { 1.908 + return luaL_error(L, 1.909 + "Could not allocate memory for binary unescaping." 1.910 + ); 1.911 + } 1.912 + lua_pushlstring(L, binval, binlen); 1.913 + PQfreemem(binval); 1.914 + } else { 1.915 + lua_pushstring(L, PQgetvalue(res, row, col)); 1.916 + } 1.917 + lua_rawseti(L, 6, col+1); 1.918 + } 1.919 + lua_rawseti(L, 5, row+1); 1.920 + } 1.921 + } else if (rows == 1) { 1.922 + for (col = 0; col < cols; col++) { 1.923 + if (PQgetisnull(res, 0, col)) { 1.924 + lua_pushnil(L); 1.925 + } else if (binary[col]) { 1.926 + size_t binlen; 1.927 + char *binval; 1.928 + binval = (char *)PQunescapeBytea( 1.929 + (unsigned char *)PQgetvalue(res, 0, col), &binlen 1.930 + ); 1.931 + if (!binval) { 1.932 + return luaL_error(L, 1.933 + "Could not allocate memory for binary unescaping." 1.934 + ); 1.935 + } 1.936 + lua_pushlstring(L, binval, binlen); 1.937 + PQfreemem(binval); 1.938 + } else { 1.939 + lua_pushstring(L, PQgetvalue(res, 0, col)); 1.940 + } 1.941 + lua_rawseti(L, 5, col+1); 1.942 + } 1.943 + } else { 1.944 + // no row in optrow mode 1.945 + lua_pop(L, 1); 1.946 + lua_pushnil(L); 1.947 + } 1.948 + lua_rawseti(L, 4, command_idx+1); 1.949 + if (lua_gettop(L) != 4) abort(); // should not happen 1.950 + PQclear(res); 1.951 + } 1.952 + // trace callback at stack position 3 1.953 + // result at stack position 4 (top of stack) 1.954 + if (lua_toboolean(L, 3)) { 1.955 + lua_pushvalue(L, 3); 1.956 + lua_call(L, 0, 0); 1.957 + } 1.958 + lua_replace(L, 3); // result at stack position 3 1.959 + lua_getfield(L, 1, "output_converter"); // output converter at stack position 4 1.960 + for (command_idx = 0; command_idx < command_count; command_idx++) { 1.961 + int mode; 1.962 + mode = modes[command_idx]; 1.963 + lua_rawgeti(L, 3, command_idx+1); // raw result at stack position 5 1.964 + if (lua_toboolean(L, 5)) { 1.965 + lua_getfield(L, 5, "_column_info"); // column_info list at position 6 1.966 + cols = lua_objlen(L, 6); 1.967 + if (mode == MONDELEFANT_QUERY_MODE_LIST) { 1.968 + rows = lua_objlen(L, 5); 1.969 + for (row = 0; row < rows; row++) { 1.970 + lua_rawgeti(L, 5, row+1); // row at stack position 7 1.971 + lua_getfield(L, 7, "_data"); // _data table at stack position 8 1.972 + for (col = 0; col < cols; col++) { 1.973 + lua_rawgeti(L, 6, col+1); // this column info at position 9 1.974 + lua_getfield(L, 9, "field_name"); // 10 1.975 + if (lua_toboolean(L, 4)) { 1.976 + lua_pushvalue(L, 4); // output-converter 1.977 + lua_pushvalue(L, 1); // connection 1.978 + lua_rawgeti(L, 7, col+1); // raw-value 1.979 + lua_pushvalue(L, 9); // this column info 1.980 + lua_call(L, 3, 1); // converted value at position 11 1.981 + } else { 1.982 + lua_rawgeti(L, 7, col+1); // raw-value at position 11 1.983 + } 1.984 + lua_pushvalue(L, 11); // 12 1.985 + lua_rawseti(L, 7, col+1); 1.986 + lua_rawset(L, 8); 1.987 + lua_settop(L, 8); 1.988 + } 1.989 + lua_settop(L, 6); 1.990 + } 1.991 + } else { 1.992 + lua_getfield(L, 5, "_data"); // _data table at stack position 7 1.993 + for (col = 0; col < cols; col++) { 1.994 + lua_rawgeti(L, 6, col+1); // this column info at position 8 1.995 + lua_getfield(L, 8, "field_name"); // 9 1.996 + if (lua_toboolean(L, 4)) { 1.997 + lua_pushvalue(L, 4); // output-converter 1.998 + lua_pushvalue(L, 1); // connection 1.999 + lua_rawgeti(L, 5, col+1); // raw-value 1.1000 + lua_pushvalue(L, 8); // this column info 1.1001 + lua_call(L, 3, 1); // converted value at position 10 1.1002 + } else { 1.1003 + lua_rawgeti(L, 5, col+1); // raw-value at position 10 1.1004 + } 1.1005 + lua_pushvalue(L, 10); // 11 1.1006 + lua_rawseti(L, 5, col+1); 1.1007 + lua_rawset(L, 7); 1.1008 + lua_settop(L, 7); 1.1009 + } 1.1010 + } 1.1011 + } 1.1012 + lua_settop(L, 4); 1.1013 + } 1.1014 + lua_settop(L, 3); 1.1015 + lua_pushnil(L); 1.1016 + for (command_idx = 0; command_idx < command_count; command_idx++) { 1.1017 + lua_rawgeti(L, 3, command_idx+1); 1.1018 + } 1.1019 + return command_count+1; 1.1020 +} 1.1021 + 1.1022 +static int mondelefant_errorobject_escalate(lua_State *L) { 1.1023 + lua_settop(L, 1); 1.1024 + lua_getfield(L, 1, "connection"); // 2 1.1025 + lua_getfield(L, 2, "error_objects"); // 3 1.1026 + if (lua_toboolean(L, 3)) { 1.1027 + lua_settop(L, 1); 1.1028 + return lua_error(L); 1.1029 + } else { 1.1030 + lua_getfield(L, 1, "message"); // 4 1.1031 + if (lua_isnil(L, 4)) { 1.1032 + return luaL_error(L, "No error message given for escalation."); 1.1033 + } 1.1034 + return lua_error(L); 1.1035 + } 1.1036 +} 1.1037 + 1.1038 +static int mondelefant_errorobject_is_kind_of(lua_State *L) { 1.1039 + lua_settop(L, 2); 1.1040 + lua_getfield(L, 1, "code"); // 3 1.1041 + if (lua_isstring(L, 3)) { 1.1042 + lua_pushboolean(L, 1.1043 + mondelefant_check_error_class( 1.1044 + lua_tostring(L, 3), luaL_checkstring(L, 2) 1.1045 + ) 1.1046 + ); 1.1047 + } else { 1.1048 + // only happens for errors where code is not set 1.1049 + lua_pushboolean(L, 0); 1.1050 + } 1.1051 + return 1; 1.1052 +} 1.1053 + 1.1054 +static int mondelefant_conn_query(lua_State *L) { 1.1055 + int argc; 1.1056 + argc = lua_gettop(L); 1.1057 + lua_pushvalue(L, 1); 1.1058 + lua_insert(L, 1); 1.1059 + lua_pushcfunction(L, mondelefant_conn_try_query); 1.1060 + lua_insert(L, 2); 1.1061 + lua_call(L, argc, LUA_MULTRET); // results (with error) starting at index 2 1.1062 + if (lua_toboolean(L, 2)) { 1.1063 + lua_pushcfunction(L, mondelefant_errorobject_escalate); 1.1064 + lua_pushvalue(L, 2); 1.1065 + lua_call(L, 1, 0); // will raise an error 1.1066 + return 0; // should not be executed 1.1067 + } else { 1.1068 + return lua_gettop(L) - 2; 1.1069 + } 1.1070 +} 1.1071 + 1.1072 +static int mondelefant_set_class(lua_State *L) { 1.1073 + lua_settop(L, 2); 1.1074 + lua_getmetatable(L, 1); // 3 1.1075 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_RESULT_MT_REGKEY); // 4 1.1076 + luaL_argcheck(L, lua_equal(L, 3, 4), 1, "not a database result"); 1.1077 + lua_settop(L, 2); 1.1078 + lua_getmetatable(L, 2); // 3 1.1079 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CLASS_MT_REGKEY); // 4 1.1080 + luaL_argcheck(L, lua_equal(L, 3, 4), 2, "not a database class"); 1.1081 + lua_settop(L, 2); 1.1082 + lua_pushvalue(L, 2); // 3 1.1083 + lua_setfield(L, 1, "_class"); 1.1084 + lua_getfield(L, 1, "_type"); // 3 1.1085 + lua_pushliteral(L, "list"); // 4 1.1086 + if (lua_rawequal(L, 3, 4)) { 1.1087 + int i; 1.1088 + for (i=0; i < lua_objlen(L, 1); i++) { 1.1089 + lua_settop(L, 2); 1.1090 + lua_rawgeti(L, 1, i+1); // 3 1.1091 + lua_pushvalue(L, 2); // 4 1.1092 + lua_setfield(L, 3, "_class"); 1.1093 + } 1.1094 + } 1.1095 + lua_settop(L, 1); 1.1096 + return 1; 1.1097 +} 1.1098 + 1.1099 +static int mondelefant_new_class(lua_State *L) { 1.1100 + lua_settop(L, 1); 1.1101 + if (!lua_toboolean(L, 1)) { 1.1102 + lua_settop(L, 0); 1.1103 + lua_newtable(L); // 1 1.1104 + } 1.1105 + lua_getfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CLASS_MT_REGKEY); // 2 1.1106 + lua_setmetatable(L, 1); 1.1107 + lua_pushliteral(L, "prototype"); // 2 1.1108 + lua_rawget(L, 1); // 2 1.1109 + if (!lua_toboolean(L, 2)) { 1.1110 + lua_pushliteral(L, "prototype"); // 3 1.1111 + lua_getfield(L, 1.1112 + LUA_REGISTRYINDEX, 1.1113 + MONDELEFANT_CLASS_PROTO_REGKEY 1.1114 + ); // 4 1.1115 + lua_rawset(L, 1); 1.1116 + } 1.1117 + lua_settop(L, 1); 1.1118 + lua_pushliteral(L, "object"); // 2 1.1119 + lua_rawget(L, 1); // 2 1.1120 + if (!lua_toboolean(L, 2)) { 1.1121 + lua_pushliteral(L, "object"); // 3 1.1122 + lua_newtable(L); // 4 1.1123 + lua_rawset(L, 1); 1.1124 + } 1.1125 + lua_settop(L, 1); 1.1126 + lua_pushliteral(L, "object_get"); // 2 1.1127 + lua_rawget(L, 1); // 2 1.1128 + if (!lua_toboolean(L, 2)) { 1.1129 + lua_pushliteral(L, "object_get"); // 3 1.1130 + lua_newtable(L); // 4 1.1131 + lua_rawset(L, 1); 1.1132 + } 1.1133 + lua_settop(L, 1); 1.1134 + lua_pushliteral(L, "object_set"); // 2 1.1135 + lua_rawget(L, 1); // 2 1.1136 + if (!lua_toboolean(L, 2)) { 1.1137 + lua_pushliteral(L, "object_set"); // 3 1.1138 + lua_newtable(L); // 4 1.1139 + lua_rawset(L, 1); 1.1140 + } 1.1141 + lua_settop(L, 1); 1.1142 + lua_pushliteral(L, "list"); // 2 1.1143 + lua_rawget(L, 1); // 2 1.1144 + if (!lua_toboolean(L, 2)) { 1.1145 + lua_pushliteral(L, "list"); // 3 1.1146 + lua_newtable(L); // 4 1.1147 + lua_rawset(L, 1); 1.1148 + } 1.1149 + lua_settop(L, 1); 1.1150 + lua_pushliteral(L, "references"); // 2 1.1151 + lua_rawget(L, 1); // 2 1.1152 + if (!lua_toboolean(L, 2)) { 1.1153 + lua_pushliteral(L, "references"); // 3 1.1154 + lua_newtable(L); // 4 1.1155 + lua_rawset(L, 1); 1.1156 + } 1.1157 + lua_settop(L, 1); 1.1158 + lua_pushliteral(L, "foreign_keys"); // 2 1.1159 + lua_rawget(L, 1); // 2 1.1160 + if (!lua_toboolean(L, 2)) { 1.1161 + lua_pushliteral(L, "foreign_keys"); // 3 1.1162 + lua_newtable(L); // 4 1.1163 + lua_rawset(L, 1); 1.1164 + } 1.1165 + lua_settop(L, 1); 1.1166 + return 1; 1.1167 +} 1.1168 + 1.1169 +static int mondelefant_class_get_reference(lua_State *L) { 1.1170 + lua_settop(L, 2); 1.1171 + while (lua_toboolean(L, 1)) { 1.1172 + lua_getfield(L, 1, "references"); // 3 1.1173 + lua_pushvalue(L, 2); // 4 1.1174 + lua_gettable(L, 3); // 4 1.1175 + if (!lua_isnil(L, 4)) return 1; 1.1176 + lua_settop(L, 2); 1.1177 + lua_pushliteral(L, "prototype"); // 3 1.1178 + lua_rawget(L, 1); // 3 1.1179 + lua_replace(L, 1); 1.1180 + } 1.1181 + return 0; 1.1182 +} 1.1183 + 1.1184 +static int mondelefant_class_iterate_over_references(lua_State *L) { 1.1185 + return luaL_error(L, "Reference iterator not implemented yet."); // TODO 1.1186 +} 1.1187 + 1.1188 +static int mondelefant_class_get_foreign_key_reference_name(lua_State *L) { 1.1189 + lua_settop(L, 2); 1.1190 + while (lua_toboolean(L, 1)) { 1.1191 + lua_getfield(L, 1, "foreign_keys"); // 3 1.1192 + lua_pushvalue(L, 2); // 4 1.1193 + lua_gettable(L, 3); // 4 1.1194 + if (!lua_isnil(L, 4)) return 1; 1.1195 + lua_settop(L, 2); 1.1196 + lua_pushliteral(L, "prototype"); // 3 1.1197 + lua_rawget(L, 1); // 3 1.1198 + lua_replace(L, 1); 1.1199 + } 1.1200 + return 0; 1.1201 +} 1.1202 + 1.1203 +static int mondelefant_result_index(lua_State *L) { 1.1204 + const char *result_type; 1.1205 + lua_settop(L, 2); 1.1206 + if (lua_type(L, 2) != LUA_TSTRING || lua_tostring(L, 2)[0] == '_') { 1.1207 + lua_rawget(L, 1); 1.1208 + return 1; 1.1209 + } 1.1210 + lua_getfield(L, 1, "_class"); // 3 1.1211 + if (!lua_toboolean(L, 3)) { 1.1212 + lua_settop(L, 2); 1.1213 + lua_getfield(L, 1.1214 + LUA_REGISTRYINDEX, 1.1215 + MONDELEFANT_CLASS_PROTO_REGKEY 1.1216 + ); // 3 1.1217 + } 1.1218 + lua_getfield(L, 1, "_type"); // 4 1.1219 + result_type = lua_tostring(L, 4); 1.1220 + if (result_type && !strcmp(result_type, "object")) { 1.1221 + lua_settop(L, 3); 1.1222 + // try inherited attributes, methods or getter functions: 1.1223 + while (lua_toboolean(L, 3)) { 1.1224 + lua_getfield(L, 3, "object"); // 4 1.1225 + lua_pushvalue(L, 2); // 5 1.1226 + lua_gettable(L, 4); // 5 1.1227 + if (!lua_isnil(L, 5)) return 1; 1.1228 + lua_settop(L, 3); 1.1229 + lua_getfield(L, 3, "object_get"); // 4 1.1230 + lua_pushvalue(L, 2); // 5 1.1231 + lua_gettable(L, 4); // 5 1.1232 + if (lua_toboolean(L, 5)) { 1.1233 + lua_pushvalue(L, 1); // 6 1.1234 + lua_call(L, 1, 1); // 5 1.1235 + return 1; 1.1236 + } 1.1237 + lua_settop(L, 3); 1.1238 + lua_pushliteral(L, "prototype"); // 4 1.1239 + lua_rawget(L, 3); // 4 1.1240 + lua_replace(L, 3); 1.1241 + } 1.1242 + lua_settop(L, 2); 1.1243 + // try primary keys of referenced objects: 1.1244 + lua_pushcfunction(L, 1.1245 + mondelefant_class_get_foreign_key_reference_name 1.1246 + ); // 3 1.1247 + lua_getfield(L, 1, "_class"); // 4 1.1248 + lua_pushvalue(L, 2); // 5 1.1249 + lua_call(L, 2, 1); // 3 1.1250 + if (!lua_isnil(L, 3)) { 1.1251 + // reference name at stack position 3 1.1252 + lua_pushcfunction(L, mondelefant_class_get_reference); // 4 1.1253 + lua_getfield(L, 1, "_class"); // 5 1.1254 + lua_pushvalue(L, 3); // 6 1.1255 + lua_call(L, 2, 1); // reference info at stack position 4 1.1256 + lua_getfield(L, 1, "_ref"); // 5 1.1257 + lua_getfield(L, 4, "ref"); // 6 1.1258 + lua_gettable(L, 5); // 6 1.1259 + if (!lua_isnil(L, 6)) { 1.1260 + if (lua_toboolean(L, 6)) { 1.1261 + lua_getfield(L, 4, "that_key"); // 7 1.1262 + if (lua_isnil(L, 7)) { 1.1263 + return luaL_error(L, "Missing 'that_key' entry in model reference."); 1.1264 + } 1.1265 + lua_gettable(L, 6); // 7 1.1266 + } else { 1.1267 + lua_pushnil(L); 1.1268 + } 1.1269 + return 1; 1.1270 + } 1.1271 + } 1.1272 + lua_settop(L, 2); 1.1273 + // try normal data field info: 1.1274 + lua_getfield(L, 1, "_data"); // 3 1.1275 + lua_pushvalue(L, 2); // 4 1.1276 + lua_gettable(L, 3); // 4 1.1277 + if (!lua_isnil(L, 4)) return 1; 1.1278 + lua_settop(L, 2); 1.1279 + // try cached referenced object (or cached NULL reference): 1.1280 + lua_getfield(L, 1, "_ref"); // 3 1.1281 + lua_pushvalue(L, 2); // 4 1.1282 + lua_gettable(L, 3); // 4 1.1283 + if (lua_isboolean(L, 4) && !lua_toboolean(L, 4)) { 1.1284 + lua_pushnil(L); 1.1285 + return 1; 1.1286 + } else if (!lua_isnil(L, 4)) { 1.1287 + return 1; 1.1288 + } 1.1289 + lua_settop(L, 2); 1.1290 + // try to load a referenced object: 1.1291 + lua_pushcfunction(L, mondelefant_class_get_reference); // 3 1.1292 + lua_getfield(L, 1, "_class"); // 4 1.1293 + lua_pushvalue(L, 2); // 5 1.1294 + lua_call(L, 2, 1); // 3 1.1295 + if (!lua_isnil(L, 3)) { 1.1296 + lua_settop(L, 2); 1.1297 + lua_getfield(L, 1, "load"); // 3 1.1298 + lua_pushvalue(L, 1); // 4 (self) 1.1299 + lua_pushvalue(L, 2); // 5 1.1300 + lua_call(L, 2, 0); 1.1301 + lua_settop(L, 2); 1.1302 + lua_getfield(L, 1, "_ref"); // 3 1.1303 + lua_pushvalue(L, 2); // 4 1.1304 + lua_gettable(L, 3); // 4 1.1305 + if (lua_isboolean(L, 4) && !lua_toboolean(L, 4)) lua_pushnil(L); // TODO: use special object instead of false 1.1306 + return 1; 1.1307 + } 1.1308 + return 0; 1.1309 + } else if (result_type && !strcmp(result_type, "list")) { 1.1310 + lua_settop(L, 3); 1.1311 + // try inherited list attributes or methods: 1.1312 + while (lua_toboolean(L, 3)) { 1.1313 + lua_getfield(L, 3, "list"); // 4 1.1314 + lua_pushvalue(L, 2); // 5 1.1315 + lua_gettable(L, 4); // 5 1.1316 + if (!lua_isnil(L, 5)) return 1; 1.1317 + lua_settop(L, 3); 1.1318 + lua_pushliteral(L, "prototype"); // 4 1.1319 + lua_rawget(L, 3); // 4 1.1320 + lua_replace(L, 3); 1.1321 + } 1.1322 + } 1.1323 + return 0; 1.1324 +} 1.1325 + 1.1326 +static int mondelefant_result_newindex(lua_State *L) { 1.1327 + const char *result_type; 1.1328 + lua_settop(L, 3); 1.1329 + if (lua_type(L, 2) != LUA_TSTRING || lua_tostring(L, 2)[0] == '_') { 1.1330 + lua_rawset(L, 1); 1.1331 + return 1; 1.1332 + } 1.1333 + lua_getfield(L, 1, "_class"); // 4 1.1334 + if (!lua_toboolean(L, 4)) { 1.1335 + lua_settop(L, 3); 1.1336 + lua_getfield(L, 1.1337 + LUA_REGISTRYINDEX, 1.1338 + MONDELEFANT_CLASS_PROTO_REGKEY 1.1339 + ); // 4 1.1340 + } 1.1341 + lua_getfield(L, 1, "_type"); // 5 1.1342 + result_type = lua_tostring(L, 5); 1.1343 + if (result_type && !strcmp(result_type, "object")) { 1.1344 + lua_settop(L, 4); 1.1345 + // try object setter functions: 1.1346 + while (lua_toboolean(L, 4)) { 1.1347 + lua_getfield(L, 4, "object_set"); // 5 1.1348 + lua_pushvalue(L, 2); // 6 1.1349 + lua_gettable(L, 5); // 6 1.1350 + if (lua_toboolean(L, 6)) { 1.1351 + lua_pushvalue(L, 1); // 7 1.1352 + lua_pushvalue(L, 3); // 8 1.1353 + lua_call(L, 2, 0); 1.1354 + return 0; 1.1355 + } 1.1356 + lua_settop(L, 4); 1.1357 + lua_pushliteral(L, "prototype"); // 5 1.1358 + lua_rawget(L, 4); // 5 1.1359 + lua_replace(L, 4); 1.1360 + } 1.1361 + lua_settop(L, 3); 1.1362 + // check, if a object reference is changed: 1.1363 + lua_pushcfunction(L, mondelefant_class_get_reference); // 4 1.1364 + lua_getfield(L, 1, "_class"); // 5 1.1365 + lua_pushvalue(L, 2); // 6 1.1366 + lua_call(L, 2, 1); // 4 1.1367 + if (!lua_isnil(L, 4)) { 1.1368 + // store object in _ref table (use false for nil): // TODO: use special object instead of false 1.1369 + lua_getfield(L, 1, "_ref"); // 5 1.1370 + lua_pushvalue(L, 2); // 6 1.1371 + if (lua_isnil(L, 3)) lua_pushboolean(L, 0); // 7 1.1372 + else lua_pushvalue(L, 3); // 7 1.1373 + lua_settable(L, 5); 1.1374 + lua_settop(L, 4); 1.1375 + // delete referencing key from _data table: 1.1376 + lua_getfield(L, 4, "this_key"); // 5 1.1377 + if (lua_isnil(L, 5)) { 1.1378 + return luaL_error(L, "Missing 'this_key' entry in model reference."); 1.1379 + } 1.1380 + lua_getfield(L, 1, "_data"); // 6 1.1381 + lua_pushvalue(L, 5); // 7 1.1382 + lua_pushnil(L); // 8 1.1383 + lua_settable(L, 6); 1.1384 + lua_settop(L, 5); 1.1385 + lua_getfield(L, 1, "_dirty"); // 6 1.1386 + lua_pushvalue(L, 5); // 7 1.1387 + lua_pushboolean(L, 1); // 8 1.1388 + lua_settable(L, 6); 1.1389 + return 0; 1.1390 + } 1.1391 + lua_settop(L, 3); 1.1392 + // store value in data field info: 1.1393 + lua_getfield(L, 1, "_data"); // 4 1.1394 + lua_pushvalue(L, 2); // 5 1.1395 + lua_pushvalue(L, 3); // 6 1.1396 + lua_settable(L, 4); 1.1397 + lua_settop(L, 3); 1.1398 + // mark field as dirty (needs to be UPDATEd on save): 1.1399 + lua_getfield(L, 1, "_dirty"); // 4 1.1400 + lua_pushvalue(L, 2); // 5 1.1401 + lua_pushboolean(L, 1); // 6 1.1402 + lua_settable(L, 4); 1.1403 + lua_settop(L, 3); 1.1404 + // reset reference cache, if neccessary: 1.1405 + lua_pushcfunction(L, 1.1406 + mondelefant_class_get_foreign_key_reference_name 1.1407 + ); // 4 1.1408 + lua_getfield(L, 1, "_class"); // 5 1.1409 + lua_pushvalue(L, 2); // 6 1.1410 + lua_call(L, 2, 1); // 4 1.1411 + if (!lua_isnil(L, 4)) { 1.1412 + lua_getfield(L, 1, "_ref"); // 5 1.1413 + lua_pushvalue(L, 4); // 6 1.1414 + lua_pushnil(L); // 7 1.1415 + lua_settable(L, 5); 1.1416 + } 1.1417 + return 0; 1.1418 + } else { 1.1419 + lua_settop(L, 3); 1.1420 + lua_rawset(L, 1); 1.1421 + return 0; 1.1422 + } 1.1423 + return 0; 1.1424 +} 1.1425 + 1.1426 +static int mondelefant_class_index(lua_State *L) { 1.1427 + lua_settop(L, 2); 1.1428 + lua_pushliteral(L, "prototype"); // 3 1.1429 + lua_rawget(L, 1); // 3 1.1430 + lua_pushvalue(L, 2); // 4 1.1431 + lua_gettable(L, 3); // 4 1.1432 + return 1; 1.1433 +} 1.1434 + 1.1435 +static const struct luaL_Reg mondelefant_module_functions[] = { 1.1436 + {"connect", mondelefant_connect}, 1.1437 + {"set_class", mondelefant_set_class}, 1.1438 + {"new_class", mondelefant_new_class}, 1.1439 + {NULL, NULL} 1.1440 +}; 1.1441 + 1.1442 +static const struct luaL_Reg mondelefant_conn_mt_functions[] = { 1.1443 + {"__gc", mondelefant_conn_free}, 1.1444 + {"__index", mondelefant_conn_index}, 1.1445 + {"__newindex", mondelefant_conn_newindex}, 1.1446 + {NULL, NULL} 1.1447 +}; 1.1448 + 1.1449 +static const struct luaL_Reg mondelefant_conn_methods[] = { 1.1450 + {"close", mondelefant_conn_close}, 1.1451 + {"is_ok", mondelefant_conn_is_ok}, 1.1452 + {"get_transaction_status", mondelefant_conn_get_transaction_status}, 1.1453 + {"create_list", mondelefant_conn_create_list}, 1.1454 + {"create_object", mondelefant_conn_create_object}, 1.1455 + {"quote_string", mondelefant_conn_quote_string}, 1.1456 + {"quote_binary", mondelefant_conn_quote_binary}, 1.1457 + {"assemble_command", mondelefant_conn_assemble_command}, 1.1458 + {"try_query", mondelefant_conn_try_query}, 1.1459 + {"query", mondelefant_conn_query}, 1.1460 + {NULL, NULL} 1.1461 +}; 1.1462 + 1.1463 +static const struct luaL_Reg mondelefant_errorobject_mt_functions[] = { 1.1464 + {NULL, NULL} 1.1465 +}; 1.1466 + 1.1467 +static const struct luaL_Reg mondelefant_errorobject_methods[] = { 1.1468 + {"escalate", mondelefant_errorobject_escalate}, 1.1469 + {"is_kind_of", mondelefant_errorobject_is_kind_of}, 1.1470 + {NULL, NULL} 1.1471 +}; 1.1472 + 1.1473 +static const struct luaL_Reg mondelefant_result_mt_functions[] = { 1.1474 + {"__index", mondelefant_result_index}, 1.1475 + {"__newindex", mondelefant_result_newindex}, 1.1476 + {NULL, NULL} 1.1477 +}; 1.1478 + 1.1479 +static const struct luaL_Reg mondelefant_class_mt_functions[] = { 1.1480 + {"__index", mondelefant_class_index}, 1.1481 + {NULL, NULL} 1.1482 +}; 1.1483 + 1.1484 +static const struct luaL_Reg mondelefant_class_methods[] = { 1.1485 + {"get_reference", mondelefant_class_get_reference}, 1.1486 + {"iterate_over_references", mondelefant_class_iterate_over_references}, 1.1487 + {"get_foreign_key_reference_name", 1.1488 + mondelefant_class_get_foreign_key_reference_name}, 1.1489 + {NULL, NULL} 1.1490 +}; 1.1491 + 1.1492 +static const struct luaL_Reg mondelefant_object_methods[] = { 1.1493 + {NULL, NULL} 1.1494 +}; 1.1495 + 1.1496 +static const struct luaL_Reg mondelefant_list_methods[] = { 1.1497 + {NULL, NULL} 1.1498 +}; 1.1499 + 1.1500 +int luaopen_mondelefant_native(lua_State *L) { 1.1501 + lua_settop(L, 0); 1.1502 + lua_newtable(L); // module at stack position 1 1.1503 + luaL_register(L, NULL, mondelefant_module_functions); 1.1504 + 1.1505 + lua_pushvalue(L, 1); // 2 1.1506 + lua_setfield(L, LUA_REGISTRYINDEX, MONDELEFANT_MODULE_REGKEY); 1.1507 + 1.1508 + lua_newtable(L); // 2 1.1509 + // NOTE: only PostgreSQL is supported yet: 1.1510 + luaL_register(L, NULL, mondelefant_conn_methods); 1.1511 + lua_setfield(L, 1, "postgresql_connection_prototype"); 1.1512 + lua_newtable(L); // 2 1.1513 + lua_setfield(L, 1, "connection_prototype"); 1.1514 + 1.1515 + luaL_newmetatable(L, MONDELEFANT_CONN_MT_REGKEY); // 2 1.1516 + luaL_register(L, NULL, mondelefant_conn_mt_functions); 1.1517 + lua_settop(L, 1); 1.1518 + luaL_newmetatable(L, MONDELEFANT_RESULT_MT_REGKEY); // 2 1.1519 + luaL_register(L, NULL, mondelefant_result_mt_functions); 1.1520 + lua_setfield(L, 1, "result_metatable"); 1.1521 + luaL_newmetatable(L, MONDELEFANT_CLASS_MT_REGKEY); // 2 1.1522 + luaL_register(L, NULL, mondelefant_class_mt_functions); 1.1523 + lua_setfield(L, 1, "class_metatable"); 1.1524 + 1.1525 + lua_newtable(L); // 2 1.1526 + lua_newtable(L); // 3 1.1527 + luaL_register(L, NULL, mondelefant_object_methods); 1.1528 + lua_setfield(L, 2, "object"); 1.1529 + lua_newtable(L); // 3 1.1530 + lua_setfield(L, 2, "object_get"); 1.1531 + lua_newtable(L); // 3 1.1532 + lua_setfield(L, 2, "object_set"); 1.1533 + lua_newtable(L); // 3 1.1534 + luaL_register(L, NULL, mondelefant_list_methods); 1.1535 + lua_setfield(L, 2, "list"); 1.1536 + lua_newtable(L); // 3 1.1537 + lua_setfield(L, 2, "references"); 1.1538 + lua_newtable(L); // 3 1.1539 + lua_setfield(L, 2, "foreign_keys"); 1.1540 + lua_pushvalue(L, 2); // 3 1.1541 + lua_setfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CLASS_PROTO_REGKEY); 1.1542 + lua_setfield(L, 1, "class_prototype"); 1.1543 + 1.1544 + lua_newtable(L); // 2 1.1545 + lua_pushliteral(L, "k"); // 3 1.1546 + lua_setfield(L, 2, "__mode"); 1.1547 + lua_newtable(L); // 3 1.1548 + lua_pushvalue(L, 2); // 4 1.1549 + lua_setmetatable(L, 3); 1.1550 + lua_setfield(L, LUA_REGISTRYINDEX, MONDELEFANT_CONN_DATA_REGKEY); 1.1551 + lua_settop(L, 1); 1.1552 + 1.1553 + luaL_newmetatable(L, MONDELEFANT_ERROROBJECT_MT_REGKEY); // 2 1.1554 + luaL_register(L, NULL, mondelefant_errorobject_mt_functions); 1.1555 + lua_newtable(L); // 3 1.1556 + luaL_register(L, NULL, mondelefant_errorobject_methods); 1.1557 + lua_setfield(L, 2, "__index"); 1.1558 + lua_setfield(L, 1, "errorobject_metatable"); 1.1559 + 1.1560 + return 1; 1.1561 +}