customsqliteds.pas 37 KB

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