sqlite3conn.pp 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744
  1. {
  2. This file is part of the Free Pascal Classes Library (FCL).
  3. Copyright (c) 2006 by the Free Pascal development team
  4. SQLite3 connection for SQLDB
  5. See the File COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. {
  12. Based on an implementation by Martin Schreiber, part of MSEIDE.
  13. Reworked all code so it conforms to FCL coding standards.
  14. }
  15. unit sqlite3conn;
  16. {$mode objfpc}
  17. {$h+}
  18. interface
  19. uses
  20. classes, db, bufdataset, sqldb, sqlite3dyn, types;
  21. const
  22. sqliteerrormax = 99;
  23. type
  24. PDateTime = ^TDateTime;
  25. TSqliteOption = (sloTransactions,sloDesignTransactions);
  26. TSqliteOptions = set of TSqliteOption;
  27. TStringArray = Array of string;
  28. PStringArray = ^TStringArray;
  29. TArrayStringArray = Array of TStringArray;
  30. PArrayStringArray = ^TArrayStringArray;
  31. TSQLite3Connection = class(TSQLConnection)
  32. private
  33. fhandle: psqlite3;
  34. foptions: TSQLiteOptions;
  35. function blobscached: boolean;
  36. procedure setoptions(const avalue: tsqliteoptions);
  37. protected
  38. function stringquery(const asql: string): TStringArray;
  39. function stringsquery(const asql: string): TArrayStringArray;
  40. procedure checkerror(const aerror: integer);
  41. procedure DoInternalConnect; override;
  42. procedure DoInternalDisconnect; override;
  43. function GetHandle : pointer; override;
  44. Function AllocateCursorHandle : TSQLCursor; override;
  45. //aowner used as blob cache
  46. Procedure DeAllocateCursorHandle(var cursor : TSQLCursor); override;
  47. Function AllocateTransactionHandle : TSQLHandle; override;
  48. procedure PrepareStatement(cursor: TSQLCursor; ATransaction : TSQLTransaction;
  49. buf: string; AParams : TParams); override;
  50. procedure Execute(cursor: TSQLCursor;atransaction:tSQLtransaction; AParams : TParams); override;
  51. function Fetch(cursor : TSQLCursor) : boolean; override;
  52. procedure AddFieldDefs(cursor: TSQLCursor; FieldDefs : TfieldDefs); override;
  53. procedure UnPrepareStatement(cursor : TSQLCursor); override;
  54. procedure FreeFldBuffers(cursor : TSQLCursor); override;
  55. function LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; override;
  56. //if bufsize < 0 -> buffer was to small, should be -bufsize
  57. function GetTransactionHandle(trans : TSQLHandle): pointer; override;
  58. function Commit(trans : TSQLHandle) : boolean; override;
  59. function RollBack(trans : TSQLHandle) : boolean; override;
  60. function StartdbTransaction(trans : TSQLHandle; aParams : string) : boolean; override;
  61. procedure CommitRetaining(trans : TSQLHandle); override;
  62. procedure RollBackRetaining(trans : TSQLHandle); override;
  63. procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction); override;
  64. // New methods
  65. procedure execsql(const asql: string);
  66. procedure UpdateIndexDefs(var IndexDefs : TIndexDefs; const TableName : string); // Differs from SQLDB.
  67. function getprimarykeyfield(const atablename: string; const acursor: tsqlcursor): string;
  68. public
  69. function GetInsertID: int64;
  70. published
  71. property Options: TSqliteOptions read FOptions write SetOptions;
  72. end;
  73. implementation
  74. uses
  75. dbconst, sysutils, typinfo, dateutils;
  76. type
  77. TStorageType = (stNone,stInteger,stFloat,stText,stBlob,stNull);
  78. TSQLite3Cursor = class(tsqlcursor)
  79. private
  80. fhandle : psqlite3;
  81. fstatement: psqlite3_stmt;
  82. ftail: pchar;
  83. fstate: integer;
  84. fparambinding: array of Integer;
  85. procedure checkerror(const aerror: integer);
  86. procedure bindparams(AParams : TParams);
  87. Procedure Prepare(Buf : String; APArams : TParams);
  88. Procedure UnPrepare;
  89. Procedure Execute;
  90. Function Fetch : Boolean;
  91. end;
  92. procedure freebindstring(astring: pointer); cdecl;
  93. begin
  94. StrDispose(AString);
  95. end;
  96. procedure TSQLite3Cursor.checkerror(const aerror: integer);
  97. Var
  98. S : String;
  99. begin
  100. if (aerror<>sqlite_ok) then
  101. begin
  102. S:=strpas(sqlite3_errmsg(fhandle));
  103. DatabaseError(S);
  104. end;
  105. end;
  106. Procedure TSQLite3Cursor.bindparams(AParams : TParams);
  107. Function PCharStr(Const S : String) : PChar;
  108. begin
  109. Result:=StrAlloc(Length(S)+1);
  110. If (Result<>Nil) then
  111. StrPCopy(Result,S);
  112. end;
  113. Var
  114. I : Integer;
  115. P : TParam;
  116. pc : pchar;
  117. str1: string;
  118. cu1: currency;
  119. do1: double;
  120. parms : array of Integer;
  121. begin
  122. for I:=1 to high(fparambinding)+1 do
  123. begin
  124. P:=aparams[fparambinding[I-1]];
  125. if P.isnull then
  126. checkerror(sqlite3_bind_null(fstatement,I))
  127. else
  128. case P.datatype of
  129. ftinteger,
  130. ftboolean,
  131. ftsmallint: checkerror(sqlite3_bind_int(fstatement,I,p.asinteger));
  132. ftword: checkerror(sqlite3_bind_int(fstatement,I,P.asword));
  133. ftlargeint: checkerror(sqlite3_bind_int64(fstatement,I,P.aslargeint));
  134. ftbcd: begin
  135. cu1:= P.ascurrency;
  136. checkerror(sqlite3_bind_int64(fstatement,I,pint64(@cu1)^));
  137. end;
  138. ftfloat,
  139. ftcurrency,
  140. ftdatetime,
  141. ftdate,
  142. fttime: begin
  143. do1:= P.asfloat;
  144. checkerror(sqlite3_bind_double(fstatement,I,do1));
  145. end;
  146. ftstring: begin
  147. str1:= p.asstring;
  148. checkerror(sqlite3_bind_text(fstatement,I,pcharstr(str1), length(str1),@freebindstring));
  149. end;
  150. ftblob: begin
  151. str1:= P.asstring;
  152. checkerror(sqlite3_bind_blob(fstatement,I,pcharstr(str1), length(str1),@freebindstring));
  153. end;
  154. else
  155. databaseerror('Parameter type '+getenumname(typeinfo(tfieldtype),ord(P.datatype))+' not supported.');
  156. end; { Case }
  157. end;
  158. end;
  159. Procedure TSQLite3Cursor.Prepare(Buf : String; APArams : TParams);
  160. begin
  161. if assigned(aparams) and (aparams.count > 0) then
  162. buf := aparams.parsesql(buf,false,false,false,psinterbase,fparambinding);
  163. checkerror(sqlite3_prepare(fhandle,pchar(buf),length(buf),@fstatement,@ftail));
  164. end;
  165. Procedure TSQLite3Cursor.UnPrepare;
  166. begin
  167. sqlite3_finalize(fstatement); // No check.
  168. end;
  169. Procedure TSQLite3Cursor.Execute;
  170. var
  171. wo1: word;
  172. begin
  173. {$ifdef i386}
  174. wo1:= get8087cw;
  175. set8087cw(wo1 or $1f); //mask exceptions, Sqlite3 has overflow
  176. Try // Why do people always forget this ??
  177. {$endif}
  178. fstate:= sqlite3_step(fstatement);
  179. {$ifdef i386}
  180. finally
  181. set8087cw(wo1); //restore
  182. end;
  183. {$endif}
  184. if (fstate<=sqliteerrormax) then
  185. checkerror(sqlite3_reset(fstatement));
  186. if (fstate=sqlite_row) then
  187. fstate:= sqliteerrormax; //first row
  188. end;
  189. Function TSQLite3Cursor.Fetch : Boolean;
  190. begin
  191. if (fstate=sqliteerrormax) then
  192. fstate:=sqlite_row //first row;
  193. else if (fstate=sqlite_row) then
  194. begin
  195. fstate:=sqlite3_step(fstatement);
  196. if (fstate<=sqliteerrormax) then
  197. checkerror(sqlite3_reset(fstatement)); //right error returned??
  198. end;
  199. result:=(fstate=sqlite_row);
  200. end;
  201. { TSQLite3Connection }
  202. procedure TSQLite3Connection.LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField; cursor: TSQLCursor; ATransaction : TSQLTransaction);
  203. var
  204. blobid: integer;
  205. int1,int2: integer;
  206. str1: string;
  207. bo1: boolean;
  208. begin
  209. {$WARNING TSQLite3Connection.LoadBlobIntoBuffer not implemented !}
  210. { if (mode = bmwrite) and (field.dataset is tmsesqlquery) then begin
  211. result:= tmsebufdataset(field.dataset).createblobbuffer(field);
  212. end
  213. else begin
  214. result:= nil;
  215. if mode = bmread then begin
  216. if field.getData(@blobId) then begin
  217. result:= acursor.getcachedblob(blobid);
  218. end;
  219. end;
  220. end;
  221. }
  222. end;
  223. function TSQLite3Connection.AllocateTransactionHandle: TSQLHandle;
  224. begin
  225. result:= tsqlhandle.create;
  226. end;
  227. function TSQLite3Connection.AllocateCursorHandle: TSQLCursor;
  228. Var
  229. Res : TSQLite3Cursor;
  230. begin
  231. Res:= TSQLite3Cursor.create;
  232. Res.fhandle:=self.fhandle;
  233. Result:=Res;
  234. end;
  235. procedure TSQLite3Connection.DeAllocateCursorHandle(var cursor: TSQLCursor);
  236. begin
  237. freeandnil(cursor);
  238. end;
  239. procedure TSQLite3Connection.PrepareStatement(cursor: TSQLCursor;
  240. ATransaction: TSQLTransaction; buf: string; AParams: TParams);
  241. begin
  242. TSQLite3Cursor(cursor).Prepare(Buf,AParams);
  243. end;
  244. procedure TSQLite3Connection.UnPrepareStatement(cursor: TSQLCursor);
  245. begin
  246. TSQLite3Cursor(cursor).UnPrepare;
  247. end;
  248. Type
  249. TFieldMap = Record
  250. N : String;
  251. T : TFieldType;
  252. end;
  253. Const
  254. FieldMapCount = 18;
  255. FieldMap : Array [1..FieldMapCount] of TFieldMap = (
  256. (n:'INT'; t: ftInteger),
  257. (n:'LARGEINT'; t:ftlargeInt),
  258. (n:'WORD'; t: ftWord),
  259. (n:'SMALLINT'; t: ftSmallint),
  260. (n:'BOOLEAN'; t: ftBoolean),
  261. (n:'REAL'; t: ftFloat),
  262. (n:'FLOAT'; t: ftFloat),
  263. (n:'DOUBLE'; t: ftFloat),
  264. (n:'DATETIME'; t: ftDateTime), // MUST be before date
  265. (n:'DATE'; t: ftDate),
  266. (n:'TIME'; t: ftTime),
  267. (n:'CURRENCY'; t: ftCurrency),
  268. (n:'VARCHAR'; t: ftString),
  269. (n:'CHAR'; t: ftString),
  270. (n:'NUMERIC'; t: ftBCD),
  271. (n:'DECIMAL'; t: ftBCD),
  272. (n:'TEXT'; t: ftmemo),
  273. (n:'BLOB'; t: ftBlob)
  274. { Template:
  275. (n:''; t: ft)
  276. }
  277. );
  278. procedure TSQLite3Connection.AddFieldDefs(cursor: TSQLCursor;
  279. FieldDefs: TfieldDefs);
  280. var
  281. i : integer;
  282. FN,FD : string;
  283. ft1 : tfieldtype;
  284. size1 : word;
  285. ar1 : TStringArray;
  286. fi : integer;
  287. st : psqlite3_stmt;
  288. begin
  289. st:=TSQLite3Cursor(cursor).fstatement;
  290. for i:= 0 to sqlite3_column_count(st) - 1 do
  291. begin
  292. FN:=sqlite3_column_name(st,i);
  293. FD:=uppercase(sqlite3_column_decltype(st,i));
  294. ft1:= ftUnknown;
  295. size1:= 0;
  296. for fi := 1 to FieldMapCount do if pos(FieldMap[fi].N,FD)=1 then
  297. begin
  298. ft1:=FieldMap[fi].t;
  299. break;
  300. end;
  301. // handle some specials.
  302. size1:=0;
  303. case ft1 of
  304. ftString: begin
  305. fi:=pos('(',FD);
  306. if (fi>0) then
  307. begin
  308. System.Delete(FD,1,fi);
  309. fi:=pos(')',FD);
  310. size1:=StrToIntDef(trim(copy(FD,1,fi-1)),255);
  311. if size1 > dsMaxStringSize then size1 := dsMaxStringSize;
  312. end
  313. else size1 := 255;
  314. end;
  315. ftBCD: begin
  316. fi:=pos(',',FD);
  317. if (fi>0) then
  318. begin
  319. System.Delete(FD,1,fi);
  320. fi:=pos(')',FD);
  321. size1:=StrToIntDef(trim(copy(FD,1,fi-1)),255);
  322. end
  323. else size1 := 4;
  324. end;
  325. ftUnknown : DatabaseError('Unknown record type: '+FN);
  326. end; // Case
  327. tfielddef.create(fielddefs,FN,ft1,size1,false,i+1);
  328. end;
  329. end;
  330. procedure TSQLite3Connection.Execute(cursor: TSQLCursor; atransaction: tsqltransaction; AParams: TParams);
  331. var
  332. SC : TSQLite3Cursor;
  333. begin
  334. SC:=TSQLite3Cursor(cursor);
  335. If (AParams<>Nil) and (AParams.count > 0) then
  336. SC.BindParams(AParams);
  337. SC.Execute;
  338. end;
  339. Function NextWord(Var S : ShortString; Sep : Char) : String;
  340. Var
  341. P : Integer;
  342. begin
  343. P:=Pos(Sep,S);
  344. If (P=0) then
  345. P:=Length(S)+1;
  346. Result:=Copy(S,1,P-1);
  347. Delete(S,1,P);
  348. end;
  349. Function ParseSQLiteDate(S : ShortString) : TDateTime;
  350. Var
  351. Year, Month, Day : Integer;
  352. begin
  353. Result:=0;
  354. If TryStrToInt(NextWord(S,'-'),Year) then
  355. if TryStrToInt(NextWord(S,'-'),Month) then
  356. if TryStrToInt(NextWord(S,'-'),Day) then
  357. Result:=EncodeDate(Year,Month,Day);
  358. end;
  359. Function ParseSQLiteTime(S : ShortString) : TDateTime;
  360. Var
  361. Hour, Min, Sec : Integer;
  362. begin
  363. Result:=0;
  364. If TryStrToInt(NextWord(S,':'),Hour) then
  365. if TryStrToInt(NextWord(S,':'),Min) then
  366. if TryStrToInt(NextWord(S,':'),Sec) then
  367. Result:=EncodeTime(Hour,Min,Sec,0);
  368. end;
  369. Function ParseSQLiteDateTime(S : String) : TDateTime;
  370. var
  371. P : Integer;
  372. DS,TS : ShortString;
  373. begin
  374. DS:='';
  375. TS:='';
  376. P:=Pos(' ',S);
  377. If (P<>0) then
  378. begin
  379. DS:=Copy(S,1,P-1);
  380. TS:=S;
  381. Delete(TS,1,P);
  382. end
  383. else
  384. begin
  385. If (Pos('-',S)<>0) then
  386. DS:=S
  387. else if (Pos(':',S)<>0) then
  388. TS:=S;
  389. end;
  390. Result:=ParseSQLiteDate(DS)+ParseSQLiteTime(TS);
  391. end;
  392. function TSQLite3Connection.LoadField(cursor : TSQLCursor;FieldDef : TfieldDef;buffer : pointer; out CreateBlob : boolean) : boolean;
  393. var
  394. st1: TStorageType;
  395. fnum: integer;
  396. i: integer;
  397. i64: int64;
  398. int1,int2: integer;
  399. str1: string;
  400. ar1,ar2: TStringArray;
  401. st : psqlite3_stmt;
  402. begin
  403. st:=TSQLite3Cursor(cursor).fstatement;
  404. fnum:= FieldDef.fieldno - 1;
  405. st1:= TStorageType(sqlite3_column_type(st,fnum));
  406. CreateBlob:=false;
  407. result:= st1 <> stnull;
  408. if Not result then
  409. Exit;
  410. case FieldDef.datatype of
  411. ftInteger : pinteger(buffer)^ := sqlite3_column_int(st,fnum);
  412. ftSmallInt : psmallint(buffer)^ := sqlite3_column_int(st,fnum);
  413. ftWord : pword(buffer)^ := sqlite3_column_int(st,fnum);
  414. ftBoolean : pwordbool(buffer)^ := sqlite3_column_int(st,fnum)<>0;
  415. ftLargeInt,
  416. ftBCD : PInt64(buffer)^:= sqlite3_column_int64(st,fnum);
  417. ftFloat,
  418. ftCurrency : pdouble(buffer)^:= sqlite3_column_double(st,fnum);
  419. ftDateTime,
  420. ftDate,
  421. ftTime: if st1 = sttext then
  422. begin
  423. result:= false;
  424. setlength(str1,sqlite3_column_bytes(st,fnum));
  425. move(sqlite3_column_text(st,fnum)^,str1[1],length(str1));
  426. PDateTime(Buffer)^:=ParseSqliteDateTime(str1)
  427. end
  428. else
  429. Pdatetime(buffer)^:= sqlite3_column_double(st,fnum);
  430. ftString: begin
  431. int1:= sqlite3_column_bytes(st,fnum);
  432. if int1>FieldDef.Size then
  433. int1:=FieldDef.Size;
  434. if int1 > 0 then
  435. move(sqlite3_column_text(st,fnum)^,buffer^,int1);
  436. end;
  437. ftMemo,
  438. ftBlob: begin
  439. CreateBlob:=True;
  440. int2:= sqlite3_column_bytes(st,fnum);
  441. {$WARNING Blob data not handled correctly }
  442. // int1:= addblobdata(sqlite3_column_text(st,fnum),int2);
  443. move(int1,buffer^,sizeof(int1)); //save id
  444. end;
  445. else { Case }
  446. result:= false; // unknown
  447. end; { Case }
  448. end;
  449. function TSQLite3Connection.Fetch(cursor: TSQLCursor): boolean;
  450. begin
  451. Result:=TSQLite3Cursor(cursor).Fetch;
  452. end;
  453. procedure TSQLite3Connection.FreeFldBuffers(cursor: TSQLCursor);
  454. begin
  455. //dummy
  456. end;
  457. function TSQLite3Connection.GetTransactionHandle(trans: TSQLHandle): pointer;
  458. begin
  459. result:= nil;
  460. end;
  461. function TSQLite3Connection.Commit(trans: TSQLHandle): boolean;
  462. begin
  463. execsql('COMMIT');
  464. result:= true;
  465. end;
  466. function TSQLite3Connection.RollBack(trans: TSQLHandle): boolean;
  467. begin
  468. execsql('ROLLBACK');
  469. result:= true;
  470. end;
  471. function TSQLite3Connection.StartdbTransaction(trans: TSQLHandle;
  472. aParams: string): boolean;
  473. begin
  474. execsql('BEGIN');
  475. result:= true;
  476. end;
  477. procedure TSQLite3Connection.CommitRetaining(trans: TSQLHandle);
  478. begin
  479. commit(trans);
  480. execsql('BEGIN');
  481. end;
  482. procedure TSQLite3Connection.RollBackRetaining(trans: TSQLHandle);
  483. begin
  484. rollback(trans);
  485. execsql('BEGIN');
  486. end;
  487. procedure TSQLite3Connection.DoInternalConnect;
  488. var
  489. str1: string;
  490. begin
  491. if Length(databasename)=0 then
  492. DatabaseError(SErrNoDatabaseName,self);
  493. initialisesqlite;
  494. str1:= databasename;
  495. checkerror(sqlite3_open(pchar(str1),@fhandle));
  496. end;
  497. procedure TSQLite3Connection.DoInternalDisconnect;
  498. begin
  499. if fhandle <> nil then
  500. begin
  501. checkerror(sqlite3_close(fhandle));
  502. fhandle:= nil;
  503. releasesqlite;
  504. end;
  505. end;
  506. function TSQLite3Connection.GetHandle: pointer;
  507. begin
  508. result:= fhandle;
  509. end;
  510. procedure TSQLite3Connection.checkerror(const aerror: integer);
  511. Var
  512. S : String;
  513. begin
  514. if (aerror<>sqlite_ok) then
  515. begin
  516. S:=strpas(sqlite3_errmsg(fhandle));
  517. DatabaseError(S,Self);
  518. end;
  519. end;
  520. procedure TSQLite3Connection.execsql(const asql: string);
  521. var
  522. err : pchar;
  523. str1 : string;
  524. res : integer;
  525. begin
  526. err:= nil;
  527. Res := sqlite3_exec(fhandle,pchar(asql),nil,nil,@err);
  528. if err <> nil then
  529. begin
  530. str1:= strpas(err);
  531. sqlite3_free(err);
  532. end;
  533. if (res<>sqlite_ok) then
  534. databaseerror(str1);
  535. end;
  536. function TSQLite3Connection.blobscached: boolean;
  537. begin
  538. result:= true;
  539. end;
  540. function execcallback(adata: pointer; ncols: longint; //adata = PStringArray
  541. avalues: PPchar; anames: PPchar):longint; cdecl;
  542. var
  543. P : PStringArray;
  544. i : integer;
  545. begin
  546. P:=PStringArray(adata);
  547. SetLength(P^,ncols);
  548. for i:= 0 to ncols - 1 do
  549. P^[i]:= strPas(avalues[i]);
  550. result:= 0;
  551. end;
  552. function TSQLite3Connection.stringquery(const asql: string): TStringArray;
  553. begin
  554. SetLength(result,0);
  555. CheckError(sqlite3_exec(fhandle,pchar(asql),@execcallback,@result,nil));
  556. end;
  557. function execscallback(adata: pointer; ncols: longint; //adata = PArrayStringArray
  558. avalues: PPchar; anames: PPchar):longint; cdecl;
  559. var
  560. I,N : integer;
  561. PP : PArrayStringArray;
  562. p : PStringArray;
  563. begin
  564. PP:=PArrayStringArray(adata);
  565. N:=high(PP^); // Length-1;
  566. setlength(PP^,N+2); // increase with 1;
  567. p:= @(PP^[N]); // newly added array, fill with data.
  568. setlength(p^,ncols);
  569. for i:= 0 to ncols - 1 do
  570. p^[i]:= strPas(avalues[i]);
  571. result:= 0;
  572. end;
  573. function TSQLite3Connection.stringsquery(const asql: string): TArrayStringArray;
  574. begin
  575. SetLength(result,0);
  576. checkerror(sqlite3_exec(fhandle,pchar(asql),@execscallback,@result,nil));
  577. end;
  578. function TSQLite3Connection.getprimarykeyfield(const atablename: string;
  579. const acursor: tsqlcursor): string;
  580. var
  581. int1,int2: integer;
  582. ar1: TArrayStringArray;
  583. str1: string;
  584. begin
  585. result:= '';
  586. if atablename <> '' then
  587. begin
  588. ar1:= stringsquery('PRAGMA table_info('+atablename+');');
  589. for int1:= 0 to high(ar1) do
  590. begin
  591. if (high(ar1[int1]) >= 5) and (ar1[int1][5] <> '0') then
  592. begin
  593. result:= ar1[int1][1];
  594. break;
  595. end;
  596. end;
  597. end;
  598. end;
  599. procedure TSQLite3Connection.UpdateIndexDefs(var IndexDefs: TIndexDefs;
  600. const TableName: string);
  601. var
  602. str1: string;
  603. begin
  604. str1:= getprimarykeyfield(tablename,nil);
  605. if str1 <> '' then
  606. begin
  607. indexdefs.add('$PRIMARY_KEY$',str1,[ixPrimary,ixUnique]);
  608. end;
  609. end;
  610. {
  611. procedure TSQLite3Connection.UpdateIndexDefs(var IndexDefs: TIndexDefs;
  612. const TableName: string);
  613. var
  614. int1,int2: integer;
  615. ar1: TArrayStringArray;
  616. str1: string;
  617. begin
  618. ar1:= stringsquery('PRAGMA table_info('+tablename+');');
  619. for int1:= 0 to high(ar1) do begin
  620. if (high(ar1[int1]) >= 5) and (ar1[int1][5] <> '0') then begin
  621. indexdefs.add('$PRIMARY_KEY$',ar1[int1][1],[ixPrimary,ixUnique]);
  622. break;
  623. end;
  624. end;
  625. end;
  626. }
  627. function TSQLite3Connection.getinsertid: int64;
  628. begin
  629. result:= sqlite3_last_insert_rowid(fhandle);
  630. end;
  631. procedure TSQLite3Connection.setoptions(const avalue: tsqliteoptions);
  632. begin
  633. if avalue <> foptions then
  634. begin
  635. checkdisconnected;
  636. foptions:= avalue;
  637. end;
  638. end;
  639. end.