sqliteds.pas 35 KB

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