dsparams.inc 28 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223
  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.GetAsAnsiString: AnsiString;
  532. begin
  533. Result := GetAsString;
  534. end;
  535. Function TParam.GetAsUnicodeString: UnicodeString;
  536. begin
  537. if IsNull then
  538. Result := ''
  539. else
  540. Result := FValue;
  541. end;
  542. Function TParam.GetAsUTF8String: UTF8String;
  543. begin
  544. if IsNull then
  545. Result := ''
  546. else
  547. Result := FValue;
  548. end;
  549. Function TParam.GetAsWideString: WideString;
  550. begin
  551. if IsNull then
  552. Result := ''
  553. else
  554. Result := FValue;
  555. end;
  556. Function TParam.GetAsVariant: Variant;
  557. begin
  558. if IsNull then
  559. Result:=Null
  560. else
  561. Result:=FValue;
  562. end;
  563. Function TParam.GetAsFMTBCD: TBCD;
  564. begin
  565. If IsNull then
  566. Result:=0
  567. else
  568. Result:=VarToBCD(FValue);
  569. end;
  570. Function TParam.GetDisplayName: string;
  571. begin
  572. if (FName<>'') then
  573. Result:=FName
  574. else
  575. Result:=inherited GetDisplayName
  576. end;
  577. Function TParam.GetIsNull: Boolean;
  578. begin
  579. Result:= VarIsNull(FValue) or VarIsClear(FValue);
  580. end;
  581. Function TParam.IsEqual(AValue: TParam): Boolean;
  582. begin
  583. Result:=(Name=AValue.Name)
  584. and (IsNull=AValue.IsNull)
  585. and (Bound=AValue.Bound)
  586. and (DataType=AValue.DataType)
  587. and (ParamType=AValue.ParamType)
  588. and (VarType(FValue)=VarType(AValue.FValue))
  589. and (FValue=AValue.FValue);
  590. end;
  591. Procedure TParam.SetAsBCD(const AValue: Currency);
  592. begin
  593. FDataType:=ftBCD;
  594. Value:=AValue;
  595. end;
  596. Procedure TParam.SetAsBlob(const AValue: TBlobData);
  597. begin
  598. FDataType:=ftBlob;
  599. Value:=AValue;
  600. end;
  601. Procedure TParam.SetAsBoolean(AValue: Boolean);
  602. begin
  603. FDataType:=ftBoolean;
  604. Value:=AValue;
  605. end;
  606. Procedure TParam.SetAsBytes(const AValue: TBytes);
  607. begin
  608. FDataType:=ftVarBytes;
  609. Value:=AValue;
  610. end;
  611. Procedure TParam.SetAsCurrency(const AValue: Currency);
  612. begin
  613. FDataType:=ftCurrency;
  614. Value:=AValue;
  615. end;
  616. Procedure TParam.SetAsDate(const AValue: TDateTime);
  617. begin
  618. FDataType:=ftDate;
  619. Value:=AValue;
  620. end;
  621. Procedure TParam.SetAsDateTime(const AValue: TDateTime);
  622. begin
  623. FDataType:=ftDateTime;
  624. Value:=AValue;
  625. end;
  626. Procedure TParam.SetAsFloat(const AValue: Double);
  627. begin
  628. FDataType:=ftFloat;
  629. Value:=AValue;
  630. end;
  631. Procedure TParam.SetAsInteger(AValue: Longint);
  632. begin
  633. FDataType:=ftInteger;
  634. Value:=AValue;
  635. end;
  636. Procedure TParam.SetAsLargeInt(AValue: LargeInt);
  637. begin
  638. FDataType:=ftLargeint;
  639. Value:=AValue;
  640. end;
  641. Procedure TParam.SetAsMemo(const AValue: string);
  642. begin
  643. FDataType:=ftMemo;
  644. Value:=AValue;
  645. end;
  646. Procedure TParam.SetAsSmallInt(AValue: LongInt);
  647. begin
  648. FDataType:=ftSmallInt;
  649. Value:=AValue;
  650. end;
  651. Procedure TParam.SetAsString(const AValue: string);
  652. begin
  653. if FDataType <> ftFixedChar then
  654. FDataType := ftString;
  655. Value:=AValue;
  656. end;
  657. Procedure TParam.SetAsAnsiString(const AValue: AnsiString);
  658. begin
  659. if FDataType <> ftFixedChar then
  660. FDataType := ftString;
  661. Value:=AValue;
  662. end;
  663. Procedure TParam.SetAsUTF8String(const AValue: UTF8String);
  664. begin
  665. if FDataType <> ftFixedChar then
  666. FDataType := ftString;
  667. Value:=AValue;
  668. end;
  669. Procedure TParam.SetAsUnicodeString(const AValue: UnicodeString);
  670. begin
  671. if FDataType <> ftFixedWideChar then
  672. FDataType := ftWideString;
  673. Value := AValue;
  674. end;
  675. Procedure TParam.SetAsWideString(const AValue: WideString);
  676. begin
  677. if FDataType <> ftFixedWideChar then
  678. FDataType := ftWideString;
  679. Value := AValue;
  680. end;
  681. Procedure TParam.SetAsTime(const AValue: TDateTime);
  682. begin
  683. FDataType:=ftTime;
  684. Value:=AValue;
  685. end;
  686. Procedure TParam.SetAsVariant(const AValue: Variant);
  687. begin
  688. FValue:=AValue;
  689. FBound:=not VarIsClear(AValue);
  690. if FDataType = ftUnknown then
  691. case VarType(Value) of
  692. varBoolean : FDataType:=ftBoolean;
  693. varSmallint,
  694. varShortInt,
  695. varByte : FDataType:=ftSmallInt;
  696. varWord,
  697. varInteger : FDataType:=ftInteger;
  698. varCurrency : FDataType:=ftCurrency;
  699. varLongWord,
  700. varSingle,
  701. varDouble : FDataType:=ftFloat;
  702. varDate : FDataType:=ftDateTime;
  703. varString,
  704. varOleStr : if (FDataType<>ftFixedChar) then
  705. FDataType:=ftString;
  706. varInt64 : FDataType:=ftLargeInt;
  707. else
  708. if VarIsFmtBCD(Value) then
  709. FDataType:=ftFmtBCD
  710. else if VarIsArray(AValue) and (VarType(AValue) and varTypeMask = varByte) then
  711. FDataType:=ftVarBytes
  712. else
  713. FDataType:=ftUnknown;
  714. end;
  715. end;
  716. Procedure TParam.SetAsWord(AValue: LongInt);
  717. begin
  718. FDataType:=ftWord;
  719. Value:=AValue;
  720. end;
  721. Procedure TParam.SetAsFMTBCD(const AValue: TBCD);
  722. begin
  723. FDataType:=ftFMTBcd;
  724. FValue:=VarFmtBCDCreate(AValue);
  725. end;
  726. Procedure TParam.SetDataType(AValue: TFieldType);
  727. Var
  728. VT : Integer;
  729. begin
  730. FDataType:=AValue;
  731. VT:=FieldTypetoVariantMap[AValue];
  732. If (VT=varError) then
  733. clear
  734. else
  735. if not VarIsEmpty(FValue) then
  736. begin
  737. Try
  738. FValue:=VarAsType(FValue,VT)
  739. except
  740. Clear;
  741. end { try }
  742. end;
  743. end;
  744. Procedure TParam.SetText(const AValue: string);
  745. begin
  746. Value:=AValue;
  747. end;
  748. constructor TParam.Create(ACollection: TCollection);
  749. begin
  750. inherited Create(ACollection);
  751. ParamType:=ptUnknown;
  752. DataType:=ftUnknown;
  753. FValue:=Unassigned;
  754. end;
  755. constructor TParam.Create(AParams: TParams; AParamType: TParamType);
  756. begin
  757. Create(AParams);
  758. ParamType:=AParamType;
  759. end;
  760. Procedure TParam.Assign(Source: TPersistent);
  761. begin
  762. if (Source is TParam) then
  763. AssignParam(TParam(Source))
  764. else if (Source is TField) then
  765. AssignField(TField(Source))
  766. else if (source is TStrings) then
  767. AsMemo:=TStrings(Source).Text
  768. else
  769. inherited Assign(Source);
  770. end;
  771. Procedure TParam.AssignField(Field: TField);
  772. begin
  773. if Assigned(Field) then
  774. begin
  775. // Need TField.Value
  776. AssignFieldValue(Field,Field.Value);
  777. Name:=Field.FieldName;
  778. end
  779. else
  780. begin
  781. Clear;
  782. Name:='';
  783. end
  784. end;
  785. Procedure TParam.AssignToField(Field : TField);
  786. begin
  787. if Assigned(Field) then
  788. case FDataType of
  789. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  790. // Need TField.AsSmallInt
  791. ftSmallint : Field.AsInteger:=AsSmallInt;
  792. // Need TField.AsWord
  793. ftWord : Field.AsInteger:=AsWord;
  794. ftInteger,
  795. ftAutoInc : Field.AsInteger:=AsInteger;
  796. ftCurrency : Field.AsCurrency:=AsCurrency;
  797. ftFloat : Field.AsFloat:=AsFloat;
  798. ftBoolean : Field.AsBoolean:=AsBoolean;
  799. ftBlob,
  800. ftGraphic..ftTypedBinary,
  801. ftOraBlob,
  802. ftOraClob,
  803. ftString,
  804. ftMemo,
  805. ftAdt,
  806. ftFixedChar: Field.AsString:=AsString;
  807. ftTime,
  808. ftDate,
  809. ftDateTime : Field.AsDateTime:=AsDateTime;
  810. ftBytes,
  811. ftVarBytes : Field.AsVariant:=Value;
  812. ftFmtBCD : Field.AsBCD:=AsFMTBCD;
  813. ftFixedWideChar,
  814. ftWideString: Field.AsWideString:=AsWideString;
  815. else
  816. If not (DataType in [ftCursor, ftArray, ftDataset,ftReference]) then
  817. DatabaseErrorFmt(SBadParamFieldType, [Name], DataSet);
  818. end;
  819. end;
  820. Procedure TParam.AssignFromField(Field : TField);
  821. begin
  822. if Assigned(Field) then
  823. begin
  824. FDataType:=Field.DataType;
  825. case Field.DataType of
  826. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  827. // Need TField.AsSmallInt
  828. ftSmallint : AsSmallint:=Field.AsInteger;
  829. // Need TField.AsWord
  830. ftWord : AsWord:=Field.AsInteger;
  831. ftInteger,
  832. ftAutoInc : AsInteger:=Field.AsInteger;
  833. ftBCD,
  834. ftCurrency : AsCurrency:=Field.AsCurrency;
  835. ftFloat : AsFloat:=Field.AsFloat;
  836. ftBoolean : AsBoolean:=Field.AsBoolean;
  837. ftBlob,
  838. ftGraphic..ftTypedBinary,
  839. ftOraBlob,
  840. ftOraClob,
  841. ftString,
  842. ftMemo,
  843. ftAdt,
  844. ftFixedChar: AsString:=Field.AsString;
  845. ftTime,
  846. ftDate,
  847. ftDateTime : AsDateTime:=Field.AsDateTime;
  848. ftBytes,
  849. ftVarBytes : Value:=Field.AsVariant;
  850. ftFmtBCD : AsFMTBCD:=Field.AsBCD;
  851. ftFixedWideChar,
  852. ftWideString: AsWideString:=Field.AsWideString;
  853. else
  854. If not (DataType in [ftCursor, ftArray, ftDataset,ftReference]) then
  855. DatabaseErrorFmt(SBadParamFieldType, [Name], DataSet);
  856. end;
  857. end;
  858. end;
  859. Procedure TParam.AssignFieldValue(Field: TField; const AValue: Variant);
  860. begin
  861. If Assigned(Field) then
  862. begin
  863. if (Field.DataType = ftString) and TStringField(Field).FixedChar then
  864. FDataType := ftFixedChar
  865. else if (Field.DataType = ftMemo) and (Field.Size > 255) then
  866. FDataType := ftString
  867. else if (Field.DataType = ftWideString) and TWideStringField(Field).FixedChar then
  868. FDataType := ftFixedWideChar
  869. else if (Field.DataType = ftWideMemo) and (Field.Size > 255) then
  870. FDataType := ftWideString
  871. else
  872. FDataType := Field.DataType;
  873. if VarIsNull(AValue) then
  874. Clear
  875. else
  876. Value:=AValue;
  877. Size:=Field.DataSize;
  878. FBound:=True;
  879. end;
  880. end;
  881. Procedure TParam.Clear;
  882. begin
  883. FValue:=UnAssigned;
  884. end;
  885. Procedure TParam.GetData(Buffer: Pointer);
  886. Var
  887. P : Pointer;
  888. S : String;
  889. ws : WideString;
  890. l : Integer;
  891. begin
  892. case FDataType of
  893. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  894. ftSmallint : PSmallint(Buffer)^:=AsSmallInt;
  895. ftWord : PWord(Buffer)^:=AsWord;
  896. ftInteger,
  897. ftAutoInc : PInteger(Buffer)^:=AsInteger;
  898. ftCurrency : PDouble(Buffer)^:=AsCurrency;
  899. ftFloat : PDouble(Buffer)^:=AsFloat;
  900. ftBoolean : PWordBool(Buffer)^:=AsBoolean;
  901. ftString,
  902. ftMemo,
  903. ftAdt,
  904. ftFixedChar:
  905. begin
  906. S:=AsString;
  907. StrMove(PChar(Buffer),PChar(S),Length(S)+1);
  908. end;
  909. ftWideString,
  910. ftWideMemo: begin
  911. ws := GetAsWideString;
  912. l := Length(ws);
  913. if l > 0 then
  914. Move(ws[1], Buffer, Succ(l)*2)
  915. else
  916. PWideChar(Buffer)^ := #0
  917. end;
  918. ftTime : PInteger(Buffer)^:=DateTimeToTimeStamp(AsTime).Time;
  919. ftDate : PInteger(Buffer)^:=DateTimeToTimeStamp(AsTime).Date;
  920. ftDateTime : PDouble(Buffer)^:=TimeStampToMSecs(DateTimeToTimeStamp(AsDateTime));
  921. ftBlob,
  922. ftGraphic..ftTypedBinary,
  923. ftOraBlob,
  924. ftOraClob :
  925. begin
  926. S:=GetAsString;
  927. Move(PChar(S)^, Buffer^, Length(S));
  928. end;
  929. ftBytes, ftVarBytes:
  930. begin
  931. if VarIsArray(FValue) then
  932. begin
  933. P:=VarArrayLock(FValue);
  934. try
  935. Move(P^, Buffer^, VarArrayHighBound(FValue, 1) + 1);
  936. finally
  937. VarArrayUnlock(FValue);
  938. end;
  939. end;
  940. end;
  941. ftFmtBCD : PBCD(Buffer)^:=AsFMTBCD;
  942. else
  943. If not (DataType in [ftCursor, ftArray, ftDataset,ftReference]) then
  944. DatabaseErrorFmt(SBadParamFieldType, [Name], DataSet);
  945. end;
  946. end;
  947. Function TParam.GetDataSize: Integer;
  948. begin
  949. Result:=0;
  950. case DataType of
  951. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  952. ftBoolean : Result:=SizeOf(WordBool);
  953. ftInteger,
  954. ftAutoInc : Result:=SizeOf(Integer);
  955. ftSmallint : Result:=SizeOf(SmallInt);
  956. ftWord : Result:=SizeOf(Word);
  957. ftTime,
  958. ftDate : Result:=SizeOf(Integer);
  959. ftDateTime,
  960. ftCurrency,
  961. ftFloat : Result:=SizeOf(Double);
  962. ftString,
  963. ftFixedChar,
  964. ftMemo,
  965. ftADT : Result:=Length(AsString)+1;
  966. ftBytes,
  967. ftVarBytes : if VarIsArray(FValue) then
  968. Result:=VarArrayHighBound(FValue,1)+1
  969. else
  970. Result:=0;
  971. ftBlob,
  972. ftGraphic..ftTypedBinary,
  973. ftOraClob,
  974. ftOraBlob : Result:=Length(AsString);
  975. ftArray,
  976. ftDataSet,
  977. ftReference,
  978. ftCursor : Result:=0;
  979. ftFmtBCD : Result:=SizeOf(TBCD);
  980. else
  981. DatabaseErrorFmt(SBadParamFieldType,[Name],DataSet);
  982. end;
  983. end;
  984. Procedure TParam.LoadFromFile(const FileName: string; BlobType: TBlobType);
  985. Var
  986. S : TFileStream;
  987. begin
  988. S:=TFileStream.Create(FileName,fmOpenRead);
  989. Try
  990. LoadFromStream(S,BlobType);
  991. Finally
  992. FreeAndNil(S);
  993. end;
  994. end;
  995. Procedure TParam.LoadFromStream(Stream: TStream; BlobType: TBlobType);
  996. Var
  997. Temp : String;
  998. begin
  999. FDataType:=BlobType;
  1000. With Stream do
  1001. begin
  1002. Position:=0;
  1003. SetLength(Temp,Size);
  1004. ReadBuffer(Pointer(Temp)^,Size);
  1005. FValue:=Temp;
  1006. end;
  1007. end;
  1008. Procedure TParam.SetBlobData(Buffer: Pointer; ASize: Integer);
  1009. Var
  1010. Temp : String;
  1011. begin
  1012. SetLength(Temp,ASize);
  1013. Move(Buffer^,Temp[1],ASize);
  1014. AsBlob:=Temp;
  1015. end;
  1016. Procedure TParam.SetData(Buffer: Pointer);
  1017. Function FromTimeStamp(T,D : Integer) : TDateTime;
  1018. Var TS : TTimeStamp;
  1019. begin
  1020. TS.Time:=T;
  1021. TS.Date:=D;
  1022. Result:=TimeStampToDateTime(TS);
  1023. end;
  1024. begin
  1025. case FDataType of
  1026. ftUnknown : DatabaseErrorFmt(SUnknownParamFieldType,[Name],DataSet);
  1027. ftSmallint : AsSmallInt:=PSmallint(Buffer)^;
  1028. ftWord : AsWord:=PWord(Buffer)^;
  1029. ftInteger,
  1030. ftAutoInc : AsInteger:=PInteger(Buffer)^;
  1031. ftCurrency : AsCurrency:= PDouble(Buffer)^;
  1032. ftFloat : AsFloat:=PDouble(Buffer)^;
  1033. ftBoolean : AsBoolean:=PWordBool(Buffer)^;
  1034. ftString,
  1035. ftFixedChar: AsString:=StrPas(Buffer);
  1036. ftMemo : AsMemo:=StrPas(Buffer);
  1037. ftTime : AsTime:=FromTimeStamp(PInteger(Buffer)^,DateDelta);
  1038. ftDate : Asdate:=FromTimeStamp(0,PInteger(Buffer)^);
  1039. ftDateTime : AsDateTime:=TimeStampToDateTime(MSecsToTimeStamp(trunc(PDouble(Buffer)^)));
  1040. ftCursor : FValue:=0;
  1041. ftBlob,
  1042. ftGraphic..ftTypedBinary,
  1043. ftOraBlob,
  1044. ftOraClob : SetBlobData(Buffer, StrLen(PChar(Buffer)));
  1045. ftFmtBCD : AsFMTBCD:=PBCD(Buffer)^;
  1046. else
  1047. DatabaseErrorFmt(SBadParamFieldType,[Name],DataSet);
  1048. end;
  1049. end;
  1050. Procedure TParams.CopyParamValuesFromDataset(ADataSet: TDataSet;
  1051. CopyBound: Boolean);
  1052. Var
  1053. I : Integer;
  1054. P : TParam;
  1055. F : TField;
  1056. begin
  1057. If assigned(ADataSet) then
  1058. For I:=0 to Count-1 do
  1059. begin
  1060. P:=Items[i];
  1061. if CopyBound or (not P.Bound) then
  1062. begin
  1063. // Master dataset must be active and unbound parameters must have fields
  1064. // with same names in master dataset (Delphi compatible behavior)
  1065. F:=ADataSet.FieldByName(P.Name);
  1066. P.AssignField(F);
  1067. If Not CopyBound then
  1068. P.Bound:=False;
  1069. end;
  1070. end;
  1071. end;