1
4
5# include "luametatex.h"
6# include "lmtoptional.h"
7
8typedef void PGconn;
9typedef void PGresult;
10
11typedef enum postgres_polling_status_type {
12 PGRES_POLLING_FAILED,
13 PGRES_POLLING_READING,
14 PGRES_POLLING_WRITING,
15 PGRES_POLLING_OK
16} postgres_polling_status_type;
17
18typedef enum postgres_exec_status_type {
19 PGRES_EMPTY_QUERY,
20 PGRES_COMMAND_OK,
21 PGRES_TUPLES_OK,
22 PGRES_COPY_OUT,
23 PGRES_COPY_IN,
24 PGRES_BAD_RESPONSE,
25 PGRES_NONFATAL_ERROR,
26 PGRES_FATAL_ERROR,
27 PGRES_COPY_BOTH,
28 PGRES_SINGLE_TUPLE
29} postgres_exec_status_type;
30
31typedef enum postgres_connection_status_type {
32 PGRES_CONNECTION_OK,
33 PGRES_CONNECTION_BAD,
34 PGRES_CONNECTION_STARTED,
35 PGRES_CONNECTION_MADE,
36 PGRES_CONNECTION_AWAITING_RESPONSE,
37 PGRES_CONNECTION_AUTH_OK,
38 PGRES_CONNECTION_SETENV,
39 PGRES_CONNECTION_SSL_STARTUP,
40 PGRES_CONNECTION_NEEDED
41} postgres_connection_status_type;
42
43# define POSTGRESSLIB_METATABLE "luatex.postgresslib"
44
45typedef struct postgresslib_data {
46
47 PGconn * db;
48} postgresslib_data ;
49
50typedef struct postgresslib_state_info {
51
52 int initialized;
53 int padding;
54
55 PGconn * (*PQsetdbLogin) (
56 const char *pghost,
57 const char *pgport,
58 const char *pgoptions,
59 const char *pgtty,
60 const char *dbName,
61 const char *login,
62 const char *pwd
63 );
64
65 postgres_connection_status_type (*PQstatus) (
66 const PGconn *conn
67 );
68
69 void (*PQfinish) (
70 PGconn *conn
71 );
72
73 char * (*PQerrorMessage) (
74 const PGconn *conn
75 );
76
77 int (*PQsendQuery) (
78 PGconn *conn,
79 const char *command
80 );
81
82 PGresult * (*PQgetResult) (
83 PGconn *conn
84 );
85
86 postgres_exec_status_type (*PQresultStatus) (
87 const PGresult *res
88 );
89
90 int (*PQntuples) (
91 const PGresult *res
92 );
93
94 int (*PQnfields) (
95 const PGresult *res
96 );
97
98 void (*PQclear) (
99 PGresult *res
100 );
101
102 char * (*PQfname) (
103 const PGresult *res,
104 int column_number
105 );
106
107 char * (*PQgetvalue) (
108 const PGresult *res,
109 int row_number,
110 int column_number
111 );
112
113} postgresslib_state_info;
114
115static postgresslib_state_info postgresslib_state = {
116
117 .initialized = 0,
118 .padding = 0,
119
120 .PQsetdbLogin = NULL,
121 .PQstatus = NULL,
122 .PQfinish = NULL,
123 .PQerrorMessage = NULL,
124 .PQsendQuery = NULL,
125 .PQgetResult = NULL,
126 .PQresultStatus = NULL,
127 .PQntuples = NULL,
128 .PQnfields = NULL,
129 .PQclear = NULL,
130 .PQfname = NULL,
131 .PQgetvalue = NULL,
132
133};
134
135static int postgresslib_initialize(lua_State * L)
136{
137 if (! postgresslib_state.initialized) {
138 const char *filename = lua_tostring(L, 1);
139 if (filename != NULL) {
140
141 lmt_library lib = lmt_library_load(filename);
142
143 postgresslib_state.PQsetdbLogin = lmt_library_find(lib, "PQsetdbLogin");
144 postgresslib_state.PQstatus = lmt_library_find(lib, "PQstatus");
145 postgresslib_state.PQfinish = lmt_library_find(lib, "PQfinish");
146 postgresslib_state.PQerrorMessage = lmt_library_find(lib, "PQerrorMessage");
147 postgresslib_state.PQsendQuery = lmt_library_find(lib, "PQsendQuery");
148 postgresslib_state.PQgetResult = lmt_library_find(lib, "PQgetResult");
149 postgresslib_state.PQresultStatus = lmt_library_find(lib, "PQresultStatus");
150 postgresslib_state.PQntuples = lmt_library_find(lib, "PQntuples");
151 postgresslib_state.PQnfields = lmt_library_find(lib, "PQnfields");
152 postgresslib_state.PQclear = lmt_library_find(lib, "PQclear");
153 postgresslib_state.PQfname = lmt_library_find(lib, "PQfname");
154 postgresslib_state.PQgetvalue = lmt_library_find(lib, "PQgetvalue");
155
156 postgresslib_state.initialized = lmt_library_okay(lib);
157 }
158 }
159 lua_pushboolean(L, postgresslib_state.initialized);
160 return 1;
161}
162
163static int postgresslib_open(lua_State * L)
164{
165 if (postgresslib_state.initialized) {
166 const char *database = luaL_checkstring(L, 1);
167 const char *username = luaL_optstring(L, 2, NULL);
168 const char *password = luaL_optstring(L, 3, NULL);
169 const char *host = luaL_optstring(L, 4, NULL);
170 const char *port = luaL_optstring(L, 5, NULL);
171 PGconn *db = postgresslib_state.PQsetdbLogin(host, port, NULL, NULL, database, username, password);
172 if (db != NULL && postgresslib_state.PQstatus(db) == PGRES_CONNECTION_BAD) {
173 postgresslib_state.PQfinish(db);
174 } else {
175 postgresslib_data *data = lua_newuserdatauv(L, sizeof(data), 0);
176 data->db = db ;
177 luaL_getmetatable(L, POSTGRESSLIB_METATABLE);
178 lua_setmetatable(L, -2);
179 return 1;
180 }
181 }
182 return 0;
183}
184
185static int postgresslib_close(lua_State * L)
186{
187 if (postgresslib_state.initialized) {
188 postgresslib_data *data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
189 if (data != NULL) {
190 postgresslib_state.PQfinish(data->db);
191 data->db = NULL;
192 }
193 }
194 return 0;
195}
196
197
198
199static int postgresslib_execute(lua_State * L)
200{
201 if (postgresslib_state.initialized) {
202 postgresslib_data *data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
203 if (data != NULL) {
204 size_t length = 0;
205 const char *query = lua_tolstring(L, 2, &length);
206 if (query != NULL) {
207 int error = postgresslib_state.PQsendQuery(data->db, query);
208 if (!error) {
209 PGresult * result = postgresslib_state.PQgetResult(data->db);
210 if (result) {
211 if (postgresslib_state.PQresultStatus(result) == PGRES_TUPLES_OK) {
212 int nofrows = postgresslib_state.PQntuples(result);
213 int nofcolumns = postgresslib_state.PQnfields(result);
214
215 if (nofcolumns > 0 && nofrows > 0) {
216 for (int r = 0; r < nofrows; r++) {
217 lua_pushvalue(L, -1);
218 lua_pushinteger(L, nofcolumns);
219 lua_createtable(L, nofcolumns, 0);
220 for (int c = 0; c < nofcolumns; c++) {
221 lua_pushstring(L, postgresslib_state.PQgetvalue(result, r, c));
222 lua_rawseti(L,- 2, (lua_Integer)c + 1);
223 }
224 if (r) {
225 lua_call(L, 2, 0);
226 } else {
227 lua_createtable(L, nofcolumns, 0);
228 for (int c = 0; c < nofcolumns; c++) {
229 lua_pushstring(L, postgresslib_state.PQfname(result,c));
230 lua_rawseti(L, -2, (lua_Integer)c + 1);
231 }
232 lua_call(L,3,0);
233 }
234 }
235 }
236 }
237 postgresslib_state.PQclear(result);
238 }
239 lua_pushboolean(L, 1);
240 return 1;
241 }
242 }
243 }
244 }
245 lua_pushboolean(L, 0);
246 return 1;
247}
248
249static int postgresslib_getmessage(lua_State * L)
250{
251 if (postgresslib_state.initialized) {
252 postgresslib_data *data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
253 if (data != NULL) {
254 lua_pushstring(L, postgresslib_state.PQerrorMessage(data->db));
255 return 1;
256 }
257 }
258 return 0;
259}
260
261
262
263static int postgresslib_free(lua_State * L)
264{
265 return postgresslib_close(L);
266}
267
268
269
270static int postgresslib_tostring(lua_State * L)
271 {
272 if (postgresslib_state.initialized) {
273 postgresslib_data *data = luaL_checkudata(L, 1, POSTGRESSLIB_METATABLE);
274 if (data != NULL) {
275 (void) lua_pushfstring(L, "<postgresslib-instance %p>", data);
276 } else {
277 lua_pushnil(L);
278 }
279 return 1;
280 } else {
281 return 0;
282 }
283}
284
285static const struct luaL_Reg postgresslib_metatable[] = {
286 { "__tostring", postgresslib_tostring },
287 { "__gc", postgresslib_free },
288 { NULL, NULL },
289};
290
291static struct luaL_Reg postgresslib_function_list[] = {
292 { "initialize", postgresslib_initialize },
293 { "open", postgresslib_open },
294 { "close", postgresslib_close },
295 { "execute", postgresslib_execute },
296 { "getmessage", postgresslib_getmessage },
297 { NULL, NULL },
298};
299
300int luaopen_postgress(lua_State * L)
301{
302 luaL_newmetatable(L, POSTGRESSLIB_METATABLE);
303 luaL_setfuncs(L, postgresslib_metatable, 0);
304 lmt_library_register(L, "postgress", postgresslib_function_list);
305 return 0;
306}
307 |