sqldbindexdb.pp 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304
  1. {
  2. This file is part of the Free Component Library (FCL)
  3. Copyright (c) 2012 by the Free Pascal development team
  4. SQLDB-based index database
  5. See the file COPYING.FPC, included in this distribution,
  6. for details about the copyright.
  7. This program is distributed in the hope that it will be useful,
  8. but WITHOUT ANY WARRANTY; without even the implied warranty of
  9. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  10. **********************************************************************}
  11. unit SQLDBIndexDB;
  12. {$mode objfpc}{$H+}
  13. interface
  14. uses
  15. SysUtils, fpIndexer, sqldb, db;
  16. // SQLDB Specific, cache query objects
  17. type
  18. TCachedQueryType = (cqtInsertWord, cqtGetWordID, cqtInsertFile, cqtGetFileID,
  19. cqtInsertLanguage, cqtGetLanguageID, cqtInsertMatch);
  20. // Interbase specific
  21. const
  22. {$note @MvC, TIndexTable is defined as: itWords, itLanguages, itFiles, itMatches, below order seems to be wrong}
  23. DefaultGeneratorNames: array[TIndexTable] of string = ('GEN_WORDS', 'GEN_MATCHES', 'GEN_LANGUAGES', 'GEN_FILES');
  24. type
  25. { TSQLDBIndexDB }
  26. TSQLDBIndexDB = class(TSQLIndexDB)
  27. private
  28. // SQLDB specific
  29. db: TSQLConnection;
  30. FLastURLID: int64;
  31. FLastURL: string;
  32. FLastLanguageID: int64;
  33. FLastLanguage: string;
  34. FLastWordID: int64;
  35. FLastWord: string;
  36. FQueries: array [TCachedQueryType] of TSQLQuery;
  37. protected
  38. // SQLDB Specific statements
  39. procedure Execute(const sql: string; ignoreErrors: boolean = True); override;
  40. function GetLanguageID(const ALanguage: string): int64;
  41. function GetWordID(const AWord: string): int64;
  42. function GetURLID(const URL: string; ATimeStamp: TDateTime; ALanguageID: int64; DoCreate: boolean = True): int64; override;
  43. function CreateQuery(const ASQL: string): TSQLQuery;
  44. function CreateCachedQuery(QueryType: TCachedQueryType; const ASQL: string): TSQLQuery;
  45. // Connection specific, need to be overridden
  46. function GetConnection: TSQLConnection; virtual; abstract;
  47. procedure InsertMatch(AWordID, aFileID, aLanguageID: int64; const ASearchData: TSearchWordData); virtual; abstract;
  48. function InsertWord(const AWord: string): int64; virtual; abstract;
  49. function InsertURL(const URL: string; ATimeStamp: TDateTime; ALanguageID: int64): int64; virtual; abstract;
  50. function InsertLanguage(const ALanguage: string): int64; virtual; abstract;
  51. public
  52. destructor Destroy; override;
  53. procedure Connect; override;
  54. procedure Disconnect; override;
  55. procedure CreateDB; override;
  56. procedure BeginTrans; override;
  57. procedure CommitTrans; override;
  58. procedure CompactDB; override;
  59. procedure AddSearchData(ASearchData: TSearchWordData); override;
  60. procedure FindSearchData(SearchWord: TWordParser; FPSearch: TFPSearch; SearchOptions: TSearchOptions); override;
  61. procedure DeleteWordsFromFile(URL: string); override;
  62. end;
  63. implementation
  64. { TSQLDBIndexDB }
  65. function TSQLDBIndexDB.GetLanguageID(const ALanguage: string): int64;
  66. var
  67. Q: TSQLQuery;
  68. begin
  69. if SameFileName(FLastLanguage, ALanguage) then
  70. Result := FLastLanguageID
  71. else
  72. begin
  73. Q := CreateCachedQuery(cqtGetLanguageID, GetLanguageSQL);
  74. Q.ParamByName(GetFieldName(ifLanguagesName)).AsString := ALanguage;
  75. Q.Open;
  76. try
  77. if (Q.EOF and Q.BOF) then
  78. Result := InsertLanguage(ALanguage)
  79. else
  80. Result := Q.FieldByName(GetFieldName(ifLanguagesID)).AsLargeInt;
  81. FLastLanguageID := Result;
  82. FLastLanguage := ALanguage;
  83. finally
  84. Q.Close;
  85. end;
  86. end;
  87. end;
  88. function TSQLDBIndexDB.GetWordID(const AWord: string): int64;
  89. var
  90. Q: TSQLQuery;
  91. begin
  92. if (FLastWord = AWord) then
  93. Result := FLastWordID
  94. else
  95. begin
  96. Q := CreateCachedQuery(cqtGetWordID, GetWordSQL);
  97. Q.ParamByName(GetFieldName(ifWordsWord)).AsString := AWord;
  98. Q.Open;
  99. try
  100. if (Q.EOF and Q.BOF) then
  101. Result := InsertWord(AWord)
  102. else
  103. Result := Q.FieldByName(GetFieldName(ifWordsID)).AsLargeInt;
  104. FLastWordID := Result;
  105. FLastWord := AWord;
  106. finally
  107. Q.Close;
  108. end;
  109. end;
  110. end;
  111. function TSQLDBIndexDB.CreateQuery(const ASQL: string): TSQLQuery;
  112. begin
  113. Result := TSQLQuery.Create(Self);
  114. Result.Database := Self.db;
  115. Result.Transaction := Self.db.Transaction;
  116. Result.SQL.Text := ASQL;
  117. //Writeln('SQL :',ASQL);
  118. end;
  119. function TSQLDBIndexDB.GetURLID(const URL: string; ATimeStamp: TDateTime; ALanguageID: int64; DoCreate: boolean = True): int64;
  120. var
  121. Q: TSQLQuery;
  122. begin
  123. if SameFileName(FLastURL, URL) then
  124. Result := FLastURLID
  125. else
  126. begin
  127. Q := CreateCachedQuery(cqtGetFileID, GetSearchFileSQL);
  128. If Length(URL)>255 then
  129. Writeln('URL Length : ',Length(URL),' : ',URL);
  130. Q.ParamByName(GetFieldName(ifFilesURL)).AsString := URL;
  131. Q.Open;
  132. try
  133. if (Q.EOF and Q.BOF) then
  134. begin
  135. if DoCreate then
  136. Result := InsertURL(URL, ATimeStamp, ALanguageID)
  137. else
  138. Result := -1;
  139. end
  140. else
  141. Result := Q.FieldByName(GetFieldName(ifFilesID)).AsLargeInt;
  142. FLastURLID := Result;
  143. FLastURL := URL;
  144. finally
  145. Q.Close;
  146. end;
  147. end;
  148. end;
  149. function TSQLDBIndexDB.CreateCachedQuery(QueryType: TCachedQueryType; const ASQL: string): TSQLQuery;
  150. begin
  151. if FQueries[QueryType] = nil then
  152. begin
  153. FQueries[QueryType] := CreateQuery(ASQL);
  154. FQueries[QueryType].Prepare;
  155. end;
  156. Result := FQueries[QueryType];
  157. end;
  158. procedure TSQLDBIndexDB.AddSearchData(ASearchData: TSearchWordData);
  159. var
  160. WID, FID, LID: int64;
  161. begin
  162. //check if the SearchWord already is in the list
  163. LID := GetLanguageID(ASearchData.Language);
  164. FID := GetURLID(ASearchData.URL, ASearchData.FileDate, LID);
  165. WID := GetWordID(ASearchData.SearchWord);
  166. InsertMatch(WID, FID, LID, ASearchData);
  167. end;
  168. procedure TSQLDBIndexDB.FindSearchData(SearchWord: TWordParser; FPSearch: TFPSearch; SearchOptions: TSearchOptions);
  169. var
  170. Q: TSQLQuery;
  171. FN, FP, FD, FW, FC: TField;
  172. Res: TSearchWordData;
  173. S,WW : String;
  174. I,L : Integer;
  175. begin
  176. Q := CreateQuery(GetMatchSQL(SearchOptions,SearchWord,True));
  177. try
  178. Writeln(Q.SQL.Text);
  179. WW := getFieldName(ifWordsWord);
  180. for i := 0 to SearchWord.Count - 1 do
  181. If SearchWord.Token[i].TokenType=wtWord then
  182. begin
  183. S:=SearchWord.Token[i].Value;
  184. if (Length(S)>0) and (S[1]='''') then
  185. Delete(S,1,1);
  186. L:=Length(S);
  187. if (l>0) and (S[l]='''') then
  188. Delete(S,l,1);
  189. if (soContains in Searchoptions) then
  190. S:='%'+S+'%';
  191. Q.ParamByName(WW+IntToStr(i)).AsString:=S;
  192. end;
  193. Q.Open;
  194. FN := Q.FieldByName(GetFieldName(ifFilesURL));
  195. FD := Q.FieldByName(GetFieldName(ifFilesTimeStamp));
  196. FC := Q.FieldByName(GetFieldName(ifMatchesContext));
  197. FP := Q.FieldByName(GetFieldName(ifMatchesPosition));
  198. FW := Q.FieldByName(GetFieldName(ifWordsWord));
  199. while not Q.EOF do
  200. begin
  201. Res.FileDate := FD.AsDateTime;
  202. Res.URL := FN.AsString;
  203. Res.SearchWord := FW.AsString;
  204. Res.Position := FP.AsInteger;
  205. Res.Context:=FC.aSString;
  206. FPSearch.AddResult(Q.RecNo, Res);
  207. Q.Next;
  208. end;
  209. finally
  210. Q.Free;
  211. end;
  212. end;
  213. procedure TSQLDBIndexDB.DeleteWordsFromFile(URL: string);
  214. begin
  215. inherited DeleteWordsFromFile(URL);
  216. FLastURL := '';
  217. end;
  218. procedure TSQLDBIndexDB.Execute(const sql: string; ignoreErrors: boolean = True);
  219. begin
  220. if SQL = '' then
  221. exit;
  222. try
  223. DB.ExecuteDirect(sql);
  224. except
  225. if not IgnoreErrors then
  226. raise;
  227. end;
  228. end;
  229. procedure TSQLDBIndexDB.Connect;
  230. begin
  231. if (DB = nil) then
  232. db := GetConnection;
  233. if DB.Transaction = nil then
  234. DB.Transaction := TSQLTransaction.Create(db);
  235. DB.Connected := True;
  236. end;
  237. procedure TSQLDBIndexDB.Disconnect;
  238. Var
  239. T : TCachedQueryType;
  240. begin
  241. For T:=Low(TCachedQueryType) to High(TCachedQueryType) do
  242. FreeAndNil(FQueries[T]);
  243. FreeAndNil(DB);
  244. end;
  245. procedure TSQLDBIndexDB.CreateDB;
  246. begin
  247. if DB = nil then
  248. DB := GetConnection;
  249. DB.CreateDB;
  250. Connect;
  251. CreateIndexerTables;
  252. end;
  253. destructor TSQLDBIndexDB.Destroy;
  254. begin
  255. Disconnect;
  256. inherited Destroy;
  257. end;
  258. procedure TSQLDBIndexDB.BeginTrans;
  259. begin
  260. DB.Transaction.StartTransaction;
  261. end;
  262. procedure TSQLDBIndexDB.CommitTrans;
  263. begin
  264. DB.Transaction.Commit;
  265. end;
  266. procedure TSQLDBIndexDB.CompactDB;
  267. begin
  268. //not yet implemented
  269. end;
  270. end.