Sql.cpp 64 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583
  1. /******************************************************************************/
  2. #include "stdafx.h"
  3. #include "../../../ThirdPartyLibs/begin.h"
  4. #if SUPPORT_SQLITE
  5. #include "../../../ThirdPartyLibs/SQLite/sqlite3.h"
  6. #endif
  7. #if SUPPORT_ODBC
  8. #if !WINDOWS // not needed on Windows platform
  9. #define _IODBCUNIX_H // will disable some compilation errors on Unix
  10. #define UNICODE // will force SQL command names to be Unicode
  11. #define ULONG SQL_ULONG // will disable typedef conflict error on Apple
  12. #endif
  13. #if MAC
  14. #include "../../../ThirdPartyLibs/iODBC/sqlext.h"
  15. #else
  16. #include <sqlext.h>
  17. #endif
  18. #endif
  19. #include "../../../ThirdPartyLibs/end.h"
  20. namespace EE{
  21. #define SQLITE_VFS_NAME "Esenthel"
  22. /******************************************************************************/
  23. enum SQL_VAL_TYPE
  24. {
  25. SVT_RAW,
  26. SVT_STR,
  27. SVT_BIN,
  28. SVT_UID,
  29. };
  30. /******************************************************************************/
  31. SQLValues& SQLValues::New(C Str &name, Int value ) {_values.New().set(name, S+value ).type=SVT_RAW; return T;}
  32. SQLValues& SQLValues::New(C Str &name, Long value ) {_values.New().set(name, S+value ).type=SVT_RAW; return T;}
  33. SQLValues& SQLValues::New(C Str &name, Dbl value ) {_values.New().set(name, S+value ).type=SVT_RAW; return T;}
  34. SQLValues& SQLValues::New(C Str &name, C Str &value ) {_values.New().set(name, value ).type=SVT_STR; return T;}
  35. SQLValues& SQLValues::New(C Str &name, C DateTime &value ) {_values.New().set(name, S+'\''+value.asText(true)+'\'' ).type=SVT_RAW; return T;}
  36. SQLValues& SQLValues::New(C Str &name, CPtr value, Int value_size) {_values.New().set(name, TextHexMem( value, value_size , false)).type=SVT_BIN; return T;}
  37. SQLValues& SQLValues::New(C Str &name, File &file ) {_values.New().set(name, TextHexMem( file , false)).type=SVT_BIN; return T;}
  38. SQLValues& SQLValues::New(C Str &name, C UID &value ) {_values.New().set(name, TextHexMem(&value, SIZE(value), false)).type=SVT_UID; return T;}
  39. /******************************************************************************/
  40. SQL::SQL()
  41. {
  42. _type=NONE;
  43. _env=_conn=_statement=_sqlite=null;
  44. _rows_pos=0;
  45. }
  46. SQL& SQL::del()
  47. {
  48. #if SUPPORT_ODBC
  49. if(_statement){ SQLFreeHandle(SQL_HANDLE_STMT, _statement); _statement=null;}
  50. if(_conn ){SQLDisconnect(_conn); SQLFreeHandle(SQL_HANDLE_DBC , _conn ); _conn =null;}
  51. if(_env ){ SQLFreeHandle(SQL_HANDLE_ENV , _env ); _env =null;}
  52. #endif
  53. #if SUPPORT_SQLITE
  54. if(_sqlite ){ sqlite3_close( (sqlite3*&)_sqlite ); _sqlite =null;}
  55. #endif
  56. _type=NONE;
  57. _rows .del();
  58. _cols .del();
  59. _params.del();
  60. return T;
  61. }
  62. /******************************************************************************/
  63. Bool SQL::connectODBC(C Str &params, Str *messages, Int *error, Int sql_type)
  64. {
  65. #if SUPPORT_ODBC
  66. if(messages)messages->clear();
  67. if(error )*error=0;
  68. del();
  69. if(SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &_env)==SQL_SUCCESS)
  70. if(SQLSetEnvAttr (_env, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0)==SQL_SUCCESS)
  71. if(SQLAllocHandle(SQL_HANDLE_DBC, _env, &_conn)==SQL_SUCCESS)
  72. {
  73. T._type=sql_type;
  74. SQLWCHAR conn_str[1024];
  75. if(CChar *p=params())switch(SQLDriverConnect(_conn, null, (SQLWCHAR*)p, SQL_NTS, conn_str, Elms(conn_str), null, SQL_DRIVER_NOPROMPT))
  76. {
  77. case SQL_SUCCESS_WITH_INFO: getStatus(messages, error, false); break;
  78. case SQL_INVALID_HANDLE: case SQL_ERROR: getStatus(messages, error, false); del(); return false;
  79. }
  80. if(SQLAllocHandle(SQL_HANDLE_STMT, _conn, &_statement)==SQL_SUCCESS)return true;
  81. }
  82. #else
  83. if(messages)*messages="ODBC SQL is not supported on this platform";
  84. if(error )*error=0;
  85. #endif
  86. del(); return false;
  87. }
  88. Bool SQL::connectODBC(C Str &server_name, C Str &database, C Str &user, C Str &password, Str *messages, Int *error, Int port, C Str &driver_name, Int sql_type)
  89. {
  90. #if SUPPORT_ODBC
  91. Str params=S+"DRIVER={"+driver_name+"};SERVER="+server_name+";DATABASE="+database+";";
  92. switch(_type=sql_type)
  93. {
  94. case MSSQL: params+=S+"Trusted_Connection=Yes;UID="+user+";PWD="+password+";"; break;
  95. case MYSQL: params+=S+"User="+user+";Password="+password+";"; break;
  96. case PGSQL: params+=S+"Port="+port+";UID="+user+";PWD="+password+";"; break;
  97. }
  98. #else
  99. Str params;
  100. #endif
  101. return connectODBC(params, messages, error, sql_type);
  102. }
  103. Bool SQL::connectMSSQL(C Str &server_name, C Str &database, C Str &user, C Str &password, Str *messages, Int *error ) {return connectODBC(server_name, database, user, password, messages, error, 0, "SQL Server" , MSSQL);}
  104. Bool SQL::connectMySQL(C Str &server_name, C Str &database, C Str &user, C Str &password, Str *messages, Int *error, C Str &mysql_driver_name) {return connectODBC(server_name, database, user, password, messages, error, 0, mysql_driver_name, MYSQL);}
  105. Bool SQL::connectPgSQL(C Str &server_name, C Str &database, C Str &user, C Str &password, Str *messages, Int *error, Int port, C Str &pgsql_driver_name) {return connectODBC(server_name, database, user, password, messages, error, port, pgsql_driver_name, PGSQL);}
  106. Bool SQL::dsnConnectMSSQL(C Str &dsn, Str *messages, Int *error) {return connectODBC(S+"DSN="+dsn+";", messages, error, MSSQL);}
  107. Bool SQL::dsnConnectMySQL(C Str &dsn, Str *messages, Int *error) {return connectODBC(S+"DSN="+dsn+";", messages, error, MYSQL);}
  108. Bool SQL::dsnConnectPgSQL(C Str &dsn, Str *messages, Int *error) {return connectODBC(S+"DSN="+dsn+";", messages, error, PGSQL);}
  109. #if SUPPORT_SQLITE
  110. static SyncLock SQLiteCipherLock;
  111. static Cipher *SQLiteCipher;
  112. #endif
  113. Bool SQL::connectSQLite(C Str &database_file_name, const_mem_addr Cipher *cipher)
  114. {
  115. #if SUPPORT_SQLITE
  116. del();
  117. Bool from_pak=(FExist(database_file_name) && !FExistSystem(database_file_name));
  118. if(cipher // custom cipher needed
  119. || from_pak) // file exists only in project data, try to connect in read-only mode using callbacks
  120. {
  121. SyncLocker lock(SQLiteCipherLock);
  122. SQLiteCipher=cipher;
  123. if(sqlite3_open_v2(UTF8(database_file_name), &(sqlite3*&)_sqlite, from_pak ? SQLITE_OPEN_READONLY : SQLITE_OPEN_READWRITE, SQLITE_VFS_NAME)==SQLITE_OK){_type=SQLITE; return true;} // encode to UTF8 and later decode from it, because SQLite callbacks operate on char
  124. }else
  125. {
  126. if(sqlite3_open16(PLATFORM(database_file_name, UnixPath(database_file_name))(), &(sqlite3*&)_sqlite)==SQLITE_OK){_type=SQLITE; return true;}
  127. }
  128. #endif
  129. del(); return false;
  130. }
  131. /******************************************************************************/
  132. Bool SQL::command(C Str &command, Str *messages, Int *error)
  133. {
  134. if(messages)messages->clear();
  135. if(error )*error=0;
  136. switch(_type)
  137. {
  138. #if SUPPORT_ODBC
  139. case MSSQL:
  140. case MYSQL:
  141. case PGSQL:
  142. {
  143. SQLCloseCursor(_statement); // cursor needs to be closed if there was already a command executed (without closing it, executing new commands wouldn't succeed)
  144. if(CChar *c=command())if(SQLExecDirect(_statement, (SQLWCHAR*)c, SQL_NTS)!=SQL_SUCCESS)
  145. {
  146. getStatus(messages, error);
  147. return false;
  148. }
  149. }return true;
  150. #endif
  151. #if SUPPORT_SQLITE
  152. case SQLITE:
  153. {
  154. _rows_pos=-1;
  155. _rows.clear();
  156. _cols.clear();
  157. if(_sqlite)
  158. {
  159. SQLiteMutexEnter((sqlite3*&)_sqlite);
  160. sqlite3_stmt *stmt=null;
  161. Bool ok=(sqlite3_prepare16_v2((sqlite3*&)_sqlite, command(), -1, &stmt, null)==SQLITE_OK);
  162. if(ok && stmt)
  163. {
  164. _cols.setNum(sqlite3_column_count(stmt));
  165. FREPA(_cols)
  166. {
  167. Col &col=_cols[i];
  168. col.name=(CChar*)sqlite3_column_name16(stmt, i);
  169. col.type=SDT_UNKNOWN;
  170. }
  171. for(; sqlite3_step(stmt)==SQLITE_ROW; )
  172. {
  173. Row &row=_rows.New(); row.cols.setNum(_cols.elms());
  174. FREPA(_cols)
  175. {
  176. Col & col= _cols[i];
  177. Row::Col &rcol=row.cols[i];
  178. switch(sqlite3_column_type(stmt, i))
  179. {
  180. case SQLITE_INTEGER: rcol.type=SDT_LONG ; break;
  181. case SQLITE_FLOAT : rcol.type=SDT_DBL ; break;
  182. case SQLITE_TEXT : rcol.type=SDT_STR ; break;
  183. case SQLITE_BLOB : rcol.type=SDT_BINARY ; break;
  184. default : rcol.type=SDT_UNKNOWN; break;
  185. }
  186. if(col.type==SDT_UNKNOWN)col.type=rcol.type;
  187. switch(rcol.type)
  188. {
  189. case SDT_LONG : rcol.i= sqlite3_column_int64 (stmt, i); break;
  190. case SDT_DBL : rcol.d= sqlite3_column_double(stmt, i); break;
  191. case SDT_STR : rcol.s=(CChar*)sqlite3_column_text16(stmt, i); break;
  192. case SDT_BINARY:
  193. {
  194. const Byte *src=(const Byte*)sqlite3_column_blob (stmt, i); // 'sqlite3_column_blob' must be called before 'sqlite3_column_bytes'
  195. rcol.b.setNum( sqlite3_column_bytes(stmt, i)); rcol.b.copyFrom(src);
  196. }break;
  197. }
  198. }
  199. }
  200. }
  201. if(stmt){ok&=(sqlite3_finalize(stmt)==SQLITE_OK); stmt=null;}
  202. if(!ok)
  203. {
  204. if(messages)*messages=(CChar*)sqlite3_errmsg16((sqlite3*&)_sqlite);
  205. if(error )*error = sqlite3_errcode ((sqlite3*&)_sqlite);
  206. }
  207. SQLiteMutexLeave((sqlite3*&)_sqlite);
  208. return ok;
  209. }
  210. }break;
  211. #endif
  212. }
  213. if(messages)*messages="SQL not connected"; return false;
  214. }
  215. /******************************************************************************/
  216. Bool SQL::commandPrepare(C Str &command, Str *messages, Int *error)
  217. {
  218. if(messages)messages->clear();
  219. if(error )*error=0;
  220. switch(_type)
  221. {
  222. #if SUPPORT_ODBC
  223. case MSSQL:
  224. case MYSQL:
  225. case PGSQL:
  226. {
  227. SQLCloseCursor(_statement); // cursor needs to be closed if there was already a command executed (without closing it, executing new commands wouldn't succeed)
  228. CChar *c=command(); if(SQLPrepare(_statement, (SQLWCHAR*)c, SQL_NTS)==SQL_SUCCESS)return true;
  229. getStatus(messages, error);
  230. }return false;
  231. #endif
  232. case SQLITE: if(messages)*messages="'commandPrepare' is currently not supported on SQLite"; return false;
  233. }
  234. if(messages)*messages="SQL not connected"; return false;
  235. }
  236. Bool SQL::commandParamRaw(Int i, CPtr value, Int size, Int c_type, Int sql_type)
  237. {
  238. switch(_type)
  239. {
  240. #if SUPPORT_ODBC
  241. case MSSQL:
  242. case MYSQL:
  243. case PGSQL:
  244. {
  245. Memc<Byte> &param=_params(i);
  246. param.setNum(size);
  247. Copy(param.data(), value, size);
  248. return SQLBindParameter(_statement, i+1, SQL_PARAM_INPUT, c_type, sql_type, 0, 0, param.data(), 0, null)==SQL_SUCCESS;
  249. }break;
  250. #endif
  251. }
  252. return false;
  253. }
  254. Bool SQL::commandParamRaw2(Int i, CPtr value, Int size, Int c_type, Int sql_type)
  255. {
  256. switch(_type)
  257. {
  258. #if SUPPORT_ODBC
  259. case MSSQL:
  260. case MYSQL:
  261. case PGSQL:
  262. {
  263. Memc<Byte> &param=_params(i);
  264. param.setNum(size+SIZE(SQLLEN));
  265. Copy(param.data(), value, size);
  266. SQLLEN &length=*(SQLLEN*)(param.data()+size); length=size;
  267. return SQLBindParameter(_statement, i+1, SQL_PARAM_INPUT, c_type, sql_type, 0, 0, param.data(), 0, &length)==SQL_SUCCESS;
  268. }break;
  269. #endif
  270. }
  271. return false;
  272. }
  273. #if SUPPORT_ODBC
  274. SQL& SQL::commandParam(Int i, Bool value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_BIT , SQL_BIT ); return T;}
  275. SQL& SQL::commandParam(Int i, Int value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_SLONG , SQL_INTEGER ); return T;}
  276. SQL& SQL::commandParam(Int i, UInt value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_ULONG , SQL_INTEGER ); return T;}
  277. SQL& SQL::commandParam(Int i, Long value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_SBIGINT, SQL_BIGINT ); return T;}
  278. SQL& SQL::commandParam(Int i, ULong value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_UBIGINT, SQL_BIGINT ); return T;}
  279. SQL& SQL::commandParam(Int i, Flt value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_FLOAT , SQL_REAL ); return T;}
  280. SQL& SQL::commandParam(Int i, Dbl value ) {commandParamRaw (i, &value , SIZE (value) , SQL_C_DOUBLE , SQL_DOUBLE ); return T;}
  281. SQL& SQL::commandParam(Int i, CChar8 *value ) {commandParamRaw2(i, value , Length(value) , SQL_C_CHAR , SQL_VARCHAR ); return T;}
  282. SQL& SQL::commandParam(Int i, CChar *value ) {commandParamRaw2(i, value , Length(value) *2, SQL_C_WCHAR , SQL_WVARCHAR); return T;}
  283. SQL& SQL::commandParam(Int i, C Str8 &value ) {commandParamRaw2(i, value(), value.length() , SQL_C_CHAR , SQL_VARCHAR ); return T;}
  284. SQL& SQL::commandParam(Int i, C Str &value ) {commandParamRaw2(i, value(), value.length()*2, SQL_C_WCHAR , SQL_WVARCHAR); return T;}
  285. SQL& SQL::commandParam(Int i, CPtr value, Int size) {commandParamRaw2(i, value , size , SQL_C_BINARY , SQL_BINARY ); return T;}
  286. SQL& SQL::commandParam(Int i, C DateTime &value )
  287. {
  288. switch(_type)
  289. {
  290. #if SUPPORT_ODBC
  291. case MSSQL:
  292. case MYSQL:
  293. case PGSQL:
  294. {
  295. TIMESTAMP_STRUCT ts;
  296. ts.year =value.year ;
  297. ts.month =value.month ;
  298. ts.day =value.day ;
  299. ts.hour =value.hour ;
  300. ts.minute =value.minute;
  301. ts.second =value.second;
  302. ts.fraction= 0;
  303. commandParamRaw(i, &ts, SIZE(ts), SQL_C_TIMESTAMP, SQL_TIMESTAMP);
  304. }break;
  305. #endif
  306. }
  307. return T;
  308. }
  309. SQL& SQL::commandParam(Int i, C DateTimeMs &value)
  310. {
  311. switch(_type)
  312. {
  313. #if SUPPORT_ODBC
  314. case MSSQL:
  315. case MYSQL:
  316. case PGSQL:
  317. {
  318. TIMESTAMP_STRUCT ts;
  319. ts.year =value.year ;
  320. ts.month =value.month ;
  321. ts.day =value.day ;
  322. ts.hour =value.hour ;
  323. ts.minute =value.minute;
  324. ts.second =value. second;
  325. ts.fraction=value.millisecond*1000000; // 1ms is 1,000,000 units according to - https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/c-data-types
  326. commandParamRaw(i, &ts, SIZE(ts), SQL_C_TIMESTAMP, SQL_TIMESTAMP);
  327. }break;
  328. #endif
  329. }
  330. return T;
  331. }
  332. #else
  333. SQL& SQL::commandParam(Int i, Bool value ) {return T;}
  334. SQL& SQL::commandParam(Int i, Int value ) {return T;}
  335. SQL& SQL::commandParam(Int i, UInt value ) {return T;}
  336. SQL& SQL::commandParam(Int i, Long value ) {return T;}
  337. SQL& SQL::commandParam(Int i, ULong value ) {return T;}
  338. SQL& SQL::commandParam(Int i, Flt value ) {return T;}
  339. SQL& SQL::commandParam(Int i, Dbl value ) {return T;}
  340. SQL& SQL::commandParam(Int i, CChar8 *value ) {return T;}
  341. SQL& SQL::commandParam(Int i, CChar *value ) {return T;}
  342. SQL& SQL::commandParam(Int i, C Str8 &value ) {return T;}
  343. SQL& SQL::commandParam(Int i, C Str &value ) {return T;}
  344. SQL& SQL::commandParam(Int i, CPtr value, Int size) {return T;}
  345. SQL& SQL::commandParam(Int i, C DateTime &value ) {return T;}
  346. SQL& SQL::commandParam(Int i, C DateTimeMs &value ) {return T;}
  347. #endif
  348. SQL& SQL::commandParam(Int i, C UID &value)
  349. {
  350. switch(_type)
  351. {
  352. #if SUPPORT_ODBC
  353. case MSSQL:
  354. case PGSQL: commandParamRaw(i, &value, SIZE(value), SQL_C_GUID, SQL_GUID); break;
  355. case MYSQL: commandParamRaw2(i, &value, SIZE(value), SQL_C_BINARY, SQL_BINARY); break; // MySQL does not support UID
  356. #endif
  357. }
  358. return T;
  359. }
  360. SQL& SQL::commandParam(Int i, C MemPtr<Byte> &value)
  361. {
  362. switch(_type)
  363. {
  364. #if SUPPORT_ODBC
  365. case MSSQL:
  366. case MYSQL:
  367. case PGSQL:
  368. {
  369. Memc<Byte> &param=_params(i);
  370. param.setNum(value.elms()+SIZE(SQLLEN));
  371. value.copyTo(param.data());
  372. SQLLEN &length=*(SQLLEN*)(param.data()+value.elms()); length=value.elms();
  373. Bool ok=(SQLBindParameter(_statement, i+1, SQL_PARAM_INPUT, SQL_C_BINARY, SQL_BINARY, 0, 0, param.data(), 0, &length)==SQL_SUCCESS);
  374. }break;
  375. #endif
  376. }
  377. return T;
  378. }
  379. Bool SQL::commandExecute(Str *messages, Int *error)
  380. {
  381. if(messages)messages->clear();
  382. if(error )*error=0;
  383. switch(_type)
  384. {
  385. #if SUPPORT_ODBC
  386. case MSSQL:
  387. case MYSQL:
  388. case PGSQL:
  389. {
  390. SQLCloseCursor(_statement); // cursor needs to be closed if there was already a command executed (without closing it, executing new commands wouldn't succeed)
  391. if(SQLExecute(_statement)==SQL_SUCCESS)return true;
  392. getStatus(messages, error);
  393. }return false;
  394. #endif
  395. case SQLITE: if(messages)*messages="'commandExecute' is currently not supported on SQLite"; return false;
  396. }
  397. if(messages)*messages="SQL not connected"; return false;
  398. }
  399. /******************************************************************************/
  400. Bool SQL::getTables(MemPtr<Str> table_names, Str *messages, Int *error)
  401. {
  402. table_names.clear();
  403. CChar8 *cmd=null;
  404. switch(_type)
  405. {
  406. default : if(messages)*messages="SQL not connected"; if(error)*error=0; return false;
  407. case MSSQL : cmd="SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES"; break; // "INFORMATION_SCHEMA.TABLES" has 4 columns
  408. //case MSSQL : cmd="SELECT name FROM sys.tables"; break; // "sys.tables" has 27 columns
  409. //case MSSQL : cmd="SELECT Name FROM SysObjects"; break; // "SysObjects" has 25 columns and returns more elements than it should, probably would require some type filtering?
  410. case MYSQL : cmd="SHOW TABLES"; break;
  411. case PGSQL : cmd="SELECT table_name FROM information_schema.tables WHERE table_schema='public'"; break;
  412. case SQLITE: cmd="SELECT name FROM sqlite_master WHERE type='table'"; break;
  413. }
  414. if(command(cmd, messages, error))
  415. {
  416. for(; getNextRow(); )getCol(0, table_names.New());
  417. return true;
  418. }
  419. return false;
  420. }
  421. Bool SQL::delTable(C Str &table_name, Str *messages, Int *error)
  422. {
  423. return command(S+"DROP TABLE "+token(table_name), messages, error);
  424. }
  425. Bool SQL::createTable(C Str &table_name, C MemPtr<SQLColumn> &columns, Str *messages, Int *error)
  426. {
  427. if(messages)messages->clear();
  428. if(error )*error=0;
  429. if(!columns.elms())
  430. {
  431. if(messages)*messages="Can't create an empty table";
  432. return false;
  433. }
  434. Str cmd=S+"CREATE TABLE "+token(table_name)+" (", desc;
  435. FREPA(columns){if(i)cmd+=", "; if(!colDesc(columns[i], desc, messages))return false; cmd+=desc;}
  436. cmd+=')';
  437. return command(cmd, messages, error);
  438. }
  439. Bool SQL::appendTable(C Str &table_name, C MemPtr<SQLColumn> &columns, Str *messages, Int *error)
  440. {
  441. if(messages)messages->clear();
  442. if(error )*error=0;
  443. if(columns.elms())
  444. {
  445. Str cmd=S+"ALTER TABLE "+token(table_name)+" ADD ", desc;
  446. FREPA(columns){if(i)cmd+=", "; if(!colDesc(columns[i], desc, messages))return false; cmd+=desc;}
  447. return command(cmd, messages, error);
  448. }
  449. return true;
  450. //if(del_cols.elms())cmd+="DROP COLUMN "; FREPA(del_cols){if(i)cmd+=", "; cmd+=S+'['+del_cols[i]+']';}
  451. //FREPA(modify_cols)cmd+=S+"ALTER TABLE "+token(table_name)+" ALTER COLUMN "+colDesc(modify_cols[i])+" ;\n";
  452. }
  453. Bool SQL::existsTable(C Str &table_name, Str *messages, Int *error)
  454. {
  455. switch(_type)
  456. {
  457. default : if(messages)*messages="SQL not connected"; return false;
  458. case MSSQL : if(command(S+"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME=" +string(table_name), messages, error))return getNextRow(); break;
  459. //case MYSQL : if(command(S+"SHOW TABLES LIKE " +string(table_name), messages, error))return getNextRow(); break; // this fails for 'table_name' - "\'\\a"
  460. case MYSQL : return command(S+"SELECT 1 FROM "+token(table_name)+" LIMIT 1", messages, error);
  461. case PGSQL : if(command(S+"SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE table_name=" +string(table_name), messages, error))return getNextRow(); break;
  462. case SQLITE: if(command(S+"SELECT name FROM sqlite_master WHERE type='table' AND name="+string(table_name), messages, error))return getNextRow(); break;
  463. }
  464. return false;
  465. }
  466. /******************************************************************************/
  467. Bool SQL::delRow(C Str &table_name, C Str &condition, Str *messages, Int *error)
  468. {
  469. return command(S+"DELETE FROM "+token(table_name)+" WHERE "+condition, messages, error);
  470. }
  471. Bool SQL::newRow(C Str &table_name, C SQLValues &values, Str *messages, Int *error)
  472. {
  473. Str cmd=S+"INSERT INTO "+token(table_name)+" (";
  474. FREPA(values._values){if(i)cmd+=", "; cmd+=token(values._values[i].name);}
  475. cmd+=") VALUES (";
  476. FREPA(values._values){if(i)cmd+=", "; cmd+=value(values._values[i]);}
  477. cmd+=")";
  478. return command(cmd, messages, error);
  479. }
  480. Bool SQL::setRow(C Str &table_name, C Str &condition, C SQLValues &values, Str *messages, Int *error)
  481. {
  482. Str cmd=S+"UPDATE "+token(table_name)+" SET ";
  483. FREPA(values._values){if(i)cmd+=", "; cmd+=token(values._values[i].name)+'='+value(values._values[i]);}
  484. cmd+=" WHERE "; cmd+=condition;
  485. return command(cmd, messages, error);
  486. }
  487. /******************************************************************************/
  488. Bool SQL::getAllRows(C Str &table_name, Str *messages, Int *error)
  489. {
  490. return command(S+"SELECT * FROM "+token(table_name), messages, error);
  491. }
  492. Bool SQL::getRows(C Str &table_name, C Str &condition, Str *messages, Int *error)
  493. {
  494. if(!condition.is())return getAllRows(table_name, messages, error);
  495. return command(S+"SELECT * FROM "+token(table_name)+" WHERE "+condition, messages, error);
  496. }
  497. Bool SQL::getAllRowsCols(C Str &table_name, C MemPtr<Str> &columns, Str *messages, Int *error)
  498. {
  499. Str cmd="SELECT ";
  500. FREPA(columns){if(i)cmd+=", "; cmd+=token(columns[i]);}
  501. cmd+=S+" FROM "+token(table_name);
  502. return command(cmd, messages, error);
  503. }
  504. Bool SQL::getRowsCols(C Str &table_name, C Str &condition, C MemPtr<Str> &columns, Str *messages, Int *error)
  505. {
  506. if(!condition.is())return getAllRowsCols(table_name, columns, messages, error);
  507. Str cmd="SELECT ";
  508. FREPA(columns){if(i)cmd+=", "; cmd+=token(columns[i]);}
  509. cmd+=S+" FROM "+token(table_name)+" WHERE "; cmd+=condition;
  510. return command(cmd, messages, error);
  511. }
  512. /******************************************************************************/
  513. Int SQL::getAllRowsNum(C Str &table_name, Str *messages, Int *error)
  514. {
  515. if(command(S+"SELECT COUNT(*) FROM "+token(table_name), messages, error))if(getNextRow())
  516. {
  517. Int rows=0; getCol(0, rows);
  518. return rows;
  519. }
  520. return -1;
  521. }
  522. Int SQL::getRowsNum(C Str &table_name, C Str &condition, Str *messages, Int *error)
  523. {
  524. if(!condition.is())return getAllRowsNum(table_name, messages, error);
  525. if(command(S+"SELECT COUNT(*) FROM "+token(table_name)+" WHERE "+condition, messages, error))if(getNextRow())
  526. {
  527. Int rows=0; getCol(0, rows);
  528. return rows;
  529. }
  530. return -1;
  531. }
  532. Int SQL::getUniqueValuesNum(C Str &table_name, C Str &column_name, Str *messages, Int *error)
  533. {
  534. if(command(S+"SELECT COUNT(DISTINCT "+token(column_name)+") FROM "+token(table_name), messages, error))if(getNextRow())
  535. {
  536. Int rows=0; getCol(0, rows);
  537. return rows;
  538. }
  539. return -1;
  540. }
  541. /******************************************************************************/
  542. Str SQL::string(C Str &s)C
  543. {
  544. switch(_type)
  545. {
  546. case MSSQL:
  547. {
  548. Str out="N'"; FREPA(s){Char c=s[i]; if(c=='\'')out+="''";else if(c=='\n')out+="'+CHAR(10)+N'";else if(c=='\r')out+="'+CHAR(13)+N'";else out+=c;} out+='\''; // "some text" -> "'some text'", "I'm a text" -> "'I''m a text'", (' must be replaced with '')
  549. return out;
  550. }
  551. case PGSQL:
  552. case SQLITE:
  553. {
  554. Str out='\''; FREPA(s){Char c=s[i]; if(c=='\'')out+="''";else out+=c;} out+='\''; // "some text" -> "'some text'", "I'm a text" -> "'I''m a text'", (' must be replaced with '')
  555. return out;
  556. }
  557. case MYSQL: return S+'\''+Replace(Replace(s, "\\", "\\\\"), "'", "\\'")+'\''; // replace \ into \\ and ' into \'
  558. default : return s;
  559. }
  560. }
  561. /******************************************************************************/
  562. Bool SQL::getNextRow()
  563. {
  564. switch(_type)
  565. {
  566. #if SUPPORT_ODBC
  567. case MSSQL:
  568. case MYSQL:
  569. case PGSQL: return SQLFetch(_statement)==SQL_SUCCESS;
  570. #endif
  571. case SQLITE:
  572. {
  573. if(InRange(_rows_pos+1, _rows)){_rows_pos++; return true;}
  574. }return false;
  575. default: return false;
  576. }
  577. }
  578. Int SQL::getCols()
  579. {
  580. switch(_type)
  581. {
  582. #if SUPPORT_ODBC
  583. case MSSQL:
  584. case MYSQL:
  585. case PGSQL: {SQLSMALLINT cols=0; SQLNumResultCols(_statement, &cols); return cols;}
  586. #endif
  587. case SQLITE: return _cols.elms();
  588. default: return 0;
  589. }
  590. }
  591. Bool SQL::getColDesc(Int i, Str &name, SQL_DATA_TYPE &type, Int &size)
  592. {
  593. switch(_type)
  594. {
  595. #if SUPPORT_ODBC
  596. case MSSQL:
  597. case MYSQL:
  598. case PGSQL:
  599. {
  600. SQLWCHAR temp[1024]; SQLSMALLINT t; SQLULEN s; if(SQLDescribeCol(_statement, i+1, temp, Elms(temp), null, &t, &s, null, null)==SQL_SUCCESS)
  601. {
  602. name=(Char*)temp;
  603. switch(t)
  604. {
  605. case SQL_CHAR : size=s ; type=SDT_STR8 ; break;
  606. case SQL_VARCHAR : size=s ; type=SDT_STR8 ; break;
  607. case SQL_LONGVARCHAR : size=-1 ; type=SDT_STR8 ; break;
  608. case SQL_WCHAR : size=s*2 ; type=SDT_STR ; break;
  609. case SQL_WVARCHAR : size=s*2 ; type=SDT_STR ; break;
  610. case SQL_WLONGVARCHAR : size=-1 ; type=SDT_STR ; break;
  611. case SQL_BIT : size=1 ; type=SDT_BOOL ; break;
  612. case SQL_TINYINT : size=1 ; type=SDT_BYTE ; break;
  613. case SQL_SMALLINT : size=2 ; type=SDT_SHORT ; break;
  614. case SQL_INTEGER : size=4 ; type=SDT_INT ; break;
  615. case SQL_BIGINT : size=8 ; type=SDT_LONG ; break;
  616. case SQL_REAL : size=4 ; type=SDT_FLT ; break; // SQL_REAL is C++ float
  617. case SQL_FLOAT : size=8 ; type=SDT_DBL ; break; // SQL_FLOAT is C++ double
  618. case SQL_DOUBLE : size=8 ; type=SDT_DBL ; break; // encountered in MySQL
  619. case SQL_GUID : size=16 ; type=SDT_UID ; break;
  620. case SQL_BINARY : size=s ; type=SDT_BINARY ; break;
  621. case SQL_VARBINARY : size=s ; type=SDT_BINARY ; break;
  622. case SQL_LONGVARBINARY : size=-1 ; type=SDT_BINARY ; break;
  623. case SQL_TYPE_TIMESTAMP: size=SIZE(DateTime); type=SDT_DATE_TIME; break;
  624. default : size=s ; type=SDT_UNKNOWN ; break;
  625. }
  626. return true;
  627. }
  628. }break;
  629. #endif
  630. case SQLITE:
  631. {
  632. if(InRange(i, _cols))
  633. {
  634. Col &col=_cols[i];
  635. name=col.name;
  636. switch(type=col.type)
  637. {
  638. default: size=-1; break;
  639. case SDT_INT :
  640. case SDT_LONG: size=SIZE(Long); break;
  641. case SDT_FLT:
  642. case SDT_DBL: size=SIZE(Dbl); break;
  643. }
  644. return true;
  645. }
  646. }break;
  647. }
  648. name.clear(); type=SDT_UNKNOWN; size=0;
  649. return false;
  650. }
  651. /******************************************************************************/
  652. Bool SQL::getCol(Int i, Bool &value)
  653. {
  654. switch(_type)
  655. {
  656. #if SUPPORT_ODBC
  657. case MSSQL:
  658. case MYSQL:
  659. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_BIT, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  660. #endif
  661. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  662. {
  663. C Row::Col &col=_rows[_rows_pos].cols[i];
  664. switch( col.type)
  665. {
  666. case SDT_LONG : value= (col.i!=0); return true;
  667. case SDT_DBL : value= (col.d!=0); return true;
  668. case SDT_STR : value=TextBool(col.s ); return true;
  669. case SDT_BINARY: value=false; REPA(col.b)if(col.b[i]){value=true; break;} return true;
  670. }
  671. }break;
  672. }
  673. value=false; return false;
  674. }
  675. Bool SQL::getCol(Int i, Byte &value)
  676. {
  677. switch(_type)
  678. {
  679. #if SUPPORT_ODBC
  680. case MSSQL:
  681. case MYSQL:
  682. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_UTINYINT, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  683. #endif
  684. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  685. {
  686. C Row::Col &col=_rows[_rows_pos].cols[i];
  687. switch( col.type)
  688. {
  689. case SDT_LONG : value= col.i ; return true;
  690. case SDT_DBL : value= RoundU(col.d); return true;
  691. case SDT_STR : value=TextUInt(col.s); return true;
  692. case SDT_BINARY: value=(col.b.elms() ? col.b[0] : 0); return true;
  693. }
  694. }break;
  695. }
  696. value=0; return false;
  697. }
  698. Bool SQL::getCol(Int i, Int &value)
  699. {
  700. switch(_type)
  701. {
  702. #if SUPPORT_ODBC
  703. case MSSQL:
  704. case MYSQL:
  705. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_SLONG, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  706. #endif
  707. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  708. {
  709. C Row::Col &col=_rows[_rows_pos].cols[i];
  710. switch( col.type)
  711. {
  712. case SDT_LONG : value= col.i ; return true;
  713. case SDT_DBL : value= Round(col.d); return true;
  714. case SDT_STR : value=TextInt(col.s); return true;
  715. case SDT_BINARY: value=0; FREP(Min(col.b.elms(), SIZEI(value)))value|=(col.b[i]<<(i*8)); return true;
  716. }
  717. }break;
  718. }
  719. value=0; return false;
  720. }
  721. Bool SQL::getCol(Int i, UInt &value)
  722. {
  723. switch(_type)
  724. {
  725. #if SUPPORT_ODBC
  726. case MSSQL:
  727. case MYSQL:
  728. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_ULONG, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  729. #endif
  730. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  731. {
  732. C Row::Col &col=_rows[_rows_pos].cols[i];
  733. switch( col.type)
  734. {
  735. case SDT_LONG : value= col.i ; return true;
  736. case SDT_DBL : value= RoundU(col.d); return true;
  737. case SDT_STR : value=TextUInt(col.s); return true;
  738. case SDT_BINARY: value=0; FREP(Min(col.b.elms(), SIZEI(value)))value|=(col.b[i]<<(i*8)); return true;
  739. }
  740. }break;
  741. }
  742. value=0; return false;
  743. }
  744. Bool SQL::getCol(Int i, Long &value)
  745. {
  746. switch(_type)
  747. {
  748. #if SUPPORT_ODBC
  749. case MSSQL:
  750. case MYSQL:
  751. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_SBIGINT, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  752. #endif
  753. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  754. {
  755. C Row::Col &col=_rows[_rows_pos].cols[i];
  756. switch( col.type)
  757. {
  758. case SDT_LONG : value= col.i ; return true;
  759. case SDT_DBL : value= col.d ; return true;
  760. case SDT_STR : value=TextLong(col.s); return true;
  761. case SDT_BINARY: value=0; FREP(Min(col.b.elms(), SIZEI(value)))value|=(ULong(col.b[i])<<(i*8)); return true;
  762. }
  763. }break;
  764. }
  765. value=0; return false;
  766. }
  767. Bool SQL::getCol(Int i, ULong &value)
  768. {
  769. switch(_type)
  770. {
  771. #if SUPPORT_ODBC
  772. case MSSQL:
  773. case MYSQL:
  774. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_UBIGINT, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  775. #endif
  776. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  777. {
  778. C Row::Col &col=_rows[_rows_pos].cols[i];
  779. switch( col.type)
  780. {
  781. case SDT_LONG : value= col.i ; return true;
  782. case SDT_DBL : value= col.d ; return true;
  783. case SDT_STR : value=TextULong(col.s); return true;
  784. case SDT_BINARY: value=0; FREP(Min(col.b.elms(), SIZEI(value)))value|=(ULong(col.b[i])<<(i*8)); return true;
  785. }
  786. }break;
  787. }
  788. value=0; return false;
  789. }
  790. Bool SQL::getCol(Int i, Flt &value)
  791. {
  792. switch(_type)
  793. {
  794. #if SUPPORT_ODBC
  795. case MSSQL:
  796. case MYSQL:
  797. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_FLOAT, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  798. #endif
  799. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  800. {
  801. C Row::Col &col=_rows[_rows_pos].cols[i];
  802. switch( col.type)
  803. {
  804. case SDT_LONG : value= col.i ; return true;
  805. case SDT_DBL : value= col.d ; return true;
  806. case SDT_STR : value=TextFlt(col.s); return true;
  807. case SDT_BINARY: value=0; FREP(Min(col.b.elms(), SIZEI(value)))(U32&)value|=(col.b[i]<<(i*8)); return true;
  808. }
  809. }break;
  810. }
  811. value=0; return false;
  812. }
  813. Bool SQL::getCol(Int i, Dbl &value)
  814. {
  815. switch(_type)
  816. {
  817. #if SUPPORT_ODBC
  818. case MSSQL:
  819. case MYSQL:
  820. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_DOUBLE, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  821. #endif
  822. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  823. {
  824. C Row::Col &col=_rows[_rows_pos].cols[i];
  825. switch( col.type)
  826. {
  827. case SDT_LONG : value= col.i ; return true;
  828. case SDT_DBL : value= col.d ; return true;
  829. case SDT_STR : value=TextDbl(col.s); return true;
  830. case SDT_BINARY: value=0; FREP(Min(col.b.elms(), SIZEI(value)))(ULong&)value|=(ULong(col.b[i])<<(i*8)); return true;
  831. }
  832. }break;
  833. }
  834. value=0; return false;
  835. }
  836. Bool SQL::getCol(Int i, UID &value)
  837. {
  838. switch(_type)
  839. {
  840. #if SUPPORT_ODBC
  841. case MSSQL:
  842. case MYSQL:
  843. case PGSQL: if(SQLGetData(_statement, i+1, (_type==MYSQL) ? SQL_C_BINARY : SQL_C_GUID, &value, SIZE(value), null)==SQL_SUCCESS)return true; break;
  844. #endif
  845. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  846. {
  847. C Row::Col &col=_rows[_rows_pos].cols[i];
  848. switch( col.type)
  849. {
  850. case SDT_LONG : value.set (col.i, 0); return true;
  851. case SDT_DBL : value.set (col.d, 0); return true;
  852. case SDT_STR : value.fromHex(col.s ); return true;
  853. case SDT_BINARY: value.zero(); REP(Min(col.b.elms(), Elms(value.b)))value.b[i]=col.b[i]; return true;
  854. }
  855. }break;
  856. }
  857. value.zero(); return false;
  858. }
  859. Bool SQL::getCol(Int i, Char *value, Int max_length)
  860. {
  861. switch(_type)
  862. {
  863. #if SUPPORT_ODBC
  864. case MSSQL:
  865. case MYSQL:
  866. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_WCHAR, value, max_length, null)==SQL_SUCCESS)
  867. {
  868. if(_type==PGSQL)ReplaceSelf(value, '\r', '\0'); // PostgreSql will add '\r' characters to new lines
  869. return true;
  870. }break;
  871. #endif
  872. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  873. {
  874. C Row::Col &col=_rows[_rows_pos].cols[i];
  875. switch( col.type)
  876. {
  877. case SDT_LONG : Set(value, TextInt (col.i ), max_length); return true;
  878. case SDT_DBL : Set(value, TextDbl (col.d ), max_length); return true;
  879. case SDT_STR : Set(value, col.s , max_length); return true;
  880. case SDT_BINARY: Set(value, TextHexMem(col.b.data(), col.b.elms(), true), max_length); return true;
  881. }
  882. }break;
  883. }
  884. if(value && max_length>0)value[0]='\0'; return false;
  885. }
  886. Bool SQL::getCol(Int i, Char8 *value, Int max_length)
  887. {
  888. switch(_type)
  889. {
  890. #if SUPPORT_ODBC
  891. case MSSQL:
  892. case MYSQL:
  893. case PGSQL: if(SQLGetData(_statement, i+1, SQL_C_CHAR, value, max_length, null)==SQL_SUCCESS)
  894. {
  895. if(_type==PGSQL)ReplaceSelf(value, '\r', '\0'); // PostgreSql will add '\r' characters to new lines
  896. return true;
  897. }break;
  898. #endif
  899. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  900. {
  901. C Row::Col &col=_rows[_rows_pos].cols[i];
  902. switch( col.type)
  903. {
  904. case SDT_LONG : Set(value, TextInt (col.i ), max_length); return true;
  905. case SDT_DBL : Set(value, TextDbl (col.d ), max_length); return true;
  906. case SDT_STR : Set(value, col.s , max_length); return true;
  907. case SDT_BINARY: Set(value, TextHexMem(col.b.data(), col.b.elms(), true), max_length); return true;
  908. }
  909. }break;
  910. }
  911. if(value && max_length>0)value[0]='\0'; return false;
  912. }
  913. Bool SQL::getCol(Int i, Str &value)
  914. {
  915. switch(_type)
  916. {
  917. #if SUPPORT_ODBC
  918. case MSSQL:
  919. case MYSQL:
  920. case PGSQL:
  921. {
  922. Char temp[1024]; SQLLEN len=0;
  923. switch(SQLGetData(_statement, i+1, SQL_C_WCHAR, temp, SIZE(temp), &len))
  924. {
  925. case SQL_SUCCESS:
  926. {
  927. SQLSMALLINT type; if(_type==MYSQL && len==1 && (temp[0]==0 || temp[0]==1) && SQLDescribeCol(_statement, i+1, null, 0, null, &type, null, null, null)==SQL_SUCCESS_WITH_INFO)if(type==SQL_BIT){value=(temp[0] ? "1" : "0"); return true;} // MySQL returns incorrectly 0 or 1 for SQL_BIT instead of "0" or "1"
  928. if(len>0) // 'len' can be -1 for null
  929. {
  930. value=temp;
  931. if(_type==PGSQL)value.replace('\r', '\0'); // PostgreSql will add '\r' characters to new lines
  932. }else value.clear();
  933. }return true;
  934. case SQL_SUCCESS_WITH_INFO:
  935. {
  936. if(len>0)
  937. {
  938. len/=2;
  939. value.clear().reserve(len); // make room for remaining data, call this before "value=temp"
  940. value=temp ; // copy what was already received
  941. value.reserve (len); // make room for remaining data, call this after "value=temp" (in case that would somehow make the buffer smaller)
  942. if(SQLGetData(_statement, i+1, SQL_C_WCHAR, (Ptr)(value()+value.length()), (value._d.elms()-value.length())*2, null)==SQL_SUCCESS)
  943. {
  944. value._length=Length(value());
  945. if(_type==PGSQL)value.replace('\r', '\0'); // PostgreSql will add '\r' characters to new lines
  946. return true;
  947. }
  948. value._length=0;
  949. }
  950. }break;
  951. }
  952. }break;
  953. #endif
  954. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  955. {
  956. C Row::Col &col=_rows[_rows_pos].cols[i];
  957. switch( col.type)
  958. {
  959. case SDT_LONG : value= col.i ; return true;
  960. case SDT_DBL : value= col.d ; return true;
  961. case SDT_STR : value= col.s ; return true;
  962. case SDT_BINARY: value=TextHexMem(col.b.data(), col.b.elms(), true); return true;
  963. }
  964. }break;
  965. }
  966. value.clear(); return false;
  967. }
  968. Bool SQL::getCol(Int i, Str8 &value)
  969. {
  970. switch(_type)
  971. {
  972. #if SUPPORT_ODBC
  973. case MSSQL:
  974. case MYSQL:
  975. case PGSQL:
  976. {
  977. Char8 temp[1024]; SQLLEN len=0;
  978. switch(SQLGetData(_statement, i+1, SQL_C_CHAR, temp, SIZE(temp), &len))
  979. {
  980. case SQL_SUCCESS:
  981. {
  982. SQLSMALLINT type; if(_type==MYSQL && len==1 && (temp[0]==0 || temp[0]==1) && SQLDescribeCol(_statement, i+1, null, 0, null, &type, null, null, null)==SQL_SUCCESS_WITH_INFO)if(type==SQL_BIT){value=(temp[0] ? "1" : "0"); return true;} // MySQL returns incorrectly 0 or 1 for SQL_BIT instead of "0" or "1"
  983. if(len>0) // 'len' can be -1 for null
  984. {
  985. value=temp;
  986. if(_type==PGSQL)value.replace('\r', '\0'); // PostgreSql will add '\r' characters to new lines
  987. }else value.clear();
  988. }return true;
  989. case SQL_SUCCESS_WITH_INFO:
  990. {
  991. if(len>0)
  992. {
  993. value.clear().reserve(len); // make room for remaining data, call this before "value=temp"
  994. value=temp ; // copy what was already received
  995. value.reserve (len); // make room for remaining data, call this after "value=temp" (in case that would somehow make the buffer smaller)
  996. if(SQLGetData(_statement, i+1, SQL_C_CHAR, (Ptr)(value()+value.length()), value._d.elms()-value.length(), null)==SQL_SUCCESS)
  997. {
  998. value._length=Length(value());
  999. if(_type==PGSQL)value.replace('\r', '\0'); // PostgreSql will add '\r' characters to new lines
  1000. return true;
  1001. }
  1002. value._length=0;
  1003. }
  1004. }break;
  1005. }
  1006. }break;
  1007. #endif
  1008. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  1009. {
  1010. C Row::Col &col=_rows[_rows_pos].cols[i];
  1011. switch( col.type)
  1012. {
  1013. case SDT_LONG : value= col.i ; return true;
  1014. case SDT_DBL : value= col.d ; return true;
  1015. case SDT_STR : value= col.s ; return true;
  1016. case SDT_BINARY: value=TextHexMem(col.b.data(), col.b.elms(), true); return true;
  1017. }
  1018. }break;
  1019. }
  1020. value.clear(); return false;
  1021. }
  1022. Bool SQL::getCol(Int i, MemPtr<Byte> value)
  1023. {
  1024. switch(_type)
  1025. {
  1026. #if SUPPORT_ODBC
  1027. case MSSQL:
  1028. case MYSQL:
  1029. case PGSQL:
  1030. {
  1031. Byte temp[1024]; SQLLEN len=0;
  1032. switch(SQLGetData(_statement, i+1, SQL_C_BINARY, temp, SIZE(temp), &len))
  1033. {
  1034. case SQL_SUCCESS: if(len>0)value.setNum(len).copyFrom(temp);else value.clear(); return true; // 'len' can be -1 for null
  1035. case SQL_SUCCESS_WITH_INFO:
  1036. {
  1037. if(len>0)
  1038. {
  1039. Memt<Byte> full; full.setNum(len);
  1040. CopyFast(full.data(), temp, SIZE(temp)); // copy what was already received
  1041. if(SQLGetData(_statement, i+1, SQL_C_BINARY, full.data()+SIZE(temp), full.elms()-SIZE(temp), null)==SQL_SUCCESS) // get the remaining part
  1042. {
  1043. value.setNum(full.elms()).copyFrom(full.data()); // copy everything to destination
  1044. return true;
  1045. }
  1046. }
  1047. }break;
  1048. }
  1049. }break;
  1050. #endif
  1051. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  1052. {
  1053. C Row::Col &col=_rows[_rows_pos].cols[i];
  1054. switch( col.type)
  1055. {
  1056. case SDT_LONG : value.setNum(SIZE(col.i) ).copyFrom((Byte*)&col.i ); return true;
  1057. case SDT_DBL : value.setNum(SIZE(col.d) ).copyFrom((Byte*)&col.d ); return true;
  1058. case SDT_STR : value.setNum( (1+col.s.length())*SIZE(Char)).copyFrom((Byte*) col.s()); return true;
  1059. case SDT_BINARY: value=col.b; return true;
  1060. }
  1061. }break;
  1062. }
  1063. value.clear(); return false;
  1064. }
  1065. Bool SQL::getCol(Int i, File &file)
  1066. {
  1067. Memt<Byte> value; if(getCol(i, value))return file.put(value.data(), value.elms());
  1068. return false;
  1069. }
  1070. Bool SQL::getCol(Int i, DateTime &value)
  1071. {
  1072. switch(_type)
  1073. {
  1074. #if SUPPORT_ODBC
  1075. case MSSQL:
  1076. case MYSQL:
  1077. case PGSQL:
  1078. {
  1079. TIMESTAMP_STRUCT ts; if(SQLGetData(_statement, i+1, SQL_C_TIMESTAMP, &ts, SIZE(ts), null)==SQL_SUCCESS)
  1080. {
  1081. value.year =ts.year ;
  1082. value.month =ts.month ;
  1083. value.day =ts.day ;
  1084. value.hour =ts.hour ;
  1085. value.minute=ts.minute;
  1086. value.second=ts.second;
  1087. return true;
  1088. }
  1089. }break;
  1090. #endif
  1091. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  1092. {
  1093. C Row::Col &col=_rows[_rows_pos].cols[i];
  1094. switch( col.type)
  1095. {
  1096. case SDT_STR : value.fromText(col.s); return true;
  1097. case SDT_BINARY:
  1098. {
  1099. value.zero();
  1100. if(col.b.elms()>=1)value.second=col.b[0];
  1101. if(col.b.elms()>=2)value.minute=col.b[1];
  1102. if(col.b.elms()>=3)value.hour =col.b[2];
  1103. if(col.b.elms()>=4)value.day =col.b[3];
  1104. if(col.b.elms()>=5)value.month =col.b[4];
  1105. if(col.b.elms()>=6){Int ofs=5; FREP(Min(col.b.elms()-ofs, SIZEI(value.year)))value.year|=(col.b[ofs+i]<<(i*8));}
  1106. }return true;
  1107. }
  1108. }break;
  1109. }
  1110. value.zero(); return false;
  1111. }
  1112. Bool SQL::getCol(Int i, DateTimeMs &value)
  1113. {
  1114. switch(_type)
  1115. {
  1116. #if SUPPORT_ODBC
  1117. case MSSQL:
  1118. case MYSQL:
  1119. case PGSQL:
  1120. {
  1121. TIMESTAMP_STRUCT ts; if(SQLGetData(_statement, i+1, SQL_C_TIMESTAMP, &ts, SIZE(ts), null)==SQL_SUCCESS)
  1122. {
  1123. value.year =ts.year ;
  1124. value.month =ts.month ;
  1125. value.day =ts.day ;
  1126. value.hour =ts.hour ;
  1127. value.minute =ts.minute;
  1128. value. second=ts.second;
  1129. value.millisecond=ts.fraction/1000000; // 1ms is 1,000,000 units according to - https://docs.microsoft.com/en-us/sql/odbc/reference/appendixes/c-data-types
  1130. return true;
  1131. }
  1132. }break;
  1133. #endif
  1134. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  1135. {
  1136. C Row::Col &col=_rows[_rows_pos].cols[i];
  1137. switch( col.type)
  1138. { // TODO: 'millisecond' is ignored here
  1139. case SDT_STR : value.millisecond=0; value.fromText(col.s); return true;
  1140. case SDT_BINARY:
  1141. {
  1142. value.zero();
  1143. if(col.b.elms()>=1)value.second=col.b[0];
  1144. if(col.b.elms()>=2)value.minute=col.b[1];
  1145. if(col.b.elms()>=3)value.hour =col.b[2];
  1146. if(col.b.elms()>=4)value.day =col.b[3];
  1147. if(col.b.elms()>=5)value.month =col.b[4];
  1148. if(col.b.elms()>=6){Int ofs=5; FREP(Min(col.b.elms()-ofs, SIZEI(value.year)))value.year|=(col.b[ofs+i]<<(i*8));}
  1149. }return true;
  1150. }
  1151. }break;
  1152. }
  1153. value.zero(); return false;
  1154. }
  1155. Bool SQL::getCol(Int i, Ptr value, Int &size)
  1156. {
  1157. if(value)switch(_type)
  1158. {
  1159. #if SUPPORT_ODBC
  1160. case MSSQL:
  1161. case MYSQL:
  1162. case PGSQL:
  1163. {
  1164. SQLLEN len=0; if(SQLGetData(_statement, i+1, SQL_C_BINARY, value, size, &len)==SQL_SUCCESS)
  1165. {
  1166. size=len;
  1167. return true;
  1168. }
  1169. }break;
  1170. #endif
  1171. case SQLITE: if(InRange(i, _cols) && InRange(_rows_pos, _rows))
  1172. {
  1173. C Row::Col &col=_rows[_rows_pos].cols[i];
  1174. switch( col.type)
  1175. {
  1176. case SDT_LONG : MIN(size, SIZEI(col.i) ); CopyFast(value, &col.i , size); return true;
  1177. case SDT_DBL : MIN(size, SIZEI(col.d) ); CopyFast(value, &col.d , size); return true;
  1178. case SDT_STR : MIN(size, (1+col.s.length())*SIZEI(Char)); CopyFast(value, col.s (), size); return true;
  1179. case SDT_BINARY: MIN(size, col.b.elms () ); CopyFast(value, col.b.data(), size); return true;
  1180. }
  1181. }break;
  1182. }
  1183. size=0; return false;
  1184. }
  1185. /******************************************************************************/
  1186. Str SQL::value(C SQLValues::Value &value)C
  1187. {
  1188. switch(value.type)
  1189. {
  1190. default: return value.value; // SVT_RAW
  1191. case SVT_STR: return string(value.value);
  1192. case SVT_BIN: bin: switch(_type)
  1193. {
  1194. case MSSQL : return S+"0x"+value.value; // 0x 0x01 0x0102
  1195. case MYSQL : return value.value.is() ? S+"0x"+value.value : "''"; // '' 0x01 0x0102
  1196. case PGSQL : return S+"E'\\\\x"+value.value+'\''; // E'\\x' E'\\x01' E'\\x0102'
  1197. case SQLITE: return S+"x'"+value.value+'\''; // x'' x'01' x'0102'
  1198. }break;
  1199. case SVT_UID: switch(_type)
  1200. {
  1201. default : goto bin;
  1202. case PGSQL:
  1203. {
  1204. Str temp; temp.reserve(32+4+2);
  1205. temp='\''; // order of characters was specified to match the output in 'getCol(Int i, UID &value)'
  1206. for(Int i= 8-2; i>= 0; i-=2){temp+=value.value[i]; temp+=value.value[i+1];} temp+='-';
  1207. for(Int i=12-2; i>= 8; i-=2){temp+=value.value[i]; temp+=value.value[i+1];} temp+='-';
  1208. for(Int i=16-2; i>=12; i-=2){temp+=value.value[i]; temp+=value.value[i+1];} temp+='-';
  1209. for(Int i=16 ; i< 20; i+=2){temp+=value.value[i]; temp+=value.value[i+1];} temp+='-';
  1210. for(Int i=20 ; i< 32; i+=2){temp+=value.value[i]; temp+=value.value[i+1];} temp+='\'';
  1211. return temp;
  1212. }
  1213. }break;
  1214. }
  1215. return S;
  1216. }
  1217. Str SQL::token(C Str &token)C
  1218. {
  1219. switch(_type)
  1220. {
  1221. case MSSQL: return S+'['+Replace(token, "]", "]]")+']';
  1222. case MYSQL :
  1223. case SQLITE: return S+'`'+Replace(token, "`", "``")+'`';
  1224. case PGSQL: return S+'"'+Replace(token, "\"", "\"\"")+'"';
  1225. default: return token;
  1226. }
  1227. }
  1228. Bool SQL::colDesc(C SQLColumn &col, Str &desc, Str *messages)
  1229. {
  1230. desc=token(col.name)+' ';
  1231. switch(_type)
  1232. {
  1233. default: if(messages)*messages="SQL not connected"; return false;
  1234. case MSSQL:
  1235. {
  1236. switch(col.type)
  1237. {
  1238. case SDT_BOOL : desc+="BIT " ; break;
  1239. case SDT_BYTE : desc+="TINYINT " ; break;
  1240. case SDT_SHORT : desc+="SMALLINT " ; break;
  1241. case SDT_INT : desc+="INT " ; break;
  1242. case SDT_LONG : desc+="BIGINT " ; break;
  1243. case SDT_FLT : desc+="REAL " ; break;
  1244. case SDT_DBL : desc+="FLOAT " ; break;
  1245. case SDT_UID : desc+="UNIQUEIDENTIFIER "; break;
  1246. case SDT_DATE_TIME: desc+="DATETIME " ; break;
  1247. case SDT_STR : desc+=((col. str_len <=0) ? "NVARCHAR(MAX) " : S+"NVARCHAR("+col. str_len +") "); break;
  1248. case SDT_STR8 : desc+=((col. str_len <=0) ? "VARCHAR(MAX) " : S+ "VARCHAR("+col. str_len +") "); break;
  1249. case SDT_BINARY : desc+=((col.binary_size<=0) ? "VARBINARY(MAX) " : S+ "BINARY("+col.binary_size+") "); break;
  1250. default : if(messages)*messages=S+"Can't create table with column \""+col.name+"\" of UNKNOWN type"; return false;
  1251. }
  1252. switch(col.mode)
  1253. {
  1254. case SQLColumn::UNIQUE : desc+="UNIQUE "; break;
  1255. case SQLColumn::PRIMARY : desc+="PRIMARY KEY "; break;
  1256. case SQLColumn::PRIMARY_AUTO: desc+="PRIMARY KEY IDENTITY(0,1) "; break;
  1257. }
  1258. }break;
  1259. case MYSQL:
  1260. {
  1261. switch(col.type)
  1262. {
  1263. case SDT_BOOL : desc+="BIT " ; break;
  1264. case SDT_BYTE : desc+="TINYINT " ; break;
  1265. case SDT_SHORT : desc+="SMALLINT " ; break;
  1266. case SDT_INT : desc+="INT " ; break;
  1267. case SDT_LONG : desc+="BIGINT " ; break;
  1268. case SDT_FLT : desc+="FLOAT " ; break;
  1269. case SDT_DBL : desc+="DOUBLE " ; break;
  1270. case SDT_UID : desc+="BINARY(16) "; break;
  1271. case SDT_DATE_TIME: desc+="DATETIME " ; break;
  1272. case SDT_STR : desc+=((col. str_len <=0) ? "LONGTEXT CHARACTER SET utf8 " : S+"VARCHAR("+col. str_len +") CHARACTER SET utf8 "); break;
  1273. case SDT_STR8 : desc+=((col. str_len <=0) ? "LONGTEXT " : S+"VARCHAR("+col. str_len +") " ); break;
  1274. case SDT_BINARY : desc+=((col.binary_size<=0) ? "LONGBLOB " : S+ "BINARY("+col.binary_size+") " ); break;
  1275. default : if(messages)*messages=S+"Can't create table with column \""+col.name+"\" of UNKNOWN type"; return false;
  1276. }
  1277. if(col.mode==SQLColumn::PRIMARY_AUTO)desc+="AUTO_INCREMENT ";
  1278. }break;
  1279. case PGSQL:
  1280. {
  1281. if(col.mode==SQLColumn::PRIMARY_AUTO)switch(col.type)
  1282. {
  1283. case SDT_BYTE : desc+=S+"smallserial PRIMARY KEY "; break; // PostgreSQL doesn't have a 'byte' type
  1284. case SDT_SHORT: desc+=S+"smallserial PRIMARY KEY "; break;
  1285. case SDT_INT : desc+=S+ "serial PRIMARY KEY "; break;
  1286. case SDT_LONG : desc+=S+ "bigserial PRIMARY KEY "; break;
  1287. default : if(messages)*messages=S+"Can't create table with column \""+col.name+"\" of invalid type for PRIMARY_AUTO"; return false;
  1288. }else
  1289. switch(col.type)
  1290. {
  1291. case SDT_BOOL : desc+="boolean " ; break;
  1292. case SDT_BYTE : desc+="smallint " ; break; // PostgreSQL doesn't have a 'byte' type
  1293. case SDT_SHORT : desc+="smallint " ; break;
  1294. case SDT_INT : desc+="integer " ; break;
  1295. case SDT_LONG : desc+="bigint " ; break;
  1296. case SDT_FLT : desc+="real " ; break;
  1297. case SDT_DBL : desc+="double precision "; break;
  1298. case SDT_UID : desc+="uuid " ; break;
  1299. case SDT_DATE_TIME: desc+="timestamp " ; break;
  1300. case SDT_STR : desc+=((col.str_len<=0) ? "text " : S+"varchar("+col.str_len+") "); break;
  1301. case SDT_STR8 : desc+=((col.str_len<=0) ? "text " : S+"varchar("+col.str_len+") "); break;
  1302. case SDT_BINARY : desc+="bytea "; break;
  1303. default : if(messages)*messages=S+"Can't create table with column \""+col.name+"\" of UNKNOWN type"; return false;
  1304. }
  1305. switch(col.mode)
  1306. {
  1307. case SQLColumn::PRIMARY: desc+=S+"PRIMARY KEY "; break;
  1308. case SQLColumn::UNIQUE : desc+=S+"UNIQUE "; break;
  1309. }
  1310. }break;
  1311. case SQLITE:
  1312. {
  1313. if(col.mode==SQLColumn::PRIMARY_AUTO)desc+="INTEGER PRIMARY KEY ";else // PRIMARY_AUTO must use INTEGER
  1314. switch(col.type)
  1315. {
  1316. case SDT_BOOL : desc+="BIT " ; break;
  1317. case SDT_BYTE : desc+="TINYINT " ; break;
  1318. case SDT_SHORT : desc+="SMALLINT " ; break;
  1319. case SDT_INT : desc+="INT " ; break;
  1320. case SDT_LONG : desc+="BIGINT " ; break;
  1321. case SDT_FLT : desc+="FLOAT " ; break;
  1322. case SDT_DBL : desc+="DOUBLE " ; break;
  1323. case SDT_UID : desc+="BINARY(16) "; break;
  1324. case SDT_DATE_TIME: desc+="DATETIME " ; break;
  1325. case SDT_STR : desc+=((col. str_len <=0) ? "TEXT " : S+"NVARCHAR("+col. str_len +") "); break;
  1326. case SDT_STR8 : desc+=((col. str_len <=0) ? "TEXT " : S+ "VARCHAR("+col. str_len +") "); break;
  1327. case SDT_BINARY : desc+=((col.binary_size<=0) ? "BLOB " : S+ "BINARY("+col.binary_size+") "); break;
  1328. default : if(messages)*messages=S+"Can't create table with column \""+col.name+"\" of UNKNOWN type"; return false;
  1329. }
  1330. switch(col.mode)
  1331. {
  1332. case SQLColumn::UNIQUE : desc+="UNIQUE "; break;
  1333. case SQLColumn::PRIMARY: desc+="PRIMARY KEY "; break;
  1334. }
  1335. }break;
  1336. }
  1337. desc+=(col.allow_nulls ? "NULL " : "NOT NULL ");
  1338. if(col.default_val.is())
  1339. {
  1340. if(col.type==SDT_STR || col.type==SDT_STR8)
  1341. {
  1342. desc+="DEFAULT "; desc+=string(col.default_val);
  1343. }else
  1344. {
  1345. desc+="DEFAULT "; desc+=col.default_val;
  1346. }
  1347. }
  1348. if(_type==MYSQL)
  1349. {
  1350. if(col.mode==SQLColumn::PRIMARY || col.mode==SQLColumn::PRIMARY_AUTO)desc+=S+", PRIMARY KEY ("+token(col.name )+")";
  1351. if(col.mode!=SQLColumn::DEFAULT )desc+=S+", UNIQUE INDEX "+token(col.name+"_UNIQUE")+" ("+token(col.name)+" ASC)";
  1352. }
  1353. return true;
  1354. }
  1355. #if SUPPORT_ODBC
  1356. void SQL::getStatus(Str *messages, Int *error, Bool statement)
  1357. {
  1358. if(messages || error)
  1359. {
  1360. if(messages)messages->clear();
  1361. if(error )*error=0;
  1362. #if DEBUG
  1363. SQLWCHAR text[1024], state[1024]; SQLINTEGER sql_error;
  1364. if(SQLGetDiagRec(statement ? SQL_HANDLE_STMT : SQL_HANDLE_DBC, statement ? T._statement : T._conn, 1, state, &sql_error, text, Elms(text), null)==SQL_SUCCESS){if(messages)*messages=(Char*)text; if(error)*error=sql_error;}
  1365. #else
  1366. SQLWCHAR text[1024]; SQLINTEGER sql_error;
  1367. if(SQLGetDiagRec(statement ? SQL_HANDLE_STMT : SQL_HANDLE_DBC, statement ? T._statement : T._conn, 1, null, &sql_error, text, Elms(text), null)==SQL_SUCCESS){if(messages)*messages=(Char*)text; if(error)*error=sql_error;}
  1368. #endif
  1369. }
  1370. }
  1371. #endif
  1372. /******************************************************************************/
  1373. // SQLite VFS
  1374. /******************************************************************************/
  1375. #if SUPPORT_SQLITE
  1376. struct SQLiteFile : sqlite3_file // 'sqlite3_file' base must be first
  1377. {
  1378. File file;
  1379. SQLiteFile() {Zero(SCAST(sqlite3_file, T));}
  1380. };
  1381. static int SQLiteClose(sqlite3_file *pFile)
  1382. {
  1383. SQLiteFile &f=*(SQLiteFile*)pFile;
  1384. int rc=(f.file.flush() ? SQLITE_OK : SQLITE_IOERR_WRITE);
  1385. f.file.del(); DTOR(f); return rc;
  1386. }
  1387. static int SQLiteRead(sqlite3_file *pFile, void *zBuf, int iAmt, sqlite_int64 iOfst)
  1388. {
  1389. SQLiteFile &f=*(SQLiteFile*)pFile;
  1390. if(!f.file.pos(iOfst))return SQLITE_IOERR_SEEK; // TODO: this could trigger data loss if flush failed, however how to handle this error?
  1391. Int read=f.file.getReturnSize(zBuf, iAmt);
  1392. if( read>=iAmt )return SQLITE_OK; // read all
  1393. if( read<=0 && !f.file.end())return SQLITE_IOERR_READ; // read nothing but still have some left (not at the end)
  1394. // partial read
  1395. Zero((Byte*)zBuf+read, iAmt-read); // zero remaining data (this is required by SQLite)
  1396. return SQLITE_IOERR_SHORT_READ;
  1397. }
  1398. static int SQLiteWrite(sqlite3_file *pFile, const void *zBuf, int iAmt, sqlite_int64 iOfst)
  1399. {
  1400. SQLiteFile &f=*(SQLiteFile*)pFile;
  1401. if(!f.file.pos(iOfst))return SQLITE_IOERR_SEEK; // TODO: this could trigger data loss if flush failed, however how to handle this error?
  1402. return f.file.put(zBuf, iAmt) ? SQLITE_OK : SQLITE_IOERR_WRITE;
  1403. }
  1404. static int SQLiteTruncate(sqlite3_file *pFile, sqlite_int64 size)
  1405. {
  1406. SQLiteFile &f=*(SQLiteFile*)pFile;
  1407. return f.file.size(size) ? SQLITE_OK : SQLITE_IOERR_TRUNCATE;
  1408. }
  1409. static int SQLiteSync(sqlite3_file *pFile, int flags)
  1410. {
  1411. SQLiteFile &f=*(SQLiteFile*)pFile;
  1412. if(!f.file.flush())return SQLITE_IOERR_WRITE;
  1413. return f.file.sync() ? SQLITE_OK : SQLITE_IOERR_FSYNC;
  1414. }
  1415. static int SQLiteFileSize(sqlite3_file *pFile, sqlite_int64 *pSize)
  1416. {
  1417. SQLiteFile &f=*(SQLiteFile*)pFile;
  1418. *pSize=f.file.size();
  1419. return SQLITE_OK;
  1420. }
  1421. static int SQLiteLock (sqlite3_file *pFile, int eLock) {return SQLITE_OK;}
  1422. static int SQLiteUnlock (sqlite3_file *pFile, int eLock) {return SQLITE_OK;}
  1423. static int SQLiteCheckReservedLock (sqlite3_file *pFile, int *pResOut) {*pResOut=0; return SQLITE_OK;}
  1424. static int SQLiteFileControl (sqlite3_file *pFile, int op, void *pArg) {return SQLITE_NOTFOUND;}
  1425. static int SQLiteSectorSize (sqlite3_file *pFile) {return 4096;} // use some default based on SQLite SQLITE_DEFAULT_SECTOR_SIZE
  1426. static int SQLiteDeviceCharacteristics(sqlite3_file *pFile) {return (WINDOWS ? SQLITE_IOCAP_UNDELETABLE_WHEN_OPEN : 0);}
  1427. static const sqlite3_io_methods SQLiteIO=
  1428. {
  1429. 1, /* iVersion */
  1430. SQLiteClose, /* xClose */
  1431. SQLiteRead, /* xRead */
  1432. SQLiteWrite, /* xWrite */
  1433. SQLiteTruncate, /* xTruncate */
  1434. SQLiteSync, /* xSync */
  1435. SQLiteFileSize, /* xFileSize */
  1436. SQLiteLock, /* xLock */
  1437. SQLiteUnlock, /* xUnlock */
  1438. SQLiteCheckReservedLock, /* xCheckReservedLock */
  1439. SQLiteFileControl, /* xFileControl */
  1440. SQLiteSectorSize, /* xSectorSize */
  1441. SQLiteDeviceCharacteristics, /* xDeviceCharacteristics */
  1442. };
  1443. static int SQLiteOpen(sqlite3_vfs *pVfs, const char *zName, sqlite3_file *pFile, int flags, int *pOutFlags)
  1444. {
  1445. if(pOutFlags)*pOutFlags=flags;
  1446. SQLiteFile &f=*(SQLiteFile*)pFile;
  1447. CTOR(f);
  1448. f.pMethods=&SQLiteIO;
  1449. Str name=FromUTF8(zName);
  1450. if((flags&SQLITE_OPEN_READONLY) ? f.file. readTry(name, SQLiteCipher)
  1451. : f.file.appendTry(name, SQLiteCipher))return SQLITE_OK;
  1452. return SQLITE_CANTOPEN; // 'SQLiteClose' will be called upon 'SQLITE_CANTOPEN'
  1453. }
  1454. static int SQLiteDelete(sqlite3_vfs *pVfs, const char *zPath, int dirSync)
  1455. {
  1456. Str name=FromUTF8(zPath);
  1457. return (!FExistSystem(name) || FDelFile(name)) ? SQLITE_OK : SQLITE_IOERR_DELETE;
  1458. }
  1459. static int SQLiteAccess(sqlite3_vfs *pVfs, const char *zPath, int flags, int *pResOut)
  1460. {
  1461. FileInfo fi; Bool exists=fi.get(FromUTF8(zPath));
  1462. switch(flags)
  1463. {
  1464. case SQLITE_ACCESS_EXISTS : *pResOut=(exists && fi.size>0 ); break; // SQLite requires check for size>0
  1465. case SQLITE_ACCESS_READ : *pResOut= exists ; break;
  1466. case SQLITE_ACCESS_READWRITE: *pResOut=(exists && !(fi.attrib&FATTRIB_READ_ONLY)); break;
  1467. default : return SQLITE_ERROR;
  1468. }
  1469. return SQLITE_OK;
  1470. }
  1471. static int SQLiteFullPathname(sqlite3_vfs *pVfs, const char *zPath, int nPathOut, char *zPathOut)
  1472. {
  1473. Set(zPathOut, zPath, nPathOut); // just copy
  1474. return SQLITE_OK;
  1475. }
  1476. static void *SQLiteDlOpen (sqlite3_vfs *pVfs, const char *zPath) {return null;}
  1477. static void SQLiteDlError(sqlite3_vfs *pVfs, int nByte, char *zErrMsg) {Set(zErrMsg, "Loadable extensions are not supported", nByte);}
  1478. static void (*SQLiteDlSym (sqlite3_vfs *pVfs, void *pH, const char *z))(void) {return null;}
  1479. static void SQLiteDlClose(sqlite3_vfs *pVfs, void *pHandle) {}
  1480. /******************************************************************************/
  1481. static struct SQLiteInitializer // thanks to this class, we don't need to call a function such as 'InitSQL' (now removed), if we would call it from other CPP file, then we would always link with this CPP file, and forced inclusion of SQLite libraries which would increase the executable file size even if the app would not use it
  1482. {
  1483. static sqlite3_vfs SQLiteVFS;
  1484. SQLiteInitializer()
  1485. {
  1486. sqlite3_initialize();
  1487. if(sqlite3_vfs *default_vfs=sqlite3_vfs_find(null))
  1488. {
  1489. SQLiteVFS.xRandomness =default_vfs->xRandomness;
  1490. SQLiteVFS.xSleep =default_vfs->xSleep;
  1491. SQLiteVFS.xCurrentTime =default_vfs->xCurrentTime;
  1492. SQLiteVFS.xGetLastError =null;
  1493. SQLiteVFS.xCurrentTimeInt64=default_vfs->xCurrentTimeInt64;
  1494. sqlite3_vfs_register(&SQLiteVFS, false);
  1495. }
  1496. }
  1497. ~SQLiteInitializer()
  1498. {
  1499. sqlite3_vfs_unregister(&SQLiteVFS);
  1500. //sqlite3_shutdown(); don't call this in case there are still open SQL connections, as the SQLite header says: "All open [database connections] must be closed and all other SQLite resources must be deallocated prior to invoking 'sqlite3_shutdown'
  1501. }
  1502. }SQLiteInit; // this object is needed to force calling constructor at the start of the Application
  1503. sqlite3_vfs SQLiteInitializer::SQLiteVFS=
  1504. {
  1505. 2, /* iVersion */
  1506. SIZE(SQLiteFile), /* szOsFile */
  1507. MAX_UTF_PATH, /* mxPathname */
  1508. null, /* pNext */
  1509. SQLITE_VFS_NAME, /* zName */
  1510. null, /* pAppData */
  1511. SQLiteOpen, /* xOpen */
  1512. SQLiteDelete, /* xDelete */
  1513. SQLiteAccess, /* xAccess */
  1514. SQLiteFullPathname, /* xFullPathname */
  1515. SQLiteDlOpen, /* xDlOpen */
  1516. SQLiteDlError, /* xDlError */
  1517. SQLiteDlSym, /* xDlSym */
  1518. SQLiteDlClose, /* xDlClose */
  1519. };
  1520. #endif
  1521. /******************************************************************************/
  1522. }
  1523. /******************************************************************************/