PageRenderTime 322ms CodeModel.GetById 55ms RepoModel.GetById 2ms app.codeStats 1ms

/dependencies/luasql-2.1.1/src/ls_postgres.c

https://bitbucket.org/zielmicha/freeciv-mirror
C | 566 lines | 361 code | 91 blank | 114 comment | 52 complexity | d68ac44feb3f6b21f8e1f0b2730f3db5 MD5 | raw file
  1. /*
  2. ** LuaSQL, PostgreSQL driver
  3. ** Authors: Pedro Rabinovitch, Roberto Ierusalimschy, Carlos Cassino
  4. ** Tomas Guisasola, Eduardo Quintao
  5. ** See Copyright Notice in license.html
  6. ** $Id: ls_postgres.c,v 1.9 2007/06/18 01:22:45 tomas Exp $
  7. */
  8. /* This file is slightly addapted for use in the freeciv project:
  9. * - include fc_config.h
  10. */
  11. #ifdef HAVE_CONFIG_H
  12. #include <fc_config.h>
  13. #endif
  14. #include <assert.h>
  15. #include <stdio.h>
  16. #include <stdlib.h>
  17. #include <string.h>
  18. #include <ctype.h>
  19. #include "libpq-fe.h"
  20. #include "lua.h"
  21. #include "lauxlib.h"
  22. #include "luasql.h"
  23. #define LUASQL_ENVIRONMENT_PG "PostgreSQL environment"
  24. #define LUASQL_CONNECTION_PG "PostgreSQL connection"
  25. #define LUASQL_CURSOR_PG "PostgreSQL cursor"
  26. typedef struct {
  27. short closed;
  28. } env_data;
  29. typedef struct {
  30. short closed;
  31. int env; /* reference to environment */
  32. int auto_commit; /* 0 for manual commit */
  33. PGconn *pg_conn;
  34. } conn_data;
  35. typedef struct {
  36. short closed;
  37. int conn; /* reference to connection */
  38. int numcols; /* number of columns */
  39. int colnames, coltypes; /* reference to column information tables */
  40. int curr_tuple; /* next tuple to be read */
  41. PGresult *pg_res;
  42. } cur_data;
  43. typedef void (*creator) (lua_State *L, cur_data *cur);
  44. LUASQL_API int luaopen_luasql_postgres(lua_State *L);
  45. /*
  46. ** Check for valid environment.
  47. */
  48. static env_data *getenvironment (lua_State *L) {
  49. env_data *env = (env_data *)luaL_checkudata (L, 1, LUASQL_ENVIRONMENT_PG);
  50. luaL_argcheck (L, env != NULL, 1, LUASQL_PREFIX"environment expected");
  51. luaL_argcheck (L, !env->closed, 1, LUASQL_PREFIX"environment is closed");
  52. return env;
  53. }
  54. /*
  55. ** Check for valid connection.
  56. */
  57. static conn_data *getconnection (lua_State *L) {
  58. conn_data *conn = (conn_data *)luaL_checkudata (L, 1, LUASQL_CONNECTION_PG);
  59. luaL_argcheck (L, conn != NULL, 1, LUASQL_PREFIX"connection expected");
  60. luaL_argcheck (L, !conn->closed, 1, LUASQL_PREFIX"connection is closed");
  61. return conn;
  62. }
  63. /*
  64. ** Check for valid cursor.
  65. */
  66. static cur_data *getcursor (lua_State *L) {
  67. cur_data *cur = (cur_data *)luaL_checkudata (L, 1, LUASQL_CURSOR_PG);
  68. luaL_argcheck (L, cur != NULL, 1, LUASQL_PREFIX"cursor expected");
  69. luaL_argcheck (L, !cur->closed, 1, LUASQL_PREFIX"cursor is closed");
  70. return cur;
  71. }
  72. /*
  73. ** Push the value of #i field of #tuple row.
  74. */
  75. static void pushvalue (lua_State *L, PGresult *res, int tuple, int i) {
  76. if (PQgetisnull (res, tuple, i-1))
  77. lua_pushnil (L);
  78. else
  79. lua_pushstring (L, PQgetvalue (res, tuple, i-1));
  80. }
  81. /*
  82. ** Get another row of the given cursor.
  83. */
  84. static int cur_fetch (lua_State *L) {
  85. cur_data *cur = getcursor (L);
  86. PGresult *res = cur->pg_res;
  87. int tuple = cur->curr_tuple;
  88. if (tuple >= PQntuples(cur->pg_res)) {
  89. lua_pushnil(L); /* no more results */
  90. return 1;
  91. }
  92. cur->curr_tuple++;
  93. if (lua_istable (L, 2)) {
  94. int i;
  95. const char *opts = luaL_optstring (L, 3, "n");
  96. if (strchr (opts, 'n') != NULL)
  97. /* Copy values to numerical indices */
  98. for (i = 1; i <= cur->numcols; i++) {
  99. pushvalue (L, res, tuple, i);
  100. lua_rawseti (L, 2, i);
  101. }
  102. if (strchr (opts, 'a') != NULL)
  103. /* Copy values to alphanumerical indices */
  104. for (i = 1; i <= cur->numcols; i++) {
  105. lua_pushstring (L, PQfname (res, i-1));
  106. pushvalue (L, res, tuple, i);
  107. lua_rawset (L, 2);
  108. }
  109. lua_pushvalue(L, 2);
  110. return 1; /* return table */
  111. }
  112. else {
  113. int i;
  114. luaL_checkstack (L, cur->numcols, LUASQL_PREFIX"too many columns");
  115. for (i = 1; i <= cur->numcols; i++)
  116. pushvalue (L, res, tuple, i);
  117. return cur->numcols; /* return #numcols values */
  118. }
  119. }
  120. /*
  121. ** Close the cursor on top of the stack.
  122. ** Return 1
  123. */
  124. static int cur_close (lua_State *L) {
  125. cur_data *cur = (cur_data *)luaL_checkudata (L, 1, LUASQL_CURSOR_PG);
  126. luaL_argcheck (L, cur != NULL, 1, LUASQL_PREFIX"cursor expected");
  127. if (cur->closed) {
  128. lua_pushboolean (L, 0);
  129. return 1;
  130. }
  131. /* Nullify structure fields. */
  132. cur->closed = 1;
  133. PQclear(cur->pg_res);
  134. luaL_unref (L, LUA_REGISTRYINDEX, cur->conn);
  135. luaL_unref (L, LUA_REGISTRYINDEX, cur->colnames);
  136. luaL_unref (L, LUA_REGISTRYINDEX, cur->coltypes);
  137. lua_pushboolean (L, 1);
  138. return 1;
  139. }
  140. /*
  141. ** Get the internal database type of the given column.
  142. */
  143. static char *getcolumntype (PGconn *conn, PGresult *result, int i, char *buff) {
  144. Oid codigo = PQftype (result, i);
  145. char stmt[100];
  146. PGresult *res;
  147. sprintf (stmt, "select typname from pg_type where oid = %d", codigo);
  148. res = PQexec(conn, stmt);
  149. strcpy (buff, "undefined");
  150. if (PQresultStatus (res) == PGRES_TUPLES_OK) {
  151. if (PQntuples(res) > 0) {
  152. char *name = PQgetvalue(res, 0, 0);
  153. if (strcmp (name, "bpchar")==0 || strcmp (name, "varchar")==0) {
  154. int modifier = PQfmod (result, i) - 4;
  155. sprintf (buff, "%.20s (%d)", name, modifier);
  156. }
  157. else
  158. strncpy (buff, name, 20);
  159. }
  160. }
  161. PQclear(res);
  162. return buff;
  163. }
  164. /*
  165. ** Creates the list of fields names and pushes it on top of the stack.
  166. */
  167. static void create_colnames (lua_State *L, cur_data *cur) {
  168. PGresult *result = cur->pg_res;
  169. int i;
  170. lua_newtable (L);
  171. for (i = 1; i <= cur->numcols; i++) {
  172. lua_pushstring (L, PQfname (result, i-1));
  173. lua_rawseti (L, -2, i);
  174. }
  175. }
  176. /*
  177. ** Creates the list of fields types and pushes it on top of the stack.
  178. */
  179. static void create_coltypes (lua_State *L, cur_data *cur) {
  180. PGresult *result = cur->pg_res;
  181. conn_data *conn;
  182. char typename[100];
  183. int i;
  184. lua_rawgeti (L, LUA_REGISTRYINDEX, cur->conn);
  185. if (!lua_isuserdata (L, -1))
  186. luaL_error (L, LUASQL_PREFIX"invalid connection");
  187. conn = (conn_data *)lua_touserdata (L, -1);
  188. lua_newtable (L);
  189. for (i = 1; i <= cur->numcols; i++) {
  190. lua_pushstring(L, getcolumntype (conn->pg_conn, result, i-1, typename));
  191. lua_rawseti (L, -2, i);
  192. }
  193. }
  194. /*
  195. ** Pushes a column information table on top of the stack.
  196. ** If the table isn't built yet, call the creator function and stores
  197. ** a reference to it on the cursor structure.
  198. */
  199. static void _pushtable (lua_State *L, cur_data *cur, size_t off, creator func) {
  200. int *ref = (int *)((char *)cur + off);
  201. if (*ref != LUA_NOREF)
  202. lua_rawgeti (L, LUA_REGISTRYINDEX, *ref);
  203. else {
  204. func (L, cur);
  205. /* Stores a reference to it on the cursor structure */
  206. lua_pushvalue (L, -1);
  207. *ref = luaL_ref (L, LUA_REGISTRYINDEX);
  208. }
  209. }
  210. #define pushtable(L,c,m,f) (_pushtable(L,c,offsetof(cur_data,m),f))
  211. /*
  212. ** Return the list of field names.
  213. */
  214. static int cur_getcolnames (lua_State *L) {
  215. pushtable (L, getcursor(L), colnames, create_colnames);
  216. return 1;
  217. }
  218. /*
  219. ** Return the list of field types.
  220. */
  221. static int cur_getcoltypes (lua_State *L) {
  222. pushtable (L, getcursor(L), coltypes, create_coltypes);
  223. return 1;
  224. }
  225. /*
  226. ** Push the number of rows.
  227. */
  228. static int cur_numrows (lua_State *L) {
  229. lua_pushnumber (L, PQntuples (getcursor(L)->pg_res));
  230. return 1;
  231. }
  232. /*
  233. ** Create a new Cursor object and push it on top of the stack.
  234. */
  235. static int create_cursor (lua_State *L, int conn, PGresult *result) {
  236. cur_data *cur = (cur_data *)lua_newuserdata(L, sizeof(cur_data));
  237. luasql_setmeta (L, LUASQL_CURSOR_PG);
  238. /* fill in structure */
  239. cur->closed = 0;
  240. cur->conn = LUA_NOREF;
  241. cur->numcols = PQnfields(result);
  242. cur->colnames = LUA_NOREF;
  243. cur->coltypes = LUA_NOREF;
  244. cur->curr_tuple = 0;
  245. cur->pg_res = result;
  246. lua_pushvalue (L, conn);
  247. cur->conn = luaL_ref (L, LUA_REGISTRYINDEX);
  248. return 1;
  249. }
  250. static void sql_commit(conn_data *conn) {
  251. PQclear(PQexec(conn->pg_conn, "COMMIT"));
  252. }
  253. static void sql_begin(conn_data *conn) {
  254. PQclear(PQexec(conn->pg_conn, "BEGIN"));
  255. }
  256. static void sql_rollback(conn_data *conn) {
  257. PQclear(PQexec(conn->pg_conn, "ROLLBACK"));
  258. }
  259. /*
  260. ** Close a Connection object.
  261. */
  262. static int conn_close (lua_State *L) {
  263. conn_data *conn = (conn_data *)luaL_checkudata (L, 1, LUASQL_CONNECTION_PG);
  264. luaL_argcheck (L, conn != NULL, 1, LUASQL_PREFIX"connection expected");
  265. if (conn->closed) {
  266. lua_pushboolean (L, 0);
  267. return 1;
  268. }
  269. /* Nullify structure fields. */
  270. conn->closed = 1;
  271. luaL_unref (L, LUA_REGISTRYINDEX, conn->env);
  272. PQfinish (conn->pg_conn);
  273. lua_pushboolean (L, 1);
  274. return 1;
  275. }
  276. /*
  277. ** Escapes a string for use within an SQL statement.
  278. ** Returns a string with the escaped string.
  279. */
  280. static int conn_escape (lua_State *L) {
  281. conn_data *conn = getconnection (L);
  282. size_t len;
  283. const char *from = luaL_checklstring (L, 2, &len);
  284. char to[len*2+1];
  285. int error;
  286. len = PQescapeStringConn (conn->pg_conn, to, from, len, &error);
  287. if (error == 0) { /* success ! */
  288. lua_pushlstring (L, to, len);
  289. return 1;
  290. } else
  291. return luasql_faildirect (L, PQerrorMessage (conn->pg_conn));
  292. }
  293. /*
  294. ** Execute an SQL statement.
  295. ** Return a Cursor object if the statement is a query, otherwise
  296. ** return the number of tuples affected by the statement.
  297. */
  298. static int conn_execute (lua_State *L) {
  299. conn_data *conn = getconnection (L);
  300. const char *statement = luaL_checkstring (L, 2);
  301. PGresult *res = PQexec(conn->pg_conn, statement);
  302. if (res && PQresultStatus(res)==PGRES_COMMAND_OK) {
  303. /* no tuples returned */
  304. lua_pushnumber(L, atof(PQcmdTuples(res)));
  305. PQclear (res);
  306. return 1;
  307. }
  308. else if (res && PQresultStatus(res)==PGRES_TUPLES_OK)
  309. /* tuples returned */
  310. return create_cursor (L, 1, res);
  311. else {
  312. /* error */
  313. PQclear (res);
  314. return luasql_faildirect(L, PQerrorMessage(conn->pg_conn));
  315. }
  316. }
  317. /*
  318. ** Commit the current transaction.
  319. */
  320. static int conn_commit (lua_State *L) {
  321. conn_data *conn = getconnection (L);
  322. sql_commit(conn);
  323. if (conn->auto_commit == 0) {
  324. sql_begin(conn);
  325. lua_pushboolean (L, 1);
  326. } else
  327. lua_pushboolean (L, 0);
  328. return 1;
  329. }
  330. /*
  331. ** Rollback the current transaction.
  332. */
  333. static int conn_rollback (lua_State *L) {
  334. conn_data *conn = getconnection (L);
  335. sql_rollback(conn);
  336. if (conn->auto_commit == 0) {
  337. sql_begin(conn);
  338. lua_pushboolean (L, 1);
  339. } else
  340. lua_pushboolean (L, 0);
  341. return 1;
  342. }
  343. /*
  344. ** Set "auto commit" property of the connection.
  345. ** If 'true', then rollback current transaction.
  346. ** If 'false', then start a new transaction.
  347. */
  348. static int conn_setautocommit (lua_State *L) {
  349. conn_data *conn = getconnection (L);
  350. if (lua_toboolean (L, 2)) {
  351. conn->auto_commit = 1;
  352. sql_rollback(conn); /* Undo active transaction. */
  353. }
  354. else {
  355. conn->auto_commit = 0;
  356. sql_begin(conn);
  357. }
  358. lua_pushboolean(L, 1);
  359. return 1;
  360. }
  361. /*
  362. ** Create a new Connection object and push it on top of the stack.
  363. */
  364. static int create_connection (lua_State *L, int env, PGconn *const pg_conn) {
  365. conn_data *conn = (conn_data *)lua_newuserdata(L, sizeof(conn_data));
  366. luasql_setmeta (L, LUASQL_CONNECTION_PG);
  367. /* fill in structure */
  368. conn->closed = 0;
  369. conn->env = LUA_NOREF;
  370. conn->auto_commit = 1;
  371. conn->pg_conn = pg_conn;
  372. lua_pushvalue (L, env);
  373. conn->env = luaL_ref (L, LUA_REGISTRYINDEX);
  374. return 1;
  375. }
  376. static void notice_processor (void *arg, const char *message) {
  377. (void)arg; (void)message;
  378. /* arg == NULL */
  379. }
  380. /*
  381. ** Connects to a data source.
  382. ** This driver provides two ways to connect to a data source:
  383. ** (1) giving the connection parameters as a set of pairs separated
  384. ** by whitespaces in a string (first method parameter)
  385. ** (2) giving one string for each connection parameter, said
  386. ** datasource, username, password, host and port.
  387. */
  388. static int env_connect (lua_State *L) {
  389. const char *sourcename = luaL_checkstring(L, 2);
  390. PGconn *conn;
  391. getenvironment (L); /* validate environment */
  392. if ((lua_gettop (L) == 2) && (strchr (sourcename, '=') != NULL))
  393. conn = PQconnectdb (sourcename);
  394. else {
  395. const char *username = luaL_optstring(L, 3, NULL);
  396. const char *password = luaL_optstring(L, 4, NULL);
  397. const char *pghost = luaL_optstring(L, 5, NULL);
  398. const char *pgport = luaL_optstring(L, 6, NULL);
  399. conn = PQsetdbLogin(pghost, pgport, NULL, NULL,
  400. sourcename, username, password);
  401. }
  402. if (PQstatus(conn) == CONNECTION_BAD)
  403. return luasql_faildirect(L, LUASQL_PREFIX"Error connecting to database.");
  404. PQsetNoticeProcessor(conn, notice_processor, NULL);
  405. return create_connection(L, 1, conn);
  406. }
  407. /*
  408. ** Close environment object.
  409. */
  410. static int env_close (lua_State *L) {
  411. env_data *env = (env_data *)luaL_checkudata (L, 1, LUASQL_ENVIRONMENT_PG);
  412. luaL_argcheck (L, env != NULL, 1, LUASQL_PREFIX"environment expected");
  413. if (env->closed) {
  414. lua_pushboolean (L, 0);
  415. return 1;
  416. }
  417. env->closed = 1;
  418. lua_pushboolean (L, 1);
  419. return 1;
  420. }
  421. /*
  422. ** Create metatables for each class of object.
  423. */
  424. static void create_metatables (lua_State *L) {
  425. struct luaL_reg environment_methods[] = {
  426. {"close", env_close},
  427. {"connect", env_connect},
  428. {NULL, NULL},
  429. };
  430. struct luaL_reg connection_methods[] = {
  431. {"close", conn_close},
  432. {"escape", conn_escape},
  433. {"execute", conn_execute},
  434. {"commit", conn_commit},
  435. {"rollback", conn_rollback},
  436. {"setautocommit", conn_setautocommit},
  437. {NULL, NULL},
  438. };
  439. struct luaL_reg cursor_methods[] = {
  440. {"close", cur_close},
  441. {"getcolnames", cur_getcolnames},
  442. {"getcoltypes", cur_getcoltypes},
  443. {"fetch", cur_fetch},
  444. {"numrows", cur_numrows},
  445. {NULL, NULL},
  446. };
  447. luasql_createmeta (L, LUASQL_ENVIRONMENT_PG, environment_methods);
  448. luasql_createmeta (L, LUASQL_CONNECTION_PG, connection_methods);
  449. luasql_createmeta (L, LUASQL_CURSOR_PG, cursor_methods);
  450. lua_pop (L, 3);
  451. }
  452. /*
  453. ** Creates an Environment and returns it.
  454. */
  455. static int create_environment (lua_State *L) {
  456. env_data *env = (env_data *)lua_newuserdata(L, sizeof(env_data));
  457. luasql_setmeta (L, LUASQL_ENVIRONMENT_PG);
  458. /* fill in structure */
  459. env->closed = 0;
  460. return 1;
  461. }
  462. /*
  463. ** Creates the metatables for the objects and registers the
  464. ** driver open method.
  465. */
  466. LUASQL_API int luaopen_luasql_postgres (lua_State *L) {
  467. struct luaL_reg driver[] = {
  468. {"postgres", create_environment},
  469. {NULL, NULL},
  470. };
  471. create_metatables (L);
  472. luaL_openlib (L, LUASQL_TABLENAME, driver, 0);
  473. luasql_set_info (L);
  474. return 1;
  475. }