sqliteds.pas 36 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. unit sqliteds;
  2. {
  3. This is SqliteDS/TSqliteDataset, a TDataset descendant class for use with fpc compiler
  4. Copyright (C) 2004 Luiz Américo Pereira Câmara
  5. Email: [email protected]
  6. This program is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU Lesser General Public License as published by
  8. the Free Software Foundation; either version 2.1 of the License, or
  9. (at your option) any later version.
  10. This program is distributed in the hope that it will be useful,
  11. but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. GNU Lesser General Public License for more details.
  14. You should have received a copy of the GNU Lesser General Public License
  15. along with this program; if not, write to the Free Software
  16. Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
  17. }
  18. {$Mode ObjFpc}
  19. {$H+}
  20. { $Define USE_SQLITEDS_INTERNALS}
  21. { $Define DEBUG}
  22. { $Define DEBUGACTIVEBUFFER}
  23. interface
  24. uses Classes, SysUtils, Db
  25. {$ifdef DEBUG}
  26. ,Crt
  27. {$endif}
  28. ;
  29. type
  30. PDataRecord = ^DataRecord;
  31. PPDataRecord = ^PDataRecord;
  32. DataRecord = record
  33. Row: PPchar;
  34. BookmarkData: Pointer;
  35. BookmarkFlag: TBookmarkFlag;
  36. Next: PDataRecord;
  37. Previous: PDataRecord;
  38. end;
  39. TDSStream = class(TStream)
  40. private
  41. FActiveItem:PDataRecord;
  42. FFieldRow:PChar;
  43. FFieldIndex:Integer;
  44. FRowSize: Integer;
  45. FPosition: Longint;
  46. public
  47. constructor Create(const ActiveItem: PDataRecord; FieldIndex:Integer);
  48. function Write(const Buffer; Count: Longint): Longint; override;
  49. function Read(var Buffer; Count: Longint): Longint; override;
  50. function Seek(Offset: Longint; Origin: Word): Longint; override;
  51. end;
  52. { TSqliteDataset }
  53. TSqliteDataset = class(TDataSet)
  54. private
  55. FFileName: String;
  56. FSql: String;
  57. FTableName: String;
  58. FPrimaryKey: String;
  59. FPrimaryKeyNo: Integer;
  60. FAutoIncFieldNo: Integer;
  61. FNextAutoInc:Integer;
  62. {$ifdef DEBUGACTIVEBUFFER}
  63. FFCurrentItem: PDataRecord;
  64. {$else}
  65. FCurrentItem: PDataRecord;
  66. {$endif}
  67. FBeginItem: PDataRecord;
  68. FEndItem: PDataRecord;
  69. FCacheItem: PDataRecord;
  70. FBufferSize: Integer;
  71. FRowBufferSize: Integer;
  72. FRowCount: Integer;
  73. FRecordCount: Integer;
  74. FExpectedAppends: Integer;
  75. FExpectedDeletes: Integer;
  76. FExpectedUpdates: Integer;
  77. FSqliteReturnId: Integer;
  78. FDataAllocated: Boolean;
  79. FSaveOnClose: Boolean;
  80. FSaveOnRefetch: Boolean;
  81. FComplexSql: Boolean;
  82. FSqliteHandle: Pointer;
  83. FUpdatedItems: TList;
  84. FAddedItems: TList;
  85. FDeletedItems: TList;
  86. FOrphanItems: TList;
  87. protected
  88. procedure DisposeLinkedList;
  89. procedure BuildLinkedList; virtual;
  90. //TDataSet overrides
  91. function AllocRecordBuffer: PChar; override;
  92. function CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream; override;
  93. procedure FreeRecordBuffer(var Buffer: PChar); override;
  94. procedure GetBookmarkData(Buffer: PChar; Data: Pointer); override;
  95. function GetBookmarkFlag(Buffer: PChar): TBookmarkFlag; override;
  96. function GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult; override;
  97. function GetRecordCount: Integer; override;
  98. function GetRecNo: Integer; override;
  99. function GetRecordSize: Word; override;
  100. procedure InternalAddRecord(Buffer: Pointer; DoAppend: Boolean); override;
  101. procedure InternalClose; override;
  102. procedure InternalDelete; override;
  103. procedure InternalFirst; override;
  104. procedure InternalGotoBookmark(ABookmark: Pointer); override;
  105. procedure InternalHandleException; override;
  106. procedure InternalInitFieldDefs; override;
  107. procedure InternalInitRecord(Buffer: PChar); override;
  108. procedure InternalLast; override;
  109. procedure InternalOpen; override;
  110. procedure InternalPost; override;
  111. procedure InternalSetToRecord(Buffer: PChar); override;
  112. function IsCursorOpen: Boolean; override;
  113. procedure SetBookmarkData(Buffer: PChar; Data: Pointer); override;
  114. procedure SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag); override;
  115. procedure SetExpectedAppends(AValue:Integer);
  116. procedure SetExpectedUpdates(AValue:Integer);
  117. procedure SetExpectedDeletes(AValue:Integer);
  118. procedure SetFieldData(Field: TField; Buffer: Pointer); override;
  119. procedure SetRecNo(Value: Integer); override;
  120. public
  121. constructor Create(AOwner: TComponent); override;
  122. destructor Destroy; override;
  123. function GetFieldData(Field: TField; Buffer: Pointer): Boolean; override;
  124. // Additional procedures
  125. function ApplyUpdates: Boolean; virtual;
  126. function CreateTable: Boolean; virtual;
  127. function ExecSQL:Integer;
  128. function ExecSQL(ASql:String):Integer;
  129. function TableExists: Boolean;
  130. procedure RefetchData;
  131. function SqliteReturnString: String;
  132. function UpdatesPending: Boolean;
  133. {$ifdef DEBUGACTIVEBUFFER}
  134. procedure SetCurrentItem(Value:PDataRecord);
  135. property FCurrentItem: PDataRecord read FFCurrentItem write SetCurrentItem;
  136. {$endif}
  137. {$ifdef USE_SQLITEDS_INTERNALS}
  138. property BeginItem: PDataRecord read FBeginItem;
  139. property EndItem: PDataRecord read FEndItem;
  140. property UpdatedItems: TList read FUpdatedItems;
  141. property AddedItems: TList read FAddedItems;
  142. property DeletedItems: TList read FDeletedItems;
  143. {$endif}
  144. property ComplexSql: Boolean read FComplexSql write FComplexSql;
  145. property ExpectedAppends: Integer read FExpectedAppends write SetExpectedAppends;
  146. property ExpectedUpdates: Integer read FExpectedUpdates write SetExpectedUpdates;
  147. property ExpectedDeletes: Integer read FExpectedDeletes write SetExpectedDeletes;
  148. property SqliteReturnId: Integer read FSqliteReturnId;
  149. published
  150. property FileName: String read FFileName write FFileName;
  151. property PrimaryKey: String read FPrimaryKey write FPrimaryKey;
  152. property SaveOnClose: Boolean read FSaveOnClose write FSaveOnClose;
  153. property SaveOnRefetch: Boolean read FSaveOnRefetch write FSaveOnRefetch;
  154. property SQL: String read FSql write FSql;
  155. property TableName: String read FTableName write FTableName;
  156. //property Active;
  157. property FieldDefs;
  158. //Events
  159. property BeforeOpen;
  160. property AfterOpen;
  161. property BeforeClose;
  162. property AfterClose;
  163. property BeforeInsert;
  164. property AfterInsert;
  165. property BeforeEdit;
  166. property AfterEdit;
  167. property BeforePost;
  168. property AfterPost;
  169. property BeforeCancel;
  170. property AfterCancel;
  171. property BeforeDelete;
  172. property AfterDelete;
  173. property BeforeScroll;
  174. property AfterScroll;
  175. property OnDeleteError;
  176. property OnEditError;
  177. end;
  178. procedure Register;
  179. implementation
  180. uses SQLite,strutils;
  181. function GetAutoIncValue(NextValue: Pointer; Columns: Integer; ColumnValues: PPChar; ColumnNames: PPChar): integer; cdecl;
  182. var
  183. CodeError, TempInt: Integer;
  184. begin
  185. TempInt:=-1;
  186. if ColumnValues[0] <> nil then
  187. begin
  188. Val(StrPas(ColumnValues[0]),TempInt,CodeError);
  189. if CodeError <> 0 then
  190. DatabaseError('SqliteDs - Error trying to get last autoinc value');
  191. end;
  192. Integer(NextValue^):=Succ(TempInt);
  193. Result:=1;
  194. end;
  195. function GetFieldDefs(TheDataset: Pointer; Columns: Integer; ColumnValues: PPChar; ColumnNames: PPChar): integer; cdecl;
  196. var
  197. FieldSize:Word;
  198. Counter:Integer;
  199. AType:TFieldType;
  200. ColumnStr:String;
  201. begin
  202. // Sqlite is typeless (allows any type in any field)
  203. // regardless of what is in Create Table, but returns
  204. // exactly what is in Create Table statement
  205. // here is a trick to get the datatype.
  206. // If the field contains another type, there will be problems
  207. For Counter:= 0 to Columns - 1 do
  208. begin
  209. ColumnStr:= UpCase(StrPas(ColumnNames[Counter + Columns]));
  210. If (ColumnStr = 'INTEGER') then
  211. begin
  212. AType:= ftInteger;
  213. FieldSize:=SizeOf(Integer);
  214. end else if (ColumnStr = 'BOOLEAN') then
  215. begin
  216. AType:= ftBoolean;
  217. FieldSize:=SizeOf(Boolean);
  218. end else if (ColumnStr = 'FLOAT') then
  219. begin
  220. AType:= ftFloat;
  221. FieldSize:=SizeOf(Double);
  222. end else if (ColumnStr = 'WORD') then
  223. begin
  224. AType:= ftWord;
  225. FieldSize:=SizeOf(Word);
  226. end else if (ColumnStr = 'DATETIME') then
  227. begin
  228. AType:= ftDateTime;
  229. FieldSize:=SizeOf(TDateTime);
  230. end else if (ColumnStr = 'DATE') then
  231. begin
  232. AType:= ftDate;
  233. FieldSize:=SizeOf(TDateTime);
  234. end else if (ColumnStr = 'TIME') then
  235. begin
  236. AType:= ftTime;
  237. FieldSize:=SizeOf(TDateTime);
  238. end else if (ColumnStr = 'MEMO') then
  239. begin
  240. AType:= ftMemo;
  241. FieldSize:=10;//??
  242. end else if (ColumnStr = 'AUTOINC') then
  243. begin
  244. AType:= ftAutoInc;
  245. FieldSize:=SizeOf(Integer);
  246. if TSqliteDataset(TheDataset).FAutoIncFieldNo = -1 then
  247. TSqliteDataset(TheDataset).FAutoIncFieldNo:= Counter;
  248. end else
  249. begin
  250. AType:= ftString;
  251. FieldSize:=10; //??
  252. end;
  253. TDataset(TheDataset).FieldDefs.Add(StrPas(ColumnNames[Counter]), AType, FieldSize, False);
  254. end;
  255. result:=-1;
  256. end;
  257. // TDSStream
  258. constructor TDSStream.Create(const ActiveItem: PDataRecord; FieldIndex:Integer);
  259. begin
  260. inherited Create;
  261. FPosition:=0;
  262. FActiveItem:=ActiveItem;
  263. FFieldIndex:=FieldIndex;
  264. FFieldRow:=ActiveItem^.Row[FieldIndex];
  265. if FFieldRow <> nil then
  266. FRowSize:=StrLen(FFieldRow)
  267. else
  268. FRowSize:=0;
  269. end;
  270. function TDSStream.Seek(Offset: Longint; Origin: Word): Longint;
  271. begin
  272. Case Origin of
  273. soFromBeginning : FPosition:=Offset;
  274. soFromEnd : FPosition:=FRowSize+Offset;
  275. soFromCurrent : FPosition:=FPosition+Offset;
  276. end;
  277. Result:=FPosition;
  278. end;
  279. function TDSStream.Write(const Buffer; Count: Longint): Longint;
  280. var
  281. NewRow:PChar;
  282. begin
  283. Result:=Count;
  284. if Count = 0 then
  285. Exit;
  286. //Todo: see how TDbMemo read/write to field and choose best if order
  287. if FPosition = 0 then
  288. begin
  289. NewRow:=StrAlloc(Count+1);
  290. (NewRow+Count)^:=#0;
  291. Move(Buffer,NewRow^,Count);
  292. end
  293. else
  294. begin
  295. NewRow:=StrAlloc(FRowSize+Count+1);
  296. (NewRow+Count+FRowSize)^:=#0;
  297. Move(FFieldRow^,NewRow^,FRowSize);
  298. Move(Buffer,(NewRow+FRowSize)^,Count);
  299. end;
  300. FActiveItem^.Row[FFieldIndex]:=NewRow;
  301. StrDispose(FFieldRow);
  302. FFieldRow:=NewRow;
  303. FRowSize:=StrLen(NewRow);
  304. Inc(FPosition,Count);
  305. {$ifdef DEBUG}
  306. WriteLn('Writing a BlobStream');
  307. WriteLn('Stream.Size: ',StrLen(NewRow));
  308. WriteLn('Stream Value: ',NewRow);
  309. WriteLn('FPosition:',FPosition);
  310. {$endif}
  311. end;
  312. function TDSStream.Read(var Buffer; Count: Longint): Longint;
  313. var
  314. BytesToMove:Integer;
  315. begin
  316. if (FRowSize - FPosition) >= Count then
  317. BytesToMove:=Count
  318. else
  319. BytesToMove:=FRowSize - FPosition;
  320. Move((FFieldRow+FPosition)^,Buffer,BytesToMove);
  321. Inc(FPosition,BytesToMove);
  322. Result:=BytesToMove;
  323. {$ifdef DEBUG}
  324. WriteLn('Reading a BlobStream');
  325. WriteLn('Bytes requested: ',Count);
  326. WriteLn('Bytes Moved: ',BytesToMove);
  327. WriteLn('Stream.Size: ',FRowSize);
  328. WriteLn('Stream Value: ',FFieldRow);
  329. {$endif}
  330. end;
  331. // TSqliteDataset override methods
  332. function TSqliteDataset.AllocRecordBuffer: PChar;
  333. var
  334. APointer:Pointer;
  335. begin
  336. APointer := AllocMem(FBufferSize);
  337. PDataRecord(APointer^):=FBeginItem;
  338. Result:=APointer;
  339. end;
  340. procedure TSqliteDataset.BuildLinkedList;
  341. var
  342. TempItem:PDataRecord;
  343. vm:Pointer;
  344. ColumnNames,ColumnValues:PPChar;
  345. Counter:Integer;
  346. begin
  347. //Get AutoInc Field initial value
  348. if FAutoIncFieldNo <> -1 then
  349. sqlite_exec(FSqliteHandle,PChar('Select Max('+Fields[FAutoIncFieldNo].FieldName+') from ' + FTableName),
  350. @GetAutoIncValue,@FNextAutoInc,nil);
  351. FSqliteReturnId:=sqlite_compile(FSqliteHandle,Pchar(FSql),nil,@vm,nil);
  352. if FSqliteReturnId <> SQLITE_OK then
  353. case FSqliteReturnId of
  354. SQLITE_ERROR:
  355. DatabaseError('Invalid SQL',Self);
  356. else
  357. DatabaseError('Error returned by sqlite while retrieving data: '+SqliteReturnString,Self);
  358. end;
  359. FDataAllocated:=True;
  360. New(FBeginItem);
  361. FBeginItem^.Next:=nil;
  362. FBeginItem^.Previous:=nil;
  363. FBeginItem^.BookMarkFlag:=bfBOF;
  364. TempItem:=FBeginItem;
  365. FRecordCount:=0;
  366. FSqliteReturnId:=sqlite_step(vm,@FRowCount,@ColumnValues,@ColumnNames);
  367. while FSqliteReturnId = SQLITE_ROW do
  368. begin
  369. Inc(FRecordCount);
  370. New(TempItem^.Next);
  371. TempItem^.Next^.Previous:=TempItem;
  372. TempItem:=TempItem^.Next;
  373. GetMem(TempItem^.Row,FRowBufferSize);
  374. For Counter := 0 to FRowCount - 1 do
  375. TempItem^.Row[Counter]:=StrNew(ColumnValues[Counter]);
  376. FSqliteReturnId:=sqlite_step(vm,@FRowCount,@ColumnValues,@ColumnNames);
  377. end;
  378. sqlite_finalize(vm, nil);
  379. // Init EndItem
  380. if FRecordCount <> 0 then
  381. begin
  382. New(TempItem^.Next);
  383. TempItem^.Next^.Previous:=TempItem;
  384. FEndItem:=TempItem^.Next;
  385. end
  386. else
  387. begin
  388. New(FEndItem);
  389. FEndItem^.Previous:=FBeginItem;
  390. FBeginItem^.Next:=FEndItem;
  391. end;
  392. FEndItem^.Next:=nil;
  393. // Alloc item used in append/insert
  394. New(FCacheItem);
  395. GetMem(FCacheItem^.Row,FRowBufferSize);
  396. For Counter := 0 to FRowCount - 1 do
  397. FCacheItem^.Row[Counter]:=nil;
  398. // Fill FBeginItem.Row with nil -> necessary for avoid exceptions in empty datasets
  399. GetMem(FBeginItem^.Row,FRowBufferSize);
  400. For Counter := 0 to FRowCount - 1 do
  401. FBeginItem^.Row[Counter]:=nil;
  402. end;
  403. constructor TSqliteDataset.Create(AOwner: TComponent);
  404. begin
  405. BookmarkSize := SizeOf(Pointer);
  406. FBufferSize := SizeOf(PPDataRecord);
  407. FUpdatedItems:= TList.Create;
  408. FUpdatedItems.Capacity:=20;
  409. FAddedItems:= TList.Create;
  410. FAddedItems.Capacity:=20;
  411. FOrphanItems:= TList.Create;
  412. FOrphanItems.Capacity:=20;
  413. FDeletedItems:= TList.Create;
  414. FDeletedItems.Capacity:=20;
  415. inherited Create(AOwner);
  416. end;
  417. function TSqliteDataset.CreateBlobStream(Field: TField; Mode: TBlobStreamMode): TStream;
  418. begin
  419. Result:= TDSStream.Create(PPDataRecord(ActiveBuffer)^,Field.FieldNo - 1);
  420. end;
  421. destructor TSqliteDataset.Destroy;
  422. begin
  423. inherited Destroy;
  424. FUpdatedItems.Destroy;
  425. FAddedItems.Destroy;
  426. FDeletedItems.Destroy;
  427. FOrphanItems.Destroy;
  428. end;
  429. procedure TSqliteDataset.DisposeLinkedList;
  430. var
  431. TempItem:PDataRecord;
  432. Counter,I:Integer;
  433. begin
  434. //Todo: insert debug info
  435. FDataAllocated:=False;
  436. TempItem:=FBeginItem^.Next;
  437. if TempItem <> nil then
  438. while TempItem^.Next <> nil do
  439. begin
  440. for Counter:= 0 to FRowCount - 1 do
  441. StrDispose(TempItem^.Row[Counter]);
  442. FreeMem(TempItem^.Row,FRowBufferSize);
  443. TempItem:=TempItem^.Next;
  444. Dispose(TempItem^.Previous);
  445. end;
  446. //Dispose FBeginItem
  447. FreeMem(FBeginItem^.Row,FRowBufferSize);
  448. Dispose(FBeginItem);
  449. //Dispose cache item
  450. for Counter:= 0 to FRowCount - 1 do
  451. StrDispose(FCacheItem^.Row[Counter]);
  452. FreeMem(FCacheItem^.Row,FRowBufferSize);
  453. Dispose(FCacheItem);
  454. // Free last item (FEndItem)
  455. Dispose(TempItem);
  456. //Dispose OrphanItems
  457. for Counter:= 0 to FOrphanItems.Count - 1 do
  458. begin
  459. TempItem:=PDataRecord(FOrphanItems[Counter]);
  460. for I:= 0 to FRowCount - 1 do
  461. StrDispose(TempItem^.Row[I]);
  462. FreeMem(TempItem^.Row,FRowBufferSize);
  463. Dispose(TempItem);
  464. end;
  465. end;
  466. procedure TSqliteDataset.FreeRecordBuffer(var Buffer: PChar);
  467. begin
  468. FreeMem(Buffer);
  469. end;
  470. procedure TSqliteDataset.GetBookmarkData(Buffer: PChar; Data: Pointer);
  471. begin
  472. Pointer(Data^) := PPDataRecord(Buffer)^^.BookmarkData;
  473. end;
  474. function TSqliteDataset.GetBookmarkFlag(Buffer: PChar): TBookmarkFlag;
  475. begin
  476. Result := PPDataRecord(Buffer)^^.BookmarkFlag;
  477. end;
  478. function TSqliteDataset.GetFieldData(Field: TField; Buffer: Pointer): Boolean;
  479. var
  480. ValError:Word;
  481. FieldRow:PChar;
  482. begin
  483. FieldRow:=PPDataRecord(ActiveBuffer)^^.Row[Field.FieldNo - 1];
  484. Result := FieldRow <> nil;
  485. if Result and (Buffer <> nil) then //supports GetIsNull
  486. begin
  487. case Field.Datatype of
  488. ftString:
  489. begin
  490. Move(FieldRow^,PChar(Buffer)^,StrLen(FieldRow)+1);
  491. end;
  492. ftInteger,ftBoolean,ftWord,ftAutoInc:
  493. begin
  494. Val(StrPas(FieldRow),LongInt(Buffer^),ValError);
  495. Result:= ValError = 0;
  496. end;
  497. ftFloat,ftDateTime,ftTime,ftDate:
  498. begin
  499. Val(StrPas(FieldRow),Double(Buffer^),ValError);
  500. Result:= ValError = 0;
  501. end;
  502. end;
  503. end;
  504. end;
  505. function TSqliteDataset.GetRecord(Buffer: PChar; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
  506. begin
  507. Result := grOk;
  508. case GetMode of
  509. gmPrior:
  510. if (FCurrentItem^.Previous = FBeginItem) or (FCurrentItem = FBeginItem) then
  511. begin
  512. Result := grBOF;
  513. FCurrentItem := FBeginItem;
  514. end
  515. else
  516. FCurrentItem:=FCurrentItem^.Previous;
  517. gmCurrent:
  518. if (FCurrentItem = FBeginItem) or (FCurrentItem = FEndItem) then
  519. Result := grError;
  520. gmNext:
  521. if (FCurrentItem = FEndItem) or (FCurrentItem^.Next = FEndItem) then
  522. Result := grEOF
  523. else
  524. FCurrentItem:=FCurrentItem^.Next;
  525. end; //case
  526. if Result = grOk then
  527. begin
  528. PDataRecord(Pointer(Buffer)^):=FCurrentItem;
  529. with FCurrentItem^ do
  530. begin
  531. BookmarkData := FCurrentItem;
  532. BookmarkFlag := bfCurrent;
  533. end;
  534. end
  535. else if (Result = grError) and DoCheck then
  536. DatabaseError('SqliteDs - No records',Self);
  537. end;
  538. function TSqliteDataset.GetRecordCount: Integer;
  539. begin
  540. Result := FRecordCount;
  541. end;
  542. function TSqliteDataset.GetRecNo: Integer;
  543. var
  544. TempItem,TempActive:PDataRecord;
  545. begin
  546. Result:= -1;
  547. if FRecordCount = 0 then
  548. Exit;
  549. TempItem:=FBeginItem;
  550. TempActive:=PPDataRecord(ActiveBuffer)^;
  551. if TempActive = FCacheItem then // Record not posted yet
  552. Result:=FRecordCount
  553. else
  554. while TempActive <> TempItem do
  555. begin
  556. if TempItem^.Next <> nil then
  557. begin
  558. inc(Result);
  559. TempItem:=TempItem^.Next;
  560. end
  561. else
  562. begin
  563. Result:=-1;
  564. DatabaseError('Sqliteds.GetRecNo - ActiveItem Not Found',Self);
  565. break;
  566. end;
  567. end;
  568. end;
  569. function TSqliteDataset.GetRecordSize: Word;
  570. begin
  571. Result := FBufferSize; //??
  572. end;
  573. procedure TSqliteDataset.InternalAddRecord(Buffer: Pointer; DoAppend: Boolean);
  574. var
  575. NewItem: PDataRecord;
  576. Counter:Integer;
  577. begin
  578. //Todo: implement insert ??
  579. if PPDataRecord(Buffer)^ <> FCacheItem then
  580. DatabaseError('PPDataRecord(Buffer) <> FCacheItem - Problem',Self);
  581. New(NewItem);
  582. GetMem(NewItem^.Row,FRowBufferSize);
  583. for Counter := 0 to FRowCount - 1 do
  584. NewItem^.Row[Counter]:=StrNew(FCacheItem^.Row[Counter]);
  585. FEndItem^.Previous^.Next:=NewItem;
  586. NewItem^.Previous:=FEndItem^.Previous;
  587. NewItem^.Next:=FEndItem;
  588. FEndItem^.Previous:=NewItem;
  589. Inc(FRecordCount);
  590. if FAutoIncFieldNo <> - 1 then
  591. Inc(FNextAutoInc);
  592. FAddedItems.Add(NewItem);
  593. end;
  594. procedure TSqliteDataset.InternalClose;
  595. begin
  596. if FSaveOnClose then
  597. ApplyUpdates;
  598. //BindFields(False);
  599. if DefaultFields then
  600. DestroyFields;
  601. if FDataAllocated then
  602. DisposeLinkedList;
  603. if FSqliteHandle <> nil then
  604. begin
  605. sqlite_close(FSqliteHandle);
  606. FSqliteHandle := nil;
  607. end;
  608. FAddedItems.Clear;
  609. FUpdatedItems.Clear;
  610. FDeletedItems.Clear;
  611. FOrphanItems.Clear;
  612. FRecordCount:=0;
  613. end;
  614. procedure TSqliteDataset.InternalDelete;
  615. var
  616. TempItem:PDataRecord;
  617. ValError,TempInteger:Integer;
  618. begin
  619. If FRecordCount = 0 then
  620. Exit;
  621. Dec(FRecordCount);
  622. TempItem:=PPDataRecord(ActiveBuffer)^;
  623. // Remove from changed list
  624. FUpdatedItems.Remove(TempItem);
  625. if FAddedItems.Remove(TempItem) = -1 then
  626. FDeletedItems.Add(TempItem);
  627. FOrphanItems.Add(TempItem);
  628. TempItem^.Next^.Previous:=TempItem^.Previous;
  629. TempItem^.Previous^.Next:=TempItem^.Next;
  630. if FCurrentItem = TempItem then
  631. begin
  632. if FCurrentItem^.Previous <> FBeginItem then
  633. FCurrentItem:= FCurrentItem^.Previous
  634. else
  635. FCurrentItem:= FCurrentItem^.Next;
  636. end;
  637. // Dec FNextAutoInc (only if deleted item is the last record)
  638. if FAutoIncFieldNo <> -1 then
  639. begin
  640. Val(StrPas(TempItem^.Row[FAutoIncFieldNo]),TempInteger,ValError);
  641. if (ValError = 0) and (TempInteger = (FNextAutoInc - 1)) then
  642. Dec(FNextAutoInc);
  643. end;
  644. end;
  645. procedure TSqliteDataset.InternalFirst;
  646. begin
  647. FCurrentItem := FBeginItem;
  648. end;
  649. procedure TSqliteDataset.InternalGotoBookmark(ABookmark: Pointer);
  650. begin
  651. FCurrentItem := PDataRecord(ABookmark^);
  652. end;
  653. procedure TSqliteDataset.InternalHandleException;
  654. begin
  655. //??
  656. end;
  657. procedure TSqliteDataset.InternalInitFieldDefs;
  658. begin
  659. FieldDefs.Clear;
  660. sqlite_exec(FSqliteHandle,PChar('PRAGMA empty_result_callbacks = ON;PRAGMA show_datatypes = ON;'),nil,nil,nil);
  661. FSqliteReturnId:=sqlite_exec(FSqliteHandle,PChar(FSql),@GetFieldDefs,Self,nil);
  662. {
  663. if FSqliteReturnId <> SQLITE_ABORT then
  664. DatabaseError(SqliteReturnString,Self);
  665. }
  666. FRowBufferSize:=(SizeOf(PPChar)*FieldDefs.Count);
  667. end;
  668. procedure TSqliteDataset.InternalInitRecord(Buffer: PChar);
  669. var
  670. Counter:Integer;
  671. TempStr:String;
  672. begin
  673. for Counter:= 0 to FRowCount - 1 do
  674. begin
  675. StrDispose(FCacheItem^.Row[Counter]);
  676. FCacheItem^.Row[Counter]:=nil;
  677. end;
  678. if FAutoIncFieldNo <> - 1 then
  679. begin
  680. Str(FNextAutoInc,TempStr);
  681. FCacheItem^.Row[FAutoIncFieldNo]:=StrAlloc(Length(TempStr)+1);
  682. StrPCopy(FCacheItem^.Row[FAutoIncFieldNo],TempStr);
  683. end;
  684. PPDataRecord(Buffer)^:=FCacheItem;
  685. end;
  686. procedure TSqliteDataset.InternalLast;
  687. begin
  688. FCurrentItem := FEndItem;
  689. end;
  690. procedure TSqliteDataset.InternalOpen;
  691. begin
  692. FAutoIncFieldNo:=-1;
  693. if not FileExists(FFileName) then
  694. DatabaseError('TSqliteDataset - File '+FFileName+' not found');
  695. if (FTablename = '') and not (FComplexSql) then
  696. DatabaseError('TSqliteDataset - Tablename not set');
  697. FSqliteHandle:=sqlite_open(PChar(FFileName),0,nil);
  698. if FSql = '' then
  699. FSql := 'Select * from '+FTableName+';';
  700. InternalInitFieldDefs;
  701. if DefaultFields then
  702. CreateFields;
  703. BindFields(True);
  704. // Get PrimaryKeyNo if available
  705. if Fields.FindField(FPrimaryKey) <> nil then
  706. FPrimaryKeyNo:=Fields.FindField(FPrimaryKey).FieldNo - 1
  707. else
  708. FPrimaryKeyNo:=FAutoIncFieldNo; // -1 if there's no AutoIncField
  709. BuildLinkedList;
  710. FCurrentItem:=FBeginItem;
  711. end;
  712. procedure TSqliteDataset.InternalPost;
  713. begin
  714. if (State<>dsEdit) then
  715. InternalAddRecord(ActiveBuffer,True);
  716. end;
  717. procedure TSqliteDataset.InternalSetToRecord(Buffer: PChar);
  718. begin
  719. //Todo: see why only under linux InternalSetToRecord is called with FCacheItem as parameter
  720. if PPDataRecord(Buffer)^ <> FCacheItem then
  721. FCurrentItem:=PPDataRecord(Buffer)^;
  722. end;
  723. function TSqliteDataset.IsCursorOpen: Boolean;
  724. begin
  725. Result := FDataAllocated;
  726. end;
  727. procedure TSqliteDataset.SetBookmarkData(Buffer: PChar; Data: Pointer);
  728. begin
  729. PPDataRecord(Buffer)^^.BookmarkData := Pointer(Data^);
  730. end;
  731. procedure TSqliteDataset.SetBookmarkFlag(Buffer: PChar; Value: TBookmarkFlag);
  732. begin
  733. PPDataRecord(Buffer)^^.BookmarkFlag := Value;
  734. end;
  735. procedure TSqliteDataset.SetExpectedAppends(AValue:Integer);
  736. begin
  737. if Assigned(FAddedItems) then
  738. FAddedItems.Capacity:=AValue;
  739. end;
  740. procedure TSqliteDataset.SetExpectedUpdates(AValue:Integer);
  741. begin
  742. if Assigned(FUpdatedItems) then
  743. FUpdatedItems.Capacity:=AValue;
  744. end;
  745. procedure TSqliteDataset.SetExpectedDeletes(AValue:Integer);
  746. begin
  747. if Assigned(FDeletedItems) then
  748. FDeletedItems.Capacity:=AValue;
  749. end;
  750. procedure TSqliteDataset.SetFieldData(Field: TField; Buffer: Pointer);
  751. var
  752. TempStr:String;
  753. ActiveItem:PDataRecord;
  754. begin
  755. ActiveItem:=PPDataRecord(ActiveBuffer)^;
  756. if (ActiveItem <> FCacheItem) and (FUpdatedItems.IndexOf(ActiveItem) = -1) and (FAddedItems.IndexOf(ActiveItem) = -1) then
  757. FUpdatedItems.Add(ActiveItem);
  758. if Buffer = nil then
  759. ActiveItem^.Row[Pred(Field.FieldNo)]:=nil
  760. else
  761. begin
  762. StrDispose(ActiveItem^.Row[Pred(Field.FieldNo)]);
  763. case Field.Datatype of
  764. ftString:
  765. begin
  766. ActiveItem^.Row[Pred(Field.FieldNo)]:=StrNew(PChar(Buffer));
  767. end;
  768. ftInteger,ftBoolean,ftWord:
  769. begin
  770. Str(LongInt(Buffer^),TempStr);
  771. ActiveItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
  772. StrPCopy(ActiveItem^.Row[Pred(Field.FieldNo)],TempStr);
  773. end;
  774. ftFloat,ftDateTime,ftDate,ftTime:
  775. begin
  776. Str(Double(Buffer^),TempStr);
  777. ActiveItem^.Row[Pred(Field.FieldNo)]:=StrAlloc(Length(TempStr)+1);
  778. StrPCopy(ActiveItem^.Row[Pred(Field.FieldNo)],TempStr);
  779. end;
  780. end;// case
  781. end;//if
  782. end;
  783. procedure TSqliteDataset.SetRecNo(Value: Integer);
  784. var
  785. Counter:Integer;
  786. TempItem:PDataRecord;
  787. begin
  788. if (Value >= FRecordCount) or (Value < 0) then
  789. DatabaseError('SqliteDs - Record Number Out Of Range');
  790. TempItem:=FBeginItem;
  791. for Counter := 0 to Value do
  792. TempItem:=TempItem^.Next;
  793. PPDataRecord(ActiveBuffer)^:=TempItem;
  794. end;
  795. // Specific functions
  796. function TSqliteDataset.ExecSQL(ASql:String):Integer;
  797. var
  798. AHandle: Pointer;
  799. begin
  800. Result:=0;
  801. //Todo check if Filename exists
  802. if FSqliteHandle <> nil then
  803. AHandle:=FSqliteHandle
  804. else
  805. if FFileName <> '' then
  806. AHandle := sqlite_open(PChar(FFilename),0,nil)
  807. else
  808. DatabaseError ('ExecSql - FileName not set');
  809. FSqliteReturnId:= sqlite_exec(AHandle,PChar(ASql),nil,nil,nil);
  810. Result:=sqlite_changes(AHandle);
  811. if AHandle <> FSqliteHandle then
  812. sqlite_close(AHandle);
  813. end;
  814. function TSqliteDataset.ExecSQL:Integer;
  815. begin
  816. Result:=ExecSQL(FSql);
  817. end;
  818. function TSqliteDataset.ApplyUpdates:Boolean;
  819. var
  820. CounterFields,CounterItems,StatementsCounter:Integer;
  821. SqlTemp,KeyName,ASqlLine,TemplateStr:String;
  822. begin
  823. Result:=False;
  824. if (FPrimaryKeyNo <> -1) and not FComplexSql then
  825. begin
  826. StatementsCounter:=0;
  827. KeyName:=Fields[FPrimaryKeyNo].FieldName;
  828. {$ifdef DEBUG}
  829. WriteLn('ApplyUpdates called');
  830. if FPrimaryKeyNo = FAutoIncFieldNo then
  831. WriteLn('Using an AutoInc field as primary key');
  832. WriteLn('PrimaryKey: ',KeyName);
  833. WriteLn('PrimaryKeyNo: ',FPrimaryKeyNo);
  834. {$endif}
  835. SqlTemp:='BEGIN TRANSACTION;';
  836. // Update changed records
  837. if FUpdatedItems.Count > 0 then
  838. TemplateStr:='UPDATE '+FTableName+' SET ';
  839. for CounterItems:= 0 to FUpdatedItems.Count - 1 do
  840. begin
  841. ASqlLine:=TemplateStr;
  842. for CounterFields:= 0 to Fields.Count - 1 do
  843. begin
  844. if PDataRecord(FUpdatedItems[CounterItems])^.Row[CounterFields] <> nil then
  845. begin
  846. ASqlLine:=ASqlLine + Fields[CounterFields].FieldName +' = ';
  847. if not (Fields[CounterFields].DataType in [ftString,ftMemo]) then
  848. ASqlLine:=ASqlLine+StrPas(PDataRecord(FUpdatedItems[CounterItems])^.Row[CounterFields])+ ','
  849. else
  850. ASqlLine:=ASqlLine+''''+
  851. AnsiReplaceStr(StrPas(PDataRecord(FUpdatedItems[CounterItems])^.Row[CounterFields]),'''','''''')+''',';
  852. end
  853. else
  854. ASqlLine:=ASqlLine + Fields[CounterFields].FieldName +' = NULL,';
  855. end;
  856. //Todo: see if system.delete trunks AnsiString
  857. system.delete(ASqlLine,Length(ASqlLine),1);
  858. SqlTemp:=SqlTemp + ASqlLine+' WHERE '+KeyName+' = '+StrPas(PDataRecord(FUpdatedItems[CounterItems])^.Row[FPrimaryKeyNo])+';';
  859. inc(StatementsCounter);
  860. //ApplyUpdates each 400 statements
  861. if StatementsCounter = 400 then
  862. begin
  863. SqlTemp:=SqlTemp+'END TRANSACTION;';
  864. FSqliteReturnId:=sqlite_exec(FSqliteHandle,PChar(SqlTemp),nil,nil,nil);
  865. StatementsCounter:=0;
  866. SqlTemp:='BEGIN TRANSACTION;';
  867. end;
  868. end;
  869. // Add new records
  870. // Build TemplateStr
  871. if FAddedItems.Count > 0 then
  872. begin
  873. TemplateStr:='INSERT INTO '+FTableName+ ' (';
  874. for CounterFields:= 0 to Fields.Count - 1 do
  875. begin
  876. TemplateStr:=TemplateStr + Fields[CounterFields].FieldName;
  877. if CounterFields <> Fields.Count - 1 then
  878. TemplateStr:=TemplateStr+',';
  879. end;
  880. TemplateStr:=TemplateStr+') VALUES (';
  881. end;
  882. for CounterItems:= 0 to FAddedItems.Count - 1 do
  883. begin
  884. ASqlLine:=TemplateStr;
  885. for CounterFields:= 0 to Fields.Count - 1 do
  886. begin
  887. if PDataRecord(FAddedItems[CounterItems])^.Row[CounterFields] <> nil then
  888. begin
  889. if not (Fields[CounterFields].DataType in [ftString,ftMemo]) then
  890. ASqlLine:=ASqlLine+StrPas(PDataRecord(FAddedItems[CounterItems])^.Row[CounterFields])
  891. else
  892. ASqlLine:=ASqlLine+''''+
  893. AnsiReplaceStr(StrPas(PDataRecord(FAddedItems[CounterItems])^.Row[CounterFields]),'''','''''')+'''';
  894. end
  895. else
  896. ASqlLine:=ASqlLine + 'NULL';
  897. //Todo: see if delete ASqline is faster
  898. if CounterFields <> Fields.Count - 1 then
  899. ASqlLine:=ASqlLine+',';
  900. end;
  901. SqlTemp:=SqlTemp+ASqlLine+');';
  902. inc(StatementsCounter);
  903. //ApplyUpdates each 400 statements
  904. if StatementsCounter = 400 then
  905. begin
  906. SqlTemp:=SqlTemp+'END TRANSACTION;';
  907. FSqliteReturnId:=sqlite_exec(FSqliteHandle,PChar(SqlTemp),nil,nil,nil);
  908. StatementsCounter:=0;
  909. SqlTemp:='BEGIN TRANSACTION;';
  910. end;
  911. end;
  912. // Delete Items
  913. if FDeletedItems.Count > 0 then
  914. TemplateStr:='DELETE FROM '+FTableName+ ' WHERE '+KeyName+' = ';
  915. for CounterItems:= 0 to FDeletedItems.Count - 1 do
  916. begin
  917. SqlTemp:=SqlTemp+TemplateStr+
  918. StrPas(PDataRecord(FDeletedItems[CounterItems])^.Row[FPrimaryKeyNo])+';';
  919. inc(StatementsCounter);
  920. //ApplyUpdates each 400 statements
  921. if StatementsCounter = 400 then
  922. begin
  923. SqlTemp:=SqlTemp+'END TRANSACTION;';
  924. FSqliteReturnId:=sqlite_exec(FSqliteHandle,PChar(SqlTemp),nil,nil,nil);
  925. StatementsCounter:=0;
  926. SqlTemp:='BEGIN TRANSACTION;';
  927. end;
  928. end;
  929. SqlTemp:=SqlTemp+'END TRANSACTION;';
  930. {$ifdef DEBUG}
  931. writeln('ApplyUpdates Sql: ',SqlTemp);
  932. {$endif}
  933. FAddedItems.Clear;
  934. FUpdatedItems.Clear;
  935. FDeletedItems.Clear;
  936. FSqliteReturnId:=sqlite_exec(FSqliteHandle,PChar(SqlTemp),nil,nil,nil);
  937. Result:= FSqliteReturnId = SQLITE_OK;
  938. end;
  939. {$ifdef DEBUG}
  940. writeln('ApplyUpdates Result: ',Result);
  941. {$endif}
  942. end;
  943. function TSqliteDataset.CreateTable: Boolean;
  944. var
  945. SqlTemp:String;
  946. Counter:Integer;
  947. begin
  948. {$ifdef DEBUG}
  949. if FTableName = '' then
  950. WriteLn('CreateTable : TableName Not Set');
  951. if FieldDefs.Count = 0 then
  952. WriteLn('CreateTable : FieldDefs Not Initialized');
  953. {$endif}
  954. if (FTableName <> '') and (FieldDefs.Count > 0) then
  955. begin
  956. FSqliteHandle:= sqlite_open(PChar(FFileName),0,nil);
  957. SqlTemp:='CREATE TABLE '+FTableName+' (';
  958. for Counter := 0 to FieldDefs.Count-1 do
  959. begin
  960. SqlTemp:=SqlTemp + FieldDefs[Counter].Name;
  961. case FieldDefs[Counter].DataType of
  962. ftInteger:
  963. SqlTemp:=SqlTemp + ' INTEGER';
  964. ftString:
  965. SqlTemp:=SqlTemp + ' VARCHAR';
  966. ftBoolean:
  967. SqlTemp:=SqlTemp + ' BOOLEAN';
  968. ftFloat:
  969. SqlTemp:=SqlTemp + ' FLOAT';
  970. ftWord:
  971. SqlTemp:=SqlTemp + ' WORD';
  972. ftDateTime:
  973. SqlTemp:=SqlTemp + ' DATETIME';
  974. ftDate:
  975. SqlTemp:=SqlTemp + ' DATE';
  976. ftTime:
  977. SqlTemp:=SqlTemp + ' TIME';
  978. ftAutoInc:
  979. SqlTemp:=SqlTemp + ' AUTOINC';
  980. ftMemo:
  981. SqlTemp:=SqlTemp + ' MEMO';
  982. else
  983. SqlTemp:=SqlTemp + ' VARCHAR';
  984. end;
  985. if Counter <> FieldDefs.Count - 1 then
  986. SqlTemp:=SqlTemp+ ' , ';
  987. end;
  988. SqlTemp:=SqlTemp+');';
  989. {$ifdef DEBUG}
  990. writeln('CreateTable Sql: ',SqlTemp);
  991. {$endif}
  992. FSqliteReturnId:=sqlite_exec(FSqliteHandle,PChar(SqlTemp),nil,nil,nil);
  993. Result:= FSqliteReturnId = SQLITE_OK;
  994. sqlite_close(FSqliteHandle);
  995. end
  996. else
  997. Result:=False;
  998. end;
  999. function TSqliteDataset.TableExists: Boolean;
  1000. var
  1001. AHandle,vm:Pointer;
  1002. ColumnNames,ColumnValues:PPChar;
  1003. AInt:Integer;
  1004. begin
  1005. Result:=False;
  1006. if not (FTableName = '') and FileExists(FFileName) then
  1007. begin
  1008. if FSqliteHandle = nil then
  1009. begin
  1010. {$ifdef DEBUG}
  1011. writeln('TableExists - FSqliteHandle=nil : Opening a file');
  1012. {$endif}
  1013. AHandle:=sqlite_open(PChar(FFileName),0,nil);
  1014. end
  1015. else
  1016. begin
  1017. {$ifdef DEBUG}
  1018. writeln('TableExists - FSqliteHandle<>nil : Using FSqliteHandle');
  1019. {$endif}
  1020. AHandle:=FSqliteHandle;
  1021. end;
  1022. FSqliteReturnId:=sqlite_compile(AHandle,
  1023. Pchar('SELECT name FROM SQLITE_MASTER WHERE type = ''table'' AND name LIKE '''+ FTableName+ ''';'),
  1024. nil,@vm,nil);
  1025. {$ifdef DEBUG}
  1026. WriteLn('TableExists.sqlite_compile - SqliteReturnString:',SqliteReturnString);
  1027. {$endif}
  1028. FSqliteReturnId:=sqlite_step(vm,@AInt,@ColumnValues,@ColumnNames);
  1029. {$ifdef DEBUG}
  1030. WriteLn('TableExists.sqlite_step - SqliteReturnString:',SqliteReturnString);
  1031. {$endif}
  1032. Result:=FSqliteReturnId = SQLITE_ROW;
  1033. sqlite_finalize(vm, nil);
  1034. if (FSqliteHandle = nil) then
  1035. sqlite_close(AHandle);
  1036. end;
  1037. {$ifdef DEBUG}
  1038. WriteLn('TableExists ('+FTableName+') Result:',Result);
  1039. {$endif}
  1040. end;
  1041. procedure TSqliteDataset.RefetchData;
  1042. begin
  1043. //Close
  1044. if FSaveOnRefetch then
  1045. ApplyUpdates;
  1046. if FDataAllocated then
  1047. DisposeLinkedList;
  1048. FAddedItems.Clear;
  1049. FUpdatedItems.Clear;
  1050. FDeletedItems.Clear;
  1051. FOrphanItems.Clear;
  1052. FRecordCount:=0;
  1053. //Reopen
  1054. BuildLinkedList;
  1055. FCurrentItem:=FBeginItem;
  1056. Resync([]);
  1057. end;
  1058. function TSqliteDataset.SqliteReturnString: String;
  1059. begin
  1060. case FSqliteReturnId of
  1061. SQLITE_OK : Result := 'SQLITE_OK ';
  1062. SQLITE_ERROR : Result := 'SQLITE_ERROR ';
  1063. SQLITE_INTERNAL : Result := 'SQLITE_INTERNAL ';
  1064. SQLITE_PERM : Result := 'SQLITE_PERM ';
  1065. SQLITE_ABORT : Result := 'SQLITE_ABORT ';
  1066. SQLITE_BUSY : Result := 'SQLITE_BUSY ';
  1067. SQLITE_LOCKED : Result := 'SQLITE_LOCKED ';
  1068. SQLITE_NOMEM : Result := 'SQLITE_NOMEM ';
  1069. SQLITE_READONLY : Result := 'SQLITE_READONLY ';
  1070. SQLITE_INTERRUPT : Result := 'SQLITE_INTERRUPT ';
  1071. SQLITE_IOERR : Result := 'SQLITE_IOERR ';
  1072. SQLITE_CORRUPT : Result := 'SQLITE_CORRUPT ';
  1073. SQLITE_NOTFOUND : Result := 'SQLITE_NOTFOUND ';
  1074. SQLITE_FULL : Result := 'SQLITE_FULL ';
  1075. SQLITE_CANTOPEN : Result := 'SQLITE_CANTOPEN ';
  1076. SQLITE_PROTOCOL : Result := 'SQLITE_PROTOCOL ';
  1077. SQLITE_EMPTY : Result := 'SQLITE_EMPTY ';
  1078. SQLITE_SCHEMA : Result := 'SQLITE_SCHEMA ';
  1079. SQLITE_TOOBIG : Result := 'SQLITE_TOOBIG ';
  1080. SQLITE_CONSTRAINT : Result := 'SQLITE_CONSTRAINT ';
  1081. SQLITE_MISMATCH : Result := 'SQLITE_MISMATCH ';
  1082. SQLITE_MISUSE : Result := 'SQLITE_MISUSE ';
  1083. SQLITE_NOLFS : Result := 'SQLITE_NOLFS ';
  1084. SQLITE_AUTH : Result := 'SQLITE_AUTH ';
  1085. SQLITE_FORMAT : Result := 'SQLITE_FORMAT ';
  1086. // SQLITE_RANGE : Result := 'SQLITE_RANGE ';
  1087. SQLITE_ROW : Result := 'SQLITE_ROW ';
  1088. SQLITE_DONE : Result := 'SQLITE_DONE ';
  1089. else
  1090. Result:='Unknow Return Value';
  1091. end;
  1092. end;
  1093. function TSqliteDataset.UpdatesPending: Boolean;
  1094. begin
  1095. Result:= (FDeletedItems.Count > 0) or
  1096. (FAddedItems.Count > 0) or (FUpdatedItems.Count > 0);
  1097. end;
  1098. procedure Register;
  1099. begin
  1100. RegisterComponents('Data Access', [TSqliteDataset]);
  1101. end;
  1102. {$ifdef DEBUGACTIVEBUFFER}
  1103. procedure TSqliteDataset.SetCurrentItem(Value:PDataRecord);
  1104. var
  1105. ANo:Integer;
  1106. function GetItemPos:Integer;
  1107. var
  1108. TempItem:PDataRecord;
  1109. begin
  1110. Result:= -1;
  1111. TempItem:=FBeginItem;
  1112. if Value = FCacheItem then
  1113. Result:=-2
  1114. else
  1115. while Value <> TempItem do
  1116. begin
  1117. if TempItem^.Next <> nil then
  1118. begin
  1119. inc(Result);
  1120. TempItem:=TempItem^.Next;
  1121. end
  1122. else
  1123. begin
  1124. Result:=-1;
  1125. break;
  1126. end;
  1127. end;
  1128. end;
  1129. begin
  1130. if Value = FBeginItem then
  1131. begin
  1132. writeln('FCurrentItem set to FBeginItem: ',IntToHex(Integer(Value),0));
  1133. FFCurrentItem:=Value;
  1134. end
  1135. else
  1136. if Value = FEndItem then
  1137. begin
  1138. writeln('FCurrentItem set to FEndItem: ',IntToHex(Integer(Value),0));
  1139. FFCurrentItem:=Value;
  1140. end
  1141. else
  1142. if Value = FCacheItem then
  1143. begin
  1144. writeln('FCurrentItem set to FCacheItem: ',IntToHex(Integer(Value),0));
  1145. FFCurrentItem:=Value;
  1146. end
  1147. else
  1148. begin
  1149. writeln('FCurrentItem set from ',IntToHex(Integer(FFCurrentItem),0),' to ',IntToHex(Integer(Value),0));
  1150. Ano:=GetItemPos;
  1151. writeln('Item position is ',ANo);
  1152. FFCurrentItem:=Value;
  1153. end;
  1154. end;
  1155. {$endif}
  1156. end.