sq_postgresql.cpp 38 KB

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