bufdataset_parser.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513
  1. unit bufdataset_parser;
  2. {$h+}
  3. {$mode delphi}
  4. interface
  5. uses
  6. SysUtils,
  7. Classes,
  8. db,
  9. dbf_prscore,
  10. dbf_prsdef;
  11. type
  12. TBufDatasetParser = class(TCustomExpressionParser)
  13. private
  14. FDataset: TDataSet;
  15. FFieldVarList: TStringList;
  16. FResultLen: Integer;
  17. FIsExpression: Boolean; // expression or simple field?
  18. FFieldType: TExpressionType;
  19. FCaseInsensitive: Boolean;
  20. FPartialMatch: boolean;
  21. protected
  22. FCurrentExpression: string;
  23. procedure FillExpressList; override;
  24. procedure HandleUnknownVariable(VarName: string); override;
  25. function GetVariableInfo(VarName: string): TField;
  26. function CurrentExpression: string; override;
  27. function GetResultType: TExpressionType; override;
  28. procedure SetCaseInsensitive(NewInsensitive: Boolean);
  29. procedure SetPartialMatch(NewPartialMatch: boolean);
  30. public
  31. constructor Create(ADataset: TDataset);
  32. destructor Destroy; override;
  33. procedure ClearExpressions; override;
  34. procedure ParseExpression(AExpression: string); virtual;
  35. function ExtractFromBuffer(Buffer: PChar): PChar; virtual;
  36. property Dataset: TDataSet read FDataset; // write FDataset;
  37. property Expression: string read FCurrentExpression;
  38. property ResultLen: Integer read FResultLen;
  39. property CaseInsensitive: Boolean read FCaseInsensitive write SetCaseInsensitive;
  40. property PartialMatch: boolean read FPartialMatch write SetPartialMatch;
  41. end;
  42. implementation
  43. uses dbconst;
  44. type
  45. // TFieldVar aids in retrieving field values from records
  46. // in their proper type
  47. TFieldVar = class(TObject)
  48. private
  49. FField: TField;
  50. FFieldName: string;
  51. FExprWord: TExprWord;
  52. protected
  53. function GetFieldVal: Pointer; virtual; abstract;
  54. function GetFieldType: TExpressionType; virtual; abstract;
  55. public
  56. constructor Create(UseField: TField);
  57. procedure Refresh(Buffer: PChar); virtual; abstract;
  58. property FieldVal: Pointer read GetFieldVal;
  59. property FieldDef: TField read FField;
  60. property FieldType: TExpressionType read GetFieldType;
  61. property FieldName: string read FFieldName;
  62. end;
  63. TStringFieldVar = class(TFieldVar)
  64. protected
  65. FFieldVal: PChar;
  66. function GetFieldVal: Pointer; override;
  67. function GetFieldType: TExpressionType; override;
  68. public
  69. constructor Create(UseField: TField);
  70. destructor Destroy; override;
  71. procedure Refresh(Buffer: PChar); override;
  72. end;
  73. TFloatFieldVar = class(TFieldVar)
  74. private
  75. FFieldVal: Double;
  76. protected
  77. function GetFieldVal: Pointer; override;
  78. function GetFieldType: TExpressionType; override;
  79. public
  80. procedure Refresh(Buffer: PChar); override;
  81. end;
  82. TIntegerFieldVar = class(TFieldVar)
  83. private
  84. FFieldVal: Integer;
  85. protected
  86. function GetFieldVal: Pointer; override;
  87. function GetFieldType: TExpressionType; override;
  88. public
  89. procedure Refresh(Buffer: PChar); override;
  90. end;
  91. TLargeIntFieldVar = class(TFieldVar)
  92. private
  93. FFieldVal: Int64;
  94. protected
  95. function GetFieldVal: Pointer; override;
  96. function GetFieldType: TExpressionType; override;
  97. public
  98. procedure Refresh(Buffer: PChar); override;
  99. end;
  100. TDateTimeFieldVar = class(TFieldVar)
  101. private
  102. FFieldVal: TDateTime;
  103. function GetFieldType: TExpressionType; override;
  104. protected
  105. function GetFieldVal: Pointer; override;
  106. public
  107. procedure Refresh(Buffer: PChar); override;
  108. end;
  109. TBooleanFieldVar = class(TFieldVar)
  110. private
  111. FFieldVal: wordbool;
  112. function GetFieldType: TExpressionType; override;
  113. protected
  114. function GetFieldVal: Pointer; override;
  115. public
  116. procedure Refresh(Buffer: PChar); override;
  117. end;
  118. //--TFieldVar----------------------------------------------------------------
  119. constructor TFieldVar.Create(UseField: TField);
  120. begin
  121. inherited Create;
  122. // store field
  123. //FDataset := ADataset;
  124. FField := UseField;
  125. FFieldName := UseField.FieldName;
  126. end;
  127. //--TStringFieldVar-------------------------------------------------------------
  128. function TStringFieldVar.GetFieldVal: Pointer;
  129. begin
  130. Result := @FFieldVal;
  131. end;
  132. function TStringFieldVar.GetFieldType: TExpressionType;
  133. begin
  134. Result := etString;
  135. end;
  136. constructor TStringFieldVar.Create(UseField: TField);
  137. begin
  138. inherited;
  139. GetMem(FFieldVal, dsMaxStringSize+1);
  140. end;
  141. destructor TStringFieldVar.Destroy;
  142. begin
  143. FreeMem(FFieldVal);
  144. inherited;
  145. end;
  146. procedure TStringFieldVar.Refresh(Buffer: PChar);
  147. var Fieldbuf : TStringFieldBuffer;
  148. s : string;
  149. begin
  150. if not FField.DataSet.GetFieldData(FField,@Fieldbuf) then
  151. s := ''
  152. else
  153. s := Fieldbuf;
  154. strcopy(FFieldVal,@s[1]);
  155. end;
  156. //--TFloatFieldVar-----------------------------------------------------------
  157. function TFloatFieldVar.GetFieldVal: Pointer;
  158. begin
  159. Result := @FFieldVal;
  160. end;
  161. function TFloatFieldVar.GetFieldType: TExpressionType;
  162. begin
  163. Result := etFloat;
  164. end;
  165. procedure TFloatFieldVar.Refresh(Buffer: PChar);
  166. begin
  167. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  168. FFieldVal := 0;
  169. end;
  170. //--TIntegerFieldVar----------------------------------------------------------
  171. function TIntegerFieldVar.GetFieldVal: Pointer;
  172. begin
  173. Result := @FFieldVal;
  174. end;
  175. function TIntegerFieldVar.GetFieldType: TExpressionType;
  176. begin
  177. Result := etInteger;
  178. end;
  179. procedure TIntegerFieldVar.Refresh(Buffer: PChar);
  180. begin
  181. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  182. FFieldVal := 0;
  183. end;
  184. //--TLargeIntFieldVar----------------------------------------------------------
  185. function TLargeIntFieldVar.GetFieldVal: Pointer;
  186. begin
  187. Result := @FFieldVal;
  188. end;
  189. function TLargeIntFieldVar.GetFieldType: TExpressionType;
  190. begin
  191. Result := etLargeInt;
  192. end;
  193. procedure TLargeIntFieldVar.Refresh(Buffer: PChar);
  194. begin
  195. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  196. FFieldVal := 0;
  197. end;
  198. //--TDateTimeFieldVar---------------------------------------------------------
  199. function TDateTimeFieldVar.GetFieldVal: Pointer;
  200. begin
  201. Result := @FFieldVal;
  202. end;
  203. function TDateTimeFieldVar.GetFieldType: TExpressionType;
  204. begin
  205. Result := etDateTime;
  206. end;
  207. procedure TDateTimeFieldVar.Refresh(Buffer: PChar);
  208. begin
  209. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  210. FFieldVal := 0;
  211. end;
  212. //--TBooleanFieldVar---------------------------------------------------------
  213. function TBooleanFieldVar.GetFieldVal: Pointer;
  214. begin
  215. Result := @FFieldVal;
  216. end;
  217. function TBooleanFieldVar.GetFieldType: TExpressionType;
  218. begin
  219. Result := etBoolean;
  220. end;
  221. procedure TBooleanFieldVar.Refresh(Buffer: PChar);
  222. begin
  223. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  224. FFieldVal := False;
  225. end;
  226. //--TBufDatasetParser---------------------------------------------------------------
  227. constructor TBufDatasetParser.Create(Adataset: TDataSet);
  228. begin
  229. FDataset := Adataset;
  230. FFieldVarList := TStringList.Create;
  231. FCaseInsensitive := true;
  232. inherited Create;
  233. end;
  234. destructor TBufDatasetParser.Destroy;
  235. begin
  236. ClearExpressions;
  237. inherited;
  238. FreeAndNil(FFieldVarList);
  239. end;
  240. function TBufDatasetParser.GetResultType: TExpressionType;
  241. begin
  242. // if not a real expression, return type ourself
  243. if FIsExpression then
  244. Result := inherited GetResultType
  245. else
  246. Result := FFieldType;
  247. end;
  248. procedure TBufDatasetParser.SetCaseInsensitive(NewInsensitive: Boolean);
  249. begin
  250. if FCaseInsensitive <> NewInsensitive then
  251. begin
  252. // clear and regenerate functions
  253. FCaseInsensitive := NewInsensitive;
  254. FillExpressList;
  255. end;
  256. end;
  257. procedure TBufDatasetParser.SetPartialMatch(NewPartialMatch: boolean);
  258. begin
  259. if FPartialMatch <> NewPartialMatch then
  260. begin
  261. // refill function list
  262. FPartialMatch := NewPartialMatch;
  263. FillExpressList;
  264. end;
  265. end;
  266. procedure TBufDatasetParser.FillExpressList;
  267. var
  268. lExpression: string;
  269. begin
  270. lExpression := FCurrentExpression;
  271. ClearExpressions;
  272. FWordsList.FreeAll;
  273. FWordsList.AddList(DbfWordsGeneralList, 0, DbfWordsGeneralList.Count - 1);
  274. if FCaseInsensitive then
  275. begin
  276. FWordsList.AddList(DbfWordsInsensGeneralList, 0, DbfWordsInsensGeneralList.Count - 1);
  277. if FPartialMatch then
  278. begin
  279. FWordsList.AddList(DbfWordsInsensPartialList, 0, DbfWordsInsensPartialList.Count - 1);
  280. end else begin
  281. FWordsList.AddList(DbfWordsInsensNoPartialList, 0, DbfWordsInsensNoPartialList.Count - 1);
  282. end;
  283. end else begin
  284. FWordsList.AddList(DbfWordsSensGeneralList, 0, DbfWordsSensGeneralList.Count - 1);
  285. if FPartialMatch then
  286. begin
  287. FWordsList.AddList(DbfWordsSensPartialList, 0, DbfWordsSensPartialList.Count - 1);
  288. end else begin
  289. FWordsList.AddList(DbfWordsSensNoPartialList, 0, DbfWordsSensNoPartialList.Count - 1);
  290. end;
  291. end;
  292. if Length(lExpression) > 0 then
  293. ParseExpression(lExpression);
  294. end;
  295. function TBufDatasetParser.GetVariableInfo(VarName: string): TField;
  296. begin
  297. Result := FDataset.FindField(VarName);
  298. end;
  299. function TBufDatasetParser.CurrentExpression: string;
  300. begin
  301. Result := FCurrentExpression;
  302. end;
  303. procedure TBufDatasetParser.HandleUnknownVariable(VarName: string);
  304. var
  305. FieldInfo: TField;
  306. TempFieldVar: TFieldVar;
  307. begin
  308. // is this variable a fieldname?
  309. FieldInfo := GetVariableInfo(VarName);
  310. if FieldInfo = nil then
  311. raise EDatabaseError.CreateFmt(SErrIndexBasedOnUnkField, [VarName]);
  312. // define field in parser
  313. case FieldInfo.DataType of
  314. ftString:
  315. begin
  316. TempFieldVar := TStringFieldVar.Create(FieldInfo);
  317. TempFieldVar.FExprWord := DefineStringVariable(VarName, TempFieldVar.FieldVal);
  318. TempFieldVar.FExprWord.fixedlen := Fieldinfo.Size;
  319. end;
  320. ftBoolean:
  321. begin
  322. TempFieldVar := TBooleanFieldVar.Create(FieldInfo);
  323. TempFieldVar.FExprWord := DefineBooleanVariable(VarName, TempFieldVar.FieldVal);
  324. end;
  325. ftFloat:
  326. begin
  327. TempFieldVar := TFloatFieldVar.Create(FieldInfo);
  328. TempFieldVar.FExprWord := DefineFloatVariable(VarName, TempFieldVar.FieldVal);
  329. end;
  330. ftAutoInc, ftInteger, ftSmallInt:
  331. begin
  332. TempFieldVar := TIntegerFieldVar.Create(FieldInfo);
  333. TempFieldVar.FExprWord := DefineIntegerVariable(VarName, TempFieldVar.FieldVal);
  334. end;
  335. ftLargeInt:
  336. begin
  337. TempFieldVar := TLargeIntFieldVar.Create(FieldInfo);
  338. TempFieldVar.FExprWord := DefineLargeIntVariable(VarName, TempFieldVar.FieldVal);
  339. end;
  340. ftDate, ftDateTime:
  341. begin
  342. TempFieldVar := TDateTimeFieldVar.Create(FieldInfo);
  343. TempFieldVar.FExprWord := DefineDateTimeVariable(VarName, TempFieldVar.FieldVal);
  344. end;
  345. else
  346. raise EDatabaseError.CreateFmt(SErrIndexBasedOnInvField, [VarName]);
  347. end;
  348. // add to our own list
  349. FFieldVarList.AddObject(VarName, TempFieldVar);
  350. end;
  351. procedure TBufDatasetParser.ClearExpressions;
  352. var
  353. I: Integer;
  354. begin
  355. inherited;
  356. // test if already freed
  357. if FFieldVarList <> nil then
  358. begin
  359. // free field list
  360. for I := 0 to FFieldVarList.Count - 1 do
  361. begin
  362. // replacing with nil = undefining variable
  363. FWordsList.DoFree(TFieldVar(FFieldVarList.Objects[I]).FExprWord);
  364. TFieldVar(FFieldVarList.Objects[I]).Free;
  365. end;
  366. FFieldVarList.Clear;
  367. end;
  368. // clear expression
  369. FCurrentExpression := EmptyStr;
  370. end;
  371. procedure TBufDatasetParser.ParseExpression(AExpression: string);
  372. var
  373. TempBuffer: pchar;
  374. begin
  375. // clear any current expression
  376. ClearExpressions;
  377. // is this a simple field or complex expression?
  378. FIsExpression := GetVariableInfo(AExpression) = nil;
  379. if FIsExpression then
  380. begin
  381. // parse requested
  382. CompileExpression(AExpression);
  383. // determine length of string length expressions
  384. if ResultType = etString then
  385. begin
  386. // make empty record
  387. GetMem(TempBuffer, FDataset.RecordSize);
  388. try
  389. FillChar(TempBuffer^, FDataset.RecordSize, #0);
  390. FResultLen := StrLen(ExtractFromBuffer(TempBuffer));
  391. finally
  392. FreeMem(TempBuffer);
  393. end;
  394. end;
  395. end else begin
  396. // simple field, create field variable for it
  397. HandleUnknownVariable(AExpression);
  398. FFieldType := TFieldVar(FFieldVarList.Objects[0]).FieldType;
  399. // set result len of variable length fields
  400. if FFieldType = etString then
  401. FResultLen := TFieldVar(FFieldVarList.Objects[0]).FieldDef.Size
  402. end;
  403. // set result len for fixed length expressions / fields
  404. case ResultType of
  405. etBoolean: FResultLen := 1;
  406. etInteger: FResultLen := 4;
  407. etFloat: FResultLen := 8;
  408. etDateTime: FResultLen := 8;
  409. end;
  410. // check if expression not too long
  411. if FResultLen > 100 then
  412. raise EDatabaseError.CreateFmt(SErrIndexResultTooLong, [AExpression, FResultLen]);
  413. // if no errors, assign current expression
  414. FCurrentExpression := AExpression;
  415. end;
  416. function TBufDatasetParser.ExtractFromBuffer(Buffer: PChar): PChar;
  417. var
  418. I: Integer;
  419. begin
  420. // prepare all field variables
  421. for I := 0 to FFieldVarList.Count - 1 do
  422. TFieldVar(FFieldVarList.Objects[I]).Refresh(Buffer);
  423. // complex expression?
  424. if FIsExpression then
  425. begin
  426. // execute expression
  427. EvaluateCurrent;
  428. Result := ExpResult;
  429. end else begin
  430. // simple field, get field result
  431. Result := TFieldVar(FFieldVarList.Objects[0]).FieldVal;
  432. // if string then dereference
  433. if FFieldType = etString then
  434. Result := PPChar(Result)^;
  435. end;
  436. end;
  437. end.