├── .gitignore ├── GNUmakefile ├── Makefile ├── README.md ├── error.lua ├── luapgsql.c ├── luapgsql.h ├── notice.lua ├── testcopy.lua ├── testdb.lua ├── testencryptpassword.lua ├── testescape.lua ├── testnumbers.lua └── trace.lua /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.so 3 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | LIB= pgsql 2 | 3 | SRCS= luapgsql.c 4 | 5 | LUA_VERSION?= $(shell lua -v 2>&1 | cut -c 5-7) 6 | 7 | CFLAGS+= -O3 -Wall -fPIC -I/usr/include -I/usr/include/lua${LUA_VERSION} \ 8 | -I/usr/include/postgresql 9 | 10 | LDADD+= -L/usr/lib -lpq 11 | 12 | LIBDIR= /usr/lib 13 | LUADIR= /usr/lib/lua/${LUA_VERSION} 14 | 15 | ${LIB}.so: ${SRCS:.c=.o} 16 | cc -shared -o ${LIB}.so ${CFLAGS} ${SRCS:.c=.o} ${LDADD} 17 | 18 | clean: 19 | rm -f *.o *.so 20 | install: 21 | install -d ${DESTDIR}${LIBDIR} 22 | install -m 755 ${LIB}.so ${DESTDIR}${LUADIR}/${LIB}.so 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | LIB= pgsql 2 | SHLIB_MAJOR= 1 3 | SHLIB_MINOR= 0 4 | 5 | SRCS= luapgsql.c 6 | 7 | LUA_VERSION?= 5.2 8 | OS!= uname 9 | 10 | .if ${OS} == "NetBSD" 11 | LOCALBASE?= /usr/pkg 12 | LUA_INCDIR?= ${LOCALBASE}/include/lua-${LUA_VERSION} 13 | .else 14 | LOCALBASE?= /usr/local 15 | LUA_INCDIR?= ${LOCALBASE}/include/lua${LUA_VERSION:S/.//} 16 | .endif 17 | 18 | PQ_LIBDIR?= ${LOCALBASE}/lib 19 | 20 | CFLAGS+= -I${LOCALBASE}/include -I${LUA_INCDIR} 21 | LDADD+= -L${PQ_LIBDIR} -lpq 22 | NOLINT= 1 23 | 24 | LUA_MODLIBDIR?= ${LOCALBASE}/lib/lua/${LUA_VERSION} 25 | 26 | libinstall: 27 | 28 | install: 29 | ${INSTALL} -d ${DESTDIR}${LUA_MODLIBDIR} 30 | ${INSTALL} lib${LIB}.so ${DESTDIR}${LUA_MODLIBDIR}/${LIB}.so 31 | 32 | .include 33 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | A Lua Binding for PostgreSQL 2 | 3 | Copyright (C) Micro Systems Marc Balmer. 4 | You can reach the author at marc@msys.ch 5 | 6 | Makefile is for BSD systems 7 | GNUmakefile is for Linux systems 8 | 9 | See https://lua.msys.ch/lua-module-reference.html#pgsql for full documentation. 10 | -------------------------------------------------------------------------------- /error.lua: -------------------------------------------------------------------------------- 1 | require 'pgsql' 2 | 3 | conn = pgsql.connectdb('dbname=arcapos user=lua password=lua2011!') 4 | 5 | print("errorMessage: " .. conn:errorMessage()) 6 | conn:exec("this will not work") 7 | print("errorMessage: " .. conn:errorMessage()) 8 | conn:exec("select now()") 9 | print("errorMessage: " .. conn:errorMessage()) 10 | -------------------------------------------------------------------------------- /luapgsql.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 - 2023, Micro Systems Marc Balmer, CH-5073 Gipf-Oberfrick 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of Micro Systems Marc Balmer nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* PostgreSQL extension module (using Lua) */ 29 | 30 | #ifdef __APPLE__ 31 | #include 32 | #define htobe64(x) OSSwapHostToBigInt64(x) 33 | #elif __FreeBSD__ 34 | #include 35 | #elif __linux__ 36 | #include 37 | #endif 38 | #include 39 | #include 40 | #include 41 | 42 | #include 43 | #include 44 | #include 45 | 46 | #include 47 | #include 48 | #include 49 | 50 | #include "luapgsql.h" 51 | 52 | #if LUA_VERSION_NUM < 502 53 | #define lua_setuservalue lua_setfenv 54 | #define lua_getuservalue lua_getfenv 55 | 56 | static void 57 | luaL_setmetatable(lua_State *L, const char *tname) 58 | { 59 | luaL_getmetatable(L, tname); 60 | lua_setmetatable(L, -2); 61 | } 62 | #endif 63 | 64 | /* 65 | * Garbage collected memory 66 | */ 67 | static void * 68 | gcmalloc(lua_State *L, size_t size) 69 | { 70 | void **p; 71 | 72 | p = lua_newuserdata(L, size); 73 | *p = NULL; 74 | luaL_setmetatable(L, GCMEM_METATABLE); 75 | return p; 76 | } 77 | 78 | /* Memory can be free'ed immediately or left to the garbage collector */ 79 | static void 80 | gcfree(void *p) 81 | { 82 | void **mem = (void **)p; 83 | PQfreemem(*mem); 84 | *mem = NULL; 85 | } 86 | 87 | static int 88 | gcmem_clear(lua_State *L) 89 | { 90 | void **p = luaL_checkudata(L, 1, GCMEM_METATABLE); 91 | PQfreemem(*p); 92 | *p = NULL; 93 | return 0; 94 | } 95 | 96 | /* 97 | * Create a new connection object with a uservalue table 98 | */ 99 | static PGconn ** 100 | pgsql_conn_new(lua_State *L) { 101 | PGconn **data; 102 | 103 | data = lua_newuserdata(L, sizeof(PGconn *)); 104 | *data = NULL; 105 | lua_newtable(L); 106 | lua_setuservalue(L, -2); 107 | luaL_setmetatable(L, CONN_METATABLE); 108 | return data; 109 | } 110 | 111 | /* 112 | * Database Connection Control Functions 113 | */ 114 | static int 115 | pgsql_connectdb(lua_State *L) 116 | { 117 | PGconn **data; 118 | const char *cstr; 119 | 120 | cstr = luaL_checkstring(L, 1); 121 | data = pgsql_conn_new(L); 122 | 123 | *data = PQconnectdb(cstr); 124 | if (*data == NULL) 125 | lua_pushnil(L); 126 | return 1; 127 | } 128 | 129 | static int 130 | pgsql_connectStart(lua_State *L) 131 | { 132 | PGconn **data; 133 | const char *cstr; 134 | 135 | cstr = luaL_checkstring(L, 1); 136 | data = pgsql_conn_new(L); 137 | *data = PQconnectStart(cstr); 138 | 139 | if (*data == NULL) 140 | lua_pushnil(L); 141 | return 1; 142 | } 143 | 144 | static PGconn * 145 | pgsql_conn(lua_State *L, int n) 146 | { 147 | PGconn **data; 148 | 149 | data = luaL_checkudata(L, n, CONN_METATABLE); 150 | luaL_argcheck(L, *data != NULL, n, "database connection is finished"); 151 | return *data; 152 | } 153 | 154 | static int 155 | pgsql_connectPoll(lua_State *L) 156 | { 157 | lua_pushinteger(L, PQconnectPoll(pgsql_conn(L, 1))); 158 | return 1; 159 | } 160 | 161 | static int 162 | pgsql_libVersion(lua_State *L) 163 | { 164 | lua_pushinteger(L, PQlibVersion()); 165 | return 1; 166 | } 167 | 168 | #if PG_VERSION_NUM >= 90100 169 | static int 170 | pgsql_ping(lua_State *L) 171 | { 172 | lua_pushinteger(L, PQping(luaL_checkstring(L, 1))); 173 | return 1; 174 | } 175 | #endif 176 | 177 | static int 178 | pgsql_encryptPassword(lua_State *L) 179 | { 180 | char const **pw; 181 | const char *passwd, *user; 182 | 183 | passwd = luaL_checkstring(L, 1); 184 | user = luaL_checkstring(L, 2); 185 | pw = gcmalloc(L, sizeof(char *)); 186 | *pw = PQencryptPassword(passwd, user); 187 | lua_pushstring(L, *pw); 188 | gcfree(pw); 189 | return 1; 190 | } 191 | 192 | static int 193 | pgsql_unescapeBytea(lua_State *L) 194 | { 195 | unsigned char **p; 196 | size_t len; 197 | const char *bytea; 198 | 199 | bytea = luaL_checkstring(L, 1); 200 | p = gcmalloc(L, sizeof(char *)); 201 | *p = PQunescapeBytea((const unsigned char *)bytea, &len); 202 | if (*p == NULL) 203 | lua_pushnil(L); 204 | else { 205 | lua_pushlstring(L, (const char *)*p, len); 206 | gcfree(p); 207 | } 208 | return 1; 209 | } 210 | 211 | static int 212 | pgsql_initOpenSSL(lua_State *L) 213 | { 214 | PQinitOpenSSL(lua_toboolean(L, 1), lua_toboolean(L, 2)); 215 | return 0; 216 | } 217 | 218 | static int 219 | conn_finish(lua_State *L) 220 | { 221 | PGconn **conn; 222 | 223 | conn = luaL_checkudata(L, 1, CONN_METATABLE); 224 | if (*conn) { 225 | /* 226 | * Check in the registry if a value has been stored at 227 | * index '*conn'; if a value is found, don't close the 228 | * connection. 229 | * This mechanism can be used when the PostgreSQL connection 230 | * object is provided to Lua from a C program that wants to 231 | * ensure the connections stays open, even when the Lua 232 | * program has terminated. 233 | * To prevent the closing of the connection, use the following 234 | * code to set a value in the registry at index '*conn' just 235 | * before handing the connection object to Lua: 236 | * 237 | * PGconn *conn, **data; 238 | * 239 | * conn = PQconnectdb(...); 240 | * data = lua_newuserdata(L, sizeof(PGconn *)); 241 | * *data = conn; 242 | * lua_pushlightuserdata(L, *data); 243 | * lua_pushboolean(L, 1); 244 | * lua_settable(L, LUA_REGISTRYINDEX); 245 | */ 246 | lua_pushlightuserdata(L, *conn); 247 | lua_gettable(L, LUA_REGISTRYINDEX); 248 | if (lua_isnil(L, -1)) { 249 | PQfinish(*conn); 250 | *conn = NULL; 251 | /* clean out now invalidated keys from uservalue */ 252 | lua_getuservalue(L, 1); 253 | lua_pushnil(L); 254 | lua_setfield(L, -2, "trace_file"); 255 | } 256 | } 257 | return 0; 258 | } 259 | 260 | static int 261 | conn_reset(lua_State *L) 262 | { 263 | PQreset(pgsql_conn(L, 1)); 264 | return 0; 265 | } 266 | 267 | static int 268 | conn_resetStart(lua_State *L) 269 | { 270 | lua_pushboolean(L, PQresetStart(pgsql_conn(L, 1))); 271 | return 1; 272 | } 273 | 274 | static int 275 | conn_resetPoll(lua_State *L) 276 | { 277 | lua_pushinteger(L, PQresetPoll(pgsql_conn(L, 1))); 278 | return 1; 279 | } 280 | 281 | /* 282 | * Connection status functions 283 | */ 284 | static int 285 | conn_db(lua_State *L) 286 | { 287 | lua_pushstring(L, PQdb(pgsql_conn(L, 1))); 288 | return 1; 289 | } 290 | 291 | static int 292 | conn_user(lua_State *L) 293 | { 294 | lua_pushstring(L, PQuser(pgsql_conn(L, 1))); 295 | return 1; 296 | } 297 | 298 | static int 299 | conn_pass(lua_State *L) 300 | { 301 | lua_pushstring(L, PQpass(pgsql_conn(L, 1))); 302 | return 1; 303 | } 304 | 305 | static int 306 | conn_host(lua_State *L) 307 | { 308 | lua_pushstring(L, PQhost(pgsql_conn(L, 1))); 309 | return 1; 310 | } 311 | 312 | static int 313 | conn_port(lua_State *L) 314 | { 315 | lua_pushstring(L, PQport(pgsql_conn(L, 1))); 316 | return 1; 317 | } 318 | 319 | static int 320 | conn_tty(lua_State *L) 321 | { 322 | lua_pushstring(L, PQtty(pgsql_conn(L, 1))); 323 | return 1; 324 | } 325 | 326 | static int 327 | conn_options(lua_State *L) 328 | { 329 | lua_pushstring(L, PQoptions(pgsql_conn(L, 1))); 330 | return 1; 331 | } 332 | 333 | static int 334 | conn_status(lua_State *L) 335 | { 336 | PGconn **conn; 337 | 338 | conn = luaL_checkudata(L, 1, CONN_METATABLE); 339 | lua_pushinteger(L, PQstatus(*conn)); 340 | return 1; 341 | } 342 | 343 | static int 344 | conn_transactionStatus(lua_State *L) 345 | { 346 | lua_pushinteger(L, PQtransactionStatus(pgsql_conn(L, 1))); 347 | return 1; 348 | } 349 | 350 | static int 351 | conn_parameterStatus(lua_State *L) 352 | { 353 | const char *status; 354 | 355 | status = PQparameterStatus(pgsql_conn(L, 1), luaL_checkstring(L, 2)); 356 | if (status == NULL) 357 | lua_pushnil(L); 358 | else 359 | lua_pushstring(L, status); 360 | return 1; 361 | } 362 | 363 | static int 364 | conn_protocolVersion(lua_State *L) 365 | { 366 | lua_pushinteger(L, PQprotocolVersion(pgsql_conn(L, 1))); 367 | return 1; 368 | } 369 | 370 | static int 371 | conn_serverVersion(lua_State *L) 372 | { 373 | lua_pushinteger(L, PQserverVersion(pgsql_conn(L, 1))); 374 | return 1; 375 | } 376 | 377 | static int 378 | conn_errorMessage(lua_State *L) 379 | { 380 | lua_pushstring(L, PQerrorMessage(pgsql_conn(L, 1))); 381 | return 1; 382 | } 383 | 384 | static int 385 | conn_socket(lua_State *L) 386 | { 387 | int fd; 388 | 389 | fd = PQsocket(pgsql_conn(L, 1)); 390 | if (fd >= 0) 391 | lua_pushinteger(L, fd); 392 | else 393 | lua_pushnil(L); 394 | return 1; 395 | } 396 | 397 | static int 398 | conn_backendPID(lua_State *L) 399 | { 400 | lua_pushinteger(L, PQbackendPID(pgsql_conn(L, 1))); 401 | return 1; 402 | } 403 | 404 | static int 405 | conn_connectionNeedsPassword(lua_State *L) 406 | { 407 | lua_pushboolean(L, PQconnectionNeedsPassword(pgsql_conn(L, 1))); 408 | return 1; 409 | } 410 | 411 | static int 412 | conn_connectionUsedPassword(lua_State *L) 413 | { 414 | lua_pushboolean(L, PQconnectionUsedPassword(pgsql_conn(L, 1))); 415 | return 1; 416 | } 417 | 418 | #if PG_VERSION_NUM >= 90500 419 | static int 420 | conn_sslInUse(lua_State *L) 421 | { 422 | lua_pushboolean(L, PQsslInUse(pgsql_conn(L, 1))); 423 | return 1; 424 | } 425 | 426 | static int 427 | conn_sslAttribute(lua_State *L) 428 | { 429 | lua_pushstring(L, 430 | PQsslAttribute(pgsql_conn(L, 1), luaL_checkstring(L, 2))); 431 | return 1; 432 | } 433 | 434 | static int 435 | conn_sslAttributeNames(lua_State *L) 436 | { 437 | const char * const *attribNames; 438 | int k; 439 | 440 | attribNames = PQsslAttributeNames(pgsql_conn(L, 1)); 441 | lua_newtable(L); 442 | for (k = 1; *attribNames; k++, attribNames++) { 443 | lua_pushinteger(L, k); 444 | lua_pushstring(L, *attribNames); 445 | lua_settable(L, -3); 446 | } 447 | return 1; 448 | } 449 | #endif 450 | 451 | /* 452 | * Command Execution Functions 453 | */ 454 | static int 455 | conn_exec(lua_State *L) 456 | { 457 | PGconn *conn; 458 | PGresult **res; 459 | const char *command; 460 | 461 | conn = pgsql_conn(L, 1); 462 | command = luaL_checkstring(L, 2); 463 | 464 | res = lua_newuserdata(L, sizeof(PGresult *)); 465 | *res = PQexec(conn, command); 466 | if (*res == NULL) 467 | lua_pushnil(L); 468 | else 469 | luaL_setmetatable(L, RES_METATABLE); 470 | return 1; 471 | } 472 | 473 | static void 474 | get_param(lua_State *L, int t, int n, Oid *paramTypes, char **paramValues, 475 | int *paramLengths, int *paramFormats) 476 | { 477 | switch (lua_type(L, t)) { 478 | case LUA_TBOOLEAN: 479 | if (paramTypes != NULL) 480 | paramTypes[n] = BOOLOID; 481 | if (paramValues != NULL) { 482 | paramValues[n] = lua_newuserdata(L, sizeof(char)); 483 | *(char *)paramValues[n] = lua_toboolean(L, t); 484 | paramLengths[n] = 1; 485 | } 486 | if (paramFormats != NULL) 487 | paramFormats[n] = 1; 488 | break; 489 | case LUA_TNUMBER: 490 | if (paramTypes != NULL) { 491 | #if LUA_VERSION_NUM >= 503 492 | if (lua_isinteger(L, t)) 493 | paramTypes[n] = INT8OID; 494 | else 495 | #endif 496 | paramTypes[n] = FLOAT8OID; 497 | } 498 | if (paramValues != NULL) { 499 | union { 500 | double v; 501 | uint64_t i; 502 | } swap; 503 | 504 | #if LUA_VERSION_NUM >= 503 505 | if (lua_isinteger(L, t)) 506 | swap.i = lua_tointeger(L, t); 507 | else 508 | #endif 509 | swap.v = lua_tonumber(L, t); 510 | paramValues[n] = lua_newuserdata(L, sizeof(uint64_t)); 511 | *(uint64_t *)paramValues[n] = htobe64(swap.i); 512 | paramLengths[n] = sizeof(uint64_t); 513 | } 514 | if (paramFormats != NULL) 515 | paramFormats[n] = 1; 516 | break; 517 | case LUA_TSTRING: 518 | if (paramTypes != NULL) 519 | paramTypes[n] = TEXTOID; 520 | if (paramValues != NULL) { 521 | const char *s; 522 | size_t len; 523 | 524 | s = lua_tolstring(L, t, &len); 525 | paramValues[n] = lua_newuserdata(L, len + 1); 526 | /* 527 | * lua_tolstring returns a string with '\0' after 528 | * the last character. 529 | */ 530 | memcpy(paramValues[n], s, len + 1); 531 | } 532 | if (paramFormats != NULL) 533 | paramFormats[n] = 0; 534 | break; 535 | case LUA_TNIL: 536 | if (paramTypes != NULL) 537 | paramTypes[n] = 0; 538 | if (paramValues != NULL) 539 | paramValues[n] = NULL; 540 | if (paramFormats != NULL) 541 | paramFormats[n] = 0; 542 | break; 543 | default: 544 | luaL_error(L, "unsupported PostgreSQL parameter type %s (" 545 | "use table.unpack() for table types)", luaL_typename(L, t)); 546 | /* NOTREACHED */ 547 | } 548 | } 549 | 550 | static int 551 | conn_execParams(lua_State *L) 552 | { 553 | PGconn *conn; 554 | PGresult **res; 555 | Oid *paramTypes; 556 | char **paramValues; 557 | const char *command; 558 | int n, nParams, *paramLengths, *paramFormats; 559 | 560 | conn = pgsql_conn(L, 1); 561 | command = luaL_checkstring(L, 2); 562 | 563 | nParams = lua_gettop(L) - 2; /* subtract connection and command */ 564 | 565 | if (nParams > 65535) 566 | luaL_error(L, "number of parameters must not exceed 65535"); 567 | 568 | if (nParams) { 569 | luaL_checkstack(L, 4 + nParams, "out of stack space"); 570 | 571 | paramTypes = lua_newuserdata(L, nParams * sizeof(Oid)); 572 | paramValues = lua_newuserdata(L, nParams * sizeof(char *)); 573 | paramLengths = lua_newuserdata(L, nParams * sizeof(int)); 574 | paramFormats = lua_newuserdata(L, nParams * sizeof(int)); 575 | 576 | for (n = 0; n < nParams; n++) 577 | get_param(L, 3 + n, n, paramTypes, paramValues, 578 | paramLengths, paramFormats); 579 | } else { 580 | paramTypes = NULL; 581 | paramValues = NULL; 582 | paramLengths = NULL; 583 | paramFormats = NULL; 584 | } 585 | luaL_checkstack(L, 2, "out of stack space"); 586 | res = lua_newuserdata(L, sizeof(PGresult *)); 587 | *res = PQexecParams(conn, command, nParams, paramTypes, 588 | (const char * const*)paramValues, paramLengths, paramFormats, 0); 589 | if (*res == NULL) 590 | lua_pushnil(L); 591 | else 592 | luaL_setmetatable(L, RES_METATABLE); 593 | return 1; 594 | } 595 | 596 | static int 597 | conn_prepare(lua_State *L) 598 | { 599 | PGconn *conn; 600 | PGresult **res; 601 | Oid *paramTypes; 602 | const char *command, *name; 603 | int n, nParams; 604 | 605 | conn = pgsql_conn(L, 1); 606 | command = luaL_checkstring(L, 2); 607 | name = luaL_checkstring(L, 3); 608 | 609 | nParams = lua_gettop(L) - 3; /* subtract connection, name, command */ 610 | 611 | if (nParams > 65535) 612 | luaL_error(L, "number of parameters must not exceed 65535"); 613 | 614 | if (nParams) { 615 | paramTypes = lua_newuserdata(L, nParams * sizeof(Oid)); 616 | 617 | for (n = 0; n < nParams; n++) 618 | get_param(L, 4 + n, n, paramTypes, NULL, NULL, NULL); 619 | } else 620 | paramTypes = NULL; 621 | 622 | res = lua_newuserdata(L, sizeof(PGresult *)); 623 | *res = PQprepare(conn, command, name, nParams, paramTypes); 624 | if (*res == NULL) 625 | lua_pushnil(L); 626 | else 627 | luaL_setmetatable(L, RES_METATABLE); 628 | return 1; 629 | } 630 | 631 | static int 632 | conn_execPrepared(lua_State *L) 633 | { 634 | PGconn *conn; 635 | PGresult **res; 636 | char **paramValues; 637 | const char *command; 638 | int n, nParams, *paramLengths, *paramFormats; 639 | 640 | conn = pgsql_conn(L, 1); 641 | command = luaL_checkstring(L, 2); 642 | 643 | nParams = lua_gettop(L) - 2; /* subtract connection and name */ 644 | 645 | if (nParams > 65535) 646 | luaL_error(L, "number of parameters must not exceed 65535"); 647 | 648 | if (nParams) { 649 | luaL_checkstack(L, 3 + nParams, "out of stack space"); 650 | 651 | paramValues = lua_newuserdata(L, nParams * sizeof(char *)); 652 | paramLengths = lua_newuserdata(L, nParams * sizeof(int)); 653 | paramFormats = lua_newuserdata(L, nParams * sizeof(int)); 654 | 655 | for (n = 0; n < nParams; n++) 656 | get_param(L, 3 + n, n, NULL, paramValues, paramLengths, 657 | paramFormats); 658 | } else { 659 | paramValues = NULL; 660 | paramLengths = NULL; 661 | paramFormats = NULL; 662 | } 663 | luaL_checkstack(L, 2, "out of stack space"); 664 | 665 | res = lua_newuserdata(L, sizeof(PGresult *)); 666 | *res = PQexecPrepared(conn, command, nParams, 667 | (const char * const*)paramValues, paramLengths, paramFormats, 0); 668 | if (*res == NULL) 669 | lua_pushnil(L); 670 | else 671 | luaL_setmetatable(L, RES_METATABLE); 672 | return 1; 673 | } 674 | 675 | static int 676 | conn_describePrepared(lua_State *L) 677 | { 678 | PGconn *conn; 679 | PGresult **res; 680 | const char *name; 681 | 682 | conn = pgsql_conn(L, 1); 683 | name = luaL_checkstring(L, 2); 684 | 685 | res = lua_newuserdata(L, sizeof(PGresult *)); 686 | *res = PQdescribePrepared(conn, name); 687 | if (*res == NULL) 688 | lua_pushnil(L); 689 | else 690 | luaL_setmetatable(L, RES_METATABLE); 691 | return 1; 692 | } 693 | 694 | static int 695 | conn_describePortal(lua_State *L) 696 | { 697 | PGconn *conn; 698 | PGresult **res; 699 | const char *name; 700 | 701 | conn = pgsql_conn(L, 1); 702 | name = luaL_checkstring(L, 2); 703 | 704 | res = lua_newuserdata(L, sizeof(PGresult *)); 705 | *res = PQdescribePortal(conn, name); 706 | if (*res == NULL) 707 | lua_pushnil(L); 708 | else 709 | luaL_setmetatable(L, RES_METATABLE); 710 | return 1; 711 | } 712 | 713 | static int 714 | conn_escapeString(lua_State *L) 715 | { 716 | PGconn *d; 717 | size_t len; 718 | char *buf; 719 | const char *str; 720 | int error; 721 | 722 | d = pgsql_conn(L, 1); 723 | 724 | str = lua_tolstring(L, 2, &len); 725 | if (str == NULL) { 726 | lua_pushnil(L); 727 | return 1; 728 | } 729 | buf = lua_newuserdata(L, 2 * (len + 1)); 730 | 731 | PQescapeStringConn(d, buf, str, len, &error); 732 | if (!error) 733 | lua_pushstring(L, buf); 734 | else 735 | lua_pushnil(L); 736 | return 1; 737 | } 738 | 739 | static int 740 | conn_escapeLiteral(lua_State *L) 741 | { 742 | const char *s; 743 | char **p; 744 | PGconn *d; 745 | size_t len; 746 | 747 | d = pgsql_conn(L, 1); 748 | s = luaL_checklstring(L, 2, &len); 749 | p = gcmalloc(L, sizeof(char *)); 750 | *p = PQescapeLiteral(d, s, len); 751 | lua_pushstring(L, *p); 752 | gcfree(p); 753 | return 1; 754 | } 755 | 756 | static int 757 | conn_escapeIdentifier(lua_State *L) 758 | { 759 | const char *s; 760 | char **p; 761 | PGconn *d; 762 | size_t len; 763 | 764 | d = pgsql_conn(L, 1); 765 | s = luaL_checklstring(L, 2, &len); 766 | p = gcmalloc(L, sizeof(char *)); 767 | *p = PQescapeIdentifier(d, s, len); 768 | lua_pushstring(L, *p); 769 | gcfree(p); 770 | return 1; 771 | } 772 | 773 | static int 774 | conn_escapeBytea(lua_State *L) 775 | { 776 | unsigned char **p; 777 | const unsigned char *s; 778 | PGconn *d; 779 | size_t from_length, to_length; 780 | 781 | d = pgsql_conn(L, 1); 782 | s = (const unsigned char *)luaL_checklstring(L, 2, &from_length); 783 | p = gcmalloc(L, sizeof(char *)); 784 | *p = PQescapeByteaConn(d, s, from_length, &to_length); 785 | if (*p) { 786 | lua_pushlstring(L, (const char *)*p, to_length - 1); 787 | gcfree(p); 788 | } else 789 | lua_pushnil(L); 790 | return 1; 791 | } 792 | 793 | /* 794 | * Asynchronous Command Execution Functions 795 | */ 796 | static int 797 | conn_sendQuery(lua_State *L) 798 | { 799 | lua_pushboolean(L, PQsendQuery(pgsql_conn(L, 1), 800 | luaL_checkstring(L, 2))); 801 | return 1; 802 | } 803 | 804 | static int 805 | conn_sendQueryParams(lua_State *L) 806 | { 807 | PGconn *conn; 808 | Oid *paramTypes; 809 | char **paramValues; 810 | const char *command; 811 | int n, nParams, *paramLengths, *paramFormats; 812 | 813 | conn = pgsql_conn(L, 1); 814 | command = luaL_checkstring(L, 2); 815 | 816 | nParams = lua_gettop(L) - 2; /* subtract connection and command */ 817 | 818 | if (nParams) { 819 | luaL_checkstack(L, 4 + nParams, "out of stack space"); 820 | 821 | paramTypes = lua_newuserdata(L, nParams * sizeof(Oid)); 822 | paramValues = lua_newuserdata(L, nParams * sizeof(char *)); 823 | paramLengths = lua_newuserdata(L, nParams * sizeof(int)); 824 | paramFormats = lua_newuserdata(L, nParams * sizeof(int)); 825 | 826 | for (n = 0; n < nParams; n++) 827 | get_param(L, 3 + n, n, paramTypes, paramValues, 828 | paramLengths, paramFormats); 829 | } else { 830 | paramTypes = NULL; 831 | paramValues = NULL; 832 | paramLengths = NULL; 833 | paramFormats = NULL; 834 | } 835 | lua_pushboolean(L, 836 | PQsendQueryParams(conn, command, nParams, paramTypes, 837 | (const char * const*)paramValues, paramLengths, paramFormats, 0)); 838 | return 1; 839 | } 840 | 841 | static int 842 | conn_sendPrepare(lua_State *L) 843 | { 844 | PGconn *conn; 845 | Oid *paramTypes; 846 | const char *command, *name; 847 | int n, nParams; 848 | 849 | conn = pgsql_conn(L, 1); 850 | command = luaL_checkstring(L, 2); 851 | name = luaL_checkstring(L, 3); 852 | 853 | nParams = lua_gettop(L) - 3; /* subtract connection, name, command */ 854 | 855 | if (nParams) { 856 | paramTypes = lua_newuserdata(L, nParams * sizeof(Oid)); 857 | 858 | for (n = 0; n < nParams; n++) 859 | get_param(L, 4 + n, n, paramTypes, NULL, NULL, NULL); 860 | } else 861 | paramTypes = NULL; 862 | lua_pushboolean(L, 863 | PQsendPrepare(conn, command, name, nParams, paramTypes)); 864 | return 1; 865 | } 866 | 867 | static int 868 | conn_sendQueryPrepared(lua_State *L) 869 | { 870 | PGconn *conn; 871 | char **paramValues; 872 | const char *name; 873 | int n, nParams, *paramLengths, *paramFormats; 874 | 875 | conn = pgsql_conn(L, 1); 876 | name = luaL_checkstring(L, 2); 877 | 878 | nParams = lua_gettop(L) - 2; /* subtract connection and name */ 879 | 880 | if (nParams) { 881 | luaL_checkstack(L, 3 + nParams, "out of stack space"); 882 | 883 | paramValues = lua_newuserdata(L, nParams * sizeof(char *)); 884 | paramLengths = lua_newuserdata(L, nParams * sizeof(int)); 885 | paramFormats = lua_newuserdata(L, nParams * sizeof(int)); 886 | 887 | for (n = 0; n < nParams; n++) 888 | get_param(L, 3 + n, n, NULL, paramValues, paramLengths, 889 | paramFormats); 890 | } else { 891 | paramValues = NULL; 892 | paramLengths = NULL; 893 | paramFormats = NULL; 894 | } 895 | lua_pushboolean(L, 896 | PQsendQueryPrepared(conn, name, nParams, 897 | (const char * const*)paramValues, paramLengths, paramFormats, 0)); 898 | return 1; 899 | } 900 | 901 | static int 902 | conn_sendDescribePrepared(lua_State *L) 903 | { 904 | lua_pushboolean(L, 905 | PQsendDescribePrepared(pgsql_conn(L, 1), luaL_checkstring(L, 2))); 906 | return 1; 907 | } 908 | 909 | static int 910 | conn_sendDescribePortal(lua_State *L) 911 | { 912 | lua_pushboolean(L, 913 | PQsendDescribePortal(pgsql_conn(L, 1), luaL_checkstring(L, 2))); 914 | return 1; 915 | } 916 | 917 | static int 918 | conn_getResult(lua_State *L) 919 | { 920 | PGresult *r, **res; 921 | 922 | r = PQgetResult(pgsql_conn(L, 1)); 923 | if (r == NULL) 924 | lua_pushnil(L); 925 | else { 926 | res = lua_newuserdata(L, sizeof(PGresult *)); 927 | *res = r; 928 | luaL_setmetatable(L, RES_METATABLE); 929 | } 930 | return 1; 931 | } 932 | 933 | static int 934 | conn_cancel(lua_State *L) 935 | { 936 | PGconn *d; 937 | PGcancel *cancel; 938 | char errbuf[256]; 939 | int res = 1; 940 | 941 | d = pgsql_conn(L, 1); 942 | cancel = PQgetCancel(d); 943 | if (cancel != NULL) { 944 | res = PQcancel(cancel, errbuf, sizeof errbuf); 945 | if (!res) { 946 | lua_pushboolean(L, 0); 947 | lua_pushstring(L, errbuf); 948 | } else 949 | lua_pushboolean(L, 1); 950 | PQfreeCancel(cancel); 951 | } else 952 | lua_pushboolean(L, 0); 953 | return res == 1 ? 1 : 2; 954 | } 955 | 956 | #if PG_VERSION_NUM >= 140000 957 | /* 958 | * Pipeline mode 959 | */ 960 | static int 961 | conn_pipelineStatus(lua_State *L) 962 | { 963 | lua_pushinteger(L, PQpipelineStatus(pgsql_conn(L, 1))); 964 | return 1; 965 | } 966 | 967 | static int 968 | conn_enterPipelineMode(lua_State *L) 969 | { 970 | lua_pushboolean(L, PQenterPipelineMode(pgsql_conn(L, 1))); 971 | return 1; 972 | } 973 | 974 | static int 975 | conn_exitPipelineMode(lua_State *L) 976 | { 977 | lua_pushboolean(L, PQexitPipelineMode(pgsql_conn(L, 1))); 978 | return 1; 979 | } 980 | 981 | static int 982 | conn_pipelineSync(lua_State *L) 983 | { 984 | lua_pushboolean(L, PQpipelineSync(pgsql_conn(L, 1))); 985 | return 1; 986 | } 987 | 988 | static int 989 | conn_sendFlushRequest(lua_State *L) 990 | { 991 | lua_pushboolean(L, PQsendFlushRequest(pgsql_conn(L, 1))); 992 | return 1; 993 | } 994 | #endif 995 | 996 | #if PG_VERSION_NUM >= 90200 997 | static int 998 | conn_setSingleRowMode(lua_State *L) 999 | { 1000 | lua_pushboolean(L, PQsetSingleRowMode(pgsql_conn(L, 1))); 1001 | return 1; 1002 | } 1003 | #endif 1004 | 1005 | /* 1006 | * Asynchronous Notification Functions 1007 | */ 1008 | static int 1009 | conn_notifies(lua_State *L) 1010 | { 1011 | PGnotify **notify, *n; 1012 | 1013 | n = PQnotifies(pgsql_conn(L, 1)); 1014 | if (n == NULL) 1015 | lua_pushnil(L); 1016 | else { 1017 | notify = lua_newuserdata(L, sizeof(PGnotify *)); 1018 | *notify = n; 1019 | luaL_setmetatable(L, NOTIFY_METATABLE); 1020 | } 1021 | return 1; 1022 | } 1023 | 1024 | /* 1025 | * Commands associated with the COPY command 1026 | */ 1027 | static int 1028 | conn_putCopyData(lua_State *L) 1029 | { 1030 | const char *data; 1031 | size_t len; 1032 | int r; 1033 | 1034 | data = luaL_checklstring(L, 2, &len); 1035 | r = PQputCopyData(pgsql_conn(L, 1), data, len); 1036 | 1037 | if (r != -1) 1038 | lua_pushboolean(L, r); 1039 | else 1040 | lua_pushnil(L); 1041 | return 1; 1042 | } 1043 | 1044 | static int 1045 | conn_putCopyEnd(lua_State *L) 1046 | { 1047 | PGconn *conn; 1048 | int r; 1049 | 1050 | conn = pgsql_conn(L, 1); 1051 | r = PQputCopyEnd(conn, luaL_optstring(L, 2, NULL)); 1052 | 1053 | if (r != -1) 1054 | lua_pushboolean(L, r); 1055 | else 1056 | lua_pushnil(L); 1057 | return 1; 1058 | } 1059 | 1060 | static int 1061 | conn_getCopyData(lua_State *L) 1062 | { 1063 | PGconn *conn; 1064 | int async, len; 1065 | char **data; 1066 | 1067 | conn = pgsql_conn(L, 1); 1068 | async = lua_toboolean(L, 2); 1069 | data = gcmalloc(L, sizeof(char *)); 1070 | len = PQgetCopyData(conn, data, async); 1071 | if (len > 0) 1072 | lua_pushlstring(L, *data, len); 1073 | else if (len == 0) /* no data yet */ 1074 | lua_pushboolean(L, 0); 1075 | else if (len == -1) /* copy done */ 1076 | lua_pushboolean(L, 1); 1077 | else /* an error occurred */ 1078 | lua_pushnil(L); 1079 | gcfree(data); 1080 | return 1; 1081 | } 1082 | 1083 | /* 1084 | * Control functions 1085 | */ 1086 | static int 1087 | conn_clientEncoding(lua_State *L) 1088 | { 1089 | lua_pushstring(L, 1090 | pg_encoding_to_char(PQclientEncoding(pgsql_conn(L, 1)))); 1091 | return 1; 1092 | } 1093 | 1094 | static int 1095 | conn_setClientEncoding(lua_State *L) 1096 | { 1097 | if (PQsetClientEncoding(pgsql_conn(L, 1), luaL_checkstring(L, 2))) 1098 | lua_pushboolean(L, 0); 1099 | else 1100 | lua_pushboolean(L, 1); 1101 | return 1; 1102 | } 1103 | 1104 | static int 1105 | conn_setErrorVerbosity(lua_State *L) 1106 | { 1107 | lua_pushinteger(L, 1108 | PQsetErrorVerbosity(pgsql_conn(L, 1), luaL_checkinteger(L, 2))); 1109 | return 1; 1110 | } 1111 | 1112 | static int 1113 | closef_untrace(lua_State *L) 1114 | { 1115 | PGconn *conn; 1116 | lua_CFunction cf; 1117 | 1118 | luaL_checkudata(L, 1, LUA_FILEHANDLE); 1119 | 1120 | /* untrace so libpq doesn't segfault */ 1121 | lua_getuservalue(L, 1); 1122 | lua_getfield(L, -1, "PGconn"); 1123 | conn = pgsql_conn(L, -1); 1124 | lua_getfield(L, -2, "old_uservalue"); 1125 | #if LUA_VERSION_NUM >= 502 1126 | lua_getfield(L, -3, "old_closef"); 1127 | #else 1128 | lua_getfield(L, -1, "__close"); 1129 | #endif 1130 | cf = lua_tocfunction(L, -1); 1131 | lua_pop(L, 1); 1132 | lua_setuservalue(L, 1); 1133 | 1134 | PQuntrace(conn); 1135 | 1136 | /* let go of PGconn's reference to file handle */ 1137 | lua_getuservalue(L, -1); 1138 | lua_pushnil(L); 1139 | lua_setfield(L, -2, "trace_file"); 1140 | 1141 | /* pop stream uservalue, PGconn, PGconn uservalue */ 1142 | lua_pop(L, 3); 1143 | 1144 | /* call original close function */ 1145 | return (*cf)(L); 1146 | } 1147 | 1148 | static int 1149 | conn_trace(lua_State *L) 1150 | { 1151 | PGconn *conn; 1152 | #if LUA_VERSION_NUM >= 502 1153 | luaL_Stream *stream; 1154 | 1155 | conn = pgsql_conn(L, 1); 1156 | stream = luaL_checkudata(L, 2, LUA_FILEHANDLE); 1157 | luaL_argcheck(L, stream->f != NULL, 2, "invalid file handle"); 1158 | 1159 | /* 1160 | * Keep a reference to the file object in uservalue of connection 1161 | * so it doesn't get garbage collected. 1162 | */ 1163 | lua_getuservalue(L, 1); 1164 | lua_pushvalue(L, 2); 1165 | lua_setfield(L, -2, "trace_file"); 1166 | 1167 | /* 1168 | * Swap out closef luaL_Stream member for our wrapper that will 1169 | * untrace. 1170 | */ 1171 | lua_createtable(L, 0, 3); 1172 | lua_getuservalue(L, 2); 1173 | lua_setfield(L, -2, "old_uservalue"); 1174 | lua_pushcfunction(L, stream->closef); 1175 | lua_setfield(L, -2, "old_closef"); 1176 | lua_pushvalue(L, 1); 1177 | lua_setfield(L, -2, "PGconn"); 1178 | lua_setuservalue(L, 2); 1179 | stream->closef = closef_untrace; 1180 | 1181 | PQtrace(conn, stream->f); 1182 | #else 1183 | FILE **fp; 1184 | 1185 | conn = pgsql_conn(L, 1); 1186 | fp = luaL_checkudata(L, 2, LUA_FILEHANDLE); 1187 | luaL_argcheck(L, *fp != NULL, 2, "invalid file handle"); 1188 | 1189 | /* 1190 | * Keep a reference to the file object in uservalue of connection 1191 | * so it doesn't get garbage collected. 1192 | */ 1193 | lua_getuservalue(L, 1); 1194 | lua_pushvalue(L, 2); 1195 | lua_setfield(L, -2, "trace_file"); 1196 | 1197 | /* 1198 | * Swap __close field in file environment for our wrapper that will 1199 | * untrace keep the old closef under the key of the PGconn. 1200 | */ 1201 | lua_createtable(L, 0, 3); 1202 | lua_pushcfunction(L, closef_untrace); 1203 | lua_setfield(L, -2, "__close"); 1204 | lua_getuservalue(L, 2); 1205 | lua_setfield(L, -2, "old_uservalue"); 1206 | lua_pushvalue(L, 1); 1207 | lua_setfield(L, -2, "PGconn"); 1208 | lua_setuservalue(L, 2); 1209 | 1210 | PQtrace(conn, *fp); 1211 | #endif 1212 | return 0; 1213 | } 1214 | 1215 | static int 1216 | conn_untrace(lua_State *L) 1217 | { 1218 | PQuntrace(pgsql_conn(L, 1)); 1219 | 1220 | /* Let go of PGconn's reference to file handle. */ 1221 | lua_getuservalue(L, 1); 1222 | lua_pushnil(L); 1223 | lua_setfield(L, -2, "trace_file"); 1224 | 1225 | return 0; 1226 | } 1227 | 1228 | /* 1229 | * Miscellaneous Functions 1230 | */ 1231 | static int 1232 | conn_consumeInput(lua_State *L) 1233 | { 1234 | lua_pushboolean(L, PQconsumeInput(pgsql_conn(L, 1))); 1235 | return 1; 1236 | } 1237 | 1238 | static int 1239 | conn_isBusy(lua_State *L) 1240 | { 1241 | lua_pushboolean(L, PQisBusy(pgsql_conn(L, 1))); 1242 | return 1; 1243 | } 1244 | 1245 | static int 1246 | conn_setnonblocking(lua_State *L) 1247 | { 1248 | int r; 1249 | 1250 | r = PQsetnonblocking(pgsql_conn(L, 1), lua_toboolean(L, 2)); 1251 | lua_pushboolean(L, !r); 1252 | return 1; 1253 | } 1254 | 1255 | static int 1256 | conn_isnonblocking(lua_State *L) 1257 | { 1258 | lua_pushboolean(L, PQisnonblocking(pgsql_conn(L, 1))); 1259 | return 1; 1260 | } 1261 | 1262 | static int 1263 | conn_flush(lua_State *L) 1264 | { 1265 | int r; 1266 | 1267 | r = PQflush(pgsql_conn(L, 1)); 1268 | 1269 | if (r >= 0) 1270 | lua_pushboolean(L, r == 0); 1271 | else 1272 | lua_pushnil(L); 1273 | return 1; 1274 | } 1275 | 1276 | #if PG_VERSION_NUM >= 100000 1277 | static int 1278 | conn_encryptPassword(lua_State *L) 1279 | { 1280 | const char *algorithm = NULL; 1281 | char **pw; 1282 | 1283 | if (lua_isstring(L, 4)) 1284 | algorithm = lua_tostring(L, 4); 1285 | 1286 | pw = gcmalloc(L, sizeof(char *)); 1287 | *pw = PQencryptPasswordConn(pgsql_conn(L, 1), luaL_checkstring(L, 2), 1288 | luaL_checkstring(L, 3), algorithm); 1289 | if (*pw) { 1290 | lua_pushstring(L, *pw); 1291 | gcfree(pw); 1292 | } else 1293 | lua_pushnil(L); 1294 | return 1; 1295 | } 1296 | #endif 1297 | 1298 | /* Notice processing */ 1299 | static void 1300 | noticeReceiver(void *arg, const PGresult *r) 1301 | { 1302 | notice *n = arg; 1303 | PGresult **res; 1304 | 1305 | lua_rawgeti(n->L, LUA_REGISTRYINDEX, n->f); 1306 | res = lua_newuserdata(n->L, sizeof(PGresult *)); 1307 | 1308 | *res = (PGresult *)r; 1309 | luaL_setmetatable(n->L, RES_METATABLE); 1310 | 1311 | if (lua_pcall(n->L, 1, 0, 0)) 1312 | luaL_error(n->L, "%s", lua_tostring(n->L, -1)); 1313 | *res = NULL; /* avoid double free */ 1314 | } 1315 | 1316 | static void 1317 | noticeProcessor(void *arg, const char *message) 1318 | { 1319 | notice *n = arg; 1320 | 1321 | lua_rawgeti(n->L, LUA_REGISTRYINDEX, n->f); 1322 | lua_pushstring(n->L, message); 1323 | if (lua_pcall(n->L, 1, 0, 0)) 1324 | luaL_error(n->L, "%s", lua_tostring(n->L, -1)); 1325 | } 1326 | 1327 | static int 1328 | conn_setNoticeReceiver(lua_State *L) 1329 | { 1330 | notice **n; 1331 | PGconn *conn; 1332 | int f; 1333 | 1334 | if (!lua_isfunction(L, -1)) 1335 | return luaL_argerror(L, -1, "function expected"); 1336 | 1337 | f = luaL_ref(L, LUA_REGISTRYINDEX); 1338 | conn = pgsql_conn(L, 1); 1339 | 1340 | n = gcmalloc(L, sizeof(notice *)); 1341 | *n = malloc(sizeof(notice)); 1342 | if (*n != NULL) { 1343 | (*n)->L = L; 1344 | (*n)->f = f; 1345 | PQsetNoticeReceiver(conn, noticeReceiver, *n); 1346 | } else 1347 | return luaL_error(L, "out of memory"); 1348 | return 0; 1349 | } 1350 | 1351 | static int 1352 | conn_setNoticeProcessor(lua_State *L) 1353 | { 1354 | notice **n; 1355 | PGconn *conn; 1356 | int f; 1357 | 1358 | if (!lua_isfunction(L, -1)) 1359 | return luaL_argerror(L, -1, "function expected"); 1360 | 1361 | f = luaL_ref(L, LUA_REGISTRYINDEX); 1362 | conn = pgsql_conn(L, 1); 1363 | 1364 | n = gcmalloc(L, sizeof(notice *)); 1365 | *n = malloc(sizeof(notice)); 1366 | if (*n != NULL) { 1367 | (*n)->L = L; 1368 | (*n)->f = f; 1369 | PQsetNoticeProcessor(conn, noticeProcessor, *n); 1370 | } else 1371 | return luaL_error(L, "out of memory"); 1372 | return 0; 1373 | } 1374 | 1375 | /* Large objects */ 1376 | static int 1377 | conn_lo_create(lua_State *L) 1378 | { 1379 | Oid oid; 1380 | 1381 | if (lua_gettop(L) == 2) 1382 | oid = luaL_checkinteger(L, 2); 1383 | else 1384 | oid = 0; 1385 | lua_pushinteger(L, lo_create(pgsql_conn(L, 1), oid)); 1386 | return 1; 1387 | } 1388 | 1389 | static int 1390 | conn_lo_import(lua_State *L) 1391 | { 1392 | lua_pushinteger(L, lo_import(pgsql_conn(L, 1), luaL_checkstring(L, 2))); 1393 | return 1; 1394 | } 1395 | 1396 | static int 1397 | conn_lo_import_with_oid(lua_State *L) 1398 | { 1399 | lua_pushinteger(L, 1400 | lo_import_with_oid(pgsql_conn(L, 1), luaL_checkstring(L, 2), 1401 | luaL_checkinteger(L, 3))); 1402 | return 1; 1403 | } 1404 | 1405 | static int 1406 | conn_lo_export(lua_State *L) 1407 | { 1408 | int r; 1409 | 1410 | r = lo_export(pgsql_conn(L, 1), luaL_checkinteger(L, 2), 1411 | luaL_checkstring(L, 3)); 1412 | 1413 | lua_pushboolean(L, r == 1); 1414 | return 1; 1415 | } 1416 | 1417 | static int 1418 | conn_lo_open(lua_State *L) 1419 | { 1420 | int fd; 1421 | 1422 | fd = lo_open(pgsql_conn(L, 1), luaL_checkinteger(L, 2), 1423 | luaL_checkinteger(L, 3)); 1424 | if (fd == -1) 1425 | lua_pushnil(L); 1426 | else 1427 | lua_pushinteger(L, fd); 1428 | return 1; 1429 | } 1430 | 1431 | static int 1432 | conn_lo_write(lua_State *L) 1433 | { 1434 | const char *s; 1435 | size_t len; 1436 | 1437 | s = lua_tolstring(L, 3, &len); 1438 | lua_pushinteger(L, lo_write(pgsql_conn(L, 1), luaL_checkinteger(L, 2), 1439 | s, len)); 1440 | return 1; 1441 | } 1442 | 1443 | static int 1444 | conn_lo_read(lua_State *L) 1445 | { 1446 | char *buf; 1447 | size_t len; 1448 | 1449 | len = luaL_checkinteger(L, 3); 1450 | buf = lua_newuserdata(L, len); 1451 | len = lo_read(pgsql_conn(L, 1), luaL_checkinteger(L, 2), buf, len); 1452 | lua_pushlstring(L, buf, len); 1453 | lua_pushinteger(L, len); 1454 | return 2; 1455 | } 1456 | 1457 | static int 1458 | conn_lo_lseek(lua_State *L) 1459 | { 1460 | lua_pushinteger(L, lo_lseek(pgsql_conn(L, 1), luaL_checkinteger(L, 2), 1461 | luaL_checkinteger(L, 3), luaL_checkinteger(L, 4))); 1462 | return 1; 1463 | } 1464 | 1465 | static int 1466 | conn_lo_tell(lua_State *L) 1467 | { 1468 | lua_pushinteger(L, lo_tell(pgsql_conn(L, 1), luaL_checkinteger(L, 2))); 1469 | return 1; 1470 | } 1471 | 1472 | static int 1473 | conn_lo_truncate(lua_State *L) 1474 | { 1475 | lua_pushinteger(L, lo_truncate(pgsql_conn(L, 1), 1476 | luaL_checkinteger(L, 2), luaL_checkinteger(L, 3))); 1477 | return 1; 1478 | } 1479 | 1480 | static int 1481 | conn_lo_close(lua_State *L) 1482 | { 1483 | lua_pushboolean(L, 1484 | lo_close(pgsql_conn(L, 1), luaL_checkinteger(L, 2)) == 0); 1485 | return 1; 1486 | } 1487 | 1488 | static int 1489 | conn_lo_unlink(lua_State *L) 1490 | { 1491 | lua_pushboolean(L, 1492 | lo_unlink(pgsql_conn(L, 1), luaL_checkinteger(L, 2)) == 1); 1493 | return 1; 1494 | } 1495 | 1496 | #if PG_VERSION_NUM >= 90300 1497 | static int 1498 | conn_lo_lseek64(lua_State *L) 1499 | { 1500 | lua_pushinteger(L, lo_lseek64(pgsql_conn(L, 1), luaL_checkinteger(L, 2), 1501 | luaL_checkinteger(L, 3), luaL_checkinteger(L, 4))); 1502 | return 1; 1503 | } 1504 | 1505 | static int 1506 | conn_lo_tell64(lua_State *L) 1507 | { 1508 | lua_pushinteger(L, 1509 | lo_tell64(pgsql_conn(L, 1), luaL_checkinteger(L, 2))); 1510 | return 1; 1511 | } 1512 | 1513 | static int 1514 | conn_lo_truncate64(lua_State *L) 1515 | { 1516 | lua_pushinteger(L, lo_truncate64(pgsql_conn(L, 1), 1517 | luaL_checkinteger(L, 2), luaL_checkinteger(L, 3))); 1518 | return 1; 1519 | } 1520 | #endif 1521 | 1522 | /* 1523 | * Result set functions 1524 | */ 1525 | static int 1526 | res_status(lua_State *L) 1527 | { 1528 | lua_pushinteger(L, 1529 | PQresultStatus(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1530 | return 1; 1531 | } 1532 | 1533 | static int 1534 | res_resStatus(lua_State *L) 1535 | { 1536 | lua_pushstring(L, PQresStatus(luaL_checkinteger(L, 2))); 1537 | return 1; 1538 | } 1539 | 1540 | static int 1541 | res_errorMessage(lua_State *L) 1542 | { 1543 | lua_pushstring(L, 1544 | PQresultErrorMessage(*(PGresult **)luaL_checkudata(L, 1, 1545 | RES_METATABLE))); 1546 | return 1; 1547 | } 1548 | 1549 | static int 1550 | res_errorField(lua_State *L) 1551 | { 1552 | char *field; 1553 | 1554 | field = PQresultErrorField( 1555 | *(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1556 | lua_tointeger(L, 2)); 1557 | if (field == NULL) 1558 | lua_pushnil(L); 1559 | else 1560 | lua_pushstring(L, field); 1561 | return 1; 1562 | } 1563 | 1564 | static int 1565 | res_nfields(lua_State *L) 1566 | { 1567 | lua_pushinteger(L, 1568 | PQnfields(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1569 | return 1; 1570 | } 1571 | 1572 | static int 1573 | res_ntuples(lua_State *L) 1574 | { 1575 | lua_pushinteger(L, 1576 | PQntuples(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1577 | return 1; 1578 | } 1579 | 1580 | static int 1581 | res_fname(lua_State *L) 1582 | { 1583 | lua_pushstring(L, 1584 | PQfname(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1585 | luaL_checkinteger(L, 2) - 1)); 1586 | return 1; 1587 | } 1588 | 1589 | static int 1590 | res_fnumber(lua_State *L) 1591 | { 1592 | lua_pushinteger(L, 1593 | PQfnumber(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1594 | luaL_checkstring(L, 2)) + 1); 1595 | return 1; 1596 | } 1597 | 1598 | static int 1599 | res_ftable(lua_State *L) 1600 | { 1601 | lua_pushinteger(L, 1602 | PQftable(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1603 | luaL_checkinteger(L, 2) - 1)); 1604 | return 1; 1605 | } 1606 | 1607 | static int 1608 | res_ftablecol(lua_State *L) 1609 | { 1610 | lua_pushinteger(L, 1611 | PQftablecol(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1612 | luaL_checkinteger(L, 2) - 1)); 1613 | return 1; 1614 | } 1615 | 1616 | static int 1617 | res_fformat(lua_State *L) 1618 | { 1619 | lua_pushinteger(L, 1620 | PQfformat(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1621 | luaL_checkinteger(L, 2) - 1)); 1622 | return 1; 1623 | } 1624 | 1625 | static int 1626 | res_ftype(lua_State *L) 1627 | { 1628 | lua_pushinteger(L, 1629 | PQftype(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1630 | luaL_checkinteger(L, 2) - 1)); 1631 | return 1; 1632 | } 1633 | 1634 | static int 1635 | res_fmod(lua_State *L) 1636 | { 1637 | lua_pushinteger(L, 1638 | PQfmod(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1639 | luaL_checkinteger(L, 2) - 1)); 1640 | return 1; 1641 | } 1642 | 1643 | static int 1644 | res_fsize(lua_State *L) 1645 | { 1646 | lua_pushinteger(L, 1647 | PQfsize(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1648 | luaL_checkinteger(L, 2) - 1)); 1649 | return 1; 1650 | } 1651 | 1652 | static int 1653 | res_binaryTuples(lua_State *L) 1654 | { 1655 | lua_pushboolean(L, 1656 | PQbinaryTuples(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1657 | return 1; 1658 | } 1659 | 1660 | static int 1661 | res_getvalue(lua_State *L) 1662 | { 1663 | lua_pushstring(L, 1664 | PQgetvalue(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1665 | luaL_checkinteger(L, 2) - 1, luaL_checkinteger(L, 3) - 1)); 1666 | return 1; 1667 | } 1668 | 1669 | static int 1670 | res_getisnull(lua_State *L) 1671 | { 1672 | lua_pushboolean(L, 1673 | PQgetisnull(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1674 | luaL_checkinteger(L, 2) - 1, luaL_checkinteger(L, 3) - 1)); 1675 | return 1; 1676 | } 1677 | 1678 | static int 1679 | res_getlength(lua_State *L) 1680 | { 1681 | lua_pushinteger(L, 1682 | PQgetlength(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1683 | luaL_checkinteger(L, 2) - 1, luaL_checkinteger(L, 3) - 1)); 1684 | return 1; 1685 | } 1686 | 1687 | static int 1688 | res_nparams(lua_State *L) 1689 | { 1690 | lua_pushinteger(L, 1691 | PQnparams(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1692 | return 1; 1693 | } 1694 | 1695 | static int 1696 | res_paramtype(lua_State *L) 1697 | { 1698 | lua_pushinteger(L, 1699 | PQparamtype(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE), 1700 | luaL_checkinteger(L, 2)) - 1); 1701 | return 1; 1702 | } 1703 | 1704 | static int 1705 | res_cmdStatus(lua_State *L) 1706 | { 1707 | lua_pushstring(L, 1708 | PQcmdStatus(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1709 | return 1; 1710 | } 1711 | 1712 | static int 1713 | res_cmdTuples(lua_State *L) 1714 | { 1715 | lua_pushstring(L, 1716 | PQcmdTuples(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1717 | return 1; 1718 | } 1719 | 1720 | static int 1721 | res_oidValue(lua_State *L) 1722 | { 1723 | lua_pushinteger(L, 1724 | PQoidValue(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1725 | return 1; 1726 | } 1727 | 1728 | static int 1729 | res_oidStatus(lua_State *L) 1730 | { 1731 | lua_pushstring(L, 1732 | PQoidStatus(*(PGresult **)luaL_checkudata(L, 1, RES_METATABLE))); 1733 | return 1; 1734 | } 1735 | 1736 | /* Lua specific functions */ 1737 | static int 1738 | res_copy(lua_State *L) 1739 | { 1740 | PGresult *res = *(PGresult **)luaL_checkudata(L, 1, RES_METATABLE); 1741 | int row, col, convert; 1742 | 1743 | convert = 0; /* Do not convert numeric types */ 1744 | 1745 | if (lua_gettop(L) == 2) 1746 | convert = lua_toboolean(L, 2); 1747 | 1748 | lua_newtable(L); 1749 | for (row = 0; row < PQntuples(res); row++) { 1750 | lua_pushinteger(L, row + 1); 1751 | lua_newtable(L); 1752 | for (col = 0; col < PQnfields(res); col++) { 1753 | if (convert) 1754 | switch (PQftype(res, col)) { 1755 | case BOOLOID: 1756 | lua_pushboolean(L, 1757 | strcmp(PQgetvalue(res, row, col), 1758 | "f")); 1759 | break; 1760 | case INT2OID: 1761 | case INT4OID: 1762 | case INT8OID: 1763 | lua_pushinteger(L, 1764 | atol(PQgetvalue(res, row, col))); 1765 | break; 1766 | case FLOAT4OID: 1767 | case FLOAT8OID: 1768 | case NUMERICOID: 1769 | lua_pushnumber(L, 1770 | atof(PQgetvalue(res, row, col))); 1771 | break; 1772 | default: 1773 | lua_pushstring(L, 1774 | PQgetvalue(res, row, col)); 1775 | } 1776 | else 1777 | lua_pushstring(L, PQgetvalue(res, row, col)); 1778 | lua_setfield(L, -2, PQfname(res, col)); 1779 | } 1780 | lua_settable(L, -3); 1781 | } 1782 | return 1; 1783 | } 1784 | 1785 | static int 1786 | res_fields_iterator(lua_State *L) 1787 | { 1788 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 1789 | int n; 1790 | 1791 | t->row++; 1792 | 1793 | luaL_checkstack(L, PQnfields(t->res), "out of stack space"); 1794 | if (t->row == PQntuples(t->res)) 1795 | for (n = 0; n < PQnfields(t->res); n++) 1796 | lua_pushnil(L); 1797 | else 1798 | for (n = 0; n < PQnfields(t->res); n++) 1799 | lua_pushstring(L, PQgetvalue(t->res, t->row, n)); 1800 | return PQnfields(t->res); 1801 | } 1802 | 1803 | static int 1804 | res_fields(lua_State *L) 1805 | { 1806 | tuple *t; 1807 | 1808 | lua_pushcfunction(L, res_fields_iterator); 1809 | t = lua_newuserdata(L, sizeof(tuple)); 1810 | luaL_setmetatable(L, TUPLE_METATABLE); 1811 | t->res = *(PGresult **)luaL_checkudata(L, 1, RES_METATABLE); 1812 | t->row = -1; 1813 | return 2; 1814 | } 1815 | 1816 | static int 1817 | res_tuples_iterator(lua_State *L) 1818 | { 1819 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 1820 | 1821 | t->row++; 1822 | 1823 | if (t->row == PQntuples(t->res)) { 1824 | lua_pushnil(L); 1825 | lua_pushnil(L); 1826 | } else { 1827 | lua_pushvalue(L, 1); 1828 | lua_pushinteger(L, t->row + 1); 1829 | } 1830 | return 2; 1831 | } 1832 | 1833 | static int 1834 | res_tuples(lua_State *L) 1835 | { 1836 | PGresult **res; 1837 | tuple *t; 1838 | 1839 | res = (PGresult **)luaL_checkudata(L, 1, RES_METATABLE); 1840 | 1841 | lua_pushcfunction(L, res_tuples_iterator); 1842 | t = lua_newuserdata(L, sizeof(tuple)); 1843 | luaL_setmetatable(L, TUPLE_METATABLE); 1844 | t->res = *res; 1845 | t->row = -1; 1846 | return 2; 1847 | } 1848 | 1849 | static int 1850 | res_index(lua_State *L) 1851 | { 1852 | if (lua_type(L, -1) == LUA_TNUMBER) { 1853 | tuple *t; 1854 | PGresult *res; 1855 | int row; 1856 | 1857 | res = *(PGresult **)luaL_checkudata(L, 1, RES_METATABLE); 1858 | row = luaL_checkinteger(L, 2) - 1; 1859 | 1860 | if (row < 0 || row >= PQntuples(res)) 1861 | lua_pushnil(L); 1862 | else { 1863 | t = lua_newuserdata(L, sizeof(tuple)); 1864 | t->res = res; 1865 | t->row = row; 1866 | luaL_setmetatable(L, TUPLE_METATABLE); 1867 | } 1868 | } else { 1869 | const char *nam; 1870 | 1871 | nam = lua_tostring(L, -1); 1872 | if (lua_getmetatable(L, -2)) { 1873 | lua_pushstring(L, nam); 1874 | lua_rawget(L, -2); 1875 | } else 1876 | lua_pushnil(L); 1877 | } 1878 | return 1; 1879 | } 1880 | 1881 | static int 1882 | res_clear(lua_State *L) 1883 | { 1884 | PGresult **r; 1885 | 1886 | r = luaL_checkudata(L, 1, RES_METATABLE); 1887 | if (*r) { 1888 | PQclear(*r); 1889 | *r = NULL; 1890 | } 1891 | return 0; 1892 | } 1893 | 1894 | /* 1895 | * Notifies methods (objects returned by conn:notifies()) 1896 | */ 1897 | static int 1898 | notify_relname(lua_State *L) 1899 | { 1900 | PGnotify **n; 1901 | 1902 | n = luaL_checkudata(L, 1, NOTIFY_METATABLE); 1903 | lua_pushstring(L, (*n)->relname); 1904 | return 1; 1905 | } 1906 | 1907 | static int 1908 | notify_pid(lua_State *L) 1909 | { 1910 | PGnotify **n; 1911 | 1912 | n = luaL_checkudata(L, 1, NOTIFY_METATABLE); 1913 | lua_pushinteger(L, (*n)->be_pid); 1914 | return 1; 1915 | } 1916 | 1917 | static int 1918 | notify_extra(lua_State *L) 1919 | { 1920 | PGnotify **n; 1921 | 1922 | n = luaL_checkudata(L, 1, NOTIFY_METATABLE); 1923 | lua_pushstring(L, (*n)->extra); 1924 | return 1; 1925 | } 1926 | 1927 | static int 1928 | notify_clear(lua_State *L) 1929 | { 1930 | PGnotify **n; 1931 | 1932 | n = luaL_checkudata(L, 1, NOTIFY_METATABLE); 1933 | if (*n) { 1934 | PQfreemem(*n); 1935 | *n = NULL; 1936 | } 1937 | return 0; 1938 | } 1939 | 1940 | /* 1941 | * Tuple and value functions 1942 | */ 1943 | static int 1944 | tuple_copy(lua_State *L) 1945 | { 1946 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 1947 | int col, rv = 0; 1948 | 1949 | if (lua_gettop(L) > 1) { 1950 | if (!lua_istable(L, 2)) { 1951 | if (!lua_getmetatable(L, 2)) 1952 | return luaL_error(L, "argument has no " 1953 | "metatable"); 1954 | 1955 | if (lua_getfield(L, -1, "__newindex") == LUA_TNIL) 1956 | return luaL_error(L, "metatable has no " 1957 | "__newindex metamethod"); 1958 | lua_pop(L, 2); 1959 | } 1960 | } else { 1961 | lua_newtable(L); 1962 | rv = 1; 1963 | } 1964 | for (col = 0; col < PQnfields(t->res); col++) { 1965 | lua_pushstring(L, PQgetvalue(t->res, t->row, col)); 1966 | lua_setfield(L, -2, PQfname(t->res, col)); 1967 | } 1968 | return rv; 1969 | } 1970 | 1971 | static int 1972 | field_iterator(lua_State *L) 1973 | { 1974 | field *f = luaL_checkudata(L, 1, FIELD_METATABLE); 1975 | 1976 | f->col++; 1977 | 1978 | if (f->col == PQnfields(f->tuple->res)) { 1979 | lua_pushnil(L); 1980 | lua_pushnil(L); 1981 | } else { 1982 | lua_pushstring(L, PQfname(f->tuple->res, f->col)); 1983 | lua_pushstring(L, 1984 | PQgetvalue(f->tuple->res, f->tuple->row, f->col)); 1985 | } 1986 | return 2; 1987 | } 1988 | 1989 | static int 1990 | tuple_getfields(lua_State *L) 1991 | { 1992 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 1993 | field *f; 1994 | 1995 | lua_pushcfunction(L, field_iterator); 1996 | f = lua_newuserdata(L, sizeof(field)); 1997 | f->tuple = t; 1998 | f->col = -1; 1999 | luaL_setmetatable(L, FIELD_METATABLE); 2000 | return 2; 2001 | } 2002 | 2003 | static int 2004 | tuple_getisnull(lua_State *L) 2005 | { 2006 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 2007 | const char *fnam; 2008 | int fnumber; 2009 | 2010 | switch (lua_type(L, 2)) { 2011 | case LUA_TNUMBER: 2012 | fnumber = lua_tointeger(L, 2) - 1; 2013 | if (fnumber < 0 || fnumber >= PQnfields(t->res)) 2014 | lua_pushnil(L); 2015 | else 2016 | lua_pushboolean(L, PQgetisnull(t->res, t->row, 2017 | lua_tointeger(L, 2) - 1)); 2018 | break; 2019 | case LUA_TSTRING: 2020 | fnam = lua_tostring(L, 2); 2021 | fnumber = PQfnumber(t->res, fnam); 2022 | 2023 | if (fnumber == -1) 2024 | lua_pushnil(L); 2025 | else 2026 | lua_pushboolean(L, PQgetisnull(t->res, t->row, 2027 | PQfnumber(t->res, lua_tostring(L, 2)))); 2028 | break; 2029 | default: 2030 | lua_pushnil(L); 2031 | } 2032 | return 1; 2033 | } 2034 | 2035 | static int 2036 | tuple_getlength(lua_State *L) 2037 | { 2038 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 2039 | const char *fnam; 2040 | int fnumber; 2041 | 2042 | switch (lua_type(L, 2)) { 2043 | case LUA_TNUMBER: 2044 | fnumber = lua_tointeger(L, 2) - 1; 2045 | if (fnumber < 0 || fnumber >= PQnfields(t->res)) 2046 | lua_pushnil(L); 2047 | else 2048 | lua_pushinteger(L, PQgetlength(t->res, t->row, 2049 | lua_tointeger(L, 2) - 1)); 2050 | break; 2051 | case LUA_TSTRING: 2052 | fnam = lua_tostring(L, 2); 2053 | fnumber = PQfnumber(t->res, fnam); 2054 | 2055 | if (fnumber == -1) 2056 | lua_pushnil(L); 2057 | else 2058 | lua_pushinteger(L, PQgetlength(t->res, t->row, 2059 | PQfnumber(t->res, lua_tostring(L, 2)))); 2060 | break; 2061 | default: 2062 | lua_pushnil(L); 2063 | } 2064 | return 1; 2065 | } 2066 | 2067 | static int 2068 | tuple_index(lua_State *L) 2069 | { 2070 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 2071 | const char *fnam; 2072 | int fnumber; 2073 | 2074 | switch (lua_type(L, 2)) { 2075 | case LUA_TNUMBER: 2076 | fnumber = lua_tointeger(L, 2) - 1; 2077 | if (fnumber < 0 || fnumber >= PQnfields(t->res)) 2078 | lua_pushnil(L); 2079 | else 2080 | lua_pushstring(L, PQgetvalue(t->res, t->row, fnumber)); 2081 | break; 2082 | case LUA_TSTRING: 2083 | fnam = lua_tostring(L, 2); 2084 | fnumber = PQfnumber(t->res, fnam); 2085 | 2086 | if (fnumber == -1) { 2087 | if (!strcmp(fnam, "copy")) 2088 | lua_pushcfunction(L, tuple_copy); 2089 | else if (!strcmp(fnam, "getfields")) 2090 | lua_pushcfunction(L, tuple_getfields); 2091 | else if (!strcmp(fnam, "getisnull")) 2092 | lua_pushcfunction(L, tuple_getisnull); 2093 | else if (!strcmp(fnam, "getlength")) 2094 | lua_pushcfunction(L, tuple_getlength); 2095 | else 2096 | lua_pushnil(L); 2097 | } else 2098 | lua_pushstring(L, PQgetvalue(t->res, t->row, 2099 | PQfnumber(t->res, fnam))); 2100 | break; 2101 | default: 2102 | lua_pushnil(L); 2103 | } 2104 | return 1; 2105 | } 2106 | 2107 | static int 2108 | tuple_length(lua_State *L) 2109 | { 2110 | tuple *t = luaL_checkudata(L, 1, TUPLE_METATABLE); 2111 | 2112 | lua_pushinteger(L, PQnfields(t->res)); 2113 | return 1; 2114 | } 2115 | 2116 | /* 2117 | * Module definitions, constants etc. 2118 | */ 2119 | struct constant { 2120 | char *name; 2121 | int value; 2122 | }; 2123 | 2124 | static struct constant pgsql_constant[] = { 2125 | /* Connection status */ 2126 | { "CONNECTION_STARTED", CONNECTION_STARTED }, 2127 | { "CONNECTION_MADE", CONNECTION_MADE }, 2128 | { "CONNECTION_AWAITING_RESPONSE", CONNECTION_AWAITING_RESPONSE }, 2129 | { "CONNECTION_AUTH_OK", CONNECTION_AUTH_OK }, 2130 | { "CONNECTION_OK", CONNECTION_OK }, 2131 | { "CONNECTION_SSL_STARTUP", CONNECTION_SSL_STARTUP }, 2132 | { "CONNECTION_SETENV", CONNECTION_SETENV }, 2133 | { "CONNECTION_BAD", CONNECTION_BAD }, 2134 | #if PG_VERSION_NUM >= 100000 2135 | { "CONNECTION_CONSUME", CONNECTION_CONSUME }, 2136 | #endif 2137 | /* Resultset status codes */ 2138 | { "PGRES_EMPTY_QUERY", PGRES_EMPTY_QUERY }, 2139 | { "PGRES_COMMAND_OK", PGRES_COMMAND_OK }, 2140 | { "PGRES_TUPLES_OK", PGRES_TUPLES_OK }, 2141 | #if PG_VERSION_NUM >= 140000 2142 | { "PGRES_PIPELINE_SYNC", PGRES_PIPELINE_SYNC }, 2143 | { "PGRES_PIPELINE_ABORTED", PGRES_PIPELINE_ABORTED }, 2144 | #endif 2145 | #if PG_VERSION_NUM >= 90200 2146 | { "PGRES_SINGLE_TUPLE", PGRES_SINGLE_TUPLE }, 2147 | #endif 2148 | { "PGRES_COPY_OUT", PGRES_COPY_OUT }, 2149 | { "PGRES_COPY_IN", PGRES_COPY_IN }, 2150 | #if PG_VERSION_NUM >= 90100 2151 | { "PGRES_COPY_BOTH", PGRES_COPY_BOTH }, 2152 | { "PGRES_SINGLE_TUPLE", PGRES_SINGLE_TUPLE }, 2153 | #endif 2154 | { "PGRES_BAD_RESPONSE", PGRES_BAD_RESPONSE }, 2155 | { "PGRES_NONFATAL_ERROR", PGRES_NONFATAL_ERROR }, 2156 | { "PGRES_FATAL_ERROR", PGRES_FATAL_ERROR }, 2157 | 2158 | /* Polling status */ 2159 | { "PGRES_POLLING_FAILED", PGRES_POLLING_FAILED }, 2160 | { "PGRES_POLLING_READING", PGRES_POLLING_READING }, 2161 | { "PGRES_POLLING_WRITING", PGRES_POLLING_WRITING }, 2162 | { "PGRES_POLLING_OK", PGRES_POLLING_OK }, 2163 | 2164 | /* Transaction status */ 2165 | { "PQTRANS_IDLE", PQTRANS_IDLE }, 2166 | { "PQTRANS_ACTIVE", PQTRANS_ACTIVE }, 2167 | { "PQTRANS_INTRANS", PQTRANS_INTRANS }, 2168 | { "PQTRANS_INERROR", PQTRANS_INERROR }, 2169 | { "PQTRANS_UNKNOWN", PQTRANS_UNKNOWN }, 2170 | 2171 | /* Diagnostic codes */ 2172 | { "PG_DIAG_SEVERITY", PG_DIAG_SEVERITY }, 2173 | { "PG_DIAG_SQLSTATE", PG_DIAG_SQLSTATE }, 2174 | { "PG_DIAG_MESSAGE_PRIMARY", PG_DIAG_MESSAGE_PRIMARY }, 2175 | { "PG_DIAG_MESSAGE_DETAIL", PG_DIAG_MESSAGE_DETAIL }, 2176 | { "PG_DIAG_MESSAGE_HINT", PG_DIAG_MESSAGE_HINT }, 2177 | { "PG_DIAG_STATEMENT_POSITION", PG_DIAG_STATEMENT_POSITION }, 2178 | { "PG_DIAG_INTERNAL_POSITION", PG_DIAG_INTERNAL_POSITION }, 2179 | { "PG_DIAG_INTERNAL_QUERY", PG_DIAG_INTERNAL_QUERY }, 2180 | { "PG_DIAG_CONTEXT", PG_DIAG_CONTEXT }, 2181 | { "PG_DIAG_SOURCE_FILE", PG_DIAG_SOURCE_FILE }, 2182 | { "PG_DIAG_SOURCE_LINE", PG_DIAG_SOURCE_LINE }, 2183 | { "PG_DIAG_SOURCE_FUNCTION", PG_DIAG_SOURCE_FUNCTION }, 2184 | 2185 | /* Error verbosity */ 2186 | { "PQERRORS_TERSE", PQERRORS_TERSE }, 2187 | { "PQERRORS_DEFAULT", PQERRORS_DEFAULT }, 2188 | { "PQERRORS_VERBOSE", PQERRORS_VERBOSE }, 2189 | 2190 | #if PG_VERSION_NUM >= 140000 2191 | /* Pipeline mode */ 2192 | { "PQ_PIPELINE_ON", PQ_PIPELINE_ON }, 2193 | { "PQ_PIPELINE_OFF", PQ_PIPELINE_OFF }, 2194 | { "PQ_PIPELINE_ABORTED", PQ_PIPELINE_ABORTED }, 2195 | #endif 2196 | 2197 | #if PG_VERSION_NUM >= 90100 2198 | /* PQping codes */ 2199 | { "PQPING_OK", PQPING_OK }, 2200 | { "PQPING_REJECT", PQPING_REJECT }, 2201 | { "PQPING_NO_RESPONSE", PQPING_NO_RESPONSE }, 2202 | { "PQPING_NO_ATTEMPT", PQPING_NO_ATTEMPT }, 2203 | #endif 2204 | 2205 | /* Large objects */ 2206 | { "INV_READ", INV_READ }, 2207 | { "INV_WRITE", INV_WRITE }, 2208 | { "SEEK_CUR", SEEK_CUR }, 2209 | { "SEEK_END", SEEK_END }, 2210 | { "SEEK_SET", SEEK_SET }, 2211 | 2212 | /* Miscellaneous values */ 2213 | { "InvalidOid", InvalidOid }, 2214 | 2215 | { NULL, 0 } 2216 | }; 2217 | 2218 | static void 2219 | pgsql_set_info(lua_State *L) 2220 | { 2221 | lua_pushliteral(L, "_COPYRIGHT"); 2222 | lua_pushliteral(L, "Copyright (C) 2009 - 2023 by " 2223 | "micro systems marc balmer"); 2224 | lua_settable(L, -3); 2225 | lua_pushliteral(L, "_DESCRIPTION"); 2226 | lua_pushliteral(L, "PostgreSQL binding for Lua"); 2227 | lua_settable(L, -3); 2228 | lua_pushliteral(L, "_VERSION"); 2229 | lua_pushliteral(L, "pgsql 1.7.1"); 2230 | lua_settable(L, -3); 2231 | } 2232 | 2233 | int 2234 | luaopen_pgsql(lua_State *L) 2235 | { 2236 | int n; 2237 | struct luaL_Reg luapgsql[] = { 2238 | /* Database Connection Control Functions */ 2239 | { "connectdb", pgsql_connectdb }, 2240 | { "connectStart", pgsql_connectStart }, 2241 | { "libVersion", pgsql_libVersion }, 2242 | #if PG_VERSION_NUM >= 90100 2243 | { "ping", pgsql_ping }, 2244 | #endif 2245 | { "encryptPassword", pgsql_encryptPassword }, 2246 | { "unescapeBytea", pgsql_unescapeBytea }, 2247 | 2248 | /* SSL support */ 2249 | { "initOpenSSL", pgsql_initOpenSSL }, 2250 | { NULL, NULL } 2251 | }; 2252 | 2253 | struct luaL_Reg conn_methods[] = { 2254 | /* Database Connection Control Functions */ 2255 | { "connectPoll", pgsql_connectPoll }, 2256 | { "finish", conn_finish }, 2257 | { "reset", conn_reset }, 2258 | { "resetStart", conn_resetStart }, 2259 | { "resetPoll", conn_resetPoll }, 2260 | 2261 | /* Connection Status Functions */ 2262 | { "db", conn_db }, 2263 | { "user", conn_user }, 2264 | { "pass", conn_pass }, 2265 | { "host", conn_host }, 2266 | { "port", conn_port }, 2267 | { "tty", conn_tty }, 2268 | { "options", conn_options }, 2269 | { "status", conn_status }, 2270 | { "transactionStatus", conn_transactionStatus }, 2271 | { "parameterStatus", conn_parameterStatus }, 2272 | { "protocolVersion", conn_protocolVersion }, 2273 | { "serverVersion", conn_serverVersion }, 2274 | { "errorMessage", conn_errorMessage }, 2275 | { "socket", conn_socket }, 2276 | { "backendPID", conn_backendPID }, 2277 | { "connectionNeedsPassword", conn_connectionNeedsPassword }, 2278 | { "connectionUsedPassword", conn_connectionUsedPassword }, 2279 | #if PG_VERSION_NUM >= 90500 2280 | { "sslInUse", conn_sslInUse }, 2281 | { "sslAttribute", conn_sslAttribute }, 2282 | { "sslAttributeNames", conn_sslAttributeNames }, 2283 | #endif 2284 | 2285 | /* Command Execution Functions */ 2286 | { "escapeString", conn_escapeString }, 2287 | { "escapeLiteral", conn_escapeLiteral }, 2288 | { "escapeIdentifier", conn_escapeIdentifier }, 2289 | { "escapeBytea", conn_escapeBytea }, 2290 | { "exec", conn_exec }, 2291 | { "execParams", conn_execParams }, 2292 | { "prepare", conn_prepare }, 2293 | { "execPrepared", conn_execPrepared }, 2294 | { "describePrepared", conn_describePrepared }, 2295 | { "describePortal", conn_describePortal }, 2296 | 2297 | /* Asynchronous command processing */ 2298 | { "sendQuery", conn_sendQuery }, 2299 | { "sendQueryParams", conn_sendQueryParams }, 2300 | { "sendPrepare", conn_sendPrepare }, 2301 | { "sendQueryPrepared", conn_sendQueryPrepared }, 2302 | { "sendDescribePrepared", conn_sendDescribePrepared }, 2303 | { "sendDescribePortal", conn_sendDescribePortal }, 2304 | { "getResult", conn_getResult }, 2305 | { "cancel", conn_cancel }, 2306 | 2307 | #if PG_VERSION_NUM >= 140000 2308 | /* Pipeline mode */ 2309 | { "pipelineStatus", conn_pipelineStatus }, 2310 | { "enterPipelineMode", conn_enterPipelineMode }, 2311 | { "exitPipelineMode", conn_exitPipelineMode }, 2312 | { "pipelineSync", conn_pipelineSync }, 2313 | { "sendFlushRequest", conn_sendFlushRequest }, 2314 | #endif 2315 | 2316 | #if PG_VERSION_NUM >= 90200 2317 | /* Retrieving query results row-by-row */ 2318 | { "setSingleRowMode", conn_setSingleRowMode }, 2319 | #endif 2320 | 2321 | /* Asynchronous Notifications Functions */ 2322 | { "notifies", conn_notifies }, 2323 | 2324 | /* Function associated with the COPY command */ 2325 | { "putCopyData", conn_putCopyData }, 2326 | { "putCopyEnd", conn_putCopyEnd }, 2327 | { "getCopyData", conn_getCopyData }, 2328 | 2329 | /* Control Functions */ 2330 | { "clientEncoding", conn_clientEncoding }, 2331 | { "setClientEncoding", conn_setClientEncoding }, 2332 | { "setErrorVerbosity", conn_setErrorVerbosity }, 2333 | { "trace", conn_trace }, 2334 | { "untrace", conn_untrace }, 2335 | 2336 | /* Miscellaneous Functions */ 2337 | { "consumeInput", conn_consumeInput }, 2338 | { "isBusy", conn_isBusy }, 2339 | { "setnonblocking", conn_setnonblocking }, 2340 | { "isnonblocking", conn_isnonblocking }, 2341 | { "flush", conn_flush }, 2342 | #if PG_VERSION_NUM >= 100000 2343 | { "encryptPassword", conn_encryptPassword }, 2344 | #endif 2345 | /* Notice processing */ 2346 | { "setNoticeReceiver", conn_setNoticeReceiver }, 2347 | { "setNoticeProcessor", conn_setNoticeProcessor }, 2348 | 2349 | /* Large Objects */ 2350 | { "lo_create", conn_lo_create }, 2351 | { "lo_import", conn_lo_import }, 2352 | { "lo_import_with_oid", conn_lo_import_with_oid }, 2353 | { "lo_export", conn_lo_export }, 2354 | { "lo_open", conn_lo_open }, 2355 | { "lo_write", conn_lo_write }, 2356 | { "lo_read", conn_lo_read }, 2357 | { "lo_lseek", conn_lo_lseek }, 2358 | { "lo_tell", conn_lo_tell }, 2359 | { "lo_truncate", conn_lo_truncate }, 2360 | { "lo_close", conn_lo_close }, 2361 | { "lo_unlink", conn_lo_unlink }, 2362 | #if PG_VERSION_NUM >= 90300 2363 | { "lo_lseek64", conn_lo_lseek64 }, 2364 | { "lo_tell64", conn_lo_tell64 }, 2365 | { "lo_truncate64", conn_lo_truncate64 }, 2366 | #endif 2367 | { NULL, NULL } 2368 | }; 2369 | struct luaL_Reg res_methods[] = { 2370 | /* Main functions */ 2371 | { "status", res_status }, 2372 | { "resStatus", res_resStatus }, 2373 | { "errorMessage", res_errorMessage }, 2374 | { "errorField", res_errorField }, 2375 | 2376 | /* Retrieving query result information */ 2377 | { "ntuples", res_ntuples }, 2378 | { "nfields", res_nfields }, 2379 | { "fname", res_fname }, 2380 | { "fnumber", res_fnumber }, 2381 | { "ftable", res_ftable }, 2382 | { "ftablecol", res_ftablecol }, 2383 | { "fformat", res_fformat }, 2384 | { "ftype", res_ftype }, 2385 | { "fmod", res_fmod }, 2386 | { "fsize", res_fsize }, 2387 | { "binaryTuples", res_binaryTuples }, 2388 | { "getvalue", res_getvalue }, 2389 | { "getisnull", res_getisnull }, 2390 | { "getlength", res_getlength }, 2391 | { "nparams", res_nparams }, 2392 | { "paramtype", res_paramtype }, 2393 | 2394 | /* Other result information */ 2395 | { "cmdStatus", res_cmdStatus }, 2396 | { "cmdTuples", res_cmdTuples }, 2397 | { "oidValue", res_oidValue }, 2398 | { "oidStatus", res_oidStatus }, 2399 | 2400 | /* Lua specific extension */ 2401 | { "copy", res_copy }, 2402 | { "fields", res_fields }, 2403 | { "tuples", res_tuples }, 2404 | { "clear", res_clear }, 2405 | { NULL, NULL } 2406 | }; 2407 | struct luaL_Reg notify_methods[] = { 2408 | { "relname", notify_relname }, 2409 | { "pid", notify_pid }, 2410 | { "extra", notify_extra }, 2411 | { NULL, NULL } 2412 | }; 2413 | if (luaL_newmetatable(L, CONN_METATABLE)) { 2414 | #if LUA_VERSION_NUM >= 502 2415 | luaL_setfuncs(L, conn_methods, 0); 2416 | #else 2417 | luaL_register(L, NULL, conn_methods); 2418 | #endif 2419 | lua_pushliteral(L, "__gc"); 2420 | lua_pushcfunction(L, conn_finish); 2421 | lua_settable(L, -3); 2422 | 2423 | lua_pushliteral(L, "__index"); 2424 | lua_pushvalue(L, -2); 2425 | lua_settable(L, -3); 2426 | 2427 | lua_pushliteral(L, "__metatable"); 2428 | lua_pushliteral(L, "must not access this metatable"); 2429 | lua_settable(L, -3); 2430 | } 2431 | lua_pop(L, 1); 2432 | 2433 | if (luaL_newmetatable(L, RES_METATABLE)) { 2434 | #if LUA_VERSION_NUM >= 502 2435 | luaL_setfuncs(L, res_methods, 0); 2436 | #else 2437 | luaL_register(L, NULL, res_methods); 2438 | #endif 2439 | lua_pushliteral(L, "__gc"); 2440 | lua_pushcfunction(L, res_clear); 2441 | lua_settable(L, -3); 2442 | 2443 | #if LUA_VERSION_NUM >= 504 2444 | lua_pushliteral(L, "__close"); 2445 | lua_pushcfunction(L, res_clear); 2446 | lua_settable(L, -3); 2447 | #endif 2448 | lua_pushliteral(L, "__index"); 2449 | lua_pushcfunction(L, res_index); 2450 | lua_settable(L, -3); 2451 | 2452 | lua_pushliteral(L, "__len"); 2453 | lua_pushcfunction(L, res_ntuples); 2454 | lua_settable(L, -3); 2455 | 2456 | lua_pushliteral(L, "__metatable"); 2457 | lua_pushliteral(L, "must not access this metatable"); 2458 | lua_settable(L, -3); 2459 | } 2460 | lua_pop(L, 1); 2461 | 2462 | if (luaL_newmetatable(L, NOTIFY_METATABLE)) { 2463 | #if LUA_VERSION_NUM >= 502 2464 | luaL_setfuncs(L, notify_methods, 0); 2465 | #else 2466 | luaL_register(L, NULL, notify_methods); 2467 | #endif 2468 | lua_pushliteral(L, "__gc"); 2469 | lua_pushcfunction(L, notify_clear); 2470 | lua_settable(L, -3); 2471 | 2472 | #if LUA_VERSION_NUM >= 504 2473 | lua_pushliteral(L, "__close"); 2474 | lua_pushcfunction(L, notify_clear); 2475 | lua_settable(L, -3); 2476 | #endif 2477 | 2478 | lua_pushliteral(L, "__index"); 2479 | lua_pushvalue(L, -2); 2480 | lua_settable(L, -3); 2481 | 2482 | lua_pushliteral(L, "__metatable"); 2483 | lua_pushliteral(L, "must not access this metatable"); 2484 | lua_settable(L, -3); 2485 | } 2486 | lua_pop(L, 1); 2487 | 2488 | if (luaL_newmetatable(L, TUPLE_METATABLE)) { 2489 | lua_pushliteral(L, "__index"); 2490 | lua_pushcfunction(L, tuple_index); 2491 | lua_settable(L, -3); 2492 | 2493 | lua_pushliteral(L, "__len"); 2494 | lua_pushcfunction(L, tuple_length); 2495 | lua_settable(L, -3); 2496 | 2497 | lua_pushliteral(L, "__metatable"); 2498 | lua_pushliteral(L, "must not access this metatable"); 2499 | lua_settable(L, -3); 2500 | } 2501 | lua_pop(L, 1); 2502 | 2503 | if (luaL_newmetatable(L, FIELD_METATABLE)) { 2504 | lua_pushliteral(L, "__metatable"); 2505 | lua_pushliteral(L, "must not access this metatable"); 2506 | lua_settable(L, -3); 2507 | } 2508 | lua_pop(L, 1); 2509 | 2510 | if (luaL_newmetatable(L, GCMEM_METATABLE)) { 2511 | lua_pushliteral(L, "__gc"); 2512 | lua_pushcfunction(L, gcmem_clear); 2513 | lua_settable(L, -3); 2514 | } 2515 | lua_pop(L, 1); 2516 | 2517 | #if LUA_VERSION_NUM >= 502 2518 | luaL_newlib(L, luapgsql); 2519 | #else 2520 | luaL_register(L, "pgsql", luapgsql); 2521 | #endif 2522 | pgsql_set_info(L); 2523 | for (n = 0; pgsql_constant[n].name != NULL; n++) { 2524 | lua_pushinteger(L, pgsql_constant[n].value); 2525 | lua_setfield(L, -2, pgsql_constant[n].name); 2526 | }; 2527 | 2528 | return 1; 2529 | } 2530 | -------------------------------------------------------------------------------- /luapgsql.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2009 - 2017, Micro Systems Marc Balmer, CH-5073 Gipf-Oberfrick 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * * Redistributions of source code must retain the above copyright 8 | * notice, this list of conditions and the following disclaimer. 9 | * * Redistributions in binary form must reproduce the above copyright 10 | * notice, this list of conditions and the following disclaimer in the 11 | * documentation and/or other materials provided with the distribution. 12 | * * Neither the name of Micro Systems Marc Balmer nor the 13 | * names of its contributors may be used to endorse or promote products 14 | * derived from this software without specific prior written permission. 15 | * 16 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 | * ARE DISCLAIMED. IN NO EVENT SHALL BE LIABLE FOR ANY 20 | * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 21 | * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 23 | * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 | * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | */ 27 | 28 | /* Lua binding for PostgreSQL */ 29 | 30 | #ifndef __LUAPGSQL_H__ 31 | #define __LUAPGSQL_H__ 32 | 33 | #define CONN_METATABLE "pgsql connection" 34 | #define RES_METATABLE "pgsql result" 35 | #define TUPLE_METATABLE "pgsql tuple" 36 | #define FIELD_METATABLE "pgsql tuple field" 37 | #define NOTIFY_METATABLE "pgsql asynchronous notification" 38 | #define GCMEM_METATABLE "pgsql garbage collected memory" 39 | 40 | /* OIDs from server/pg_type.h */ 41 | #define BOOLOID 16 42 | #define INT8OID 20 43 | #define INT2OID 21 44 | #define INT4OID 23 45 | #define TEXTOID 25 46 | #define FLOAT4OID 700 47 | #define FLOAT8OID 701 48 | #define NUMERICOID 1700 49 | 50 | typedef struct tuple { 51 | PGresult *res; 52 | int row; 53 | } tuple; 54 | 55 | typedef struct field { 56 | tuple *tuple; 57 | int col; 58 | } field; 59 | 60 | typedef struct notice { 61 | lua_State *L; 62 | int f; 63 | } notice; 64 | 65 | #endif /* __LUAPGSQL_H__ */ 66 | -------------------------------------------------------------------------------- /notice.lua: -------------------------------------------------------------------------------- 1 | -- Testing notice processor and notice receiver functions 2 | 3 | local pgsql = require 'pgsql' 4 | 5 | local conn1 = pgsql.connectdb('') 6 | if conn1:status() == pgsql.CONNECTION_OK then 7 | print('connection 1 is ok') 8 | else 9 | print('connection 1 is not ok') 10 | print(conn1:errorMessage()) 11 | end 12 | 13 | local conn2 = pgsql.connectdb('') 14 | if conn2:status() == pgsql.CONNECTION_OK then 15 | print('connection 2 is ok') 16 | else 17 | print('connection 2 is not ok') 18 | print(conn2:errorMessage()) 19 | end 20 | 21 | local function noticeProcessor1(msg) 22 | print('This is notice processor 1') 23 | print(msg) 24 | end 25 | 26 | local function noticeProcessor2(msg) 27 | print('This is notice processor 2') 28 | print(msg) 29 | end 30 | 31 | conn1:setNoticeProcessor(noticeProcessor1) 32 | conn2:setNoticeProcessor(noticeProcessor2) 33 | 34 | local res = conn1:exec("do $$ begin raise notice '1st notice on conn1'; end $$") 35 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 36 | print(conn1:errorMessage()) 37 | end 38 | 39 | res = conn2:exec("do $$ begin raise notice '1st notice on conn2'; end $$") 40 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 41 | print(conn2:errorMessage()) 42 | end 43 | 44 | local function noticeReceiver1(res) 45 | print('This is notice receiver 1') 46 | print(res:errorMessage()) 47 | end 48 | 49 | local function noticeReceiver2(res) 50 | print('This is notice receiver 2') 51 | print(res:errorMessage()) 52 | end 53 | 54 | conn1:setNoticeReceiver(noticeReceiver1) 55 | conn2:setNoticeReceiver(noticeReceiver2) 56 | 57 | res = conn1:exec("do $$ begin raise notice '2nd notice on conn1'; end $$") 58 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 59 | print(conn1:errorMessage()) 60 | end 61 | 62 | res = conn2:exec("do $$ begin raise notice '2nd notice on conn2'; end $$") 63 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 64 | print(conn2:errorMessage()) 65 | end 66 | 67 | 68 | print('finish connections') 69 | 70 | conn1:finish() 71 | conn2:finish() 72 | -------------------------------------------------------------------------------- /testcopy.lua: -------------------------------------------------------------------------------- 1 | local pgsql = require 'pgsql' 2 | local proxy = require 'proxy' 3 | 4 | local conn = pgsql.connectdb('') 5 | if conn:status() == pgsql.CONNECTION_OK then 6 | print('connection is ok') 7 | else 8 | print('connection is not ok') 9 | print(conn:errorMessage()) 10 | end 11 | 12 | local res = conn:exec('select * from pg_roles') 13 | 14 | local t = {} 15 | 16 | res[1]:copy(t) 17 | 18 | print 'populated table' 19 | for k, v in pairs(t) do 20 | print(k, v) 21 | end 22 | print '' 23 | 24 | 25 | t = res[1]:copy() 26 | 27 | print 'returned table' 28 | for k, v in pairs(t) do 29 | print(k, v) 30 | end 31 | print '' 32 | 33 | local p = proxy.new() 34 | 35 | res[1]:copy(p) 36 | 37 | print 'value from populated proxy' 38 | print(p.rolname) 39 | 40 | res[1]:copy(p) 41 | 42 | print 'value from populated proxy' 43 | print(p.rolname) 44 | 45 | -- provoke an error 46 | res[1]:copy(x) -------------------------------------------------------------------------------- /testdb.lua: -------------------------------------------------------------------------------- 1 | local pgsql = require 'pgsql' 2 | 3 | local conn = pgsql.connectdb('') 4 | if conn:status() == pgsql.CONNECTION_OK then 5 | print('connection is ok') 6 | else 7 | print('connection is not ok') 8 | print(conn:errorMessage()) 9 | end 10 | 11 | local res = conn:execParams([[ 12 | select * from pg_roles where rolname = $1 13 | ]], 'postgres') 14 | print(#res, 'roles with name postgres') 15 | 16 | local res = conn:exec([[ 17 | select rolname, rolsuper from pg_roles order by rolname limit 2 18 | ]]) 19 | 20 | print(#res, 'roles') 21 | 22 | print(res:ntuples(), res['ntuples'](res), res[1].rolname, res[1][1]) 23 | 24 | local res2 = conn:exec("select 'abc' as name, 'def' as surname") 25 | 26 | print(res2[1][1], res2[1][2], res2[1][3]) 27 | 28 | print(res2[3]) 29 | 30 | print(res2[1].getisnull, res2[1][1], res2[1]:getisnull('name')) 31 | 32 | for tuple, row in res:tuples() do 33 | print(row, #tuple, tuple[1], tuple.rolname) 34 | end 35 | 36 | for k, v in pairs(res:copy()) do 37 | for k2, v2 in pairs(v) do 38 | print(k, k2, v2) 39 | end 40 | end 41 | 42 | for rolname, rolsuper in res:fields() do 43 | print(rolname, rolsuper) 44 | end 45 | 46 | print(conn:errorMessage()) 47 | -------------------------------------------------------------------------------- /testencryptpassword.lua: -------------------------------------------------------------------------------- 1 | local pgsql = require 'pgsql' 2 | 3 | if pgsql.libVersion() < 100000 then 4 | print('conn:encryptPassword() requires at least PosgreSQL 10') 5 | os.exit(1) 6 | end 7 | 8 | conn = pgsql.connectdb('') 9 | print(conn:errorMessage()) 10 | if conn:status() ~= pgsql.CONNECTION_OK then 11 | print('database connection failed') 12 | os.exit(1) 13 | end 14 | 15 | 16 | local pw = conn:encryptPassword('secret', 'postgres') 17 | local pw_md5 = conn:encryptPassword('secret', 'postgres', 'md5') 18 | local pw_scram_sha_256 = conn:encryptPassword('secret', 'postgres', 19 | 'scram-sha-256') 20 | 21 | print(string.format([[ 22 | password with default algorithm: 23 | %s 24 | 25 | password with md5 algorithm: 26 | %s 27 | 28 | password with scram-sha-256 algorithm: 29 | %s 30 | ]], pw, pw_md5, pw_scram_sha_256)) 31 | 32 | conn:finish() 33 | -------------------------------------------------------------------------------- /testescape.lua: -------------------------------------------------------------------------------- 1 | local pgsql = require 'pgsql' 2 | 3 | conn = pgsql.connectdb('') 4 | print(conn:errorMessage()) 5 | if conn:status() ~= pgsql.CONNECTION_OK then 6 | print('database connection failed') 7 | os.exit(1) 8 | end 9 | 10 | local original = "abc'def" 11 | 12 | local escaped = conn:escapeBytea(original) 13 | local unescaped = pgsql.unescapeBytea(escaped) 14 | 15 | print(string.format([[ 16 | original string: %s 17 | escaped string: %s 18 | escaped string length: %d 19 | unescaped string: %s 20 | ]], original, escaped, #escaped, unescaped)) 21 | 22 | if original == unescaped then 23 | print('unescaped string matches original string') 24 | else 25 | print('unescaped string does not match original string') 26 | end 27 | 28 | conn:finish() 29 | -------------------------------------------------------------------------------- /testnumbers.lua: -------------------------------------------------------------------------------- 1 | local pgsql = require 'pgsql' 2 | 3 | conn = pgsql.connectdb('') 4 | print(conn:errorMessage()) 5 | if conn:status() == pgsql.CONNECTION_OK then 6 | print('connection is ok') 7 | else 8 | print('connection is not ok') 9 | end 10 | 11 | local n = 3.1415986 12 | print(n) 13 | 14 | local res = conn:exec('create table test (a integer, b numeric(8, 2), c float, d boolean)') 15 | 16 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 17 | print('failed to create table') 18 | print(res:errorMessage()) 19 | end 20 | 21 | res = conn:execParams('insert into test (a, b, c) values ($1::integer, $1::numeric, $1)', n, n, n) 22 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 23 | print('failed to insert data') 24 | print(res:errorMessage()) 25 | end 26 | 27 | res = conn:execParams('insert into test (c) values ($1)', n) 28 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 29 | print('failed to insert data') 30 | print(res:errorMessage()) 31 | end 32 | 33 | -- Infinity 34 | res = conn:execParams('insert into test (c) values ($1)', 1/0) 35 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 36 | print('failed to insert data') 37 | print(res:errorMessage()) 38 | end 39 | 40 | -- -Infinity 41 | res = conn:execParams('insert into test (c) values ($1)', -1/0) 42 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 43 | print('failed to insert data') 44 | print(res:errorMessage()) 45 | end 46 | 47 | -- NaN 48 | res = conn:execParams('insert into test (c) values ($1)', 0/0) 49 | if res:status() ~= pgsql.PGRES_COMMAND_OK then 50 | print('failed to insert data') 51 | print(res:errorMessage()) 52 | end 53 | 54 | res = conn:execParams('insert into test (d) values ($1)', true) 55 | res = conn:execParams('insert into test (d) values ($1)', false) 56 | 57 | conn:finish() 58 | -------------------------------------------------------------------------------- /trace.lua: -------------------------------------------------------------------------------- 1 | local pgsql = require 'pgsql' 2 | 3 | conn = pgsql.connectdb('') 4 | print(conn:errorMessage()) 5 | if conn:status() == pgsql.CONNECTION_OK then 6 | print('connection is ok') 7 | else 8 | print('connection is not ok') 9 | end 10 | 11 | local f = io.open('trace', 'w') 12 | conn:trace(f) 13 | res = conn:execParams('insert into test (d) values ($1)', true) 14 | 15 | local f2 = io.open('trace2', 'w') 16 | conn:trace(f2) 17 | 18 | print('closing first trace file') 19 | f:close() 20 | print('done') 21 | 22 | print('close second trace file') 23 | f2:close() 24 | print('done') 25 | 26 | res = conn:execParams('insert into test (d) values ($1)', true) 27 | 28 | print('finish connection') 29 | 30 | conn:finish() 31 | --------------------------------------------------------------------------------