sqlite3ds.pas 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290
  1. unit sqlite3ds;
  2. {
  3. This is TSqlite3Dataset, 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 DEBUG}
  21. interface
  22. uses
  23. Classes, SysUtils, customsqliteds;
  24. type
  25. { TSqlite3Dataset }
  26. TSqlite3Dataset = class (TCustomSqliteDataset)
  27. private
  28. function SqliteExec(AHandle: Pointer; ASql:PChar):Integer;override;
  29. function GetSqliteHandle: Pointer; override;
  30. procedure SqliteClose(AHandle: Pointer);override;
  31. procedure BuildLinkedList; override;
  32. protected
  33. procedure InternalInitFieldDefs; override;
  34. public
  35. function SqliteReturnString: String; override;
  36. function TableExists: Boolean;override;
  37. end;
  38. implementation
  39. uses
  40. sqlite3,db;
  41. function GetAutoIncValue(NextValue: Pointer; Columns: Integer; ColumnValues: PPChar; ColumnNames: PPChar): integer; cdecl;
  42. var
  43. CodeError, TempInt: Integer;
  44. begin
  45. TempInt:=-1;
  46. if ColumnValues[0] <> nil then
  47. begin
  48. Val(StrPas(ColumnValues[0]),TempInt,CodeError);
  49. if CodeError <> 0 then
  50. DatabaseError('SqliteDs - Error trying to get last autoinc value');
  51. end;
  52. Integer(NextValue^):=Succ(TempInt);
  53. Result:=1;
  54. end;
  55. { TSqlite3Dataset }
  56. function TSqlite3Dataset.SqliteExec(AHandle: Pointer; ASql: PChar): Integer;
  57. begin
  58. Result:=sqlite3_exec(AHandle, ASql, nil, nil, nil);
  59. end;
  60. procedure TSqlite3Dataset.SqliteClose(AHandle: Pointer);
  61. begin
  62. sqlite3_close(AHandle);
  63. //todo:handle return data
  64. end;
  65. function TSqlite3Dataset.GetSqliteHandle: Pointer;
  66. begin
  67. FSqliteReturnId:=sqlite3_open(PChar(FFileName),@Result);
  68. end;
  69. procedure TSqlite3Dataset.InternalInitFieldDefs;
  70. var
  71. vm:Pointer;
  72. ColumnStr:String;
  73. Counter,FieldSize:Integer;
  74. AType:TFieldType;
  75. begin
  76. FieldDefs.Clear;
  77. sqlite3_prepare(FSqliteHandle,PChar(FSql),-1,@vm,nil);
  78. sqlite3_step(vm);
  79. for Counter:= 0 to sqlite3_column_count(vm) - 1 do
  80. begin
  81. ColumnStr:= UpperCase(StrPas(sqlite3_column_decltype(vm,Counter)));
  82. if (ColumnStr = 'INTEGER') then
  83. begin
  84. AType:= ftInteger;
  85. FieldSize:=SizeOf(Integer);
  86. end else if (ColumnStr = 'BOOLEAN') then
  87. begin
  88. AType:= ftBoolean;
  89. FieldSize:=SizeOf(Boolean);
  90. end else if (ColumnStr = 'FLOAT') then
  91. begin
  92. AType:= ftFloat;
  93. FieldSize:=SizeOf(Double);
  94. end else if (ColumnStr = 'WORD') then
  95. begin
  96. AType:= ftWord;
  97. FieldSize:=SizeOf(Word);
  98. end else if (ColumnStr = 'DATETIME') then
  99. begin
  100. AType:= ftDateTime;
  101. FieldSize:=SizeOf(TDateTime);
  102. end else if (ColumnStr = 'DATE') then
  103. begin
  104. AType:= ftDate;
  105. FieldSize:=SizeOf(TDateTime);
  106. end else if (ColumnStr = 'TIME') then
  107. begin
  108. AType:= ftTime;
  109. FieldSize:=SizeOf(TDateTime);
  110. end else if (ColumnStr = 'MEMO') then
  111. begin
  112. AType:= ftMemo;
  113. FieldSize:=10;//??
  114. end else if (ColumnStr = 'AUTOINC') then
  115. begin
  116. AType:= ftAutoInc;
  117. FieldSize:=SizeOf(Integer);
  118. if FAutoIncFieldNo = -1 then
  119. FAutoIncFieldNo:= Counter;
  120. end else
  121. begin
  122. AType:= ftString;
  123. FieldSize:=10; //??
  124. end;
  125. FieldDefs.Add(StrPas(sqlite3_column_name(vm,Counter)), AType, FieldSize, False);
  126. {$ifdef DEBUG}
  127. writeln('Field Name: ',sqlite3_column_name(vm,Counter));
  128. writeln('Field Type: ',sqlite3_column_decltype(vm,Counter));
  129. {$endif}
  130. end;
  131. sqlite3_finalize(vm);
  132. FRowBufferSize:=(SizeOf(PPChar)*FieldDefs.Count);
  133. {$ifdef DEBUG}
  134. writeln('FieldDefs.Count: ',FieldDefs.Count);
  135. {$endif}
  136. end;
  137. procedure TSqlite3Dataset.BuildLinkedList;
  138. var
  139. TempItem:PDataRecord;
  140. vm:Pointer;
  141. Counter:Integer;
  142. begin
  143. //Get AutoInc Field initial value
  144. if FAutoIncFieldNo <> -1 then
  145. sqlite3_exec(FSqliteHandle,PChar('Select Max('+Fields[FAutoIncFieldNo].FieldName+') from ' + FTableName),
  146. @GetAutoIncValue,@FNextAutoInc,nil);
  147. FSqliteReturnId:=sqlite3_prepare(FSqliteHandle,Pchar(FSql),-1,@vm,nil);
  148. if FSqliteReturnId <> SQLITE_OK then
  149. case FSqliteReturnId of
  150. SQLITE_ERROR:
  151. DatabaseError('Invalid SQL',Self);
  152. else
  153. DatabaseError('Error returned by sqlite while retrieving data: '+SqliteReturnString,Self);
  154. end;
  155. FDataAllocated:=True;
  156. TempItem:=FBeginItem;
  157. FRecordCount:=0;
  158. FRowCount:=sqlite3_column_count(vm);
  159. FSqliteReturnId:=sqlite3_step(vm);
  160. while FSqliteReturnId = SQLITE_ROW do
  161. begin
  162. Inc(FRecordCount);
  163. New(TempItem^.Next);
  164. TempItem^.Next^.Previous:=TempItem;
  165. TempItem:=TempItem^.Next;
  166. GetMem(TempItem^.Row,FRowBufferSize);
  167. For Counter := 0 to FRowCount - 1 do
  168. TempItem^.Row[Counter]:=StrNew(sqlite3_column_text(vm,Counter));
  169. FSqliteReturnId:=sqlite3_step(vm);
  170. end;
  171. sqlite3_finalize(vm);
  172. // Attach EndItem
  173. TempItem^.Next:=FEndItem;
  174. FEndItem^.Previous:=TempItem;
  175. // Alloc item used in append/insert
  176. GetMem(FCacheItem^.Row,FRowBufferSize);
  177. for Counter := 0 to FRowCount - 1 do
  178. FCacheItem^.Row[Counter]:=nil;
  179. // Fill FBeginItem.Row with nil -> necessary for avoid exceptions in empty datasets
  180. GetMem(FBeginItem^.Row,FRowBufferSize);
  181. for Counter := 0 to FRowCount - 1 do
  182. FBeginItem^.Row[Counter]:=nil;
  183. end;
  184. function TSqlite3Dataset.TableExists: Boolean;
  185. var
  186. AHandle,vm:Pointer;
  187. begin
  188. Result:=False;
  189. if not (FTableName = '') and FileExists(FFileName) then
  190. begin
  191. if FSqliteHandle = nil then
  192. begin
  193. {$ifdef DEBUG}
  194. writeln('TableExists - FSqliteHandle=nil : Opening a file');
  195. {$endif}
  196. AHandle:=GetSqliteHandle;
  197. end
  198. else
  199. begin
  200. {$ifdef DEBUG}
  201. writeln('TableExists - FSqliteHandle<>nil : Using FSqliteHandle');
  202. {$endif}
  203. AHandle:=FSqliteHandle;
  204. end;
  205. FSqliteReturnId:=sqlite3_prepare(AHandle,
  206. Pchar('SELECT name FROM SQLITE_MASTER WHERE type = ''table'' AND name LIKE '''+ FTableName+ ''';'),
  207. -1,@vm,nil);
  208. {$ifdef DEBUG}
  209. WriteLn('TableExists.sqlite3_prepare - SqliteReturnString:',SqliteReturnString);
  210. {$endif}
  211. FSqliteReturnId:=sqlite3_step(vm);
  212. {$ifdef DEBUG}
  213. WriteLn('TableExists.sqlite3_step - SqliteReturnString:',SqliteReturnString);
  214. {$endif}
  215. Result:=FSqliteReturnId = SQLITE_ROW;
  216. sqlite3_finalize(vm);
  217. if (FSqliteHandle = nil) then
  218. sqlite3_close(AHandle);
  219. end;
  220. {$ifdef DEBUG}
  221. WriteLn('TableExists ('+FTableName+') Result:',Result);
  222. {$endif}
  223. end;
  224. function TSqlite3Dataset.SqliteReturnString: String;
  225. begin
  226. case FSqliteReturnId of
  227. SQLITE_OK : Result := 'SQLITE_OK ';
  228. SQLITE_ERROR : Result := 'SQLITE_ERROR ';
  229. SQLITE_INTERNAL : Result := 'SQLITE_INTERNAL ';
  230. SQLITE_PERM : Result := 'SQLITE_PERM ';
  231. SQLITE_ABORT : Result := 'SQLITE_ABORT ';
  232. SQLITE_BUSY : Result := 'SQLITE_BUSY ';
  233. SQLITE_LOCKED : Result := 'SQLITE_LOCKED ';
  234. SQLITE_NOMEM : Result := 'SQLITE_NOMEM ';
  235. SQLITE_READONLY : Result := 'SQLITE_READONLY ';
  236. SQLITE_INTERRUPT : Result := 'SQLITE_INTERRUPT ';
  237. SQLITE_IOERR : Result := 'SQLITE_IOERR ';
  238. SQLITE_CORRUPT : Result := 'SQLITE_CORRUPT ';
  239. SQLITE_NOTFOUND : Result := 'SQLITE_NOTFOUND ';
  240. SQLITE_FULL : Result := 'SQLITE_FULL ';
  241. SQLITE_CANTOPEN : Result := 'SQLITE_CANTOPEN ';
  242. SQLITE_PROTOCOL : Result := 'SQLITE_PROTOCOL ';
  243. SQLITE_EMPTY : Result := 'SQLITE_EMPTY ';
  244. SQLITE_SCHEMA : Result := 'SQLITE_SCHEMA ';
  245. SQLITE_TOOBIG : Result := 'SQLITE_TOOBIG ';
  246. SQLITE_CONSTRAINT : Result := 'SQLITE_CONSTRAINT ';
  247. SQLITE_MISMATCH : Result := 'SQLITE_MISMATCH ';
  248. SQLITE_MISUSE : Result := 'SQLITE_MISUSE ';
  249. SQLITE_NOLFS : Result := 'SQLITE_NOLFS ';
  250. SQLITE_AUTH : Result := 'SQLITE_AUTH ';
  251. SQLITE_FORMAT : Result := 'SQLITE_FORMAT ';
  252. SQLITE_RANGE : Result := 'SQLITE_RANGE ';
  253. SQLITE_ROW : Result := 'SQLITE_ROW ';
  254. SQLITE_NOTADB : Result := 'SQLITE_NOTADB ';
  255. SQLITE_DONE : Result := 'SQLITE_DONE ';
  256. else
  257. Result:='Unknow Return Value';
  258. end;
  259. end;
  260. end.