dsparams.inc 27 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177
  1. procedure SkipQuotesString(var p : pchar; QuoteChar : char; EscapeSlash, EscapeRepeat : Boolean);
  2. var notRepeatEscaped : boolean;
  3. begin
  4. Inc(p);
  5. repeat
  6. notRepeatEscaped := True;
  7. while not (p^ in [#0, QuoteChar]) do
  8. begin
  9. if EscapeSlash and (p^='\') and (p[1] <> #0) then Inc(p,2) // make sure we handle \' and \\ correct
  10. else Inc(p);
  11. end;
  12. if p^=QuoteChar then
  13. begin
  14. Inc(p); // skip final '
  15. if (p^=QuoteChar) and EscapeRepeat then // Handle escaping by ''
  16. begin
  17. notRepeatEscaped := False;
  18. inc(p);
  19. end
  20. end;
  21. until notRepeatEscaped;
  22. end;
  23. { TParamsEnumerator }
  24. function TParamsEnumerator.GetCurrent: TParam;
  25. begin
  26. Result := FParams[FPosition];
  27. end;
  28. constructor TParamsEnumerator.Create(AParams: TParams);
  29. begin
  30. inherited Create;
  31. FParams := AParams;
  32. FPosition := -1;
  33. end;
  34. function TParamsEnumerator.MoveNext: Boolean;
  35. begin
  36. inc(FPosition);
  37. Result := FPosition < FParams.Count;
  38. end;
  39. { TParams }
  40. Function TParams.GetItem(Index: Integer): TParam;
  41. begin
  42. Result:=(Inherited GetItem(Index)) as TParam;
  43. end;
  44. Function TParams.GetParamValue(const ParamName: string): Variant;
  45. begin
  46. Result:=ParamByName(ParamName).Value;
  47. end;
  48. Procedure TParams.SetItem(Index: Integer; Value: TParam);
  49. begin
  50. Inherited SetItem(Index,Value);
  51. end;
  52. Procedure TParams.SetParamValue(const ParamName: string; const Value: Variant);
  53. begin
  54. ParamByName(ParamName).Value:=Value;
  55. end;
  56. Procedure TParams.AssignTo(Dest: TPersistent);
  57. begin
  58. if (Dest is TParams) then
  59. TParams(Dest).Assign(Self)
  60. else
  61. inherited AssignTo(Dest);
  62. end;
  63. Function TParams.GetDataSet: TDataSet;
  64. begin
  65. If (FOwner is TDataset) Then
  66. Result:=TDataset(FOwner)
  67. else
  68. Result:=Nil;
  69. end;
  70. Function TParams.GetOwner: TPersistent;
  71. begin
  72. Result:=FOwner;
  73. end;
  74. Class Function TParams.ParamClass: TParamClass;
  75. begin
  76. Result:=TParam;
  77. end;
  78. Constructor TParams.Create(AOwner: TPersistent; AItemClass: TCollectionItemClass
  79. );
  80. begin
  81. Inherited Create(AItemClass);
  82. FOwner:=AOwner;
  83. end;
  84. Constructor TParams.Create(AOwner: TPersistent);
  85. begin
  86. Create(AOwner,ParamClass);
  87. end;
  88. Constructor TParams.Create;
  89. begin
  90. Create(TPersistent(Nil));
  91. end;
  92. Procedure TParams.AddParam(Value: TParam);
  93. begin
  94. Value.Collection:=Self;
  95. end;
  96. Procedure TParams.AssignValues(Value: TParams);
  97. Var
  98. I : Integer;
  99. P,PS : TParam;
  100. begin
  101. For I:=0 to Value.Count-1 do
  102. begin
  103. PS:=Value[i];
  104. P:=FindParam(PS.Name);
  105. If Assigned(P) then
  106. P.Assign(PS);
  107. end;
  108. end;
  109. Function TParams.CreateParam(FldType: TFieldType; const ParamName: string;
  110. ParamType: TParamType): TParam;
  111. begin
  112. Result:=Add as TParam;
  113. Result.Name:=ParamName;
  114. Result.DataType:=FldType;
  115. Result.ParamType:=ParamType;
  116. end;
  117. Function TParams.FindParam(const Value: string): TParam;
  118. Var
  119. I : Integer;
  120. begin
  121. Result:=Nil;
  122. I:=Count-1;
  123. While (Result=Nil) and (I>=0) do
  124. If (CompareText(Value,Items[i].Name)=0) then
  125. Result:=Items[i]
  126. else
  127. Dec(i);
  128. end;
  129. Procedure TParams.GetParamList(List: TList; const ParamNames: string);
  130. Var
  131. P: TParam;
  132. N: String;
  133. StrPos: Integer;
  134. begin
  135. if (ParamNames = '') or (List = nil) then
  136. Exit;
  137. StrPos := 1;
  138. repeat
  139. N := ExtractFieldName(ParamNames, StrPos);
  140. P := ParamByName(N);
  141. List.Add(P);
  142. until StrPos > Length(ParamNames);
  143. end;
  144. Function TParams.IsEqual(Value: TParams): Boolean;
  145. Var
  146. I : Integer;
  147. begin
  148. Result:=(Value.Count=Count);
  149. I:=Count-1;
  150. While Result and (I>=0) do
  151. begin
  152. Result:=Items[I].IsEqual(Value[i]);
  153. Dec(I);
  154. end;
  155. end;
  156. Function TParams.GetEnumerator: TParamsEnumerator;
  157. begin
  158. Result:=TParamsEnumerator.Create(Self);
  159. end;
  160. Function TParams.ParamByName(const Value: string): TParam;
  161. begin
  162. Result:=FindParam(Value);
  163. If (Result=Nil) then
  164. DatabaseErrorFmt(SParameterNotFound,[Value],Dataset);
  165. end;
  166. Function TParams.ParseSQL(SQL: String; DoCreate: Boolean): String;
  167. var pb : TParamBinding;
  168. rs : string;
  169. begin
  170. Result := ParseSQL(SQL,DoCreate,True,True,psInterbase, pb, rs);
  171. end;
  172. Function TParams.ParseSQL(SQL: String; DoCreate, EscapeSlash,
  173. EscapeRepeat: Boolean; ParameterStyle: TParamStyle): String;
  174. var pb : TParamBinding;
  175. rs : string;
  176. begin
  177. Result := ParseSQL(SQL,DoCreate,EscapeSlash,EscapeRepeat,ParameterStyle,pb, rs);
  178. end;
  179. Function TParams.ParseSQL(SQL: String; DoCreate, EscapeSlash,
  180. EscapeRepeat: Boolean; ParameterStyle: TParamStyle; out
  181. ParamBinding: TParambinding): String;
  182. var rs : string;
  183. begin
  184. Result := ParseSQL(SQL,DoCreate,EscapeSlash, EscapeRepeat, ParameterStyle,ParamBinding, rs);
  185. end;
  186. function SkipComments(var p: PChar; EscapeSlash, EscapeRepeat : Boolean) : Boolean;
  187. begin
  188. Result := False;
  189. case p^ of
  190. '''', '"', '`':
  191. begin
  192. Result := True;
  193. // single quote, double quote or backtick delimited string
  194. SkipQuotesString(p, p^, EscapeSlash, EscapeRepeat);
  195. end;
  196. '-': // possible start of -- comment
  197. begin
  198. Inc(p);
  199. if p^='-' then // -- comment
  200. begin
  201. Result := True;
  202. repeat // skip until at end of line
  203. Inc(p);
  204. until p^ in [#10, #13, #0];
  205. while p^ in [#10, #13] do Inc(p); // newline is part of comment
  206. end;
  207. end;
  208. '/': // possible start of /* */ comment
  209. begin
  210. Inc(p);
  211. if p^='*' then // /* */ comment
  212. begin
  213. Result := True;
  214. Inc(p);
  215. while p^ <> #0 do
  216. begin
  217. if p^='*' then // possible end of comment
  218. begin
  219. Inc(p);
  220. if p^='/' then Break; // end of comment
  221. end
  222. else
  223. Inc(p);
  224. end;
  225. if p^='/' then Inc(p); // skip final /
  226. end;
  227. end;
  228. end; {case}
  229. end;
  230. Function TParams.ParseSQL(SQL: String; DoCreate, EscapeSlash,
  231. EscapeRepeat: Boolean; ParameterStyle: TParamStyle; out
  232. ParamBinding: TParambinding; out ReplaceString: string): String;
  233. type
  234. // used for ParamPart
  235. TStringPart = record
  236. Start,Stop:integer;
  237. end;
  238. const
  239. ParamAllocStepSize = 8;
  240. var
  241. IgnorePart:boolean;
  242. p,ParamNameStart,BufStart:PChar;
  243. ParamName:string;
  244. QuestionMarkParamCount,ParameterIndex,NewLength:integer;
  245. ParamCount:integer; // actual number of parameters encountered so far;
  246. // always <= Length(ParamPart) = Length(Parambinding)
  247. // Parambinding will have length ParamCount in the end
  248. ParamPart:array of TStringPart; // describe which parts of buf are parameters
  249. NewQueryLength:integer;
  250. NewQuery:string;
  251. NewQueryIndex,BufIndex,CopyLen,i:integer; // Parambinding will have length ParamCount in the end
  252. b:integer;
  253. tmpParam:TParam;
  254. begin
  255. if DoCreate then Clear;
  256. // Parse the SQL and build ParamBinding
  257. ParamCount:=0;
  258. NewQueryLength:=Length(SQL);
  259. SetLength(ParamPart,ParamAllocStepSize);
  260. SetLength(ParamBinding,ParamAllocStepSize);
  261. QuestionMarkParamCount:=0; // number of ? params found in query so far
  262. ReplaceString := '$';
  263. if ParameterStyle = psSimulated then
  264. while pos(ReplaceString,SQL) > 0 do ReplaceString := ReplaceString+'$';
  265. p:=PChar(SQL);
  266. BufStart:=p; // used to calculate ParamPart.Start values
  267. repeat
  268. while SkipComments(p,EscapeSlash,EscapeRepeat) do ;
  269. case p^ of
  270. ':','?': // parameter
  271. begin
  272. IgnorePart := False;
  273. if p^=':' then
  274. begin // find parameter name
  275. Inc(p);
  276. if p^ in [':','=',' '] then // ignore ::, since some databases uses this as a cast (wb 4813)
  277. begin
  278. IgnorePart := True;
  279. Inc(p);
  280. end
  281. else
  282. begin
  283. if p^='"' then // Check if the parameter-name is between quotes
  284. begin
  285. ParamNameStart:=p;
  286. SkipQuotesString(p,'"',EscapeSlash,EscapeRepeat);
  287. // Do not include the quotes in ParamName, but they must be included
  288. // when the parameter is replaced by some place-holder.
  289. ParamName:=Copy(ParamNameStart+1,1,p-ParamNameStart-2);
  290. end
  291. else
  292. begin
  293. ParamNameStart:=p;
  294. while not (p^ in (SQLDelimiterCharacters+[#0,'=','+','-','*','\','/','[',']','|'])) do
  295. Inc(p);
  296. ParamName:=Copy(ParamNameStart,1,p-ParamNameStart);
  297. end;
  298. end;
  299. end
  300. else
  301. begin
  302. Inc(p);
  303. ParamNameStart:=p;
  304. ParamName:='';
  305. end;
  306. if not IgnorePart then
  307. begin
  308. Inc(ParamCount);
  309. if ParamCount>Length(ParamPart) then
  310. begin
  311. NewLength:=Length(ParamPart)+ParamAllocStepSize;
  312. SetLength(ParamPart,NewLength);
  313. SetLength(ParamBinding,NewLength);
  314. end;
  315. if DoCreate then
  316. begin
  317. // Check if this is the first occurance of the parameter
  318. tmpParam := FindParam(ParamName);
  319. // If so, create the parameter and assign the Parameterindex
  320. if not assigned(tmpParam) then
  321. ParameterIndex := CreateParam(ftUnknown, ParamName, ptInput).Index
  322. else // else only assign the ParameterIndex
  323. ParameterIndex := tmpParam.Index;
  324. end
  325. // else find ParameterIndex
  326. else
  327. begin
  328. if ParamName<>'' then
  329. ParameterIndex:=ParamByName(ParamName).Index
  330. else
  331. begin
  332. ParameterIndex:=QuestionMarkParamCount;
  333. Inc(QuestionMarkParamCount);
  334. end;
  335. end;
  336. if ParameterStyle in [psPostgreSQL,psSimulated] then
  337. begin
  338. i:=ParameterIndex+1;
  339. repeat
  340. inc(NewQueryLength);
  341. i:=i div 10;
  342. until i=0;
  343. end;
  344. // store ParameterIndex in FParamIndex, ParamPart data
  345. ParamBinding[ParamCount-1]:=ParameterIndex;
  346. ParamPart[ParamCount-1].Start:=ParamNameStart-BufStart;
  347. ParamPart[ParamCount-1].Stop:=p-BufStart+1;
  348. // update NewQueryLength
  349. Dec(NewQueryLength,p-ParamNameStart);
  350. end;
  351. end;
  352. #0:Break; // end of SQL
  353. else
  354. Inc(p);
  355. end;
  356. until false;
  357. SetLength(ParamPart,ParamCount);
  358. SetLength(ParamBinding,ParamCount);
  359. if ParamCount>0 then
  360. begin
  361. // replace :ParamName by ? for interbase and by $x for postgresql/psSimulated
  362. // (using ParamPart array and NewQueryLength)
  363. if (ParameterStyle = psSimulated) and (length(ReplaceString) > 1) then
  364. inc(NewQueryLength,(paramcount)*(length(ReplaceString)-1));
  365. SetLength(NewQuery,NewQueryLength);
  366. NewQueryIndex:=1;
  367. BufIndex:=1;
  368. for i:=0 to High(ParamPart) do
  369. begin
  370. CopyLen:=ParamPart[i].Start-BufIndex;
  371. Move(SQL[BufIndex],NewQuery[NewQueryIndex],CopyLen);
  372. Inc(NewQueryIndex,CopyLen);
  373. case ParameterStyle of
  374. psInterbase : begin
  375. NewQuery[NewQueryIndex]:='?';
  376. Inc(NewQueryIndex);
  377. end;
  378. psPostgreSQL,
  379. psSimulated : begin
  380. ParamName := IntToStr(ParamBinding[i]+1);
  381. for b := 1 to length(ReplaceString) do
  382. begin
  383. NewQuery[NewQueryIndex]:='$';
  384. Inc(NewQueryIndex);
  385. end;
  386. for b := 1 to length(ParamName) do
  387. begin
  388. NewQuery[NewQueryIndex]:=ParamName[b];
  389. Inc(NewQueryIndex);
  390. end;
  391. end;
  392. end;
  393. BufIndex:=ParamPart[i].Stop;
  394. end;
  395. CopyLen:=Length(SQL)+1-BufIndex;
  396. if CopyLen > 0 then
  397. Move(SQL[BufIndex],NewQuery[NewQueryIndex],CopyLen);
  398. end
  399. else
  400. NewQuery:=SQL;
  401. Result := NewQuery;
  402. end;
  403. Procedure TParams.RemoveParam(Value: TParam);
  404. begin
  405. Value.Collection:=Nil;
  406. end;
  407. { TParam }
  408. Function TParam.GetDataSet: TDataSet;
  409. begin
  410. If Assigned(Collection) and (Collection is TParams) then
  411. Result:=TParams(Collection).GetDataset
  412. else
  413. Result:=Nil;
  414. end;
  415. Function TParam.IsParamStored: Boolean;
  416. begin
  417. Result:=Bound;
  418. end;
  419. Procedure TParam.AssignParam(Param: TParam);
  420. begin
  421. if Not Assigned(Param) then
  422. begin
  423. Clear;
  424. FDataType:=ftunknown;
  425. FParamType:=ptUnknown;
  426. Name:='';
  427. Size:=0;
  428. Precision:=0;
  429. NumericScale:=0;
  430. end
  431. else
  432. begin
  433. FDataType:=Param.DataType;
  434. if Param.IsNull then
  435. Clear
  436. else
  437. FValue:=Param.FValue;
  438. FBound:=Param.Bound;
  439. Name:=Param.Name;
  440. if (ParamType=ptUnknown) then
  441. ParamType:=Param.ParamType;
  442. Size:=Param.Size;
  443. Precision:=Param.Precision;
  444. NumericScale:=Param.NumericScale;
  445. end;
  446. end;
  447. Procedure TParam.AssignTo(Dest: TPersistent);
  448. begin
  449. if (Dest is TField) then
  450. AssignToField(TField(Dest))
  451. else
  452. inherited AssignTo(Dest);
  453. end;
  454. Function TParam.GetAsBoolean: Boolean;
  455. begin
  456. If IsNull then
  457. Result:=False
  458. else
  459. Result:=FValue;
  460. end;
  461. function TParam.GetAsBytes: TBytes;
  462. begin
  463. if IsNull then
  464. Result:=nil
  465. else if VarIsArray(FValue) then
  466. Result:=FValue
  467. else
  468. // todo: conversion from other variant types to TBytes
  469. Result:=FValue;
  470. end;
  471. Function TParam.GetAsCurrency: Currency;
  472. begin
  473. If IsNull then
  474. Result:=0.0
  475. else
  476. Result:=FValue;
  477. end;
  478. Function TParam.GetAsDateTime: TDateTime;
  479. begin
  480. If IsNull then
  481. Result:=0.0
  482. else
  483. Result:=FValue;
  484. end;
  485. Function TParam.GetAsFloat: Double;
  486. begin
  487. If IsNull then
  488. Result:=0.0
  489. else
  490. Result:=FValue;
  491. end;
  492. Function TParam.GetAsInteger: Longint;
  493. begin
  494. If IsNull then
  495. Result:=0
  496. else
  497. Result:=FValue;
  498. end;
  499. Function TParam.GetAsLargeInt: LargeInt;
  500. begin
  501. If IsNull then
  502. Result:=0
  503. else
  504. Result:=FValue;
  505. end;
  506. Function TParam.GetAsMemo: string;
  507. begin
  508. If IsNull then
  509. Result:=''
  510. else
  511. Result:=FValue;
  512. end;
  513. Function TParam.GetAsString: string;
  514. var P: Pointer;
  515. begin
  516. If IsNull then
  517. Result:=''
  518. else if (FDataType in [ftBytes, ftVarBytes]) and VarIsArray(FValue) then
  519. begin
  520. SetLength(Result, (VarArrayHighBound(FValue, 1) + 1) div SizeOf(Char));
  521. P := VarArrayLock(FValue);
  522. try
  523. Move(P^, Result[1], Length(Result) * SizeOf(Char));
  524. finally
  525. VarArrayUnlock(FValue);
  526. end;
  527. end
  528. else
  529. Result:=FValue;
  530. end;
  531. function TParam.GetAsWideString: WideString;
  532. begin
  533. if IsNull then
  534. Result := ''
  535. else
  536. Result := FValue;
  537. end;
  538. Function TParam.GetAsVariant: Variant;
  539. begin
  540. if IsNull then
  541. Result:=Null
  542. else
  543. Result:=FValue;
  544. end;
  545. function TParam.GetAsFMTBCD: TBCD;
  546. begin
  547. If IsNull then
  548. Result:=0
  549. else
  550. Result:=VarToBCD(FValue);
  551. end;
  552. Function TParam.GetDisplayName: string;
  553. begin
  554. if (FName<>'') then
  555. Result:=FName
  556. else
  557. Result:=inherited GetDisplayName
  558. end;
  559. Function TParam.GetIsNull: Boolean;
  560. begin
  561. Result:= VarIsNull(FValue) or VarIsClear(FValue);
  562. end;
  563. Function TParam.IsEqual(AValue: TParam): Boolean;
  564. begin
  565. Result:=(Name=AValue.Name)
  566. and (IsNull=AValue.IsNull)
  567. and (Bound=AValue.Bound)
  568. and (DataType=AValue.DataType)
  569. and (ParamType=AValue.ParamType)
  570. and (VarType(FValue)=VarType(AValue.FValue))
  571. and (FValue=AValue.FValue);
  572. end;
  573. procedure TParam.SetAsBCD(const AValue: Currency);
  574. begin
  575. FDataType:=ftBCD;
  576. Value:=AValue;
  577. end;
  578. Procedure TParam.SetAsBlob(const AValue: TBlobData);
  579. begin
  580. FDataType:=ftBlob;
  581. Value:=AValue;
  582. end;
  583. Procedure TParam.SetAsBoolean(AValue: Boolean);
  584. begin
  585. FDataType:=ftBoolean;
  586. Value:=AValue;
  587. end;
  588. procedure TParam.SetAsBytes(const AValue: TBytes);
  589. begin
  590. FDataType:=ftVarBytes;
  591. Value:=AValue;
  592. end;
  593. Procedure TParam.SetAsCurrency(const AValue: Currency);
  594. begin
  595. FDataType:=ftCurrency;
  596. Value:=AValue;
  597. end;
  598. Procedure TParam.SetAsDate(const AValue: TDateTime);
  599. begin
  600. FDataType:=ftDate;
  601. Value:=AValue;
  602. end;
  603. Procedure TParam.SetAsDateTime(const AValue: TDateTime);
  604. begin
  605. FDataType:=ftDateTime;
  606. Value:=AValue;
  607. end;
  608. Procedure TParam.SetAsFloat(const AValue: Double);
  609. begin
  610. FDataType:=ftFloat;
  611. Value:=AValue;
  612. end;
  613. Procedure TParam.SetAsInteger(AValue: Longint);
  614. begin
  615. FDataType:=ftInteger;
  616. Value:=AValue;
  617. end;
  618. Procedure TParam.SetAsLargeInt(AValue: LargeInt);
  619. begin
  620. FDataType:=ftLargeint;
  621. Value:=AValue;
  622. end;
  623. Procedure TParam.SetAsMemo(const AValue: string);
  624. begin
  625. FDataType:=ftMemo;
  626. Value:=AValue;
  627. end;
  628. Procedure TParam.SetAsSmallInt(AValue: LongInt);
  629. begin
  630. FDataType:=ftSmallInt;
  631. Value:=AValue;
  632. end;
  633. Procedure TParam.SetAsString(const AValue: string);
  634. begin
  635. if FDataType <> ftFixedChar then
  636. FDataType := ftString;
  637. Value:=AValue;
  638. end;
  639. procedure TParam.SetAsWideString(const aValue: WideString);
  640. begin
  641. if FDataType <> ftFixedWideChar then
  642. FDataType := ftWideString;
  643. Value := aValue;
  644. end;
  645. Procedure TParam.SetAsTime(const AValue: TDateTime);
  646. begin
  647. FDataType:=ftTime;
  648. Value:=AValue;
  649. end;
  650. Procedure TParam.SetAsVariant(const AValue: Variant);
  651. begin
  652. FValue:=AValue;
  653. FBound:=not VarIsClear(AValue);
  654. if FDataType = ftUnknown then
  655. case VarType(Value) of
  656. varBoolean : FDataType:=ftBoolean;
  657. varSmallint,
  658. varShortInt,
  659. varByte : FDataType:=ftSmallInt;
  660. varWord,
  661. varInteger : FDataType:=ftInteger;
  662. varCurrency : FDataType:=ftCurrency;
  663. varLongWord,
  664. varSingle,
  665. varDouble : FDataType:=ftFloat;
  666. varDate : FDataType:=ftDateTime;
  667. varString,
  668. varOleStr : if (FDataType<>ftFixedChar) then
  669. FDataType:=ftString;
  670. varInt64 : FDataType:=ftLargeInt;
  671. else
  672. if VarIsFmtBCD(Value) then
  673. FDataType:=ftFmtBCD
  674. else if VarIsArray(AValue) and (VarType(AValue) and varTypeMask = varByte) then
  675. FDataType:=ftVarBytes
  676. else
  677. FDataType:=ftUnknown;
  678. end;
  679. end;
  680. Procedure TParam.SetAsWord(AValue: LongInt);
  681. begin
  682. FDataType:=ftWord;
  683. Value:=AValue;
  684. end;
  685. procedure TParam.SetAsFMTBCD(const AValue: TBCD);
  686. begin
  687. FDataType:=ftFMTBcd;
  688. FValue:=VarFmtBCDCreate(AValue);
  689. end;
  690. Procedure TParam.SetDataType(AValue: TFieldType);
  691. Var
  692. VT : Integer;
  693. begin
  694. FDataType:=AValue;
  695. VT:=FieldTypetoVariantMap[AValue];
  696. If (VT=varError) then
  697. clear
  698. else
  699. if not VarIsEmpty(FValue) then
  700. begin
  701. Try
  702. FValue:=VarAsType(FValue,VT)
  703. except
  704. Clear;
  705. end { try }
  706. end;
  707. end;
  708. Procedure TParam.SetText(const AValue: string);
  709. begin
  710. Value:=AValue;
  711. end;
  712. constructor TParam.Create(ACollection: TCollection);
  713. begin
  714. inherited Create(ACollection);
  715. ParamType:=ptUnknown;
  716. DataType:=ftUnknown;
  717. FValue:=Unassigned;
  718. end;
  719. constructor TParam.Create(AParams: TParams; AParamType: TParamType);
  720. begin
  721. Create(AParams);
  722. ParamType:=AParamType;
  723. end;
  724. Procedure TParam.Assign(Source: TPersistent);
  725. begin
  726. if (Source is TParam) then
  727. AssignParam(TParam(Source))
  728. else if (Source is TField) then
  729. AssignField(TField(Source))
  730. else if (source is TStrings) then
  731. AsMemo:=TStrings(Source).Text
  732. else
  733. inherited Assign(Source);
  734. end;
  735. Procedure TParam.AssignField(Field: TField);
  736. begin
  737. if Assigned(Field) then
  738. begin
  739. // Need TField.Value
  740. AssignFieldValue(Field,Field.Value);
  741. Name:=Field.FieldName;
  742. end
  743. else
  744. begin
  745. Clear;
  746. Name:='';
  747. end
  748. end;
  749. procedure TParam.AssignToField(Field : TField);
  750. begin
  751. if Assigned(Field) then
  752. case FDataType of
  753. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  754. // Need TField.AsSmallInt
  755. ftSmallint : Field.AsInteger:=AsSmallInt;
  756. // Need TField.AsWord
  757. ftWord : Field.AsInteger:=AsWord;
  758. ftInteger,
  759. ftAutoInc : Field.AsInteger:=AsInteger;
  760. ftCurrency : Field.AsCurrency:=AsCurrency;
  761. ftFloat : Field.AsFloat:=AsFloat;
  762. ftBoolean : Field.AsBoolean:=AsBoolean;
  763. ftBlob,
  764. ftGraphic..ftTypedBinary,
  765. ftOraBlob,
  766. ftOraClob,
  767. ftString,
  768. ftMemo,
  769. ftAdt,
  770. ftFixedChar: Field.AsString:=AsString;
  771. ftTime,
  772. ftDate,
  773. ftDateTime : Field.AsDateTime:=AsDateTime;
  774. ftBytes,
  775. ftVarBytes : Field.AsVariant:=Value;
  776. ftFmtBCD : Field.AsBCD:=AsFMTBCD;
  777. else
  778. If not (DataType in [ftCursor, ftArray, ftDataset,ftReference]) then
  779. DatabaseErrorFmt(SBadParamFieldType, [Name], DataSet);
  780. end;
  781. end;
  782. procedure TParam.AssignFromField(Field : TField);
  783. begin
  784. if Assigned(Field) then
  785. begin
  786. FDataType:=Field.DataType;
  787. case Field.DataType of
  788. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  789. // Need TField.AsSmallInt
  790. ftSmallint : AsSmallint:=Field.AsInteger;
  791. // Need TField.AsWord
  792. ftWord : AsWord:=Field.AsInteger;
  793. ftInteger,
  794. ftAutoInc : AsInteger:=Field.AsInteger;
  795. ftBCD,
  796. ftCurrency : AsCurrency:=Field.AsCurrency;
  797. ftFloat : AsFloat:=Field.AsFloat;
  798. ftBoolean : AsBoolean:=Field.AsBoolean;
  799. ftBlob,
  800. ftGraphic..ftTypedBinary,
  801. ftOraBlob,
  802. ftOraClob,
  803. ftString,
  804. ftMemo,
  805. ftAdt,
  806. ftFixedChar: AsString:=Field.AsString;
  807. ftTime,
  808. ftDate,
  809. ftDateTime : AsDateTime:=Field.AsDateTime;
  810. ftBytes,
  811. ftVarBytes : Value:=Field.AsVariant;
  812. ftFmtBCD : AsFMTBCD:=Field.AsBCD;
  813. else
  814. If not (DataType in [ftCursor, ftArray, ftDataset,ftReference]) then
  815. DatabaseErrorFmt(SBadParamFieldType, [Name], DataSet);
  816. end;
  817. end;
  818. end;
  819. Procedure TParam.AssignFieldValue(Field: TField; const AValue: Variant);
  820. begin
  821. If Assigned(Field) then
  822. begin
  823. if (Field.DataType = ftString) and TStringField(Field).FixedChar then
  824. FDataType := ftFixedChar
  825. else if (Field.DataType = ftMemo) and (Field.Size > 255) then
  826. FDataType := ftString
  827. else if (Field.DataType = ftWideString) and TWideStringField(Field).FixedChar then
  828. FDataType := ftFixedWideChar
  829. else if (Field.DataType = ftWideMemo) and (Field.Size > 255) then
  830. FDataType := ftWideString
  831. else
  832. FDataType := Field.DataType;
  833. if VarIsNull(AValue) then
  834. Clear
  835. else
  836. Value:=AValue;
  837. Size:=Field.DataSize;
  838. FBound:=True;
  839. end;
  840. end;
  841. Procedure TParam.Clear;
  842. begin
  843. FValue:=UnAssigned;
  844. end;
  845. Procedure TParam.GetData(Buffer: Pointer);
  846. Var
  847. P : Pointer;
  848. S : String;
  849. ws : WideString;
  850. l : Integer;
  851. begin
  852. case FDataType of
  853. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  854. ftSmallint : PSmallint(Buffer)^:=AsSmallInt;
  855. ftWord : PWord(Buffer)^:=AsWord;
  856. ftInteger,
  857. ftAutoInc : PInteger(Buffer)^:=AsInteger;
  858. ftCurrency : PDouble(Buffer)^:=AsCurrency;
  859. ftFloat : PDouble(Buffer)^:=AsFloat;
  860. ftBoolean : PWordBool(Buffer)^:=AsBoolean;
  861. ftString,
  862. ftMemo,
  863. ftAdt,
  864. ftFixedChar:
  865. begin
  866. S:=AsString;
  867. StrMove(PChar(Buffer),Pchar(S),Length(S)+1);
  868. end;
  869. ftWideString,
  870. ftWideMemo: begin
  871. ws := GetAsWideString;
  872. l := Length(ws);
  873. if l > 0 then
  874. Move(ws[1], Buffer, Succ(l)*2)
  875. else
  876. PWideChar(Buffer)^ := #0
  877. end;
  878. ftTime : PInteger(Buffer)^:=DateTimeToTimeStamp(AsTime).Time;
  879. ftDate : PInteger(Buffer)^:=DateTimeToTimeStamp(AsTime).Date;
  880. ftDateTime : PDouble(Buffer)^:=TimeStampToMSecs(DateTimeToTimeStamp(AsDateTime));
  881. ftBlob,
  882. ftGraphic..ftTypedBinary,
  883. ftOraBlob,
  884. ftOraClob :
  885. begin
  886. S:=GetAsString;
  887. Move(PChar(S)^, Buffer^, Length(S));
  888. end;
  889. ftBytes, ftVarBytes:
  890. begin
  891. if VarIsArray(FValue) then
  892. begin
  893. P:=VarArrayLock(FValue);
  894. try
  895. Move(P^, Buffer^, VarArrayHighBound(FValue, 1) + 1);
  896. finally
  897. VarArrayUnlock(FValue);
  898. end;
  899. end;
  900. end;
  901. ftFmtBCD : PBCD(Buffer)^:=AsFMTBCD;
  902. else
  903. If not (DataType in [ftCursor, ftArray, ftDataset,ftReference]) then
  904. DatabaseErrorFmt(SBadParamFieldType, [Name], DataSet);
  905. end;
  906. end;
  907. Function TParam.GetDataSize: Integer;
  908. begin
  909. Result:=0;
  910. case DataType of
  911. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  912. ftBoolean : Result:=SizeOf(WordBool);
  913. ftInteger,
  914. ftAutoInc : Result:=SizeOf(Integer);
  915. ftSmallint : Result:=SizeOf(SmallInt);
  916. ftWord : Result:=SizeOf(Word);
  917. ftTime,
  918. ftDate : Result:=SizeOf(Integer);
  919. ftDateTime,
  920. ftCurrency,
  921. ftFloat : Result:=SizeOf(Double);
  922. ftString,
  923. ftFixedChar,
  924. ftMemo,
  925. ftADT : Result:=Length(AsString)+1;
  926. ftBytes,
  927. ftVarBytes : if VarIsArray(FValue) then
  928. Result:=VarArrayHighBound(FValue,1)+1
  929. else
  930. Result:=0;
  931. ftBlob,
  932. ftGraphic..ftTypedBinary,
  933. ftOraClob,
  934. ftOraBlob : Result:=Length(AsString);
  935. ftArray,
  936. ftDataSet,
  937. ftReference,
  938. ftCursor : Result:=0;
  939. ftFmtBCD : Result:=SizeOf(TBCD);
  940. else
  941. DatabaseErrorFmt(SBadParamFieldType,[Name],DataSet);
  942. end;
  943. end;
  944. Procedure TParam.LoadFromFile(const FileName: string; BlobType: TBlobType);
  945. Var
  946. S : TFileStream;
  947. begin
  948. S:=TFileStream.Create(FileName,fmOpenRead);
  949. Try
  950. LoadFromStream(S,BlobType);
  951. Finally
  952. FreeAndNil(S);
  953. end;
  954. end;
  955. Procedure TParam.LoadFromStream(Stream: TStream; BlobType: TBlobType);
  956. Var
  957. Temp : String;
  958. begin
  959. FDataType:=BlobType;
  960. With Stream do
  961. begin
  962. Position:=0;
  963. SetLength(Temp,Size);
  964. ReadBuffer(Pointer(Temp)^,Size);
  965. FValue:=Temp;
  966. end;
  967. end;
  968. Procedure TParam.SetBlobData(Buffer: Pointer; ASize: Integer);
  969. Var
  970. Temp : String;
  971. begin
  972. SetLength(Temp,ASize);
  973. Move(Buffer^,Temp[1],ASize);
  974. AsBlob:=Temp;
  975. end;
  976. Procedure TParam.SetData(Buffer: Pointer);
  977. Function FromTimeStamp(T,D : Integer) : TDateTime;
  978. Var TS : TTimeStamp;
  979. begin
  980. TS.Time:=T;
  981. TS.Date:=D;
  982. Result:=TimeStampToDateTime(TS);
  983. end;
  984. begin
  985. case FDataType of
  986. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  987. ftSmallint : AsSmallInt:=PSmallint(Buffer)^;
  988. ftWord : AsWord:=PWord(Buffer)^;
  989. ftInteger,
  990. ftAutoInc : AsInteger:=PInteger(Buffer)^;
  991. ftCurrency : AsCurrency:= PDouble(Buffer)^;
  992. ftFloat : AsFloat:=PDouble(Buffer)^;
  993. ftBoolean : AsBoolean:=PWordBool(Buffer)^;
  994. ftString,
  995. ftFixedChar: AsString:=StrPas(Buffer);
  996. ftMemo : AsMemo:=StrPas(Buffer);
  997. ftTime : AsTime:=FromTimeStamp(PInteger(Buffer)^,DateDelta);
  998. ftDate : Asdate:=FromTimeStamp(0,PInteger(Buffer)^);
  999. ftDateTime : AsDateTime:=TimeStampToDateTime(MSecsToTimeStamp(trunc(PDouble(Buffer)^)));
  1000. ftCursor : FValue:=0;
  1001. ftBlob,
  1002. ftGraphic..ftTypedBinary,
  1003. ftOraBlob,
  1004. ftOraClob : SetBlobData(Buffer, StrLen(PChar(Buffer)));
  1005. ftFmtBCD : AsFMTBCD:=PBCD(Buffer)^;
  1006. else
  1007. DatabaseErrorFmt(SBadParamFieldType,[Name],DataSet);
  1008. end;
  1009. end;
  1010. Procedure TParams.CopyParamValuesFromDataset(ADataSet: TDataSet;
  1011. CopyBound: Boolean);
  1012. Var
  1013. I : Integer;
  1014. P : TParam;
  1015. F : TField;
  1016. begin
  1017. If assigned(ADataSet) then
  1018. For I:=0 to Count-1 do
  1019. begin
  1020. P:=Items[i];
  1021. if CopyBound or (not P.Bound) then
  1022. begin
  1023. // Master dataset must be active and unbound parameters must have fields
  1024. // with same names in master dataset (Delphi compatible behavior)
  1025. F:=ADataSet.FieldByName(P.Name);
  1026. P.AssignField(F);
  1027. If Not CopyBound then
  1028. P.Bound:=False;
  1029. end;
  1030. end;
  1031. end;