sq_postgresql.cpp 38 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181
  1. #ifdef WITH_POSTGRESQL
  2. #include "squirrel.h"
  3. #include "libpq-fe.h"
  4. //#include "pg_type.h"
  5. #include <string.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include "sqstdblobimpl.h"
  9. SQ_OPT_STRING_STRLEN();
  10. #define BOOLOID 16
  11. #define BYTEAOID 17
  12. #define CHAROID 18
  13. #define INT8OID 20
  14. #define INT2OID 21
  15. #define INT4OID 23
  16. #define FLOAT4OID 700
  17. #define FLOAT8OID 701
  18. #define TIMESTAMPOID 1114
  19. #define TIMESTAMPTZOID 1184
  20. #define VARCHAROID 1043
  21. #include "dynamic_library.h"
  22. /*SquiLu
  23. local pgsql_functions = [
  24. ["ConnStatusType", "PQstatus", "const PGconn *conn"],
  25. ["void", "PQfinish", "PGconn *conn"],
  26. ["PGresult *", "PQprepare", @"PGconn *conn,
  27. const char *stmtName,
  28. const char *query,
  29. int nParams,
  30. const Oid *paramTypes"],
  31. ["void", "PQfreemem", "void *ptr"],
  32. ["char *", "PQescapeLiteral", "PGconn *conn, const char *str, size_t length"],
  33. ["char *", "PQescapeIdentifier", "PGconn *conn, const char *str, size_t length"],
  34. ["unsigned char *", "PQescapeByteaConn", "PGconn *conn, const unsigned char *str, size_t length"],
  35. ["unsigned char *", "PQunescapeBytea", "const unsigned char *str, size_t length"],
  36. ["PGresult *", "PQdescribePrepared", "PGconn *conn, const char *stmtName"],
  37. ["int", "PQnparams", "const PGresult *res"],
  38. ["Oid", "PQparamtype", "const PGresult *res, int param_number"],
  39. ["PGresult *", "PQexecPrepared", @"PGconn *conn,
  40. const char *stmtName,
  41. int nParams,
  42. const char * const *paramValues,
  43. const int *paramLengths,
  44. const int *paramFormats,
  45. int resultFormat"],
  46. ["PGresult *", "PQexec", "PGconn *conn, const char *command"],
  47. ["const char*", "PQgetvalue", @"const PGresult *res,
  48. int row_number,
  49. int column_number"],
  50. ["int", "PQntuples", "const PGresult *res"],
  51. ["char *", "PQcmdTuples", "const PGresult *res"],
  52. ["int", "PQnfields", "const PGresult *res"],
  53. ["int", "PQgetisnull", @"const PGresult *res,
  54. int row_number,
  55. int column_number"],
  56. ["void", "PQclear", "const PGresult *res"],
  57. ["int", "PQfnumber", "const PGresult *res, const char *column_name"],
  58. ["char *", "PQfname", "const PGresult *res, int column_number"],
  59. ["ExecStatusType", "PQresultStatus", "const PGresult *res"],
  60. ["char *", "PQerrorMessage", "const PGconn *conn"],
  61. ["void", "PQreset", "PGconn *conn"],
  62. ["PGresult *", "PQgetResult", "PGconn *conn"],
  63. ["int", "PQsetnonblocking", "PGconn *conn, int arg"],
  64. ["Oid", "PQftype", "const PGresult *res, int column_number"],
  65. ["int", "PQserverVersion", "const PGconn *conn"],
  66. // Large-object access routines
  67. ["int", "lo_open", "PGconn *conn, Oid lobjId, int mode"],
  68. ["int", "lo_close", "PGconn *conn, int fd"],
  69. ["int", "lo_read", "PGconn *conn, int fd, char *buf, size_t len"],
  70. ["int", "lo_write", "PGconn *conn, int fd, const char *buf, size_t len"],
  71. ["int", "lo_lseek", "PGconn *conn, int fd, int offset, int whence"],
  72. ["Oid", "lo_creat", "PGconn *conn, int mode"],
  73. ["Oid", "lo_create", "PGconn *conn, Oid lobjId"],
  74. ["int", "lo_tell", "PGconn *conn, int fd"],
  75. ["int", "lo_truncate", "PGconn *conn, int fd, size_t len"],
  76. ["int", "lo_unlink", "PGconn *conn, Oid lobjId"],
  77. ["Oid", "lo_import", "PGconn *conn, const char *filename"],
  78. ["Oid", "lo_import_with_oid", "PGconn *conn, const char *filename, Oid lobjId"],
  79. ["int", "lo_export", "PGconn *conn, Oid lobjId, const char *filename"],
  80. //next entry should be the last one
  81. //to make valid the test made on load_libpq function
  82. ["PGconn *", "PQconnectdb", "const char *conninfo"],
  83. ];
  84. function write_pgsql_functions_declaration(){
  85. foreach(k,v in pgsql_functions) {
  86. putsnl("typedef " + v[0] + " (*" + v[1] + "_t)(" + v[2] + ");");
  87. putsnl("static " + v[1] + "_t dl" + v[1] + " = 0;");
  88. }
  89. }
  90. function write_pgsql_functions_load(){
  91. foreach(k,v in pgsql_functions){
  92. putsnl("dl" + v[1] + " = (" + v[1] + "_t) libpq.dlsym(\"" + v[1] + "\");");
  93. putsnl("if(!dl" + v[1] + ") return false;");
  94. }
  95. }
  96. SquiLu*/
  97. static DynamicLibrary libpq;
  98. //@write_pgsql_functions_declaration();
  99. // generated-code:begin
  100. typedef ConnStatusType (*PQstatus_t)(const PGconn *conn);
  101. static PQstatus_t dlPQstatus = 0;
  102. typedef void (*PQfinish_t)(PGconn *conn);
  103. static PQfinish_t dlPQfinish = 0;
  104. typedef PGresult * (*PQprepare_t)(PGconn *conn,
  105. const char *stmtName,
  106. const char *query,
  107. int nParams,
  108. const Oid *paramTypes);
  109. static PQprepare_t dlPQprepare = 0;
  110. typedef void (*PQfreemem_t)(void *ptr);
  111. static PQfreemem_t dlPQfreemem = 0;
  112. typedef char * (*PQescapeLiteral_t)(PGconn *conn, const char *str, size_t length);
  113. static PQescapeLiteral_t dlPQescapeLiteral = 0;
  114. typedef char * (*PQescapeIdentifier_t)(PGconn *conn, const char *str, size_t length);
  115. static PQescapeIdentifier_t dlPQescapeIdentifier = 0;
  116. typedef unsigned char * (*PQescapeByteaConn_t)(PGconn *conn, const unsigned char *str, size_t length);
  117. static PQescapeByteaConn_t dlPQescapeByteaConn = 0;
  118. typedef unsigned char * (*PQunescapeBytea_t)(const unsigned char *str, size_t length);
  119. static PQunescapeBytea_t dlPQunescapeBytea = 0;
  120. typedef PGresult * (*PQdescribePrepared_t)(PGconn *conn, const char *stmtName);
  121. static PQdescribePrepared_t dlPQdescribePrepared = 0;
  122. typedef int (*PQnparams_t)(const PGresult *res);
  123. static PQnparams_t dlPQnparams = 0;
  124. typedef Oid (*PQparamtype_t)(const PGresult *res, int param_number);
  125. static PQparamtype_t dlPQparamtype = 0;
  126. typedef PGresult * (*PQexecPrepared_t)(PGconn *conn,
  127. const char *stmtName,
  128. int nParams,
  129. const char * const *paramValues,
  130. const int *paramLengths,
  131. const int *paramFormats,
  132. int resultFormat);
  133. static PQexecPrepared_t dlPQexecPrepared = 0;
  134. typedef PGresult * (*PQexec_t)(PGconn *conn, const char *command);
  135. static PQexec_t dlPQexec = 0;
  136. typedef const char* (*PQgetvalue_t)(const PGresult *res,
  137. int row_number,
  138. int column_number);
  139. static PQgetvalue_t dlPQgetvalue = 0;
  140. typedef int (*PQntuples_t)(const PGresult *res);
  141. static PQntuples_t dlPQntuples = 0;
  142. typedef char * (*PQcmdTuples_t)(const PGresult *res);
  143. static PQcmdTuples_t dlPQcmdTuples = 0;
  144. typedef int (*PQnfields_t)(const PGresult *res);
  145. static PQnfields_t dlPQnfields = 0;
  146. typedef int (*PQgetisnull_t)(const PGresult *res,
  147. int row_number,
  148. int column_number);
  149. static PQgetisnull_t dlPQgetisnull = 0;
  150. typedef void (*PQclear_t)(const PGresult *res);
  151. static PQclear_t dlPQclear = 0;
  152. typedef int (*PQfnumber_t)(const PGresult *res, const char *column_name);
  153. static PQfnumber_t dlPQfnumber = 0;
  154. typedef char * (*PQfname_t)(const PGresult *res, int column_number);
  155. static PQfname_t dlPQfname = 0;
  156. typedef ExecStatusType (*PQresultStatus_t)(const PGresult *res);
  157. static PQresultStatus_t dlPQresultStatus = 0;
  158. typedef char * (*PQerrorMessage_t)(const PGconn *conn);
  159. static PQerrorMessage_t dlPQerrorMessage = 0;
  160. typedef void (*PQreset_t)(PGconn *conn);
  161. static PQreset_t dlPQreset = 0;
  162. typedef PGresult * (*PQgetResult_t)(PGconn *conn);
  163. static PQgetResult_t dlPQgetResult = 0;
  164. typedef int (*PQsetnonblocking_t)(PGconn *conn, int arg);
  165. static PQsetnonblocking_t dlPQsetnonblocking = 0;
  166. typedef Oid (*PQftype_t)(const PGresult *res, int column_number);
  167. static PQftype_t dlPQftype = 0;
  168. typedef int (*PQserverVersion_t)(const PGconn *conn);
  169. static PQserverVersion_t dlPQserverVersion = 0;
  170. typedef int (*lo_open_t)(PGconn *conn, Oid lobjId, int mode);
  171. static lo_open_t dllo_open = 0;
  172. typedef int (*lo_close_t)(PGconn *conn, int fd);
  173. static lo_close_t dllo_close = 0;
  174. typedef int (*lo_read_t)(PGconn *conn, int fd, char *buf, size_t len);
  175. static lo_read_t dllo_read = 0;
  176. typedef int (*lo_write_t)(PGconn *conn, int fd, const char *buf, size_t len);
  177. static lo_write_t dllo_write = 0;
  178. typedef int (*lo_lseek_t)(PGconn *conn, int fd, int offset, int whence);
  179. static lo_lseek_t dllo_lseek = 0;
  180. typedef Oid (*lo_creat_t)(PGconn *conn, int mode);
  181. static lo_creat_t dllo_creat = 0;
  182. typedef Oid (*lo_create_t)(PGconn *conn, Oid lobjId);
  183. static lo_create_t dllo_create = 0;
  184. typedef int (*lo_tell_t)(PGconn *conn, int fd);
  185. static lo_tell_t dllo_tell = 0;
  186. typedef int (*lo_truncate_t)(PGconn *conn, int fd, size_t len);
  187. static lo_truncate_t dllo_truncate = 0;
  188. typedef int (*lo_unlink_t)(PGconn *conn, Oid lobjId);
  189. static lo_unlink_t dllo_unlink = 0;
  190. typedef Oid (*lo_import_t)(PGconn *conn, const char *filename);
  191. static lo_import_t dllo_import = 0;
  192. typedef Oid (*lo_import_with_oid_t)(PGconn *conn, const char *filename, Oid lobjId);
  193. static lo_import_with_oid_t dllo_import_with_oid = 0;
  194. typedef int (*lo_export_t)(PGconn *conn, Oid lobjId, const char *filename);
  195. static lo_export_t dllo_export = 0;
  196. typedef PGconn * (*PQconnectdb_t)(const char *conninfo);
  197. static PQconnectdb_t dlPQconnectdb = 0;
  198. // generated-code:end
  199. #ifdef WIN32
  200. #define LIBPQ_NAME "libpq.dll"
  201. #else
  202. #define LIBPQ_NAME "libpq.so"
  203. #endif
  204. static bool load_libpq()
  205. {
  206. if(dlPQconnectdb) return true;
  207. if(libpq.open(LIBPQ_NAME))
  208. {
  209. //@write_pgsql_functions_load();
  210. // generated-code:begin
  211. dlPQstatus = (PQstatus_t) libpq.dlsym("PQstatus");
  212. if(!dlPQstatus) return false;
  213. dlPQfinish = (PQfinish_t) libpq.dlsym("PQfinish");
  214. if(!dlPQfinish) return false;
  215. dlPQprepare = (PQprepare_t) libpq.dlsym("PQprepare");
  216. if(!dlPQprepare) return false;
  217. dlPQfreemem = (PQfreemem_t) libpq.dlsym("PQfreemem");
  218. if(!dlPQfreemem) return false;
  219. dlPQescapeLiteral = (PQescapeLiteral_t) libpq.dlsym("PQescapeLiteral");
  220. if(!dlPQescapeLiteral) return false;
  221. dlPQescapeIdentifier = (PQescapeIdentifier_t) libpq.dlsym("PQescapeIdentifier");
  222. if(!dlPQescapeIdentifier) return false;
  223. dlPQescapeByteaConn = (PQescapeByteaConn_t) libpq.dlsym("PQescapeByteaConn");
  224. if(!dlPQescapeByteaConn) return false;
  225. dlPQunescapeBytea = (PQunescapeBytea_t) libpq.dlsym("PQunescapeBytea");
  226. if(!dlPQunescapeBytea) return false;
  227. dlPQdescribePrepared = (PQdescribePrepared_t) libpq.dlsym("PQdescribePrepared");
  228. if(!dlPQdescribePrepared) return false;
  229. dlPQnparams = (PQnparams_t) libpq.dlsym("PQnparams");
  230. if(!dlPQnparams) return false;
  231. dlPQparamtype = (PQparamtype_t) libpq.dlsym("PQparamtype");
  232. if(!dlPQparamtype) return false;
  233. dlPQexecPrepared = (PQexecPrepared_t) libpq.dlsym("PQexecPrepared");
  234. if(!dlPQexecPrepared) return false;
  235. dlPQexec = (PQexec_t) libpq.dlsym("PQexec");
  236. if(!dlPQexec) return false;
  237. dlPQgetvalue = (PQgetvalue_t) libpq.dlsym("PQgetvalue");
  238. if(!dlPQgetvalue) return false;
  239. dlPQntuples = (PQntuples_t) libpq.dlsym("PQntuples");
  240. if(!dlPQntuples) return false;
  241. dlPQcmdTuples = (PQcmdTuples_t) libpq.dlsym("PQcmdTuples");
  242. if(!dlPQcmdTuples) return false;
  243. dlPQnfields = (PQnfields_t) libpq.dlsym("PQnfields");
  244. if(!dlPQnfields) return false;
  245. dlPQgetisnull = (PQgetisnull_t) libpq.dlsym("PQgetisnull");
  246. if(!dlPQgetisnull) return false;
  247. dlPQclear = (PQclear_t) libpq.dlsym("PQclear");
  248. if(!dlPQclear) return false;
  249. dlPQfnumber = (PQfnumber_t) libpq.dlsym("PQfnumber");
  250. if(!dlPQfnumber) return false;
  251. dlPQfname = (PQfname_t) libpq.dlsym("PQfname");
  252. if(!dlPQfname) return false;
  253. dlPQresultStatus = (PQresultStatus_t) libpq.dlsym("PQresultStatus");
  254. if(!dlPQresultStatus) return false;
  255. dlPQerrorMessage = (PQerrorMessage_t) libpq.dlsym("PQerrorMessage");
  256. if(!dlPQerrorMessage) return false;
  257. dlPQreset = (PQreset_t) libpq.dlsym("PQreset");
  258. if(!dlPQreset) return false;
  259. dlPQgetResult = (PQgetResult_t) libpq.dlsym("PQgetResult");
  260. if(!dlPQgetResult) return false;
  261. dlPQsetnonblocking = (PQsetnonblocking_t) libpq.dlsym("PQsetnonblocking");
  262. if(!dlPQsetnonblocking) return false;
  263. dlPQftype = (PQftype_t) libpq.dlsym("PQftype");
  264. if(!dlPQftype) return false;
  265. dlPQserverVersion = (PQserverVersion_t) libpq.dlsym("PQserverVersion");
  266. if(!dlPQserverVersion) return false;
  267. dllo_open = (lo_open_t) libpq.dlsym("lo_open");
  268. if(!dllo_open) return false;
  269. dllo_close = (lo_close_t) libpq.dlsym("lo_close");
  270. if(!dllo_close) return false;
  271. dllo_read = (lo_read_t) libpq.dlsym("lo_read");
  272. if(!dllo_read) return false;
  273. dllo_write = (lo_write_t) libpq.dlsym("lo_write");
  274. if(!dllo_write) return false;
  275. dllo_lseek = (lo_lseek_t) libpq.dlsym("lo_lseek");
  276. if(!dllo_lseek) return false;
  277. dllo_creat = (lo_creat_t) libpq.dlsym("lo_creat");
  278. if(!dllo_creat) return false;
  279. dllo_create = (lo_create_t) libpq.dlsym("lo_create");
  280. if(!dllo_create) return false;
  281. dllo_tell = (lo_tell_t) libpq.dlsym("lo_tell");
  282. if(!dllo_tell) return false;
  283. dllo_truncate = (lo_truncate_t) libpq.dlsym("lo_truncate");
  284. if(!dllo_truncate) return false;
  285. dllo_unlink = (lo_unlink_t) libpq.dlsym("lo_unlink");
  286. if(!dllo_unlink) return false;
  287. dllo_import = (lo_import_t) libpq.dlsym("lo_import");
  288. if(!dllo_import) return false;
  289. dllo_import_with_oid = (lo_import_with_oid_t) libpq.dlsym("lo_import_with_oid");
  290. if(!dllo_import_with_oid) return false;
  291. dllo_export = (lo_export_t) libpq.dlsym("lo_export");
  292. if(!dllo_export) return false;
  293. dlPQconnectdb = (PQconnectdb_t) libpq.dlsym("PQconnectdb");
  294. if(!dlPQconnectdb) return false;
  295. // generated-code:end
  296. return true;
  297. }
  298. return false;
  299. }
  300. ////////////////////////////////////////////////////////////////////////////////
  301. static const SQChar *PostgreSQL_TAG = _SC("PostgreSQL");
  302. static SQRESULT get_pgsql_instance(HSQUIRRELVM v, SQInteger idx, PGconn **self){
  303. SQRESULT _rc_;
  304. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)PostgreSQL_TAG)) < 0) return _rc_;
  305. if(!*self) return sq_throwerror(v, _SC("database is closed"));
  306. return _rc_;
  307. }
  308. #define GET_pgsql_INSTANCE_AT(idx) \
  309. PGconn *self=NULL; \
  310. if((_rc_ = get_pgsql_instance(v,idx,&self)) < 0) return _rc_;
  311. #define GET_pgsql_INSTANCE() GET_pgsql_INSTANCE_AT(1)
  312. static const SQChar *PostgreSQL_Result_TAG = _SC("PostgreSQL_Result");
  313. static const SQChar *_curr_row_key = _SC("_curr_row");
  314. static SQRESULT get_pgsql_result_instance(HSQUIRRELVM v, SQInteger idx, PGresult **self){
  315. SQRESULT _rc_;
  316. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)PostgreSQL_Result_TAG)) < 0) return _rc_;
  317. if(!*self) return sq_throwerror(v, _SC("PGresult is closed"));
  318. return _rc_;
  319. }
  320. #define GET_pgsql_result_INSTANCE_AT(idx) \
  321. PGresult *self=NULL; \
  322. if((_rc_ = get_pgsql_result_instance(v,idx,&self)) < 0) return _rc_;
  323. #define GET_pgsql_result_INSTANCE() GET_pgsql_result_INSTANCE_AT(1)
  324. static SQRESULT sq_pgsql_result_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  325. {
  326. PGresult *self = ((PGresult *)p);
  327. if (self) dlPQclear(self);
  328. return 0;
  329. }
  330. static SQRESULT sq_pgsql_result_close(HSQUIRRELVM v){
  331. SQ_FUNC_VARS_NO_TOP(v);
  332. GET_pgsql_result_INSTANCE();
  333. dlPQclear(self);
  334. sq_setinstanceup(v, 1, 0); //next calls will fail with "Pgresult is closed"
  335. return 0;
  336. }
  337. static SQRESULT sq_pgsql_result_col_count(HSQUIRRELVM v){
  338. SQ_FUNC_VARS_NO_TOP(v);
  339. GET_pgsql_result_INSTANCE();
  340. sq_pushinteger(v, dlPQnfields(self));
  341. return 1;
  342. }
  343. static SQRESULT sq_pgsql_result_row_count(HSQUIRRELVM v){
  344. SQ_FUNC_VARS_NO_TOP(v);
  345. GET_pgsql_result_INSTANCE();
  346. sq_pushinteger(v, dlPQntuples(self));
  347. return 1;
  348. }
  349. static SQRESULT sq_pgsql_result_col_name(HSQUIRRELVM v){
  350. SQ_FUNC_VARS_NO_TOP(v);
  351. GET_pgsql_result_INSTANCE();
  352. SQ_GET_INTEGER(v, 2, col);
  353. sq_pushstring(v, dlPQfname(self, col), -1);
  354. return 1;
  355. }
  356. static SQRESULT sq_pgsql_result_col_type(HSQUIRRELVM v){
  357. SQ_FUNC_VARS_NO_TOP(v);
  358. GET_pgsql_result_INSTANCE();
  359. SQ_GET_INTEGER(v, 2, col);
  360. sq_pushinteger(v, dlPQftype(self, col));
  361. return 1;
  362. }
  363. static SQRESULT sq_pgsql_result_col_index(HSQUIRRELVM v){
  364. SQ_FUNC_VARS_NO_TOP(v);
  365. GET_pgsql_result_INSTANCE();
  366. SQ_GET_STRING(v, 2, name);
  367. sq_pushinteger(v, dlPQfnumber(self, name));
  368. return 1;
  369. }
  370. static SQRESULT sq_pgsql_result_eof(HSQUIRRELVM v){
  371. SQ_FUNC_VARS_NO_TOP(v);
  372. GET_pgsql_result_INSTANCE();
  373. sq_pushstring(v, _curr_row_key, -1);
  374. if(sq_get(v, 1) == SQ_OK){
  375. SQ_GET_INTEGER(v, -1, curr_row);
  376. sq_pushbool(v, curr_row < dlPQntuples(self));
  377. }
  378. else sq_pushbool(v, SQTrue);
  379. return 1;
  380. }
  381. static SQRESULT sq_pgsql_result_next_row(HSQUIRRELVM v){
  382. SQ_FUNC_VARS_NO_TOP(v);
  383. GET_pgsql_result_INSTANCE();
  384. sq_pushstring(v, _curr_row_key, -1);
  385. sq_push(v, -1); //make a copy
  386. if(sq_get(v, 1) == SQ_OK){
  387. SQ_GET_INTEGER(v, -1, curr_row);
  388. if(++curr_row < dlPQntuples(self)){
  389. sq_poptop(v);
  390. sq_pushinteger(v, curr_row);
  391. sq_set(v, 1);
  392. sq_pushbool(v, SQTrue);
  393. return 1;
  394. }
  395. }
  396. sq_pushbool(v, SQFalse);
  397. return 1;
  398. }
  399. static SQRESULT sq_pgsql_result_col_value(HSQUIRRELVM v){
  400. SQ_FUNC_VARS_NO_TOP(v);
  401. GET_pgsql_result_INSTANCE();
  402. SQObjectType ptype = sq_gettype(v, 2);
  403. int col = -1;
  404. if(ptype == OT_STRING){
  405. SQ_GET_STRING(v, 2, col_name);
  406. col = dlPQfnumber(self, col_name);
  407. }
  408. else
  409. {
  410. SQ_GET_INTEGER(v, 2, idx);
  411. col = idx;
  412. }
  413. if(col < 0) return sq_throwerror(v, _SC("invalid col index/name"));
  414. sq_pushstring(v, _curr_row_key, -1);
  415. if(sq_get(v, 1) == SQ_OK){
  416. SQ_GET_INTEGER(v, -1, curr_row);
  417. if(curr_row < dlPQntuples(self)){
  418. sq_pushstring(v, dlPQgetvalue(self, curr_row, col), -1);
  419. return 1;
  420. }
  421. }
  422. return SQ_ERROR;
  423. }
  424. static SQRESULT sq_pgsql_result_row_as_array(HSQUIRRELVM v){
  425. SQ_FUNC_VARS(v);
  426. GET_pgsql_result_INSTANCE();
  427. SQ_OPT_INTEGER(v, 2, row, -1);
  428. if(row < 0){
  429. sq_pushstring(v, _curr_row_key, -1);
  430. if(sq_get(v, 1) == SQ_OK){
  431. sq_getinteger(v, -1, &row);
  432. }
  433. }
  434. int row_count = dlPQntuples(self);
  435. if(row < 0 || row >= row_count) return sq_throwerror(v, _SC("invalid row (%d)"), row);
  436. int col_count = dlPQnfields(self);
  437. sq_newarray(v, col_count);
  438. for(int i=0; i < col_count; ++i){
  439. sq_pushinteger(v, i);
  440. sq_pushstring(v, dlPQgetvalue(self, row, i), -1);
  441. sq_rawset(v, -3);
  442. }
  443. return 1;
  444. }
  445. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_pgsql_result_##name,nparams,tycheck}
  446. static SQRegFunction sq_pgsql_result_methods[] =
  447. {
  448. _DECL_FUNC(close, 1, _SC("x")),
  449. _DECL_FUNC(eof, 1, _SC("x")),
  450. _DECL_FUNC(next_row, 1, _SC("x")),
  451. _DECL_FUNC(col_count, 1, _SC("x")),
  452. _DECL_FUNC(row_count, 1, _SC("x")),
  453. _DECL_FUNC(col_name, 2, _SC("xi")),
  454. _DECL_FUNC(col_index, 2, _SC("xs")),
  455. _DECL_FUNC(col_value, 2, _SC("x i|s")),
  456. _DECL_FUNC(col_type, 2, _SC("x i|s")),
  457. _DECL_FUNC(row_as_array, -1, _SC("xi")),
  458. {0,0}
  459. };
  460. #undef _DECL_FUNC
  461. struct PgSqlStatement {
  462. PGconn *db;
  463. char name[64];
  464. int param_count;
  465. int isGetPrepared;
  466. void **param_values;
  467. int *param_sizes;
  468. int *param_types;
  469. };
  470. static const SQChar *PostgreSQL_Statement_TAG = _SC("PostgreSQL_Statement");
  471. static SQRESULT get_pgsql_statement_instance(HSQUIRRELVM v, SQInteger idx, PgSqlStatement **self){
  472. SQRESULT _rc_;
  473. if((_rc_ = sq_getinstanceup(v,idx,(SQUserPointer*)self,(void*)PostgreSQL_Statement_TAG)) < 0) return _rc_;
  474. if(!*self) return sq_throwerror(v, _SC("PGstatement is closed"));
  475. return _rc_;
  476. }
  477. #define GET_pgsql_statement_INSTANCE_AT(idx) \
  478. PgSqlStatement *self=NULL; \
  479. if((_rc_ = get_pgsql_statement_instance(v,idx,&self)) < 0) return _rc_;
  480. #define GET_pgsql_statement_INSTANCE() GET_pgsql_statement_INSTANCE_AT(1)
  481. static SQRESULT sq_pgsql_statement_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  482. {
  483. PgSqlStatement *self = ((PgSqlStatement *)p);
  484. if (self){
  485. if(!self->isGetPrepared)
  486. {
  487. char sql[128];
  488. snprintf(sql, sizeof(sql), "DEALLOCATE %s", self->name);
  489. PGresult *qres = dlPQexec(self->db, sql);
  490. dlPQclear(qres);
  491. }
  492. if(self->param_count)
  493. {
  494. SQUnsignedInteger the_size;
  495. if(self->param_values)
  496. {
  497. the_size = self->param_count * sizeof(self->param_values);
  498. sq_free(self->param_values, the_size);
  499. }
  500. if(self->param_sizes)
  501. {
  502. the_size = self->param_count * sizeof(self->param_sizes);
  503. sq_free(self->param_sizes, the_size);
  504. }
  505. if(self->param_types)
  506. {
  507. the_size = self->param_count * sizeof(self->param_types);
  508. sq_free(self->param_types, the_size);
  509. }
  510. }
  511. sq_free(self, sizeof(PgSqlStatement));
  512. }
  513. return 0;
  514. }
  515. static SQRESULT sq_pgsql_statement_close(HSQUIRRELVM v){
  516. SQ_FUNC_VARS_NO_TOP(v);
  517. GET_pgsql_statement_INSTANCE();
  518. sq_pgsql_statement_releasehook(self, 0, v);
  519. sq_setinstanceup(v, 1, 0); //next calls will fail with "Pgstatement is closed"
  520. return 0;
  521. }
  522. /*
  523. static SQRESULT sq_pgsql_statement_exec(HSQUIRRELVM v){
  524. SQ_FUNC_VARS(v);
  525. GET_pgsql_statement_INSTANCE();
  526. SQ_OPT_INTEGER(v, 3, result_type, 0);
  527. SQInteger psize = sq_getsize(v, 2);
  528. void **param_values;
  529. int *param_sizes;
  530. int *param_types;
  531. bool bresult = false;
  532. SQBool bval;
  533. PGresult *qres;
  534. SQUnsignedInteger param_values_size = psize * sizeof(param_values);
  535. SQUnsignedInteger param_sizes_size = psize * sizeof(param_sizes);
  536. if(self->result)
  537. {
  538. dlPQclear(self->result);
  539. self->result = NULL;
  540. }
  541. param_values = (void **)sq_malloc(param_values_size);
  542. memset(param_values, 0, param_values_size);
  543. param_sizes = (int *)sq_malloc(param_sizes_size);
  544. memset(param_sizes, 0, param_sizes_size);
  545. param_types = (int *)sq_malloc(param_sizes_size);
  546. memset(param_types, 0, param_sizes_size);
  547. for(SQInteger i=0; i < psize; ++i)
  548. {
  549. sq_pushinteger(v, i);
  550. if(sq_get(v, 2) == SQ_OK)
  551. {
  552. switch(sq_gettype(v, -1))
  553. {
  554. case OT_NULL:
  555. param_values[i] = NULL;
  556. param_sizes[i] = 0;
  557. param_types[i] = 0;
  558. sq_poptop(v);
  559. break;
  560. case OT_BOOL:
  561. sq_getbool(v, -1, &bval);
  562. param_values[i] = (void*)(bval == SQTrue ? "1" : "0");
  563. param_sizes[i] = 1;
  564. param_types[i] = BOOLOID;
  565. sq_poptop(v);
  566. break;
  567. case OT_INTEGER:
  568. param_values[i] = (void*)sq_tostring(v, -1);
  569. param_sizes[i] = (int)sq_getsize(v, -1);
  570. param_types[i] = INT4OID;
  571. break;
  572. case OT_FLOAT:
  573. param_values[i] = (void*)sq_tostring(v, -1);
  574. param_sizes[i] = (int)sq_getsize(v, -1);
  575. param_types[i] = FLOAT8OID;
  576. break;
  577. case OT_STRING:
  578. param_values[i] = (void*)sq_tostring(v, -1);
  579. param_sizes[i] = (int)sq_getsize(v, -1);
  580. param_types[i] = VARCHAROID;
  581. break;
  582. default:
  583. goto cleanup;
  584. }
  585. }
  586. }
  587. qres = dlPQexecPrepared(self->db, self->name, psize, (const char**)param_values, param_sizes, NULL, result_type);
  588. bresult = dlPQresultStatus(qres) == PGRES_COMMAND_OK;
  589. if(bresult) self->result = qres;
  590. else dlPQclear(qres);
  591. cleanup:
  592. sq_free(param_values, param_values_size);
  593. sq_free(param_sizes, param_sizes_size);
  594. sq_settop(v, _top_);
  595. sq_pushbool(v, bresult);
  596. return 1;
  597. }
  598. */
  599. #define SQ_EXEC_DML 1
  600. #define SQ_EXEC_SCALAR 2
  601. #define SQ_EXEC_QUERY 3
  602. static SQRESULT sq_pgsql_statement_exec(HSQUIRRELVM v, int exec_type){
  603. SQ_FUNC_VARS(v);
  604. GET_pgsql_statement_INSTANCE();
  605. SQ_OPT_INTEGER(v, 3, result_type, 0);
  606. SQInteger psize = sq_getsize(v, 2);
  607. if(psize != self->param_count)
  608. {
  609. return sq_throwerror(v, _SC("Wrong number of paramters, exptexted %d"), self->param_count);
  610. }
  611. int result = SQ_ERROR;
  612. SQBool bval;
  613. const SQChar *str_val;
  614. PGresult *qres;
  615. SQUnsignedInteger param_values_size = psize * sizeof(self->param_values);
  616. SQUnsignedInteger param_sizes_size = psize * sizeof(self->param_sizes);
  617. if(!self->param_values)
  618. {
  619. //only allocate once
  620. self->param_values = (void **)sq_malloc(param_values_size);
  621. self->param_sizes = (int *)sq_malloc(param_sizes_size);
  622. }
  623. memset(self->param_values, 0, param_values_size);
  624. memset(self->param_sizes, 0, param_sizes_size);
  625. sq_reservestack(v, psize*2);
  626. for(SQInteger i=0; i < psize; ++i)
  627. {
  628. sq_pushinteger(v, i);
  629. if(sq_get(v, 2) == SQ_OK)
  630. {
  631. switch(sq_gettype(v, -1))
  632. {
  633. case OT_NULL:
  634. sq_poptop(v);
  635. break;
  636. case OT_BOOL:
  637. sq_getbool(v, -1, &bval);
  638. self->param_values[i] = (void*)(bval == SQTrue ? "1" : "0");
  639. self->param_sizes[i] = 1;
  640. sq_poptop(v);
  641. break;
  642. case OT_INTEGER:
  643. case OT_FLOAT:
  644. case OT_STRING:
  645. sq_tostring(v, -1);
  646. sq_getstring(v, -1, &str_val);
  647. self->param_values[i] = (void*)str_val;
  648. self->param_sizes[i] = (int)sq_getsize(v, -1);
  649. break;
  650. default:
  651. result = sq_throwerror(v, _SC("Unknow parameter type at pos %d"), i);
  652. goto cleanup;
  653. }
  654. }
  655. }
  656. qres = dlPQexecPrepared(self->db, self->name, psize,
  657. (const char**)self->param_values, self->param_sizes, NULL, result_type);
  658. result = dlPQresultStatus(qres);
  659. if(result == PGRES_COMMAND_OK || result == PGRES_TUPLES_OK)
  660. {
  661. if(exec_type == SQ_EXEC_DML)
  662. {
  663. sq_pushinteger(v, atoi(dlPQcmdTuples(qres)));
  664. dlPQclear(qres);
  665. }
  666. else if(exec_type == SQ_EXEC_SCALAR)
  667. {
  668. int ntuples = dlPQntuples(qres);
  669. int nfields = dlPQnfields(qres);
  670. if(exec_type == SQ_EXEC_SCALAR && (ntuples == 1) && (nfields > 0))
  671. {
  672. result = atoi(dlPQgetvalue(qres, 0, 0));
  673. sq_pushinteger(v, result);
  674. dlPQclear(qres);
  675. }
  676. else
  677. {
  678. sq_pushnull(v);
  679. }
  680. }
  681. else if(exec_type == SQ_EXEC_QUERY)
  682. {
  683. sq_pushroottable(v);
  684. sq_pushstring(v, PostgreSQL_Result_TAG, -1);
  685. if(sq_get(v, -2) == SQ_OK){
  686. if(sq_createinstance(v, -1) == SQ_OK){
  687. sq_setinstanceup(v, -1, qres);
  688. sq_setreleasehook(v, -1, sq_pgsql_result_releasehook);
  689. sq_pushstring(v, _curr_row_key, -1);
  690. sq_pushinteger(v, -1);
  691. sq_set(v, -3);
  692. }
  693. }
  694. }
  695. result = 1;
  696. }
  697. else
  698. {
  699. dlPQclear(qres);
  700. //sq_settop(v, _top_);
  701. result = sq_throwerror(v, dlPQerrorMessage(self->db));
  702. }
  703. cleanup:
  704. return result;
  705. }
  706. static SQRESULT sq_pgsql_statement_exec_query(HSQUIRRELVM v){
  707. return sq_pgsql_statement_exec(v, SQ_EXEC_QUERY);
  708. }
  709. static SQRESULT sq_pgsql_statement_exec_scalar(HSQUIRRELVM v){
  710. return sq_pgsql_statement_exec(v, SQ_EXEC_SCALAR);
  711. }
  712. static SQRESULT sq_pgsql_statement_exec_dml(HSQUIRRELVM v){
  713. return sq_pgsql_statement_exec(v, SQ_EXEC_DML);
  714. }
  715. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_pgsql_statement_##name,nparams,tycheck}
  716. static SQRegFunction sq_pgsql_statement_methods[] =
  717. {
  718. _DECL_FUNC(exec_query, -2, _SC("xai")),
  719. _DECL_FUNC(exec_scalar, 2, _SC("xa")),
  720. _DECL_FUNC(exec_dml, 2, _SC("xa")),
  721. _DECL_FUNC(close, 1, _SC("x")),
  722. {0,0}
  723. };
  724. #undef _DECL_FUNC
  725. static SQRESULT sq_pgsql_releasehook(SQUserPointer p, SQInteger size, HSQUIRRELVM v)
  726. {
  727. PGconn *self = ((PGconn *)p);
  728. if (self) dlPQfinish(self);
  729. return 0;
  730. }
  731. static SQRESULT sq_pgsql_constructor(HSQUIRRELVM v)
  732. {
  733. SQ_FUNC_VARS_NO_TOP(v);
  734. SQ_GET_STRING(v, 2, szConnInfo);
  735. PGconn *self=0;
  736. if(load_libpq())
  737. {
  738. self = dlPQconnectdb(szConnInfo);
  739. if (dlPQstatus(self) == CONNECTION_BAD) return sq_throwerror(v, _SC("Failed to connect ot database !"));
  740. }
  741. else return sq_throwerror(v, _SC("Failed to load libpq !"));
  742. sq_setinstanceup(v, 1, self);
  743. sq_setreleasehook(v,1, sq_pgsql_releasehook);
  744. //save a weakref to allow statement return it's db
  745. sq_pushuserpointer(v, self);
  746. sq_weakref(v, 1);
  747. sq_setonregistrytable(v);
  748. return 1;
  749. }
  750. static SQRESULT sq_pgsql_close(HSQUIRRELVM v){
  751. SQ_FUNC_VARS_NO_TOP(v);
  752. GET_pgsql_INSTANCE();
  753. dlPQfinish(self);
  754. sq_setinstanceup(v, 1, 0); //next calls will fail with "database is closed"
  755. return 0;
  756. }
  757. static SQRESULT sq_pgsql_exec_dml(HSQUIRRELVM v){
  758. SQ_FUNC_VARS_NO_TOP(v);
  759. GET_pgsql_INSTANCE();
  760. SQ_GET_STRING(v, 2, szSQL);
  761. int result = 0;
  762. PGresult *qres = dlPQexec(self, szSQL);
  763. bool is_ok = dlPQresultStatus(qres) == PGRES_COMMAND_OK;
  764. if (is_ok) result = atoi(dlPQcmdTuples(qres));
  765. dlPQclear(qres);
  766. if (!is_ok) return sq_throwerror(v, dlPQerrorMessage(self));
  767. sq_pushinteger(v, result);
  768. return 1;
  769. }
  770. static SQRESULT sq_pgsql_exec_scalar(HSQUIRRELVM v){
  771. SQ_FUNC_VARS_NO_TOP(v);
  772. GET_pgsql_INSTANCE();
  773. SQ_GET_STRING(v, 2, szSQL);
  774. int result = 0;
  775. PGresult *qres = dlPQexec(self, szSQL);
  776. bool is_ok = (dlPQresultStatus(qres) == PGRES_TUPLES_OK) &&
  777. (dlPQntuples(qres) == 1) && (dlPQnfields(qres) > 0);
  778. if (is_ok) result = atoi(dlPQgetvalue(qres, 0, 0));
  779. dlPQclear(qres);
  780. if (!is_ok) return sq_throwerror(v, dlPQerrorMessage(self));
  781. sq_pushinteger(v, result);
  782. return 1;
  783. }
  784. static SQRESULT sq_pgsql_exec_query(HSQUIRRELVM v){
  785. SQ_FUNC_VARS_NO_TOP(v);
  786. GET_pgsql_INSTANCE();
  787. SQ_GET_STRING(v, 2, szSQL);
  788. PGresult *qres = dlPQexec(self, szSQL);
  789. if(dlPQresultStatus(qres) == PGRES_TUPLES_OK){
  790. sq_pushroottable(v);
  791. sq_pushstring(v, PostgreSQL_Result_TAG, -1);
  792. if(sq_get(v, -2) == SQ_OK){
  793. if(sq_createinstance(v, -1) == SQ_OK){
  794. sq_setinstanceup(v, -1, qres);
  795. sq_setreleasehook(v, -1, sq_pgsql_result_releasehook);
  796. sq_pushstring(v, _curr_row_key, -1);
  797. sq_pushinteger(v, -1);
  798. sq_set(v, -3);
  799. return 1;
  800. }
  801. }
  802. }
  803. return sq_throwerror(v, dlPQerrorMessage(self));
  804. }
  805. static SQRESULT sq_pgsql_do_prepare(HSQUIRRELVM v, int isGetPrepared){
  806. SQ_FUNC_VARS_NO_TOP(v);
  807. GET_pgsql_INSTANCE();
  808. SQ_GET_STRING(v, 2, szSQL);
  809. PGresult *qres;
  810. bool bresult;
  811. PgSqlStatement *stmt = (PgSqlStatement*)sq_malloc(sizeof(PgSqlStatement));
  812. memset(stmt, 0, sizeof(PgSqlStatement));
  813. stmt->db = self;
  814. stmt->isGetPrepared = isGetPrepared;
  815. if(isGetPrepared)
  816. {
  817. snprintf(stmt->name, sizeof(stmt->name), "%s", szSQL);
  818. qres = dlPQdescribePrepared(self, stmt->name);
  819. bresult = dlPQresultStatus(qres) == PGRES_COMMAND_OK;
  820. if(bresult) stmt->param_count = dlPQnparams(qres);
  821. dlPQclear(qres);
  822. }
  823. else
  824. {
  825. snprintf(stmt->name, sizeof(stmt->name), "sq_stmt_%p_%p", self, stmt);
  826. qres = dlPQprepare(self, stmt->name, szSQL, 0, NULL);
  827. bresult = dlPQresultStatus(qres) == PGRES_COMMAND_OK;
  828. dlPQclear(qres);
  829. }
  830. if(bresult){
  831. if(!isGetPrepared)
  832. {
  833. qres = dlPQdescribePrepared(self, stmt->name);
  834. stmt->param_count = dlPQnparams(qres);
  835. dlPQclear(qres);
  836. }
  837. sq_pushroottable(v);
  838. sq_pushstring(v, PostgreSQL_Statement_TAG, -1);
  839. if(sq_get(v, -2) == SQ_OK){
  840. if(sq_createinstance(v, -1) == SQ_OK){
  841. sq_setinstanceup(v, -1, stmt);
  842. sq_setreleasehook(v, -1, sq_pgsql_statement_releasehook);
  843. return 1;
  844. }
  845. }
  846. }
  847. sq_free(stmt, sizeof(PgSqlStatement));
  848. return sq_throwerror(v, dlPQerrorMessage(self));
  849. }
  850. static SQRESULT sq_pgsql_prepare(HSQUIRRELVM v){
  851. return sq_pgsql_do_prepare(v, 0);
  852. }
  853. static SQRESULT sq_pgsql_get_prepared(HSQUIRRELVM v){
  854. return sq_pgsql_do_prepare(v, 1);
  855. }
  856. static SQRESULT sq_pgsql_error_message(HSQUIRRELVM v){
  857. SQ_FUNC_VARS_NO_TOP(v);
  858. GET_pgsql_INSTANCE();
  859. sq_pushstring(v, dlPQerrorMessage(self), -1);
  860. return 1;
  861. }
  862. static SQRESULT sq_pgsql_version(HSQUIRRELVM v){
  863. SQ_FUNC_VARS_NO_TOP(v);
  864. GET_pgsql_INSTANCE();
  865. sq_pushinteger(v, dlPQserverVersion(self));
  866. return 1;
  867. }
  868. static int
  869. inv_read = 0x40000,
  870. inv_write = 0x20000,
  871. invalidoid = 0,
  872. inv_seek_set = 0,
  873. inv_seek_curr = 1,
  874. inv_seek_end = 2;
  875. static SQRESULT sq_pgsql_get_blob_field(HSQUIRRELVM v){
  876. SQ_FUNC_VARS_NO_TOP(v);
  877. GET_pgsql_INSTANCE();
  878. SQ_GET_INTEGER(v, 2, oid);
  879. //begin_recursive_transaction();
  880. char *result = 0;
  881. int ofd = dllo_open(self, oid, inv_read);
  882. if(ofd >= 0){
  883. int blobSize = dllo_lseek(self, ofd, 0, inv_seek_end);
  884. dllo_lseek(self, ofd, 0, inv_seek_set);
  885. SQBlob blob(blobSize);
  886. result = (char*)blob.GetBuf();
  887. int numRead = 0;
  888. while(blobSize > 0){
  889. int i = dllo_read(self, ofd, result+numRead, blobSize);
  890. numRead += i;
  891. blobSize -= i;
  892. }
  893. dllo_close(self, oid);
  894. sq_pushstring(v, (const SQChar*)blob.GetBuf(), blob.Len());
  895. }
  896. //commit_recursive_transaction();
  897. if(!result) sq_pushnull(v);
  898. return 1;
  899. }
  900. static SQRESULT sq_pgsql_insert_blob_field(HSQUIRRELVM v){
  901. SQ_FUNC_VARS_NO_TOP(v);
  902. GET_pgsql_INSTANCE();
  903. int result = 0;
  904. SQ_GET_STRING(v, 2, blob);
  905. SQ_GET_BOOL(v, 3, isFileName);
  906. if(isFileName){
  907. result = dllo_import(self, blob);
  908. } else {
  909. result = dllo_creat(self, inv_write);
  910. if(result){
  911. int ofd = dllo_open(self, result, inv_write);
  912. if (ofd >= 0){
  913. int i = blob_size;
  914. const char *blopPtr = (const char *)blob;
  915. int numWriten = 0;
  916. while(i > 0){
  917. int i2 = dllo_write(self, ofd, blopPtr+numWriten, i);
  918. numWriten += i2;
  919. i -= i2;
  920. }
  921. dllo_close(self, ofd);
  922. }
  923. else return sq_throwerror(v, _SC("Failed to insert blob !"));
  924. }
  925. }
  926. if(!result) sq_pushnull(v);
  927. return 1;
  928. }
  929. static SQRESULT sq_pgsql_update_blob_field(HSQUIRRELVM v){
  930. SQ_FUNC_VARS_NO_TOP(v);
  931. GET_pgsql_INSTANCE();
  932. SQ_GET_INTEGER(v, 2, oid);
  933. SQ_GET_STRING(v, 3, blob);
  934. SQ_GET_BOOL(v, 4, isFileName);
  935. int result_oid = 0;
  936. int result_error = SQ_OK;
  937. int loid = dllo_creat(self, inv_write);
  938. int ofd = dllo_open(self, loid, inv_write);
  939. if(ofd >= 0){
  940. dllo_unlink(self, oid);
  941. result_oid = loid;
  942. if(isFileName)
  943. {
  944. char buf[2048];
  945. FILE *fp = fopen(blob, "rb");
  946. if(!fp) {
  947. sq_throwerror(v, _SC("Failed to update blob from file !"));
  948. result_error = SQ_ERROR;
  949. }
  950. else
  951. {
  952. char *charPtr = buf;
  953. int numRead;
  954. do{
  955. numRead = fread(buf, 1, sizeof(buf), fp);
  956. int numWriten = dllo_write(self, ofd, charPtr, numRead);
  957. if (numWriten != numRead) {
  958. sq_throwerror(v, _SC("Failed to update blob from file !"));
  959. result_error = SQ_ERROR;
  960. break;
  961. }
  962. } while (numRead == 0);
  963. fclose(fp);
  964. }
  965. }else{
  966. int i = blob_size;
  967. const char *blopPtr = (const char *)blob;
  968. int numWriten = 0;
  969. while(i > 0){
  970. int i2 = dllo_write(self, ofd, blopPtr+numWriten, i);
  971. numWriten += i2;
  972. i -= i2;
  973. }
  974. }
  975. dllo_close(self, ofd);
  976. }
  977. if(result_error == SQ_ERROR) return result_error;
  978. sq_pushinteger(v, result_oid);
  979. return 1;
  980. }
  981. static SQRESULT sq_pgsql_delete_blob_field(HSQUIRRELVM v){
  982. SQ_FUNC_VARS_NO_TOP(v);
  983. GET_pgsql_INSTANCE();
  984. SQ_GET_INTEGER(v, 2, oid);
  985. sq_pushinteger(v, dllo_unlink(self, oid));
  986. return 1;
  987. }
  988. static SQRESULT sq_pgsql_escape_string(HSQUIRRELVM v){
  989. SQ_FUNC_VARS_NO_TOP(v);
  990. GET_pgsql_INSTANCE();
  991. SQ_GET_STRING(v, 2, str);
  992. char *escaped_str = dlPQescapeLiteral(self, str, str_size);
  993. if(escaped_str) {
  994. sq_pushstring(v, escaped_str, -1);
  995. dlPQfreemem(escaped_str);
  996. return 1;
  997. }
  998. return sq_throwerror(v, _SC("could not allocate escaped string"));
  999. }
  1000. static SQRESULT sq_pgsql_escape_bytea(HSQUIRRELVM v){
  1001. SQ_FUNC_VARS_NO_TOP(v);
  1002. GET_pgsql_INSTANCE();
  1003. SQ_GET_STRING(v, 2, str);
  1004. char *escaped_str = (char*)dlPQescapeByteaConn(self, (const unsigned char*)str, str_size);
  1005. if(escaped_str) {
  1006. sq_pushstring(v, escaped_str, -1);
  1007. dlPQfreemem(escaped_str);
  1008. return 1;
  1009. }
  1010. return sq_throwerror(v, _SC("could not allocate escaped bytea"));
  1011. }
  1012. static SQRESULT sq_pgsql_unescape_bytea(HSQUIRRELVM v){
  1013. SQ_FUNC_VARS_NO_TOP(v);
  1014. GET_pgsql_INSTANCE();
  1015. SQ_GET_STRING(v, 2, str);
  1016. char *escaped_str = (char*)dlPQunescapeBytea((const unsigned char*)str, str_size);
  1017. if(escaped_str) {
  1018. sq_pushstring(v, escaped_str, -1);
  1019. dlPQfreemem(escaped_str);
  1020. return 1;
  1021. }
  1022. return sq_throwerror(v, _SC("could not allocate unescaped bytea"));
  1023. }
  1024. #define _DECL_FUNC(name,nparams,tycheck) {_SC(#name), sq_pgsql_##name,nparams,tycheck}
  1025. static SQRegFunction sq_pgsql_methods[] =
  1026. {
  1027. _DECL_FUNC(constructor, 2, _SC("xs")),
  1028. _DECL_FUNC(close, 1, _SC("x")),
  1029. _DECL_FUNC(exec_dml, 2, _SC("xs")),
  1030. _DECL_FUNC(exec_scalar, 2, _SC("xs")),
  1031. _DECL_FUNC(exec_query, 2, _SC("xs")),
  1032. _DECL_FUNC(prepare, 2, _SC("xs")),
  1033. _DECL_FUNC(get_prepared, 2, _SC("xs")),
  1034. _DECL_FUNC(error_message, 1, _SC("x")),
  1035. _DECL_FUNC(version, 1, _SC("x")),
  1036. _DECL_FUNC(get_blob_field, 2, _SC("xi")),
  1037. _DECL_FUNC(insert_blob_field, 3, _SC("xsb")),
  1038. _DECL_FUNC(update_blob_field, 3, _SC("xisb")),
  1039. _DECL_FUNC(delete_blob_field, 2, _SC("xi")),
  1040. _DECL_FUNC(escape_string, 2, _SC("xs")),
  1041. _DECL_FUNC(escape_bytea, 2, _SC("xs")),
  1042. _DECL_FUNC(unescape_bytea, 2, _SC("xs")),
  1043. {0,0}
  1044. };
  1045. #undef _DECL_FUNC
  1046. #ifdef __cplusplus
  1047. extern "C" {
  1048. #endif
  1049. SQRESULT sqext_register_PostgreSQL(HSQUIRRELVM v)
  1050. {
  1051. sq_pushstring(v,PostgreSQL_TAG,-1);
  1052. sq_newclass(v,SQFalse);
  1053. sq_settypetag(v,-1,(void*)PostgreSQL_TAG);
  1054. sq_insert_reg_funcs(v, sq_pgsql_methods);
  1055. sq_newslot(v,-3,SQTrue);
  1056. sq_pushstring(v,PostgreSQL_Statement_TAG,-1);
  1057. sq_newclass(v,SQFalse);
  1058. sq_settypetag(v,-1,(void*)PostgreSQL_Statement_TAG);
  1059. sq_insert_reg_funcs(v, sq_pgsql_statement_methods);
  1060. sq_newslot(v,-3,SQTrue);
  1061. sq_pushstring(v,PostgreSQL_Result_TAG,-1);
  1062. sq_newclass(v,SQFalse);
  1063. sq_settypetag(v,-1,(void*)PostgreSQL_Result_TAG);
  1064. sq_insert_reg_funcs(v, sq_pgsql_result_methods);
  1065. sq_pushstring(v, _curr_row_key, -1);
  1066. sq_pushnull(v);
  1067. sq_newslot(v, -3, SQFalse);
  1068. sq_newslot(v,-3,SQTrue);
  1069. return 0;
  1070. }
  1071. #ifdef __cplusplus
  1072. }
  1073. #endif
  1074. #endif // WITH_POSTGRESQL