sq_postgresql.cpp 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824
  1. #ifdef WITH_POSTGRESQL
  2. #include "squirrel.h"
  3. #include "libpq-fe.h"
  4. #include <string.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include "sqstdblobimpl.h"
  8. #include "dynamic_library.h"
  9. /*SquiLu
  10. local pgsql_functions = [
  11. ["ConnStatusType", "PQstatus", "const PGconn *conn"],
  12. ["void", "PQfinish", "PGconn *conn"],
  13. ["PGresult *", "PQprepare", @"PGconn *conn,
  14. const char *stmtName,
  15. const char *query,
  16. int nParams,
  17. const Oid *paramTypes"],
  18. ["PGresult *", "PQdescribePrepared", "PGconn *conn, const char *stmtName"],
  19. ["int", "PQnparams", "const PGresult *res"],
  20. ["Oid", "PQparamtype", "const PGresult *res, int param_number"],
  21. ["PGresult *", "PQexecPrepared", @"PGconn *conn,
  22. const char *stmtName,
  23. int nParams,
  24. const char * const *paramValues,
  25. const int *paramLengths,
  26. const int *paramFormats,
  27. int resultFormat"],
  28. ["PGresult *", "PQexec", "PGconn *conn, const char *command"],
  29. ["const char*", "PQgetvalue", @"const PGresult *res,
  30. int row_number,
  31. int column_number"],
  32. ["int", "PQntuples", "const PGresult *res"],
  33. ["char *", "PQcmdTuples", "const PGresult *res"],
  34. ["int", "PQnfields", "const PGresult *res"],
  35. ["int", "PQgetisnull", @"const PGresult *res,
  36. int row_number,
  37. int column_number"],
  38. ["void", "PQclear", "const PGresult *res"],
  39. ["int", "PQfnumber", "const PGresult *res, const char *column_name"],
  40. ["char *", "PQfname", "const PGresult *res, int column_number"],
  41. ["ExecStatusType", "PQresultStatus", "const PGresult *res"],
  42. ["char *", "PQerrorMessage", "const PGconn *conn"],
  43. ["void", "PQreset", "PGconn *conn"],
  44. ["PGresult *", "PQgetResult", "PGconn *conn"],
  45. ["int", "PQsetnonblocking", "PGconn *conn, int arg"],
  46. ["Oid", "PQftype", "const PGresult *res, int column_number"],
  47. ["int", "PQserverVersion", "const PGconn *conn"],
  48. // Large-object access routines
  49. ["int", "lo_open", "PGconn *conn, Oid lobjId, int mode"],
  50. ["int", "lo_close", "PGconn *conn, int fd"],
  51. ["int", "lo_read", "PGconn *conn, int fd, char *buf, size_t len"],
  52. ["int", "lo_write", "PGconn *conn, int fd, const char *buf, size_t len"],
  53. ["int", "lo_lseek", "PGconn *conn, int fd, int offset, int whence"],
  54. ["Oid", "lo_creat", "PGconn *conn, int mode"],
  55. ["Oid", "lo_create", "PGconn *conn, Oid lobjId"],
  56. ["int", "lo_tell", "PGconn *conn, int fd"],
  57. ["int", "lo_truncate", "PGconn *conn, int fd, size_t len"],
  58. ["int", "lo_unlink", "PGconn *conn, Oid lobjId"],
  59. ["Oid", "lo_import", "PGconn *conn, const char *filename"],
  60. ["Oid", "lo_import_with_oid", "PGconn *conn, const char *filename, Oid lobjId"],
  61. ["int", "lo_export", "PGconn *conn, Oid lobjId, const char *filename"],
  62. //next entry should be the last one
  63. //to make valid the test made on load_libpq function
  64. ["PGconn *", "PQconnectdb", "const char *conninfo"],
  65. ];
  66. function write_pgsql_functions_declaration(){
  67. foreach(k,v in pgsql_functions) {
  68. putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
  69. putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
  70. }
  71. }
  72. function write_pgsql_functions_load(){
  73. foreach(k,v in pgsql_functions){
  74. putsnl("dl" + v[1] + " = (" + v[1] + "_t) libpq.dlsym(\"" + v[1] + "\");");
  75. putsnl("if(!dl" + v[1] + ") return false;");
  76. }
  77. }
  78. SquiLu*/
  79. static DynamicLibrary libpq;
  80. //@write_pgsql_functions_declaration();
  81. // generated-code:begin
  82. typedef ConnStatusType (*PQstatus_t)(const PGconn *conn);
  83. static PQstatus_t dlPQstatus = 0;
  84. typedef void (*PQfinish_t)(PGconn *conn);
  85. static PQfinish_t dlPQfinish = 0;
  86. typedef PGresult * (*PQprepare_t)(PGconn *conn,
  87. const char *stmtName,
  88. const char *query,
  89. int nParams,
  90. const Oid *paramTypes);
  91. static PQprepare_t dlPQprepare = 0;
  92. typedef PGresult * (*PQdescribePrepared_t)(PGconn *conn, const char *stmtName);
  93. static PQdescribePrepared_t dlPQdescribePrepared = 0;
  94. typedef int (*PQnparams_t)(const PGresult *res);
  95. static PQnparams_t dlPQnparams = 0;
  96. typedef Oid (*PQparamtype_t)(const PGresult *res, int param_number);
  97. static PQparamtype_t dlPQparamtype = 0;
  98. typedef PGresult * (*PQexecPrepared_t)(PGconn *conn,
  99. const char *stmtName,
  100. int nParams,
  101. const char * const *paramValues,
  102. const int *paramLengths,
  103. const int *paramFormats,
  104. int resultFormat);
  105. static PQexecPrepared_t dlPQexecPrepared = 0;
  106. typedef PGresult * (*PQexec_t)(PGconn *conn, const char *command);
  107. static PQexec_t dlPQexec = 0;
  108. typedef const char* (*PQgetvalue_t)(const PGresult *res,
  109. int row_number,
  110. int column_number);
  111. static PQgetvalue_t dlPQgetvalue = 0;
  112. typedef int (*PQntuples_t)(const PGresult *res);
  113. static PQntuples_t dlPQntuples = 0;
  114. typedef char * (*PQcmdTuples_t)(const PGresult *res);
  115. static PQcmdTuples_t dlPQcmdTuples = 0;
  116. typedef int (*PQnfields_t)(const PGresult *res);
  117. static PQnfields_t dlPQnfields = 0;
  118. typedef int (*PQgetisnull_t)(const PGresult *res,
  119. int row_number,
  120. int column_number);
  121. static PQgetisnull_t dlPQgetisnull = 0;
  122. typedef void (*PQclear_t)(const PGresult *res);
  123. static PQclear_t dlPQclear = 0;
  124. typedef int (*PQfnumber_t)(const PGresult *res, const char *column_name);
  125. static PQfnumber_t dlPQfnumber = 0;
  126. typedef char * (*PQfname_t)(const PGresult *res, int column_number);
  127. static PQfname_t dlPQfname = 0;
  128. typedef ExecStatusType (*PQresultStatus_t)(const PGresult *res);
  129. static PQresultStatus_t dlPQresultStatus = 0;
  130. typedef char * (*PQerrorMessage_t)(const PGconn *conn);
  131. static PQerrorMessage_t dlPQerrorMessage = 0;
  132. typedef void (*PQreset_t)(PGconn *conn);
  133. static PQreset_t dlPQreset = 0;
  134. typedef PGresult * (*PQgetResult_t)(PGconn *conn);
  135. static PQgetResult_t dlPQgetResult = 0;
  136. typedef int (*PQsetnonblocking_t)(PGconn *conn, int arg);
  137. static PQsetnonblocking_t dlPQsetnonblocking = 0;
  138. typedef Oid (*PQftype_t)(const PGresult *res, int column_number);
  139. static PQftype_t dlPQftype = 0;
  140. typedef int (*PQserverVersion_t)(const PGconn *conn);
  141. static PQserverVersion_t dlPQserverVersion = 0;
  142. typedef int (*lo_open_t)(PGconn *conn, Oid lobjId, int mode);
  143. static lo_open_t dllo_open = 0;
  144. typedef int (*lo_close_t)(PGconn *conn, int fd);
  145. static lo_close_t dllo_close = 0;
  146. typedef int (*lo_read_t)(PGconn *conn, int fd, char *buf, size_t len);
  147. static lo_read_t dllo_read = 0;
  148. typedef int (*lo_write_t)(PGconn *conn, int fd, const char *buf, size_t len);
  149. static lo_write_t dllo_write = 0;
  150. typedef int (*lo_lseek_t)(PGconn *conn, int fd, int offset, int whence);
  151. static lo_lseek_t dllo_lseek = 0;
  152. typedef Oid (*lo_creat_t)(PGconn *conn, int mode);
  153. static lo_creat_t dllo_creat = 0;
  154. typedef Oid (*lo_create_t)(PGconn *conn, Oid lobjId);
  155. static lo_create_t dllo_create = 0;
  156. typedef int (*lo_tell_t)(PGconn *conn, int fd);
  157. static lo_tell_t dllo_tell = 0;
  158. typedef int (*lo_truncate_t)(PGconn *conn, int fd, size_t len);
  159. static lo_truncate_t dllo_truncate = 0;
  160. typedef int (*lo_unlink_t)(PGconn *conn, Oid lobjId);
  161. static lo_unlink_t dllo_unlink = 0;
  162. typedef Oid (*lo_import_t)(PGconn *conn, const char *filename);
  163. static lo_import_t dllo_import = 0;
  164. typedef Oid (*lo_import_with_oid_t)(PGconn *conn, const char *filename, Oid lobjId);
  165. static lo_import_with_oid_t dllo_import_with_oid = 0;
  166. typedef int (*lo_export_t)(PGconn *conn, Oid lobjId, const char *filename);
  167. static lo_export_t dllo_export = 0;
  168. typedef PGconn * (*PQconnectdb_t)(const char *conninfo);
  169. static PQconnectdb_t dlPQconnectdb = 0;
  170. // generated-code:end
  171. #ifdef WIN32
  172. #define LIBPQ_NAME "libpq.dll"
  173. #else
  174. #define LIBPQ_NAME "libpq.so"
  175. #endif
  176. static bool load_libpq()
  177. {
  178. if(dlPQconnectdb) return true;
  179. if(libpq.open(LIBPQ_NAME))
  180. {
  181. //@write_pgsql_functions_load();
  182. // generated-code:begin
  183. dlPQstatus = (PQstatus_t) libpq.dlsym("PQstatus");
  184. if(!dlPQstatus) return false;
  185. dlPQfinish = (PQfinish_t) libpq.dlsym("PQfinish");
  186. if(!dlPQfinish) return false;
  187. dlPQprepare = (PQprepare_t) libpq.dlsym("PQprepare");
  188. if(!dlPQprepare) return false;
  189. dlPQdescribePrepared = (PQdescribePrepared_t) libpq.dlsym("PQdescribePrepared");
  190. if(!dlPQdescribePrepared) return false;
  191. dlPQnparams = (PQnparams_t) libpq.dlsym("PQnparams");
  192. if(!dlPQnparams) return false;
  193. dlPQparamtype = (PQparamtype_t) libpq.dlsym("PQparamtype");
  194. if(!dlPQparamtype) return false;
  195. dlPQexecPrepared = (PQexecPrepared_t) libpq.dlsym("PQexecPrepared");
  196. if(!dlPQexecPrepared) return false;
  197. dlPQexec = (PQexec_t) libpq.dlsym("PQexec");
  198. if(!dlPQexec) return false;
  199. dlPQgetvalue = (PQgetvalue_t) libpq.dlsym("PQgetvalue");
  200. if(!dlPQgetvalue) return false;
  201. dlPQntuples = (PQntuples_t) libpq.dlsym("PQntuples");
  202. if(!dlPQntuples) return false;
  203. dlPQcmdTuples = (PQcmdTuples_t) libpq.dlsym("PQcmdTuples");
  204. if(!dlPQcmdTuples) return false;
  205. dlPQnfields = (PQnfields_t) libpq.dlsym("PQnfields");
  206. if(!dlPQnfields) return false;
  207. dlPQgetisnull = (PQgetisnull_t) libpq.dlsym("PQgetisnull");
  208. if(!dlPQgetisnull) return false;
  209. dlPQclear = (PQclear_t) libpq.dlsym("PQclear");
  210. if(!dlPQclear) return false;
  211. dlPQfnumber = (PQfnumber_t) libpq.dlsym("PQfnumber");
  212. if(!dlPQfnumber) return false;
  213. dlPQfname = (PQfname_t) libpq.dlsym("PQfname");
  214. if(!dlPQfname) return false;
  215. dlPQresultStatus = (PQresultStatus_t) libpq.dlsym("PQresultStatus");
  216. if(!dlPQresultStatus) return false;
  217. dlPQerrorMessage = (PQerrorMessage_t) libpq.dlsym("PQerrorMessage");
  218. if(!dlPQerrorMessage) return false;
  219. dlPQreset = (PQreset_t) libpq.dlsym("PQreset");
  220. if(!dlPQreset) return false;
  221. dlPQgetResult = (PQgetResult_t) libpq.dlsym("PQgetResult");
  222. if(!dlPQgetResult) return false;
  223. dlPQsetnonblocking = (PQsetnonblocking_t) libpq.dlsym("PQsetnonblocking");
  224. if(!dlPQsetnonblocking) return false;
  225. dlPQftype = (PQftype_t) libpq.dlsym("PQftype");
  226. if(!dlPQftype) return false;
  227. dlPQserverVersion = (PQserverVersion_t) libpq.dlsym("PQserverVersion");
  228. if(!dlPQserverVersion) return false;
  229. dllo_open = (lo_open_t) libpq.dlsym("lo_open");
  230. if(!dllo_open) return false;
  231. dllo_close = (lo_close_t) libpq.dlsym("lo_close");
  232. if(!dllo_close) return false;
  233. dllo_read = (lo_read_t) libpq.dlsym("lo_read");
  234. if(!dllo_read) return false;
  235. dllo_write = (lo_write_t) libpq.dlsym("lo_write");
  236. if(!dllo_write) return false;
  237. dllo_lseek = (lo_lseek_t) libpq.dlsym("lo_lseek");
  238. if(!dllo_lseek) return false;
  239. dllo_creat = (lo_creat_t) libpq.dlsym("lo_creat");
  240. if(!dllo_creat) return false;
  241. dllo_create = (lo_create_t) libpq.dlsym("lo_create");
  242. if(!dllo_create) return false;
  243. dllo_tell = (lo_tell_t) libpq.dlsym("lo_tell");
  244. if(!dllo_tell) return false;
  245. dllo_truncate = (lo_truncate_t) libpq.dlsym("lo_truncate");
  246. if(!dllo_truncate) return false;
  247. dllo_unlink = (lo_unlink_t) libpq.dlsym("lo_unlink");
  248. if(!dllo_unlink) return false;
  249. dllo_import = (lo_import_t) libpq.dlsym("lo_import");
  250. if(!dllo_import) return false;
  251. dllo_import_with_oid = (lo_import_with_oid_t) libpq.dlsym("lo_import_with_oid");
  252. if(!dllo_import_with_oid) return false;
  253. dllo_export = (lo_export_t) libpq.dlsym("lo_export");
  254. if(!dllo_export) return false;
  255. dlPQconnectdb = (PQconnectdb_t) libpq.dlsym("PQconnectdb");
  256. if(!dlPQconnectdb) return false;
  257. // generated-code:end
  258. return true;
  259. }
  260. return false;
  261. }
  262. ////////////////////////////////////////////////////////////////////////////////
  263. static const SQChar *PostgreSQL_TAG = _SC("PostgreSQL");
  264. static SQRESULT get_pgsql_instance(HSQUIRRELVM v, SQInteger idx, PGconn **self){
  265. SQRESULT _rc_;
  266. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)PostgreSQL_TAG)) < 0) return _rc_;
  267. if(!*self) return sq_throwerror(v, _SC("database is closed"));
  268. return _rc_;
  269. }
  270. #define GET_pgsql_INSTANCE_AT(idx) \
  271. PGconn *self=NULL; \
  272. if((_rc_ = get_pgsql_instance(v,idx,&self)) < 0) return _rc_;
  273. #define GET_pgsql_INSTANCE() GET_pgsql_INSTANCE_AT(1)
  274. static const SQChar *PostgreSQL_Result_TAG = _SC("PostgreSQL_Result");
  275. static const SQChar *_curr_row_key = _SC("_curr_row");
  276. static SQRESULT get_pgsql_result_instance(HSQUIRRELVM v, SQInteger idx, PGresult **self){
  277. SQRESULT _rc_;
  278. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)PostgreSQL_Result_TAG)) < 0) return _rc_;
  279. if(!*self) return sq_throwerror(v, _SC("PGresult is closed"));
  280. return _rc_;
  281. }
  282. #define GET_pgsql_result_INSTANCE_AT(idx) \
  283. PGresult *self=NULL; \
  284. if((_rc_ = get_pgsql_result_instance(v,idx,&self)) < 0) return _rc_;
  285. #define GET_pgsql_result_INSTANCE() GET_pgsql_result_INSTANCE_AT(1)
  286. static SQRESULT sq_pgsql_result_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  287. {
  288. PGresult *self = ((PGresult *)p);
  289. if (self) dlPQclear(self);
  290. return 0;
  291. }
  292. static SQRESULT sq_pgsql_result_close(HSQUIRRELVM v){
  293. SQ_FUNC_VARS_NO_TOP(v);
  294. GET_pgsql_result_INSTANCE();
  295. dlPQclear(self);
  296. sq_setinstanceup(v, 1, 0); //next calls will fail with "Pgresult is closed"
  297. return 0;
  298. }
  299. static SQRESULT sq_pgsql_result_col_count(HSQUIRRELVM v){
  300. SQ_FUNC_VARS_NO_TOP(v);
  301. GET_pgsql_result_INSTANCE();
  302. sq_pushinteger(v, dlPQnfields(self));
  303. return 1;
  304. }
  305. static SQRESULT sq_pgsql_result_row_count(HSQUIRRELVM v){
  306. SQ_FUNC_VARS_NO_TOP(v);
  307. GET_pgsql_result_INSTANCE();
  308. sq_pushinteger(v, dlPQntuples(self));
  309. return 1;
  310. }
  311. static SQRESULT sq_pgsql_result_col_name(HSQUIRRELVM v){
  312. SQ_FUNC_VARS_NO_TOP(v);
  313. GET_pgsql_result_INSTANCE();
  314. SQ_GET_INTEGER(v, 2, col);
  315. sq_pushstring(v, dlPQfname(self, col), -1);
  316. return 1;
  317. }
  318. static SQRESULT sq_pgsql_result_col_index(HSQUIRRELVM v){
  319. SQ_FUNC_VARS_NO_TOP(v);
  320. GET_pgsql_result_INSTANCE();
  321. SQ_GET_STRING(v, 2, name);
  322. sq_pushinteger(v, dlPQfnumber(self, name));
  323. return 1;
  324. }
  325. static SQRESULT sq_pgsql_result_eof(HSQUIRRELVM v){
  326. SQ_FUNC_VARS_NO_TOP(v);
  327. GET_pgsql_result_INSTANCE();
  328. sq_pushstring(v, _curr_row_key, -1);
  329. if(sq_get(v, 1) == SQ_OK){
  330. SQ_GET_INTEGER(v, -1, curr_row);
  331. sq_pushbool(v, curr_row < dlPQntuples(self));
  332. }
  333. else sq_pushbool(v, SQTrue);
  334. return 1;
  335. }
  336. static SQRESULT sq_pgsql_result_next_row(HSQUIRRELVM v){
  337. SQ_FUNC_VARS_NO_TOP(v);
  338. GET_pgsql_result_INSTANCE();
  339. sq_pushstring(v, _curr_row_key, -1);
  340. sq_push(v, -1); //make a copy
  341. if(sq_get(v, 1) == SQ_OK){
  342. SQ_GET_INTEGER(v, -1, curr_row);
  343. if(++curr_row < dlPQntuples(self)){
  344. sq_poptop(v);
  345. sq_pushinteger(v, curr_row);
  346. sq_set(v, 1);
  347. sq_pushbool(v, SQTrue);
  348. return 1;
  349. }
  350. }
  351. sq_pushbool(v, SQFalse);
  352. return 1;
  353. }
  354. static SQRESULT sq_pgsql_result_col_value(HSQUIRRELVM v){
  355. SQ_FUNC_VARS_NO_TOP(v);
  356. GET_pgsql_result_INSTANCE();
  357. SQObjectType ptype = sq_gettype(v, 2);
  358. int col = -1;
  359. if(ptype == OT_STRING){
  360. SQ_GET_STRING(v, 2, col_name);
  361. col = dlPQfnumber(self, col_name);
  362. }
  363. else
  364. {
  365. SQ_GET_INTEGER(v, 2, idx);
  366. col = idx;
  367. }
  368. if(col < 0) return sq_throwerror(v, _SC("invalid col index/name"));
  369. sq_pushstring(v, _curr_row_key, -1);
  370. if(sq_get(v, 1) == SQ_OK){
  371. SQ_GET_INTEGER(v, -1, curr_row);
  372. if(curr_row < dlPQntuples(self)){
  373. sq_pushstring(v, dlPQgetvalue(self, curr_row, col), -1);
  374. return 1;
  375. }
  376. }
  377. return SQ_ERROR;
  378. }
  379. static SQRESULT sq_pgsql_result_row_as_array(HSQUIRRELVM v){
  380. SQ_FUNC_VARS(v);
  381. GET_pgsql_result_INSTANCE();
  382. SQ_OPT_INTEGER(v, 2, row, -1);
  383. if(row < 0){
  384. sq_pushstring(v, _curr_row_key, -1);
  385. if(sq_get(v, 1) == SQ_OK){
  386. sq_getinteger(v, -1, &row);
  387. }
  388. }
  389. int row_count = dlPQntuples(self);
  390. if(row < 0 || row >= row_count) return sq_throwerror(v, _SC("invalid row (%d)"), row);
  391. int col_count = dlPQnfields(self);
  392. sq_newarray(v, col_count);
  393. for(int i=0; i < col_count; ++i){
  394. sq_pushinteger(v, i);
  395. sq_pushstring(v, dlPQgetvalue(self, row, i), -1);
  396. sq_rawset(v, -3);
  397. }
  398. return 1;
  399. }
  400. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_pgsql_result_##name,nparams,tycheck}
  401. static SQRegFunction sq_pgsql_result_methods[] =
  402. {
  403. _DECL_FUNC(close, 1, _SC("x")),
  404. _DECL_FUNC(eof, 1, _SC("x")),
  405. _DECL_FUNC(next_row, 1, _SC("x")),
  406. _DECL_FUNC(col_count, 1, _SC("x")),
  407. _DECL_FUNC(row_count, 1, _SC("x")),
  408. _DECL_FUNC(col_name, 2, _SC("xi")),
  409. _DECL_FUNC(col_index, 2, _SC("xs")),
  410. _DECL_FUNC(col_value, 2, _SC("x i|s")),
  411. _DECL_FUNC(row_as_array, -1, _SC("xi")),
  412. {0,0}
  413. };
  414. #undef _DECL_FUNC
  415. struct PgSqlStatement {
  416. PGconn *db;
  417. PGresult *result;
  418. char name[64];
  419. };
  420. static const SQChar *PostgreSQL_Statement_TAG = _SC("PostgreSQL_Statement");
  421. static SQRESULT get_pgsql_statement_instance(HSQUIRRELVM v, SQInteger idx, PgSqlStatement **self){
  422. SQRESULT _rc_;
  423. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)PostgreSQL_Statement_TAG)) < 0) return _rc_;
  424. if(!*self) return sq_throwerror(v, _SC("PGstatement is closed"));
  425. return _rc_;
  426. }
  427. #define GET_pgsql_statement_INSTANCE_AT(idx) \
  428. PgSqlStatement *self=NULL; \
  429. if((_rc_ = get_pgsql_statement_instance(v,idx,&self)) < 0) return _rc_;
  430. #define GET_pgsql_statement_INSTANCE() GET_pgsql_statement_INSTANCE_AT(1)
  431. static SQRESULT sq_pgsql_statement_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  432. {
  433. PgSqlStatement *self = ((PgSqlStatement *)p);
  434. if (self && self->result){
  435. char sql[128];
  436. snprintf(sql, sizeof(sql), "DEALLOCATE '%s'", self->name);
  437. PGresult *qres = dlPQexec(self->db, sql);
  438. bool is_ok = dlPQresultStatus(qres) != PGRES_BAD_RESPONSE;
  439. dlPQclear(qres);
  440. if(is_ok) dlPQclear(self->result);
  441. sq_free(self, sizeof(PgSqlStatement));
  442. }
  443. return 0;
  444. }
  445. static SQRESULT sq_pgsql_statement_close(HSQUIRRELVM v){
  446. SQ_FUNC_VARS_NO_TOP(v);
  447. GET_pgsql_statement_INSTANCE();
  448. sq_pgsql_statement_releasehook(self, 0, v);
  449. sq_setinstanceup(v, 1, 0); //next calls will fail with "Pgstatement is closed"
  450. return 0;
  451. }
  452. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_pgsql_statement_##name,nparams,tycheck}
  453. static SQRegFunction sq_pgsql_statement_methods[] =
  454. {
  455. _DECL_FUNC(close, 1, _SC("x")),
  456. {0,0}
  457. };
  458. #undef _DECL_FUNC
  459. static SQRESULT sq_pgsql_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  460. {
  461. PGconn *self = ((PGconn *)p);
  462. if (self) dlPQfinish(self);
  463. return 0;
  464. }
  465. static SQRESULT sq_pgsql_constructor(HSQUIRRELVM v)
  466. {
  467. SQ_FUNC_VARS_NO_TOP(v);
  468. SQ_GET_STRING(v, 2, szConnInfo);
  469. PGconn *self=0;
  470. if(load_libpq())
  471. {
  472. self = dlPQconnectdb(szConnInfo);
  473. if (dlPQstatus(self) == CONNECTION_BAD) return sq_throwerror(v, _SC("Failed to connect ot database !"));
  474. }
  475. else return sq_throwerror(v, _SC("Failed to load libpq !"));
  476. sq_setinstanceup(v, 1, self);
  477. sq_setreleasehook(v,1, sq_pgsql_releasehook);
  478. //save a weakref to allow statement return it's db
  479. sq_pushuserpointer(v, self);
  480. sq_weakref(v, 1);
  481. sq_setonregistrytable(v);
  482. return 1;
  483. }
  484. static SQRESULT sq_pgsql_close(HSQUIRRELVM v){
  485. SQ_FUNC_VARS_NO_TOP(v);
  486. GET_pgsql_INSTANCE();
  487. dlPQfinish(self);
  488. sq_setinstanceup(v, 1, 0); //next calls will fail with "database is closed"
  489. return 0;
  490. }
  491. static SQRESULT sq_pgsql_exec_dml(HSQUIRRELVM v){
  492. SQ_FUNC_VARS_NO_TOP(v);
  493. GET_pgsql_INSTANCE();
  494. SQ_GET_STRING(v, 2, szSQL);
  495. int result = 0;
  496. PGresult *qres = dlPQexec(self, szSQL);
  497. bool is_ok = dlPQresultStatus(qres) == PGRES_COMMAND_OK;
  498. if (is_ok) result = atoi(dlPQcmdTuples(qres));
  499. dlPQclear(qres);
  500. if (!is_ok) return sq_throwerror(v, dlPQerrorMessage(self));
  501. sq_pushinteger(v, result);
  502. return 1;
  503. }
  504. static SQRESULT sq_pgsql_exec_scalar(HSQUIRRELVM v){
  505. SQ_FUNC_VARS_NO_TOP(v);
  506. GET_pgsql_INSTANCE();
  507. SQ_GET_STRING(v, 2, szSQL);
  508. int result = 0;
  509. PGresult *qres = dlPQexec(self, szSQL);
  510. bool is_ok = (dlPQresultStatus(qres) == PGRES_TUPLES_OK) &&
  511. (dlPQntuples(qres) == 1) && (dlPQnfields(qres) > 0);
  512. if (is_ok) result = atoi(dlPQgetvalue(qres, 0, 0));
  513. dlPQclear(qres);
  514. if (!is_ok) return sq_throwerror(v, dlPQerrorMessage(self));
  515. sq_pushinteger(v, result);
  516. return 1;
  517. }
  518. static SQRESULT sq_pgsql_exec_query(HSQUIRRELVM v){
  519. SQ_FUNC_VARS_NO_TOP(v);
  520. GET_pgsql_INSTANCE();
  521. SQ_GET_STRING(v, 2, szSQL);
  522. PGresult *qres = dlPQexec(self, szSQL);
  523. if(dlPQresultStatus(qres) == PGRES_TUPLES_OK){
  524. sq_pushroottable(v);
  525. sq_pushstring(v, PostgreSQL_Result_TAG, -1);
  526. if(sq_get(v, -2) == SQ_OK){
  527. if(sq_createinstance(v, -1) == SQ_OK){
  528. sq_setinstanceup(v, -1, qres);
  529. sq_setreleasehook(v, -1, sq_pgsql_result_releasehook);
  530. sq_pushstring(v, _curr_row_key, -1);
  531. sq_pushinteger(v, -1);
  532. sq_set(v, -3);
  533. return 1;
  534. }
  535. }
  536. }
  537. return sq_throwerror(v, dlPQerrorMessage(self));
  538. }
  539. static SQRESULT sq_pgsql_prepare(HSQUIRRELVM v){
  540. SQ_FUNC_VARS_NO_TOP(v);
  541. GET_pgsql_INSTANCE();
  542. SQ_GET_STRING(v, 2, szSQL);
  543. PgSqlStatement *stmt = (PgSqlStatement*)sq_malloc(sizeof(PgSqlStatement));
  544. stmt->db = self;
  545. snprintf(stmt->name, sizeof(stmt->name), "sq_pg_preared_stmt_%p", stmt);
  546. stmt->result = dlPQprepare(self, stmt->name, szSQL, 0, NULL);
  547. if(dlPQresultStatus(stmt->result) == PGRES_COMMAND_OK){
  548. sq_pushroottable(v);
  549. sq_pushstring(v, PostgreSQL_Statement_TAG, -1);
  550. if(sq_get(v, -2) == SQ_OK){
  551. if(sq_createinstance(v, -1) == SQ_OK){
  552. sq_setinstanceup(v, -1, stmt);
  553. sq_setreleasehook(v, -1, sq_pgsql_statement_releasehook);
  554. return 1;
  555. }
  556. }
  557. }
  558. sq_free(stmt, sizeof(PgSqlStatement));
  559. return sq_throwerror(v, dlPQerrorMessage(self));
  560. }
  561. static SQRESULT sq_pgsql_error_message(HSQUIRRELVM v){
  562. SQ_FUNC_VARS_NO_TOP(v);
  563. GET_pgsql_INSTANCE();
  564. sq_pushstring(v, dlPQerrorMessage(self), -1);
  565. return 1;
  566. }
  567. static SQRESULT sq_pgsql_version(HSQUIRRELVM v){
  568. SQ_FUNC_VARS_NO_TOP(v);
  569. GET_pgsql_INSTANCE();
  570. sq_pushinteger(v, dlPQserverVersion(self));
  571. return 1;
  572. }
  573. static int
  574. inv_read = 0x40000,
  575. inv_write = 0x20000,
  576. invalidoid = 0,
  577. inv_seek_set = 0,
  578. inv_seek_curr = 1,
  579. inv_seek_end = 2;
  580. static SQRESULT sq_pgsql_get_blob_field(HSQUIRRELVM v){
  581. SQ_FUNC_VARS_NO_TOP(v);
  582. GET_pgsql_INSTANCE();
  583. SQ_GET_INTEGER(v, 2, oid);
  584. //begin_recursive_transaction();
  585. char *result = 0;
  586. int ofd = dllo_open(self, oid, inv_read);
  587. if(ofd >= 0){
  588. int blobSize = dllo_lseek(self, ofd, 0, inv_seek_end);
  589. dllo_lseek(self, ofd, 0, inv_seek_set);
  590. SQBlob blob(blobSize);
  591. result = (char*)blob.GetBuf();
  592. int numRead = 0;
  593. while(blobSize > 0){
  594. int i = dllo_read(self, ofd, result+numRead, blobSize);
  595. numRead += i;
  596. blobSize -= i;
  597. }
  598. dllo_close(self, oid);
  599. sq_pushstring(v, (const SQChar*)blob.GetBuf(), blob.Len());
  600. }
  601. //commit_recursive_transaction();
  602. if(!result) sq_pushnull(v);
  603. return 1;
  604. }
  605. static SQRESULT sq_pgsql_insert_blob_field(HSQUIRRELVM v){
  606. SQ_FUNC_VARS_NO_TOP(v);
  607. GET_pgsql_INSTANCE();
  608. int result = 0;
  609. SQ_GET_STRING(v, 2, blob);
  610. SQ_GET_BOOL(v, 3, isFileName);
  611. if(isFileName){
  612. result = dllo_import(self, blob);
  613. } else {
  614. result = dllo_creat(self, inv_write);
  615. if(result){
  616. int ofd = dllo_open(self, result, inv_write);
  617. if (ofd >= 0){
  618. int i = blob_size;
  619. const char *blopPtr = (const char *)blob;
  620. int numWriten = 0;
  621. while(i > 0){
  622. int i2 = dllo_write(self, ofd, blopPtr+numWriten, i);
  623. numWriten += i2;
  624. i -= i2;
  625. }
  626. dllo_close(self, ofd);
  627. }
  628. else return sq_throwerror(v, _SC("Failed to insert blob !"));
  629. }
  630. }
  631. if(!result) sq_pushnull(v);
  632. return 1;
  633. }
  634. static SQRESULT sq_pgsql_update_blob_field(HSQUIRRELVM v){
  635. SQ_FUNC_VARS_NO_TOP(v);
  636. GET_pgsql_INSTANCE();
  637. SQ_GET_INTEGER(v, 2, oid);
  638. SQ_GET_STRING(v, 3, blob);
  639. SQ_GET_BOOL(v, 4, isFileName);
  640. int result_oid = 0;
  641. int result_error = SQ_OK;
  642. int loid = dllo_creat(self, inv_write);
  643. int ofd = dllo_open(self, loid, inv_write);
  644. if(ofd >= 0){
  645. dllo_unlink(self, oid);
  646. result_oid = loid;
  647. if(isFileName)
  648. {
  649. char buf[2048];
  650. FILE *fp = fopen(blob, "rb");
  651. if(!fp) {
  652. sq_throwerror(v, _SC("Failed to update blob from file !"));
  653. result_error = SQ_ERROR;
  654. }
  655. else
  656. {
  657. char *charPtr = buf;
  658. int numRead;
  659. do{
  660. numRead = fread(buf, 1, sizeof(buf), fp);
  661. int numWriten = dllo_write(self, ofd, charPtr, numRead);
  662. if (numWriten != numRead) {
  663. sq_throwerror(v, _SC("Failed to update blob from file !"));
  664. result_error = SQ_ERROR;
  665. break;
  666. }
  667. } while (numRead == 0);
  668. fclose(fp);
  669. }
  670. }else{
  671. int i = blob_size;
  672. const char *blopPtr = (const char *)blob;
  673. int numWriten = 0;
  674. while(i > 0){
  675. int i2 = dllo_write(self, ofd, blopPtr+numWriten, i);
  676. numWriten += i2;
  677. i -= i2;
  678. }
  679. }
  680. dllo_close(self, ofd);
  681. }
  682. if(result_error == SQ_ERROR) return result_error;
  683. sq_pushinteger(v, result_oid);
  684. return 1;
  685. }
  686. static SQRESULT sq_pgsql_delete_blob_field(HSQUIRRELVM v){
  687. SQ_FUNC_VARS_NO_TOP(v);
  688. GET_pgsql_INSTANCE();
  689. SQ_GET_INTEGER(v, 2, oid);
  690. sq_pushinteger(v, dllo_unlink(self, oid));
  691. return 1;
  692. }
  693. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_pgsql_##name,nparams,tycheck}
  694. static SQRegFunction sq_pgsql_methods[] =
  695. {
  696. _DECL_FUNC(constructor, 2, _SC("xs")),
  697. _DECL_FUNC(close, 1, _SC("x")),
  698. _DECL_FUNC(exec_dml, 2, _SC("xs")),
  699. _DECL_FUNC(exec_scalar, 2, _SC("xs")),
  700. _DECL_FUNC(exec_query, 2, _SC("xs")),
  701. _DECL_FUNC(prepare, 2, _SC("xs")),
  702. _DECL_FUNC(error_message, 1, _SC("x")),
  703. _DECL_FUNC(version, 1, _SC("x")),
  704. _DECL_FUNC(get_blob_field, 2, _SC("xi")),
  705. _DECL_FUNC(insert_blob_field, 3, _SC("xsb")),
  706. _DECL_FUNC(update_blob_field, 3, _SC("xisb")),
  707. _DECL_FUNC(delete_blob_field, 2, _SC("xi")),
  708. {0,0}
  709. };
  710. #undef _DECL_FUNC
  711. #ifdef __cplusplus
  712. extern "C" {
  713. #endif
  714. SQRESULT sqext_register_PostgreSQL(HSQUIRRELVM v)
  715. {
  716. sq_pushstring(v,PostgreSQL_TAG,-1);
  717. sq_newclass(v,SQFalse);
  718. sq_settypetag(v,-1,(void*)PostgreSQL_TAG);
  719. sq_insert_reg_funcs(v, sq_pgsql_methods);
  720. sq_newslot(v,-3,SQTrue);
  721. sq_pushstring(v,PostgreSQL_Statement_TAG,-1);
  722. sq_newclass(v,SQFalse);
  723. sq_settypetag(v,-1,(void*)PostgreSQL_Statement_TAG);
  724. sq_insert_reg_funcs(v, sq_pgsql_statement_methods);
  725. sq_newslot(v,-3,SQTrue);
  726. sq_pushstring(v,PostgreSQL_Result_TAG,-1);
  727. sq_newclass(v,SQFalse);
  728. sq_settypetag(v,-1,(void*)PostgreSQL_Result_TAG);
  729. sq_insert_reg_funcs(v, sq_pgsql_result_methods);
  730. sq_pushstring(v, _curr_row_key, -1);
  731. sq_pushnull(v);
  732. sq_newslot(v, -3, SQFalse);
  733. sq_newslot(v,-3,SQTrue);
  734. return 0;
  735. }
  736. #ifdef __cplusplus
  737. }
  738. #endif
  739. #endif // WITH_POSTGRESQL