bufdataset_parser.pp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511
  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: TRecordBuffer): 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: TRecordBuffer); 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: TRecordBuffer); 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: TRecordBuffer); 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: TRecordBuffer); 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: TRecordBuffer); 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: TRecordBuffer); 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: TRecordBuffer); 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: TRecordBuffer);
  147. var Fieldbuf : TStringFieldBuffer;
  148. begin
  149. if not FField.DataSet.GetFieldData(FField,@Fieldbuf) then
  150. FFieldVal^:=#0
  151. else
  152. strcopy(FFieldVal,@Fieldbuf[0]);
  153. end;
  154. //--TFloatFieldVar-----------------------------------------------------------
  155. function TFloatFieldVar.GetFieldVal: Pointer;
  156. begin
  157. Result := @FFieldVal;
  158. end;
  159. function TFloatFieldVar.GetFieldType: TExpressionType;
  160. begin
  161. Result := etFloat;
  162. end;
  163. procedure TFloatFieldVar.Refresh(Buffer: TRecordBuffer);
  164. begin
  165. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  166. FFieldVal := 0;
  167. end;
  168. //--TIntegerFieldVar----------------------------------------------------------
  169. function TIntegerFieldVar.GetFieldVal: Pointer;
  170. begin
  171. Result := @FFieldVal;
  172. end;
  173. function TIntegerFieldVar.GetFieldType: TExpressionType;
  174. begin
  175. Result := etInteger;
  176. end;
  177. procedure TIntegerFieldVar.Refresh(Buffer: TRecordBuffer);
  178. begin
  179. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  180. FFieldVal := 0;
  181. end;
  182. //--TLargeIntFieldVar----------------------------------------------------------
  183. function TLargeIntFieldVar.GetFieldVal: Pointer;
  184. begin
  185. Result := @FFieldVal;
  186. end;
  187. function TLargeIntFieldVar.GetFieldType: TExpressionType;
  188. begin
  189. Result := etLargeInt;
  190. end;
  191. procedure TLargeIntFieldVar.Refresh(Buffer: TRecordBuffer);
  192. begin
  193. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  194. FFieldVal := 0;
  195. end;
  196. //--TDateTimeFieldVar---------------------------------------------------------
  197. function TDateTimeFieldVar.GetFieldVal: Pointer;
  198. begin
  199. Result := @FFieldVal;
  200. end;
  201. function TDateTimeFieldVar.GetFieldType: TExpressionType;
  202. begin
  203. Result := etDateTime;
  204. end;
  205. procedure TDateTimeFieldVar.Refresh(Buffer:TRecordBuffer );
  206. begin
  207. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  208. FFieldVal := 0;
  209. end;
  210. //--TBooleanFieldVar---------------------------------------------------------
  211. function TBooleanFieldVar.GetFieldVal: Pointer;
  212. begin
  213. Result := @FFieldVal;
  214. end;
  215. function TBooleanFieldVar.GetFieldType: TExpressionType;
  216. begin
  217. Result := etBoolean;
  218. end;
  219. procedure TBooleanFieldVar.Refresh(Buffer: TRecordBuffer);
  220. begin
  221. if not FField.DataSet.GetFieldData(FField,@FFieldVal) then
  222. FFieldVal := False;
  223. end;
  224. //--TBufDatasetParser---------------------------------------------------------------
  225. constructor TBufDatasetParser.Create(Adataset: TDataSet);
  226. begin
  227. FDataset := Adataset;
  228. FFieldVarList := TStringList.Create;
  229. FCaseInsensitive := true;
  230. inherited Create;
  231. end;
  232. destructor TBufDatasetParser.Destroy;
  233. begin
  234. ClearExpressions;
  235. inherited;
  236. FreeAndNil(FFieldVarList);
  237. end;
  238. function TBufDatasetParser.GetResultType: TExpressionType;
  239. begin
  240. // if not a real expression, return type ourself
  241. if FIsExpression then
  242. Result := inherited GetResultType
  243. else
  244. Result := FFieldType;
  245. end;
  246. procedure TBufDatasetParser.SetCaseInsensitive(NewInsensitive: Boolean);
  247. begin
  248. if FCaseInsensitive <> NewInsensitive then
  249. begin
  250. // clear and regenerate functions
  251. FCaseInsensitive := NewInsensitive;
  252. FillExpressList;
  253. end;
  254. end;
  255. procedure TBufDatasetParser.SetPartialMatch(NewPartialMatch: boolean);
  256. begin
  257. if FPartialMatch <> NewPartialMatch then
  258. begin
  259. // refill function list
  260. FPartialMatch := NewPartialMatch;
  261. FillExpressList;
  262. end;
  263. end;
  264. procedure TBufDatasetParser.FillExpressList;
  265. var
  266. lExpression: string;
  267. begin
  268. lExpression := FCurrentExpression;
  269. ClearExpressions;
  270. FWordsList.FreeAll;
  271. FWordsList.AddList(DbfWordsGeneralList, 0, DbfWordsGeneralList.Count - 1);
  272. if FCaseInsensitive then
  273. begin
  274. FWordsList.AddList(DbfWordsInsensGeneralList, 0, DbfWordsInsensGeneralList.Count - 1);
  275. if FPartialMatch then
  276. begin
  277. FWordsList.AddList(DbfWordsInsensPartialList, 0, DbfWordsInsensPartialList.Count - 1);
  278. end else begin
  279. FWordsList.AddList(DbfWordsInsensNoPartialList, 0, DbfWordsInsensNoPartialList.Count - 1);
  280. end;
  281. end else begin
  282. FWordsList.AddList(DbfWordsSensGeneralList, 0, DbfWordsSensGeneralList.Count - 1);
  283. if FPartialMatch then
  284. begin
  285. FWordsList.AddList(DbfWordsSensPartialList, 0, DbfWordsSensPartialList.Count - 1);
  286. end else begin
  287. FWordsList.AddList(DbfWordsSensNoPartialList, 0, DbfWordsSensNoPartialList.Count - 1);
  288. end;
  289. end;
  290. if Length(lExpression) > 0 then
  291. ParseExpression(lExpression);
  292. end;
  293. function TBufDatasetParser.GetVariableInfo(VarName: string): TField;
  294. begin
  295. Result := FDataset.FindField(VarName);
  296. end;
  297. function TBufDatasetParser.CurrentExpression: string;
  298. begin
  299. Result := FCurrentExpression;
  300. end;
  301. procedure TBufDatasetParser.HandleUnknownVariable(VarName: string);
  302. var
  303. FieldInfo: TField;
  304. TempFieldVar: TFieldVar;
  305. begin
  306. // is this variable a fieldname?
  307. FieldInfo := GetVariableInfo(VarName);
  308. if FieldInfo = nil then
  309. raise EDatabaseError.CreateFmt(SErrIndexBasedOnUnkField, [VarName]);
  310. // define field in parser
  311. case FieldInfo.DataType of
  312. ftString, ftFixedChar:
  313. begin
  314. TempFieldVar := TStringFieldVar.Create(FieldInfo);
  315. TempFieldVar.FExprWord := DefineStringVariable(VarName, TempFieldVar.FieldVal);
  316. TempFieldVar.FExprWord.fixedlen := Fieldinfo.Size;
  317. end;
  318. ftBoolean:
  319. begin
  320. TempFieldVar := TBooleanFieldVar.Create(FieldInfo);
  321. TempFieldVar.FExprWord := DefineBooleanVariable(VarName, TempFieldVar.FieldVal);
  322. end;
  323. ftFloat:
  324. begin
  325. TempFieldVar := TFloatFieldVar.Create(FieldInfo);
  326. TempFieldVar.FExprWord := DefineFloatVariable(VarName, TempFieldVar.FieldVal);
  327. end;
  328. ftAutoInc, ftInteger, ftSmallInt:
  329. begin
  330. TempFieldVar := TIntegerFieldVar.Create(FieldInfo);
  331. TempFieldVar.FExprWord := DefineIntegerVariable(VarName, TempFieldVar.FieldVal);
  332. end;
  333. ftLargeInt:
  334. begin
  335. TempFieldVar := TLargeIntFieldVar.Create(FieldInfo);
  336. TempFieldVar.FExprWord := DefineLargeIntVariable(VarName, TempFieldVar.FieldVal);
  337. end;
  338. ftDate, ftDateTime:
  339. begin
  340. TempFieldVar := TDateTimeFieldVar.Create(FieldInfo);
  341. TempFieldVar.FExprWord := DefineDateTimeVariable(VarName, TempFieldVar.FieldVal);
  342. end;
  343. else
  344. raise EDatabaseError.CreateFmt(SErrIndexBasedOnInvField, [VarName,Fieldtypenames[FieldInfo.DataType]]);
  345. end;
  346. // add to our own list
  347. FFieldVarList.AddObject(VarName, TempFieldVar);
  348. end;
  349. procedure TBufDatasetParser.ClearExpressions;
  350. var
  351. I: Integer;
  352. begin
  353. inherited;
  354. // test if already freed
  355. if FFieldVarList <> nil then
  356. begin
  357. // free field list
  358. for I := 0 to FFieldVarList.Count - 1 do
  359. begin
  360. // replacing with nil = undefining variable
  361. FWordsList.DoFree(TFieldVar(FFieldVarList.Objects[I]).FExprWord);
  362. TFieldVar(FFieldVarList.Objects[I]).Free;
  363. end;
  364. FFieldVarList.Clear;
  365. end;
  366. // clear expression
  367. FCurrentExpression := EmptyStr;
  368. end;
  369. procedure TBufDatasetParser.ParseExpression(AExpression: string);
  370. var
  371. TempBuffer: TRecordBuffer;
  372. begin
  373. // clear any current expression
  374. ClearExpressions;
  375. // is this a simple field or complex expression?
  376. FIsExpression := GetVariableInfo(AExpression) = nil;
  377. if FIsExpression then
  378. begin
  379. // parse requested
  380. CompileExpression(AExpression);
  381. // determine length of string length expressions
  382. if ResultType = etString then
  383. begin
  384. // make empty record
  385. GetMem(TempBuffer, FDataset.RecordSize);
  386. try
  387. FillChar(TempBuffer^, FDataset.RecordSize, #0);
  388. FResultLen := StrLen(ExtractFromBuffer(TempBuffer));
  389. finally
  390. FreeMem(TempBuffer);
  391. end;
  392. end;
  393. end else begin
  394. // simple field, create field variable for it
  395. HandleUnknownVariable(AExpression);
  396. FFieldType := TFieldVar(FFieldVarList.Objects[0]).FieldType;
  397. // set result len of variable length fields
  398. if FFieldType = etString then
  399. FResultLen := TFieldVar(FFieldVarList.Objects[0]).FieldDef.Size
  400. end;
  401. // set result len for fixed length expressions / fields
  402. case ResultType of
  403. etBoolean: FResultLen := 1;
  404. etInteger: FResultLen := 4;
  405. etFloat: FResultLen := 8;
  406. etDateTime: FResultLen := 8;
  407. end;
  408. // check if expression not too long
  409. if FResultLen > 100 then
  410. raise EDatabaseError.CreateFmt(SErrIndexResultTooLong, [AExpression, FResultLen]);
  411. // if no errors, assign current expression
  412. FCurrentExpression := AExpression;
  413. end;
  414. function TBufDatasetParser.ExtractFromBuffer(Buffer: TRecordBuffer): PChar;
  415. var
  416. I: Integer;
  417. begin
  418. // prepare all field variables
  419. for I := 0 to FFieldVarList.Count - 1 do
  420. TFieldVar(FFieldVarList.Objects[I]).Refresh(Buffer);
  421. // complex expression?
  422. if FIsExpression then
  423. begin
  424. // execute expression
  425. EvaluateCurrent;
  426. Result := ExpResult;
  427. end else begin
  428. // simple field, get field result
  429. Result := TFieldVar(FFieldVarList.Objects[0]).FieldVal;
  430. // if string then dereference
  431. if FFieldType = etString then
  432. Result := PPChar(Result)^;
  433. end;
  434. end;
  435. end.