/dependencies/luasql-2.1.1/src/ls_postgres.c
C | 566 lines | 361 code | 91 blank | 114 comment | 52 complexity | d68ac44feb3f6b21f8e1f0b2730f3db5 MD5 | raw file
- /*
- ** LuaSQL, PostgreSQL driver
- ** Authors: Pedro Rabinovitch, Roberto Ierusalimschy, Carlos Cassino
- ** Tomas Guisasola, Eduardo Quintao
- ** See Copyright Notice in license.html
- ** $Id: ls_postgres.c,v 1.9 2007/06/18 01:22:45 tomas Exp $
- */
- /* This file is slightly addapted for use in the freeciv project:
- * - include fc_config.h
- */
- #ifdef HAVE_CONFIG_H
- #include <fc_config.h>
- #endif
- #include <assert.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <ctype.h>
- #include "libpq-fe.h"
- #include "lua.h"
- #include "lauxlib.h"
- #include "luasql.h"
- #define LUASQL_ENVIRONMENT_PG "PostgreSQL environment"
- #define LUASQL_CONNECTION_PG "PostgreSQL connection"
- #define LUASQL_CURSOR_PG "PostgreSQL cursor"
- typedef struct {
- short closed;
- } env_data;
- typedef struct {
- short closed;
- int env; /* reference to environment */
- int auto_commit; /* 0 for manual commit */
- PGconn *pg_conn;
- } conn_data;
- typedef struct {
- short closed;
- int conn; /* reference to connection */
- int numcols; /* number of columns */
- int colnames, coltypes; /* reference to column information tables */
- int curr_tuple; /* next tuple to be read */
- PGresult *pg_res;
- } cur_data;
- typedef void (*creator) (lua_State *L, cur_data *cur);
- LUASQL_API int luaopen_luasql_postgres(lua_State *L);
- /*
- ** Check for valid environment.
- */
- static env_data *getenvironment (lua_State *L) {
- env_data *env = (env_data *)luaL_checkudata (L, 1, LUASQL_ENVIRONMENT_PG);
- luaL_argcheck (L, env != NULL, 1, LUASQL_PREFIX"environment expected");
- luaL_argcheck (L, !env->closed, 1, LUASQL_PREFIX"environment is closed");
- return env;
- }
- /*
- ** Check for valid connection.
- */
- static conn_data *getconnection (lua_State *L) {
- conn_data *conn = (conn_data *)luaL_checkudata (L, 1, LUASQL_CONNECTION_PG);
- luaL_argcheck (L, conn != NULL, 1, LUASQL_PREFIX"connection expected");
- luaL_argcheck (L, !conn->closed, 1, LUASQL_PREFIX"connection is closed");
- return conn;
- }
- /*
- ** Check for valid cursor.
- */
- static cur_data *getcursor (lua_State *L) {
- cur_data *cur = (cur_data *)luaL_checkudata (L, 1, LUASQL_CURSOR_PG);
- luaL_argcheck (L, cur != NULL, 1, LUASQL_PREFIX"cursor expected");
- luaL_argcheck (L, !cur->closed, 1, LUASQL_PREFIX"cursor is closed");
- return cur;
- }
- /*
- ** Push the value of #i field of #tuple row.
- */
- static void pushvalue (lua_State *L, PGresult *res, int tuple, int i) {
- if (PQgetisnull (res, tuple, i-1))
- lua_pushnil (L);
- else
- lua_pushstring (L, PQgetvalue (res, tuple, i-1));
- }
- /*
- ** Get another row of the given cursor.
- */
- static int cur_fetch (lua_State *L) {
- cur_data *cur = getcursor (L);
- PGresult *res = cur->pg_res;
- int tuple = cur->curr_tuple;
- if (tuple >= PQntuples(cur->pg_res)) {
- lua_pushnil(L); /* no more results */
- return 1;
- }
- cur->curr_tuple++;
- if (lua_istable (L, 2)) {
- int i;
- const char *opts = luaL_optstring (L, 3, "n");
- if (strchr (opts, 'n') != NULL)
- /* Copy values to numerical indices */
- for (i = 1; i <= cur->numcols; i++) {
- pushvalue (L, res, tuple, i);
- lua_rawseti (L, 2, i);
- }
- if (strchr (opts, 'a') != NULL)
- /* Copy values to alphanumerical indices */
- for (i = 1; i <= cur->numcols; i++) {
- lua_pushstring (L, PQfname (res, i-1));
- pushvalue (L, res, tuple, i);
- lua_rawset (L, 2);
- }
- lua_pushvalue(L, 2);
- return 1; /* return table */
- }
- else {
- int i;
- luaL_checkstack (L, cur->numcols, LUASQL_PREFIX"too many columns");
- for (i = 1; i <= cur->numcols; i++)
- pushvalue (L, res, tuple, i);
- return cur->numcols; /* return #numcols values */
- }
- }
- /*
- ** Close the cursor on top of the stack.
- ** Return 1
- */
- static int cur_close (lua_State *L) {
- cur_data *cur = (cur_data *)luaL_checkudata (L, 1, LUASQL_CURSOR_PG);
- luaL_argcheck (L, cur != NULL, 1, LUASQL_PREFIX"cursor expected");
- if (cur->closed) {
- lua_pushboolean (L, 0);
- return 1;
- }
- /* Nullify structure fields. */
- cur->closed = 1;
- PQclear(cur->pg_res);
- luaL_unref (L, LUA_REGISTRYINDEX, cur->conn);
- luaL_unref (L, LUA_REGISTRYINDEX, cur->colnames);
- luaL_unref (L, LUA_REGISTRYINDEX, cur->coltypes);
- lua_pushboolean (L, 1);
- return 1;
- }
- /*
- ** Get the internal database type of the given column.
- */
- static char *getcolumntype (PGconn *conn, PGresult *result, int i, char *buff) {
- Oid codigo = PQftype (result, i);
- char stmt[100];
- PGresult *res;
- sprintf (stmt, "select typname from pg_type where oid = %d", codigo);
- res = PQexec(conn, stmt);
- strcpy (buff, "undefined");
- if (PQresultStatus (res) == PGRES_TUPLES_OK) {
- if (PQntuples(res) > 0) {
- char *name = PQgetvalue(res, 0, 0);
- if (strcmp (name, "bpchar")==0 || strcmp (name, "varchar")==0) {
- int modifier = PQfmod (result, i) - 4;
- sprintf (buff, "%.20s (%d)", name, modifier);
- }
- else
- strncpy (buff, name, 20);
- }
- }
- PQclear(res);
- return buff;
- }
- /*
- ** Creates the list of fields names and pushes it on top of the stack.
- */
- static void create_colnames (lua_State *L, cur_data *cur) {
- PGresult *result = cur->pg_res;
- int i;
- lua_newtable (L);
- for (i = 1; i <= cur->numcols; i++) {
- lua_pushstring (L, PQfname (result, i-1));
- lua_rawseti (L, -2, i);
- }
- }
- /*
- ** Creates the list of fields types and pushes it on top of the stack.
- */
- static void create_coltypes (lua_State *L, cur_data *cur) {
- PGresult *result = cur->pg_res;
- conn_data *conn;
- char typename[100];
- int i;
- lua_rawgeti (L, LUA_REGISTRYINDEX, cur->conn);
- if (!lua_isuserdata (L, -1))
- luaL_error (L, LUASQL_PREFIX"invalid connection");
- conn = (conn_data *)lua_touserdata (L, -1);
- lua_newtable (L);
- for (i = 1; i <= cur->numcols; i++) {
- lua_pushstring(L, getcolumntype (conn->pg_conn, result, i-1, typename));
- lua_rawseti (L, -2, i);
- }
- }
- /*
- ** Pushes a column information table on top of the stack.
- ** If the table isn't built yet, call the creator function and stores
- ** a reference to it on the cursor structure.
- */
- static void _pushtable (lua_State *L, cur_data *cur, size_t off, creator func) {
- int *ref = (int *)((char *)cur + off);
- if (*ref != LUA_NOREF)
- lua_rawgeti (L, LUA_REGISTRYINDEX, *ref);
- else {
- func (L, cur);
-