summaryrefslogtreecommitdiff
path: root/source/luametatex/source/luaoptional/lmtpostgress.c
diff options
context:
space:
mode:
Diffstat (limited to 'source/luametatex/source/luaoptional/lmtpostgress.c')
-rw-r--r--source/luametatex/source/luaoptional/lmtpostgress.c306
1 files changed, 306 insertions, 0 deletions
diff --git a/source/luametatex/source/luaoptional/lmtpostgress.c b/source/luametatex/source/luaoptional/lmtpostgress.c
new file mode 100644
index 000000000..cdf515155
--- /dev/null
+++ b/source/luametatex/source/luaoptional/lmtpostgress.c
@@ -0,0 +1,306 @@
+/*
+ See license.txt in the root of this project.
+*/
+
+# include "luametatex.h"
+# include "lmtoptional.h"
+
+typedef void PGconn;
+typedef void PGresult;
+
+typedef enum postgres_polling_status_type {
+ PGRES_POLLING_FAILED,
+ PGRES_POLLING_READING,
+ PGRES_POLLING_WRITING,
+ PGRES_POLLING_OK
+} postgres_polling_status_type;
+
+typedef enum postgres_exec_status_type {
+ PGRES_EMPTY_QUERY,
+ PGRES_COMMAND_OK,
+ PGRES_TUPLES_OK,
+ PGRES_COPY_OUT,
+ PGRES_COPY_IN,
+ PGRES_BAD_RESPONSE,
+ PGRES_NONFATAL_ERROR,
+ PGRES_FATAL_ERROR,
+ PGRES_COPY_BOTH,
+ PGRES_SINGLE_TUPLE
+} postgres_exec_status_type;
+
+typedef enum postgres_connection_status_type {
+ PGRES_CONNECTION_OK,
+ PGRES_CONNECTION_BAD,
+ PGRES_CONNECTION_STARTED,
+ PGRES_CONNECTION_MADE,
+ PGRES_CONNECTION_AWAITING_RESPONSE,
+ PGRES_CONNECTION_AUTH_OK,
+ PGRES_CONNECTION_SETENV,
+ PGRES_CONNECTION_SSL_STARTUP,
+ PGRES_CONNECTION_NEEDED
+} postgres_connection_status_type;
+
+# define POSTGRESSLIB_METATABLE "luatex.postgresslib"
+
+typedef struct postgresslib_data {
+ /*tex There is not much more than a pointer currently. */
+ PGconn * db;
+} postgresslib_data ;
+
+typedef struct postgresslib_state_info {
+
+ int initialized;
+ int padding;
+
+ PGconn * (*PQsetdbLogin) (
+ const char *pghost,
+ const char *pgport,
+ const char *pgoptions,
+ const char *pgtty,
+ const char *dbName,
+ const char *login,
+ const char *pwd
+ );
+
+ postgres_connection_status_type (*PQstatus) (
+ const PGconn *conn
+ );
+
+ void (*PQfinish) (
+ PGconn *conn
+ );
+
+ char * (*PQerrorMessage) (
+ const PGconn *conn
+ );
+
+ int (*PQsendQuery) (
+ PGconn *conn,
+ const char *command
+ );
+
+ PGresult * (*PQgetResult) (
+ PGconn *conn
+ );
+
+ postgres_exec_status_type (*PQresultStatus) (
+ const PGresult *res
+ );
+
+ int (*PQntuples) (
+ const PGresult *res
+ );
+
+ int (*PQnfields) (
+ const PGresult *res
+ );
+
+ void (*PQclear) (
+ PGresult *res
+ );
+
+ char * (*PQfname) (
+ const PGresult *res,
+ int column_number
+ );
+
+ char * (*PQgetvalue) (
+ const PGresult *res,
+ int row_number,
+ int column_number
+ );
+
+} postgresslib_state_info;
+
+static postgresslib_state_info postgresslib_state = {
+
+ .initialized = 0,
+ .padding = 0,
+
+ .PQsetdbLogin = NULL,
+ .PQstatus = NULL,
+ .PQfinish = NULL,
+ .PQerrorMessage = NULL,
+ .PQsendQuery = NULL,
+ .PQgetResult = NULL,
+ .PQresultStatus = NULL,
+ .PQntuples = NULL,
+ .PQnfields = NULL,
+ .PQclear = NULL,
+ .PQfname = NULL,
+ .PQgetvalue = NULL,
+
+};
+
+static int postgresslib_initialize(lua_State * L)
+{
+ if (! postgresslib_state.initialized) {
+ const char *filename = lua_tostring(L, 1);
+ if (filename != NULL) {
+
+ lmt_library lib = lmt_library_load(filename);
+
+ postgresslib_state.PQsetdbLogin = lmt_library_find(lib, "PQsetdbLogin");
+ postgresslib_state.PQstatus = lmt_library_find(lib, "PQstatus");
+ postgresslib_state.PQfinish = lmt_library_find(lib, "PQfinish");
+ postgresslib_state.PQerrorMessage = lmt_library_find(lib, "PQerrorMessage");
+ postgresslib_state.PQsendQuery = lmt_library_find(lib, "PQsendQuery");
+ postgresslib_state.PQgetResult = lmt_library_find(lib, "PQgetResult");
+ postgresslib_state.PQresultStatus = lmt_library_find(lib, "PQresultStatus");
+ postgresslib_state.PQntuples = lmt_library_find(lib, "PQntuples");
+ postgresslib_state.PQnfields = lmt_library_find(lib, "PQnfields");
+ postgresslib_state.PQclear = lmt_library_find(lib, "PQclear");
+ postgresslib_state.PQfname = lmt_library_find(lib, "PQfname");
+ postgresslib_state.PQgetvalue = lmt_library_find(lib, "PQgetvalue");
+
+ postgresslib_state.initialized = lmt_library_okay(lib);
+ }
+ }
+ lua_pushboolean(L, postgresslib_state.initialized);
+ return 1;
+}
+
+static int postgresslib_open(lua_State * L)
+{
+ if (postgresslib_state.initialized) {
+ const char *database = luaL_checkstring(L, 1);
+ const char *username = luaL_optstring(L, 2, NULL);
+ const char *password = luaL_optstring(L, 3, NULL);
+ const char *host = luaL_optstring(L, 4, NULL);
+ const char *port = luaL_optstring(L, 5, NULL);
+ PGconn *db = postgresslib_state.PQsetdbLogin(host, port, NULL, NULL, database, username, password);
+ if (db != NULL && postgresslib_state.PQstatus(db) == PGRES_CONNECTION_BAD) {
+ postgresslib_state.PQfinish(db);
+ } else {
+ postgresslib_data *data = lua_newuserdatauv(L, sizeof(data), 0);
+ data->db = db ;
+ luaL_getmetatable(L, POSTGRESSLIB_METATABLE);
+ lua_setmetatable(L, -2);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+static int postgresslib_close(lua_State * L)
+{
+ if (postgresslib_state.initialized) {
+ postgresslib_data * data = luaL_checkudata(L,1,POSTGRESSLIB_METATABLE);
+ if (data != NULL) {
+ postgresslib_state.PQfinish(data->db);
+ data->db = NULL;
+ }
+ }
+ return 0;
+}
+
+/* execute(database,querystring,callback) : callback(nofcolumns,values,fields) */
+
+static int postgresslib_execute(lua_State * L)
+{
+ if (postgresslib_state.initialized) {
+ postgresslib_data * data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
+ if (data != NULL) {
+ size_t length = 0;
+ const char *query = lua_tolstring(L, 2, &length);
+ if (query != NULL) {
+ int error = postgresslib_state.PQsendQuery(data->db, query);
+ if (!error) {
+ PGresult * result = postgresslib_state.PQgetResult(data->db);
+ if (result) {
+ if (postgresslib_state.PQresultStatus(result) == PGRES_TUPLES_OK) {
+ int nofrows = postgresslib_state.PQntuples(result);
+ int nofcolumns = postgresslib_state.PQnfields(result);
+ /* This is similar to sqlite but there the callback is more indirect. */
+ if (nofcolumns > 0 && nofrows > 0) {
+ for (int r = 0; r < nofrows; r++) {
+ lua_pushvalue(L, -1);
+ lua_pushinteger(L, nofcolumns);
+ lua_createtable(L, nofcolumns, 0);
+ for (int c = 0; c < nofcolumns; c++) {
+ lua_pushstring(L, postgresslib_state.PQgetvalue(result, r, c));
+ lua_rawseti(L,- 2, (lua_Integer)c + 1);
+ }
+ if (r) {
+ lua_call(L, 2, 0);
+ } else {
+ lua_createtable(L, nofcolumns, 0);
+ for (int c = 0; c < nofcolumns; c++) {
+ lua_pushstring(L, postgresslib_state.PQfname(result,c));
+ lua_rawseti(L, -2, (lua_Integer)c + 1);
+ }
+ lua_call(L,3,0);
+ }
+ }
+ }
+ }
+ postgresslib_state.PQclear(result);
+ }
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+ }
+ }
+ }
+ lua_pushboolean(L, 0);
+ return 1;
+}
+
+static int postgresslib_getmessage(lua_State * L)
+{
+ if (postgresslib_state.initialized) {
+ postgresslib_data * data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
+ if (data != NULL) {
+ lua_pushstring(L, postgresslib_state.PQerrorMessage(data->db));
+ return 1;
+ }
+ }
+ return 0;
+}
+
+/* private */
+
+static int postgresslib_free(lua_State * L)
+{
+ return postgresslib_close(L);
+}
+
+/* <string> = tostring(instance) */
+
+static int postgresslib_tostring(lua_State * L)
+ {
+ if (postgresslib_state.initialized) {
+ postgresslib_data * data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
+ if (data != NULL) {
+ (void) lua_pushfstring(L, "<postgresslib-instance %p>", data);
+ } else {
+ lua_pushnil(L);
+ }
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+static const struct luaL_Reg postgresslib_metatable[] = {
+ { "__tostring", postgresslib_tostring },
+ { "__gc", postgresslib_free },
+ { NULL, NULL },
+};
+
+static struct luaL_Reg postgresslib_function_list[] = {
+ { "initialize", postgresslib_initialize },
+ { "open", postgresslib_open },
+ { "close", postgresslib_close },
+ { "execute", postgresslib_execute },
+ { "getmessage", postgresslib_getmessage },
+ { NULL, NULL },
+};
+
+int luaopen_postgress(lua_State * L)
+{
+ luaL_newmetatable(L, POSTGRESSLIB_METATABLE);
+ luaL_setfuncs(L, postgresslib_metatable, 0);
+ lmt_library_register(L, "postgress", postgresslib_function_list);
+ return 0;
+}