Provider.pas
上传用户:etonglee
上传日期:2014-03-01
资源大小:698k
文件大小:136k
源码类别:

Internet/IE编程

开发平台:

Delphi

  1.   out ErrorCount: Integer): OleVariant;
  2. var
  3.   OwnerData: OleVariant;
  4. begin
  5.   Result := ApplyUpdates(Delta, MaxErrors, ErrorCount, OwnerData);
  6. end;
  7. function TCustomProvider.ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  8.   out ErrorCount: Integer; var OwnerData: OleVariant): OleVariant;
  9. begin
  10.   DoBeforeApplyUpdates(OwnerData);
  11.   Result := InternalApplyUpdates(Delta, MaxErrors, ErrorCount);
  12.   DoAfterApplyUpdates(OwnerData);
  13. end;
  14. procedure TCustomProvider.DoAfterGetRecords(var OwnerData: OleVariant);
  15. begin
  16.   if Assigned(FAfterGetRecords) then FAfterGetRecords(Self, OwnerData);
  17. end;
  18. procedure TCustomProvider.DoBeforeGetRecords(Count: Integer; Options: Integer;
  19.   const CommandText: WideString; var Params, OwnerData: OleVariant);
  20. begin
  21.   if Assigned(FBeforeGetRecords) then FBeforeGetRecords(Self, OwnerData);
  22. end;
  23. function TCustomProvider.GetRecords(Count: Integer; out RecsOut: Integer; Options: Integer): OleVariant;
  24. var
  25.   Params, OwnerData: OleVariant;
  26. begin
  27.   Result := GetRecords(Count, RecsOut, Options, '', Params, OwnerData);
  28. end;
  29. function TCustomProvider.GetRecords(Count: Integer; out RecsOut: Integer; Options: Integer;
  30.   const CommandText: WideString; var Params, OwnerData: OleVariant): OleVariant;
  31. begin
  32.   DoBeforeGetRecords(Count, Options, CommandText, Params, OwnerData);
  33.   Result := InternalGetRecords(Count, RecsOut, TGetRecordOptions(Byte(Options)),
  34.     CommandText, Params);
  35.   DoAfterGetRecords(OwnerData);
  36.   Params := InternalGetParams([ptOutput, ptInputOutput]);
  37. end;
  38. procedure TCustomProvider.DoAfterRowRequest(var OwnerData: OleVariant);
  39. begin
  40.   if Assigned(FAfterRowRequest) then FAfterRowRequest(Self, OwnerData);
  41. end;
  42. procedure TCustomProvider.DoBeforeRowRequest(var OwnerData: OleVariant);
  43. begin
  44.   if Assigned(FBeforeRowRequest) then FBeforeRowRequest(Self, OwnerData);
  45. end;
  46. function TCustomProvider.RowRequest(const Row: OleVariant; RequestType: Integer;
  47.   var OwnerData: OleVariant): OleVariant;
  48. begin
  49.   DoBeforeRowRequest(OwnerData);
  50.   Result := InternalRowRequest(Row, TFetchOptions(Byte(RequestType)));
  51.   DoAfterRowRequest(OwnerData);
  52. end;
  53. procedure TCustomProvider.DoAfterExecute(var OwnerData: OleVariant);
  54. begin
  55.   if Assigned(FAfterExecute) then FAfterExecute(Self, OwnerData);
  56. end;
  57. procedure TCustomProvider.DoBeforeExecute(const CommandText: WideString; var Params,
  58.       OwnerData: OleVariant);
  59. begin
  60.   if Assigned(FBeforeExecute) then FBeforeExecute(Self, OwnerData);
  61. end;
  62. procedure TCustomProvider.Execute(const CommandText: WideString;
  63.   var Params, OwnerData: OleVariant);
  64. begin
  65.   DoBeforeExecute(CommandText, Params, OwnerData);
  66.   InternalExecute(CommandText, Params);
  67.   DoAfterExecute(OwnerData);
  68.   Params := InternalGetParams([ptOutput, ptInputOutput]);
  69. end;
  70. procedure TCustomProvider.DoAfterGetParams(var OwnerData: OleVariant);
  71. begin
  72.   if Assigned(FAfterGetParams) then FAfterGetParams(Self, OwnerData);
  73. end;
  74. procedure TCustomProvider.DoBeforeGetParams(var OwnerData: OleVariant);
  75. begin
  76.   if Assigned(FBeforeGetParams) then FBeforeGetParams(Self, OwnerData);
  77. end;
  78. function TCustomProvider.GetParams(var OwnerData: OleVariant): OleVariant;
  79. begin
  80.   DoBeforeGetParams(OwnerData); 
  81.   Result := InternalGetParams;
  82.   DoAfterGetParams(OwnerData); 
  83. end;
  84. function TCustomProvider.InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant;
  85. begin
  86.   Result := NULL;
  87. end;
  88. procedure TCustomProvider.InternalExecute(const CommandText: WideString; var Params: OleVariant);
  89. begin
  90. end;
  91. function TCustomProvider.InternalGetRecords(Count: Integer; out RecsOut: Integer;
  92.   Options: TGetRecordOptions; const CommandText: WideString;
  93.   var Params: OleVariant): OleVariant;
  94. begin
  95.   Result := NULL;
  96. end;
  97. function TCustomProvider.InternalRowRequest(const Row: OleVariant; RequestType: TFetchOptions): OleVariant;
  98. begin
  99.   Result := NULL;
  100. end;
  101. function TCustomProvider.DataRequest(Input: OleVariant): OleVariant;
  102. begin
  103.   if Assigned(FOnDataRequest) then
  104.     Result := FOnDataRequest(Self, Input) else
  105.     Result := NULL;
  106. end;
  107. { TBaseProvider }
  108. constructor TBaseProvider.Create(AOwner: TComponent);
  109. begin
  110.   inherited Create(AOwner);
  111.   FProviderOptions := [];
  112. end;
  113. destructor TBaseProvider.Destroy;
  114. begin
  115.   FResolver.Free;
  116.   inherited Destroy;
  117. end;
  118. procedure TBaseProvider.LocateRecord(Source, Delta: TDataSet);
  119. begin
  120. end;
  121. procedure TBaseProvider.UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean);
  122. begin
  123. end;
  124. procedure TBaseProvider.FetchDetails(Source, Delta: TDataSet);
  125. begin
  126. end;
  127. procedure TBaseProvider.CheckResolver;
  128. begin
  129.   if not Assigned(FResolver) then
  130.     FResolver := CreateResolver;
  131. end;
  132. procedure TBaseProvider.FreeResolver;
  133. begin
  134.   FResolver.Free;
  135.   FResolver := nil;
  136. end;
  137. function TBaseProvider.InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  138.   out ErrorCount: Integer): OleVariant;
  139. begin
  140.   if poReadOnly in Options then DatabaseError(SReadOnlyProvider);
  141.   CheckResolver;
  142.   Result := Resolver.ApplyUpdates(Delta, MaxErrors, ErrorCount);
  143. end;
  144. function TBaseProvider.InternalRowRequest(const Row: OleVariant; RequestType: TFetchOptions): OleVariant;
  145. begin
  146.   CheckResolver;
  147.   Result := Resolver.RowRequest(Row, RequestType);
  148. end;
  149. function TBaseProvider.InternalGetRecords(Count: Integer; out RecsOut: Integer;
  150.   Options: TGetRecordOptions; const CommandText: WideString;
  151.   var Params: OleVariant): OleVariant;
  152. begin
  153.   if (Count = 0) then
  154.     Include(Options, grMetaData);
  155.   RecsOut := Count;
  156.   CreateDataPacket(Options, Self.Options, RecsOut, Result);
  157.   DoOnGetData(Result);
  158. end;
  159. procedure TBaseProvider.DoOnGetData(var Data: OleVariant);
  160. begin
  161.   if Assigned(OnGetData) then
  162.   begin
  163.     if not Assigned(FDataDS) then
  164.       FDataDS := TPacketDataSet.Create(Self) else
  165.       FDataDS.StreamMetaData := False;
  166.     FDataDS.AppendData(Data, False);
  167.     OnGetData(Self, FDataDS);
  168.     if FDataDS.ChangeCount > 0 then
  169.     begin
  170.       FDataDS.MergeChangeLog;
  171.       Data := FDataDS.Data;
  172.     end;
  173.     FDataDS.EmptyDataSet;
  174.   end;
  175. end;
  176. procedure TBaseProvider.DoOnUpdateData(Delta: TPacketDataSet);
  177. begin
  178.   if Assigned(FOnUpdateData) then
  179.   begin
  180.     Delta.LogChanges := False;
  181.     FOnUpdateData(Self, Delta);
  182.   end;
  183. end;
  184. function TBaseProvider.CreateResolver: TCustomResolver;
  185. begin
  186.   Result := nil;
  187. end;
  188. procedure TBaseProvider.CreateDataPacket(PacketOpts: TGetRecordOptions;
  189.   ProvOpts: TProviderOptions; var RecsOut: Integer; var Data: OleVariant);
  190. begin
  191.   RecsOut := 0;
  192.   Data := NULL;
  193. end;
  194. { TDataSetProvider }
  195. type
  196.   PSQLInfo = ^TSQLInfo;
  197.   TSQLInfo = record
  198.     IsSQLBased: Boolean;
  199.     QuoteChar: string;
  200.     QuotedTable: string;
  201.     QuotedTableDot: string;
  202.     Opened: Boolean;
  203.     HasObjects: Boolean;
  204.   end;
  205. constructor TDataSetProvider.Create(AOwner: TComponent);
  206. begin
  207.   inherited Create(AOwner);
  208.   FResolveToDataSet := False;
  209.   FUpdateMode := upWhereAll;
  210.   FDSWriter := nil;
  211.   FConstraints := True;
  212.   FRecordsSent := 0;
  213. end;
  214. destructor TDataSetProvider.Destroy;
  215. begin
  216.   FDSWriter.Free;
  217.   if Assigned(FParams) then
  218.     FParams.Free;
  219.   inherited Destroy;
  220. end;
  221. procedure TDataSetProvider.LocateRecord(Source, Delta: TDataSet);
  222. begin
  223.   FDataSetOpened := not Source.Active;
  224.   if FDataSetOpened then Source.Open;
  225.   if not FindRecord(Source, Delta, UpdateMode) then
  226.     DatabaseError(SRecordChanged);
  227. end;
  228. function TDataSetProvider.FindRecord(Source, Delta: TDataSet;
  229.   UpdateMode: TUpdateMode): Boolean;
  230.   procedure GetFieldList(DataSet: TDataSet; UpdateMode: TUpdateMode; List: TList);
  231.   var
  232.     i: Integer;
  233.   begin
  234.     for i := 0 to DataSet.FieldCount - 1 do
  235.       with DataSet.Fields[i] do
  236.       begin
  237.         if (DataType in [ftBytes, ftVarBytes]) or IsBlob or
  238.            (DataSet.Fields[i] is TObjectField) then continue;
  239.         case UpdateMode of
  240.           upWhereKeyOnly:
  241.             if pfInKey in ProviderFlags then List.Add(DataSet.Fields[i]);
  242.           upWhereAll:
  243.             if pfInWhere in ProviderFlags then List.Add(DataSet.Fields[i]);
  244.           upWhereChanged:
  245.             if (pfInKey in ProviderFlags) or (not VarIsClear(NewValue)) then
  246.               List.Add(DataSet.Fields[i]);
  247.         end;
  248.       end;
  249.   end;
  250. var
  251.   i: Integer;
  252.   KeyValues: Variant;
  253.   Fields: string;
  254.   FieldList: TList;
  255.   IsDelta: LongBool;
  256. begin
  257.   Result := False;
  258.   TPacketDataSet(Delta).DSBase.GetProp(dspropISDELTA, @IsDelta);
  259.   FieldList := TList.Create;
  260.   try
  261.     GetFieldList(Delta, UpdateMode, FieldList);
  262.     if FieldList.Count > 1 then
  263.     begin
  264.       KeyValues := VarArrayCreate([0, FieldList.Count - 1], varVariant);
  265.       Fields := '';
  266.       for i := 0 to FieldList.Count - 1 do
  267.         with TField(FieldList[i]) do
  268.         begin
  269.           if IsDelta then
  270.             KeyValues[i] := OldValue else
  271.             KeyValues[i] := Value;
  272.           if Fields <> '' then Fields := Fields + ';';
  273.           Fields := Fields + FieldName;
  274.         end;
  275.       Result := Source.Locate(Fields, KeyValues, []);
  276.     end
  277.     else if FieldList.Count = 1 then
  278.     begin
  279.       with TField(FieldList[0]) do
  280.         if IsDelta then
  281.           Result := Source.Locate(FieldName, OldValue, []) else
  282.           Result := Source.Locate(FieldName, Value, []);
  283.     end else
  284.       DatabaseError(SNoKeySpecified);
  285.   finally
  286.     FieldList.Free;
  287.   end;
  288. end;
  289. procedure TDataSetProvider.FetchDetails(Source, Delta: TDataSet);
  290. var
  291.   i: Integer;
  292.   Field: TField;
  293. begin
  294.   FDataSetOpened := not Source.Active;
  295.   if FDataSetOpened then Source.Open;
  296.   Source.First;
  297.   while not Source.EOF do
  298.   begin
  299.     Delta.Insert;
  300.     for i := 0 to Delta.FieldCount - 1 do
  301.     begin
  302.       Field := Source.FindField(Delta.Fields[i].FieldName);
  303.       if Field <> nil then
  304.         Delta.Fields[i].Assign(Field);
  305.     end;
  306.     Delta.Post;
  307.     Source.Next;
  308.   end;
  309. end;
  310. function TDataSetProvider.GetDataSetFromDelta(ATree: TUpdateTree; Source, Delta: TDataSet; Mode: TUpdateMode): TDataSet;
  311. var
  312.   Alias: String;
  313.   FSQL: TStringList;
  314.   FParams: TParams;
  315. begin
  316.   Result := nil;
  317.   FSQL := TStringList.Create;
  318.   FParams := TParams.Create;
  319.   try
  320.     CheckResolver;
  321.     if PSQLInfo(Resolver.FUpdateTree.Data)^.HasObjects then Alias := DefAlias else Alias := '';
  322.     TSQLResolver(Resolver).GenSelectSQL(ATree, FSQL, FParams, Alias, Mode);
  323.     IProviderSupport(Source).PSExecuteStatement(FSQL.Text, FParams, @Result);
  324.     if Result.EOF then
  325.       DatabaseError(SRecordChanged);
  326.   finally
  327.     FSQL.Free;
  328.     FParams.Free;
  329.   end;
  330. end;
  331. procedure TDataSetProvider.UpdateRecord(Source, Delta: TDataSet; BlobsOnly, KeyOnly: Boolean);
  332. var
  333.   Field: TField;
  334.   i: Integer;
  335.   UseUpMode: TUpdateMode;
  336.   DS: TDataSet;
  337. begin
  338.   if KeyOnly then
  339.     UseUpMode := upWhereKeyOnly
  340.   else
  341.     UseUpMode := UpdateMode;
  342.   if Source.IsUnidirectional then
  343.      DS := TDataSetProvider(Self.Resolver.FProvider).GetDataSetFromDelta(
  344.            Self.Resolver.FUpdateTree, Source, Delta, UseUpMode)
  345.   else begin
  346.     if not FindRecord(Source, Delta, UseUpMode) then
  347.       DatabaseError(SRecordChanged);
  348.     DS := Source;
  349.   end;
  350.   with Delta do
  351.   begin
  352.     Edit;
  353.     for I := 0 to FieldCount - 1 do
  354.     begin
  355.       Field := DS.FindField(Fields[I].FieldName);
  356.         if (Field <> nil) and (not (Field.Lookup or Field.Calculated)) and
  357.            (not BlobsOnly or (Field.IsBlob and VarIsNull(Fields[i].NewValue))) then
  358.           Fields[i].Assign(Field);
  359.     end;
  360.     Post;
  361.   end;
  362.   if Source.IsUnidirectional then
  363.     DS.Free;
  364. end;
  365. procedure TDataSetProvider.DoBeforeExecute(const CommandText: WideString;
  366.   var Params, OwnerData: OleVariant);
  367. begin
  368.   SetCommandText(CommandText);
  369.   SetParams(Params);
  370.   inherited DoBeforeExecute(CommandText, Params, OwnerData);
  371. end;
  372. procedure TDataSetProvider.InternalExecute(const CommandText: WideString;
  373.   var Params: OleVariant);
  374. begin
  375.   CheckDataSet;
  376.   IProviderSupport(DataSet).PSExecute;
  377. end;
  378. procedure TDataSetProvider.DoGetTableName(DataSet: TDataSet; var TableName: string);
  379. begin
  380.   if Assigned(OnGetTableName) then
  381.     OnGetTableName(Self, DataSet, TableName);
  382. end;
  383. procedure TDataSetProvider.Reset;
  384. begin
  385.   CheckDataSet;
  386.   if FDataSetOpened then
  387.   begin
  388.     FDSWriter.Reset;
  389.     DataSet.Close;
  390.     FDataSetOpened := False;
  391.   end;
  392.   IProviderSupport(DataSet).PSReset;
  393.   if DataSet.Active then
  394.     DataSet.First;
  395.   FRecordsSent := 0;
  396. end;
  397. procedure TDataSetProvider.SetCommandText(const CommandText: string);
  398. begin
  399.   if CommandText = '' then Exit;
  400.   if not (poAllowCommandText in Options) then
  401.     DatabaseError(SCannotChangeCommandText);
  402.   CheckDataSet;
  403.   IProviderSupport(DataSet).PSSetCommandText(CommandText);
  404. end;
  405. procedure TDataSetProvider.SetParams(Values: OleVariant);
  406. begin
  407.   if VarIsClear(Values) then Exit;
  408.   CheckDataSet;
  409.   if not Assigned(FParams) then
  410.     FParams := TParams.Create;
  411.   FParams.Clear;
  412.   UnpackParams(Values, FParams);
  413.   IProviderSupport(DataSet).PSSetParams(FParams);
  414. end;
  415. function TDataSetProvider.InternalGetParams(Types: TParamTypes = AllParamTypes): OleVariant;
  416. var
  417.   Params: TParams;
  418. begin
  419.   CheckDataSet;
  420.   Params := IProviderSupport(DataSet).PSGetParams;
  421.   if (Params = nil) or (Params.Count = 0) then
  422.     Result := NULL else
  423.     Result := PackageParams(Params, Types);
  424. end;
  425. function TDataSetProvider.InternalRowRequest(const Row: OleVariant; Options: TFetchOptions): OleVariant;
  426. begin
  427.   CheckResolver;
  428.   CheckDataSet;
  429.   Resolver.FUpdateTree.InitData(DataSet);
  430.   try
  431.     if not DataSet.Active then
  432.     begin
  433.       DataSet.Open;
  434.       FDataSetOpened := True;
  435.     end;
  436.     Result := inherited InternalRowRequest(Row, Options);
  437.   finally
  438.     Resolver.FUpdateTree.InitData(nil);
  439.     if FDataSetOpened then
  440.     begin
  441.       if Assigned(FDSWriter) then
  442.         FDSWriter.Reset;
  443.       DataSet.Close;
  444.       FDataSetOpened := False;
  445.     end;    
  446.   end;
  447. end;
  448. function TDataSetProvider.InternalApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  449.   out ErrorCount: Integer): OleVariant;
  450. begin
  451.   CheckDataSet;
  452.   FTransactionStarted := not IProviderSupport(DataSet).PSInTransaction;
  453.   if FTransactionStarted and (GetObjectContext=nil) then
  454.     IProviderSupport(DataSet).PSStartTransaction;
  455.   try
  456.     CheckResolver;
  457.     Resolver.FUpdateTree.InitData(DataSet);
  458.     try
  459.       Result := inherited InternalApplyUpdates(Delta, MaxErrors, ErrorCount);
  460.     finally
  461.       Resolver.FUpdateTree.InitData(nil);
  462.     end;
  463.   finally
  464.     if FTransactionStarted and (GetObjectContext=nil) then
  465.       IProviderSupport(DataSet).PSEndTransaction((ErrorCount <= MaxErrors) or (MaxErrors = -1));
  466.   end;
  467. end;
  468. procedure TDataSetProvider.SetDataSet(ADataSet: TDataSet);
  469. begin
  470.   FDataSet := ADataSet;
  471. end;
  472. procedure TDataSetProvider.SetResolveToDataSet(Value: Boolean);
  473. begin
  474.   if (Value <> FResolveToDataSet) and Assigned(Resolver) then
  475.     FreeResolver;
  476.   FResolveToDataSet := Value;
  477. end;
  478. function TDataSetProvider.CreateResolver: TCustomResolver;
  479. begin
  480.   if ResolveToDataSet then
  481.     Result := TDataSetResolver.Create(Self) else
  482.     Result := TSQLResolver.Create(Self);
  483. end;
  484. procedure TDataSetProvider.CheckDataSet;
  485. begin
  486.   if not Assigned(DataSet) then DatabaseError(SMissingDataSet);
  487. end;
  488. procedure TDataSetProvider.DoBeforeGetRecords(Count: Integer; Options: Integer;
  489.   const CommandText: WideString; var Params, OwnerData: OleVariant);
  490. begin
  491.   SetCommandText(CommandText);
  492.   SetParams(Params);
  493.   inherited DoBeforeGetRecords(Count, Options, CommandText, Params, OwnerData);
  494. end;
  495. function TDataSetProvider.InternalGetRecords(Count: Integer; out RecsOut: Integer;
  496.   Options: TGetRecordOptions; const CommandText: WideString;
  497.   var Params: OleVariant): OleVariant;
  498. begin
  499.   try
  500.     if grReset in Options then
  501.     begin
  502.       Reset;
  503.       { When doing only a reset and not getting more data then exit }
  504.       if Count = 0 then Exit;
  505.     end;
  506.     if not DataSet.Active then
  507.     begin
  508.       DataSet.Open;
  509.       FDataSetOpened := True;
  510.     end;
  511.     if (Count = 0) or (grMetaData in Options) then
  512.     begin
  513.       FDataDS.Free;
  514.       FDataDS := nil;
  515.       FRecordsSent := 0;
  516.     end;
  517.     DataSet.CheckBrowseMode;
  518.     DataSet.BlockReadSize := Count;
  519.     try
  520.       Result := inherited InternalGetRecords(Count, RecsOut, Options,
  521.         CommandText, Params);
  522.       Inc(FRecordsSent, RecsOut);
  523.       if (RecsOut <> Count) then Reset;
  524.     finally
  525.       if DataSet.Active then
  526.       begin
  527.         DataSet.BlockReadSize := 0;
  528.         if (Count <> 0) and (RecsOut = Count) then
  529.           DataSet.Next;
  530.       end;
  531.     end;
  532.   except
  533.     Reset;
  534.     raise;
  535.   end;
  536. end;
  537. procedure TDataSetProvider.DoGetProviderAttributes(DataSet: TDataSet; List: TList);
  538. var
  539.   CustParams: OleVariant;
  540.   Attr: PPacketAttribute;
  541.   i, j: Integer;
  542. begin
  543.   IProviderSupport(DataSet).PSGetAttributes(List);
  544.   if Assigned(FGetDSProps) then
  545.   begin
  546.     FGetDSProps(Self, DataSet, CustParams);
  547.     if VarIsArray(CustParams) then
  548.     begin
  549.       for i := VarArrayLowBound(CustParams, 1) to VarArrayHighBound(CustParams, 1) do
  550.       begin
  551.         if VarIsArray(CustParams[i]) and
  552.           (VarArrayHighBound(CustParams[i], 1) - VarArrayLowBound(CustParams[i], 1) = 2) then
  553.         begin
  554.           j := VarArrayLowBound(CustParams[i], 1);
  555.           New(Attr);
  556.           List.Add(Attr);
  557.           with Attr^ do
  558.           begin
  559.             Name := CustParams[i][j];
  560.             Value := CustParams[i][j + 1];
  561.             IncludeInDelta := CustParams[i][j + 2];
  562.           end;
  563.         end;
  564.       end;
  565.     end;
  566.   end;
  567. end;
  568. procedure TDataSetProvider.CreateDataPacket(PacketOpts: TGetRecordOptions;
  569.   ProvOpts: TProviderOptions; var RecsOut: Integer; var Data: OleVariant);
  570. begin
  571.   if not Assigned(FDSWriter) then
  572.     FDSWriter := TDataPacketWriter.Create;
  573.   FDSWriter.Constraints := Constraints;
  574.   FDSWriter.OnGetParams := DoGetProviderAttributes;
  575.   FDSWriter.PacketOptions := PacketOpts;
  576.   FDSWriter.Options := ProvOpts;
  577.   FDSWriter.GetDataPacket(DataSet, RecsOut, Data);
  578. end;
  579. procedure TDataSetProvider.Notification(AComponent: TComponent; Operation: TOperation);
  580. begin
  581.   inherited Notification(AComponent, Operation);
  582.   if (Operation = opRemove) and (FDataSet <> nil) and
  583.     (AComponent = FDataSet) then FDataSet := nil;
  584. end;
  585. { TUpdateTree }
  586. constructor TUpdateTree.Create(AParent: TUpdateTree; AResolver: TCustomResolver);
  587. begin
  588.   FResolver := AResolver;
  589.   FParent := AParent;
  590.   FDeltaDS := TPacketDataSet.Create(nil);
  591.   FDeltaDS.ObjectView := True;
  592.   FDeltaDS.FieldDefs.HiddenFields := True;
  593.   FDetails := TList.Create;
  594.   FName := '';
  595. end;
  596. destructor TUpdateTree.Destroy;
  597. begin
  598.   if Assigned(FResolver) then
  599.     FResolver.FreeTreeData(Self);
  600.   Clear;
  601.   FDetails.Free;
  602.   if not Assigned(Parent) then
  603.     FDeltaDS.Free;
  604.   inherited Destroy;
  605. end;
  606. function TUpdateTree.GetIsNested: Boolean;
  607. begin
  608.   Result := Assigned(Source) and Assigned(Source.DataSetField);
  609. end;
  610. procedure TUpdateTree.Clear;
  611. var
  612.   i: Integer;
  613. begin
  614.   for i := 0 to DetailCount - 1 do
  615.     Details[i].Free;
  616.   FDetails.Clear;
  617.   FDeltaDS.Data := NULL;
  618.   if not Assigned(Parent) then
  619.   begin
  620.     FErrorDS.Free;
  621.     FErrorDS := nil;
  622.   end;
  623. end;
  624. function TUpdateTree.GetTree(const AName: string): TUpdateTree;
  625. var
  626.   i: Integer;
  627. begin
  628.   for i := 0 to DetailCount - 1 do
  629.     if AnsiCompareText(Details[i].Name, AName) = 0 then
  630.     begin
  631.       Result := Details[i];
  632.       Exit;
  633.     end;
  634.   Result := TUpdateTree.Create(Self, FResolver);
  635.   Result.Name := AName;
  636.   FDetails.Add(Result);
  637. end;
  638. procedure TUpdateTree.InitData(ASource: TDataSet);
  639. var
  640.   i: Integer;
  641.   Tree: TUpdateTree;
  642.   List: TList;
  643. begin
  644.   if ASource = nil then
  645.   begin
  646.     for i := 0 to FDetails.Count - 1 do
  647.       TUpdateTree(FDetails[i]).InitData(nil);
  648.     if FOpened then FSourceDS.Close;
  649.     FOpened := False;
  650.   end else
  651.   begin
  652.     FSourceDS := ASource;
  653.     FOpened := (FSourceDS.FieldCount = 0) and FSourceDS.ObjectView and 
  654.             (not FSourceDS.IsUniDirectional);
  655.     if FOpened then FSourceDS.Open;
  656.     if FSourceDS.ObjectView then
  657.       for i := 0 to FSourceDS.FieldCount - 1 do
  658.         if FSourceDS.Fields[i].DataType in [ftDataSet] then
  659.           with TDataSetField(FSourceDS.Fields[i]) do
  660.           begin
  661.             Tree := GetTree(FSourceDS.Fields[i].FieldName);
  662.             Tree.InitData(NestedDataSet);
  663.           end;
  664.     List := TList.Create;
  665.     try
  666.       FSourceDS.GetDetailDataSets(List);
  667.       for i := 0 to List.Count - 1 do
  668.       begin
  669.         Tree := GetTree(TDataSet(List[i]).Name);
  670.         Tree.InitData(TDataSet(List[i]));
  671.       end;
  672.     finally
  673.       List.Free;
  674.     end;
  675.   end;
  676. end;
  677. type
  678.   TPropReader = class(TReader);
  679. procedure TUpdateTree.InitDelta(ADelta: TPacketDataSet);
  680. var
  681.   i: Integer;
  682.   Attr: Variant;
  683.   KeySet: Boolean;
  684.   Tree: TUpdateTree;
  685.   FieldInfo: TFieldInfo;
  686.   P: Pointer;
  687.   Stream: TMemoryStream;
  688.   Reader: TPropReader;
  689. begin
  690.   if (FDeltaDS <> nil) and (FDeltaDS <> ADelta) then
  691.     FDeltaDS.Free;
  692.   FDeltaDS := ADelta;
  693.   FDeltaDS.LogChanges := False;
  694.   KeySet := False;
  695.   Stream := TMemoryStream.Create;
  696.   try
  697.     for i := 0 to FDeltaDS.FieldCount - 1 do
  698.     begin
  699.       Attr := FDeltaDS.InternalGetOptionalParam(szPROVFLAGS, FDeltaDS.Fields[i].FieldNo);
  700.       if not (VarIsNull(Attr) or VarIsClear(Attr)) then
  701.         FDeltaDS.Fields[i].ProviderFlags := TProviderFlags(Byte(Attr));
  702.       Attr := FDeltaDS.InternalGetOptionalParam(szORIGIN, FDeltaDS.Fields[i].FieldNo);
  703.       if not (VarIsNull(Attr) or VarIsClear(Attr)) then
  704.         FDeltaDS.Fields[i].Origin := Attr;
  705.       Attr := FDeltaDS.InternalGetOptionalParam(szSERVERCALC, FDeltaDS.Fields[i].FieldNo);
  706.       if not (VarIsClear(Attr) or VarIsNull(Attr)) and
  707.         (VarType(Attr) = varBoolean) and Boolean(Attr) then
  708.         FDeltaDS.Fields[i].Tag := tagSERVERCALC;
  709.       {Setup included field properties}
  710. (**)      Attr := FDeltaDS.InternalGetOptionalParam(szFIELDPROPS, FDeltaDS.Fields[i].FieldNo);
  711.       if not (VarIsNull(Attr) or VarIsClear(Attr) or not VarIsArray(Attr)) then
  712.       begin
  713.         Stream.Size := VarArrayHighBound(Attr, 1);
  714.         P := VarArrayLock(Attr);
  715.         try
  716.           Stream.Position := 0;
  717.           Stream.Write(Pointer(Integer(P))^, Stream.Size);
  718.           Stream.Position := 0;
  719.         finally
  720.           VarArrayUnlock(Attr);
  721.         end;
  722.         Attr := NULL;
  723.         Reader := TPropReader.Create(Stream, 1024);
  724.         try
  725.           Reader.ReadListBegin;
  726.           while not Reader.EndOfList do
  727.             Reader.ReadProperty(FDeltaDS.Fields[i]);
  728.         finally
  729.           Reader.Free;
  730.         end;
  731.       end;
  732.       if GetFieldInfo(FDeltaDS.Fields[i].Origin, FieldInfo) then
  733.         FDeltaDS.Fields[i].Origin := FieldInfo.OriginalFieldName else
  734.         FDeltaDS.Fields[i].Origin := FDeltaDS.Fields[i].FieldName;
  735.       if pfInKey in FDeltaDS.Fields[i].ProviderFlags then
  736.         KeySet := True;
  737.       if Delta.Fields[i].DataType = ftDataSet then
  738.         with TDataSetField(Delta.Fields[i]) do
  739.         begin
  740.           Tree := GetTree(Delta.Fields[i].FieldName);
  741.           Tree.InitDelta(TPacketDataSet(NestedDataSet));
  742.         end;
  743.     end;
  744.   finally
  745.     Stream.Free;
  746.   end;
  747.   FResolver.InitTreeData(Self);
  748.   if not KeySet then
  749.     FResolver.InitKeyFields(Self, FDeltaDS);
  750. end;
  751. procedure TUpdateTree.InitDelta(const ADelta: OleVariant);
  752. begin
  753.   if FDeltaDS.Active then Clear;
  754.   FDeltaDS.Data := ADelta;
  755.   InitDelta(FDeltaDS);
  756. end;
  757. function TUpdateTree.GetDetailCount: Integer;
  758. begin
  759.   Result := FDetails.Count;
  760. end;
  761. function TUpdateTree.GetDetail(Index: Integer): TUpdateTree;
  762. begin
  763.   Result := TUpdateTree(FDetails[Index]);
  764. end;
  765. procedure TUpdateTree.RefreshData(Options: TFetchOptions);
  766.   function NeedsUpdate(DataSet: TDataSet): Boolean;
  767.   var
  768.     i: Integer;
  769.     Field: TField;
  770.   begin
  771.     Result := False;
  772.     if DataSet.RecordCount = 0 then Exit;
  773.     for i := 0 to DataSet.FieldCount - 1 do
  774.     begin
  775.       Field := DataSet.Fields[i];
  776.       Result := (Field is TDataSetField) and
  777.                 (VarIsNull(Field.NewValue) or
  778.                  NeedsUpdate(TDataSetField(Field).NestedDataSet));
  779.       if Result then Exit;
  780.     end;
  781.   end;
  782. var
  783.   i: Integer;
  784.   Tree: TUpdateTree;
  785.   Field: TField;
  786.   Updated: Boolean;
  787. begin
  788.   Updated := False;
  789.   if (foRecord in Options) and (Delta.RecordCount > 0) then
  790.   begin
  791.     Updated := True;
  792.     FResolver.Provider.UpdateRecord(Source, Delta, False, True);
  793.   end;
  794.   for i := 0 to Delta.FieldCount - 1 do
  795.   begin
  796.     Field := Delta.Fields[i];
  797.     if (not Updated) and (foBlobs in Options) and Field.IsBlob and
  798.        VarIsNull(Field.NewValue) then
  799.     begin
  800.       Updated := True;
  801.       FResolver.Provider.UpdateRecord(Source, Delta, True, False);
  802.     end;
  803.     if (Field is TDataSetField) then
  804.     begin
  805.       if not Updated then
  806.         FResolver.Provider.LocateRecord(Source, Delta);
  807.       Tree := GetTree(Field.FieldName);
  808.       if Assigned(Tree) then
  809.       begin
  810.         if not VarIsNull(Field.NewValue) then
  811.         begin
  812.           if Tree.Delta.RecordCount > 0 then
  813.             Tree.RefreshData(Options);
  814.         end else
  815.           FResolver.Provider.FetchDetails(Tree.Source, Tree.Delta);
  816.       end;
  817.     end;
  818.   end;
  819. end;
  820. function TUpdateTree.DoUpdates: Boolean;
  821. var
  822.   i: Integer;
  823. begin
  824.   Result := True;
  825.   Delta.First;
  826.   while not Delta.EOF do
  827.   begin
  828.     Delta.InitAltRecBuffers(False);
  829.     FResolver.InternalBeforeResolve(Self);
  830.     if (Delta.UpdateStatus = usInserted) then
  831.     begin
  832.       Result := FResolver.InternalUpdateRecord(Self);
  833.       if not Result then Exit;
  834.     end;
  835.     for i := 0 to DetailCount - 1 do
  836.     begin
  837.       Result := Details[i].DoUpdates;
  838.       if not Result then Exit;
  839.     end;
  840.     if Delta.UpdateStatus = usUnmodified then
  841.       Delta.InitAltRecBuffers(True);
  842.     if (Delta.UpdateStatus = usModified) then
  843.       Result := FResolver.InternalUpdateRecord(Self);
  844.     if (Delta.UpdateStatus = usDeleted) then
  845.       Result := FResolver.InternalUpdateRecord(Self);
  846.     if not Result then Exit;
  847.     Delta.Next;
  848.   end;
  849. end;
  850. function TUpdateTree.GetErrorDS: TPacketDataSet;
  851. var
  852.   Field: TField;
  853. begin
  854.   if not Assigned(FErrorDS) then
  855.   begin
  856.     if not Assigned(Parent) then
  857.     begin
  858.       FErrorDS := TPacketDataSet.Create(nil);
  859.       FErrorDS.ObjectView := True;
  860.       FErrorDS.CreateFromDelta(Delta);
  861.     end else
  862.     begin
  863.       Field := Parent.ErrorDS.FieldByName(Delta.DataSetField.FieldName);
  864.       FErrorDS := (Field as TDataSetField).NestedDataSet as TPacketDataSet;
  865.     end;
  866.     FErrorDS.LogChanges := False;
  867.     FErrorDS.DSBase.SetProp(DSProp(dspropAUTOINC_DISABLED), Integer(True));
  868.   end;
  869.   Result := FErrorDS;
  870. end;
  871. function TUpdateTree.GetHasErrors: Boolean;
  872. begin
  873.   Result := Assigned(FErrorDS);
  874. end;
  875. procedure TUpdateTree.InitErrorPacket(E: EUpdateError; Response: TResolverResponse);
  876. var
  877.   TrueRecNo: DWord;
  878. begin
  879.   with ErrorDS do
  880.   begin
  881.     if Assigned(Parent) then Parent.InitErrorPacket(nil, rrSkip);
  882.     Self.Delta.UpdateCursorPos;
  883.     Self.Delta.DSCursor.GetRecordNumber(TrueRecNo);
  884.     if not Locate('ERROR_RECORDNO', Integer(TrueRecNo), []) then
  885.       Append else
  886.       Edit;
  887.     if not Assigned(E) then
  888.     begin
  889.       if Response = rrSkip then
  890.       begin
  891.         SetFields([TrueRecNo]);
  892.         Post;
  893.       end else
  894.         SetFields([TrueRecNo, 0, '', '', 0, 0]);
  895.     end else
  896.       SetFields([TrueRecNo, Ord(Response)+1, E.Message, '', 1, E.ErrorCode]);
  897.   end;
  898. end;
  899. { TCustomResolver }
  900. constructor TCustomResolver.Create(AProvider: TBaseProvider);
  901. begin
  902.   FProvider := AProvider;
  903.   FUpdateTree := TUpdateTree.Create(nil, Self);
  904. end;
  905. destructor TCustomResolver.Destroy;
  906. begin
  907.   FUpdateTree.Free;
  908.   inherited Destroy;
  909. end;
  910. { Updates }
  911. procedure TCustomResolver.BeginUpdate;
  912. begin
  913. end;
  914. procedure TCustomResolver.EndUpdate;
  915. begin
  916. end;
  917. procedure TCustomResolver.InitKeyFields(Tree: TUpdateTree; ADelta: TPacketDataSet);
  918. var
  919.   Pos, i: Integer;
  920.   KeyFields, FieldName: string;
  921. begin
  922.   KeyFields := IProviderSupport(Tree.Source).PSGetKeyFields;
  923.   Pos := 1;
  924.   while Pos <= Length(KeyFields) do
  925.   begin
  926.     FieldName := ExtractFieldName(KeyFields, Pos);
  927.     for i := 0 to ADelta.FieldCount - 1 do
  928.       if AnsiCompareText(FieldName, ADelta.Fields[i].Origin) = 0 then
  929.       begin
  930.         ADelta.Fields[i].ProviderFlags := ADelta.Fields[i].ProviderFlags + [pfInKey];
  931.         break;
  932.       end;
  933.   end;
  934. end;
  935. procedure TCustomResolver.InitTreeData(Tree: TUpdateTree);
  936. begin
  937. end;
  938. procedure TCustomResolver.FreeTreeData(Tree: TUpdateTree);
  939. begin
  940. end;
  941. procedure TCustomResolver.InternalBeforeResolve(Tree: TUpdateTree);
  942. begin
  943. end;
  944. function TCustomResolver.InternalUpdateRecord(Tree: TUpdateTree): Boolean;
  945. var
  946.   RecNoSave: Integer;
  947.   Applied: Boolean;
  948.   UpdateKind: TUpdateKind;
  949.   E: Exception;
  950.   PrevErr, Err: EUpdateError;
  951. begin
  952.   PrevErr := nil;
  953.   Err := nil;
  954.   Tree.Delta.UseCurValues := False;
  955.   while True do
  956.   try
  957.     UpdateKind := Tree.Delta.UpdateKind;
  958.     if ((UpdateKind = ukInsert) and (FPrevResponse in [rrMerge, rrApply])) or
  959.        ((FPrevResponse = rrMerge) and Tree.Delta.HasMergeConflicts) then
  960.       DatabaseError(SInvalidResponse);
  961.     Applied := False;
  962.     RecNoSave := Tree.Delta.RecNo;
  963.     try
  964.       if Assigned(Provider.BeforeUpdateRecord) then
  965.         Provider.BeforeUpdateRecord(Provider, Tree.Source, Tree.Delta, UpdateKind, Applied);
  966.     finally
  967.       if Tree.Delta.RecNo <> RecNoSave then
  968.         Tree.Delta.RecNo := RecNoSave;
  969.     end;
  970.     if not Applied then
  971.       case UpdateKind of
  972.         ukModify:
  973.         begin
  974.           if poDisableEdits in Provider.Options then
  975.             raise Exception.CreateRes(@SNoEditsAllowed);
  976.           DoUpdate(Tree);
  977.         end;
  978.         ukDelete:
  979.         begin
  980.           if poDisableDeletes in Provider.Options then
  981.             raise Exception.CreateRes(@SNoDeletesAllowed);
  982.           DoDelete(Tree);
  983.         end;
  984.         ukInsert:
  985.         begin
  986.           if poDisableInserts in Provider.Options then
  987.             raise Exception.CreateRes(@SNoInsertsAllowed);
  988.           DoInsert(Tree);
  989.         end;
  990.       end;
  991.     if Assigned(Provider.AfterUpdateRecord) then
  992.       Provider.AfterUpdateRecord(Provider, Tree.Source, Tree.Delta, UpdateKind);
  993.     if (poPropogateChanges in Provider.Options) and Tree.Delta.NewValuesModified then
  994.       LogUpdateRecord(Tree);
  995.     Break;
  996.   except
  997.       E := AcquireExceptionObject;
  998.       PrevErr.Free;
  999.       PrevErr := Err;
  1000.       Err := IProviderSupport(Tree.Source).PSGetUpdateException(E, PrevErr);
  1001.       if HandleUpdateError(Tree, Err, FMaxErrors, FErrorCount) then
  1002.       begin
  1003.         Tree.Delta.UseCurValues := True;
  1004.         Continue;
  1005.       end else
  1006.         break;
  1007.   end;
  1008.   PrevErr.Free;
  1009.   Err.Free;
  1010.   FPrevResponse := rrSkip;
  1011.   Result := FErrorCount <= FMaxErrors;
  1012. end;
  1013. function TCustomResolver.RowRequest(Row: OleVariant; Options: TFetchOptions): OleVariant;
  1014. begin
  1015.   BeginUpdate;
  1016.   try
  1017.     FUpdateTree.InitDelta(Row);
  1018.     try
  1019.       FUpdateTree.RefreshData(Options);
  1020.       Result := FUpdateTree.Delta.Data;
  1021.     finally
  1022.       FUpdateTree.Clear;
  1023.     end;
  1024.   finally
  1025.     EndUpdate;
  1026.   end;
  1027. end;
  1028. function TCustomResolver.ApplyUpdates(const Delta: OleVariant; MaxErrors: Integer;
  1029.   out ErrorCount: Integer): OleVariant;
  1030. var
  1031.   XmlMode: LongWord;
  1032.   Status: Integer;
  1033.   DataPacket: TDataPacket;
  1034. begin
  1035.   BeginUpdate;
  1036.   try
  1037.     FUpdateTree.InitDelta(Delta);
  1038.     try
  1039.       Provider.DoOnUpdateData(FUpdateTree.Delta);
  1040.       FPrevResponse := rrSkip;
  1041.       if MaxErrors = -1 then MaxErrors := MaxInt;
  1042.       FMaxErrors := MaxErrors;
  1043.       FErrorCount := 0;
  1044.       FUpdateTree.DoUpdates;
  1045.       ErrorCount := FErrorCount;
  1046.       if FUpdateTree.HasErrors then
  1047.       begin
  1048.         Status := FUpdateTree.ErrorDS.DSBase.GetProp(dspropXML_StreamMode, @XMLMode);
  1049.         if (Status <> 0) or (XMLMode = 0) then
  1050.           Result := FUpdateTree.ErrorDS.Data
  1051.         else
  1052.         begin
  1053.           FUpdateTree.ErrorDS.Check(FUpdateTree.ErrorDS.DSBase.StreamDS(DataPacket));
  1054.           DataPacketToVariant(DataPacket, Result);
  1055.         end;  
  1056.       end else
  1057.         Result := Null;
  1058.     finally
  1059.       FUpdateTree.Clear;
  1060.     end;
  1061.   finally
  1062.     EndUpdate;
  1063.   end;
  1064. end;
  1065. { Update error handling }
  1066. function TCustomResolver.HandleUpdateError(Tree: TUpdateTree;
  1067.   E: EUpdateError; var MaxErrors, ErrorCount: Integer): Boolean;
  1068. var
  1069.   Response: TResolverResponse;
  1070.   UpdateKind: TUpdateKind;
  1071. begin
  1072.   UpdateKind := Tree.Delta.UpdateKind;
  1073.   if ErrorCount < MaxErrors then
  1074.     Response := rrSkip else
  1075.     Response := rrAbort;
  1076.   try
  1077.     InitializeConflictBuffer(Tree);
  1078.   except
  1079.     { Ignore errors that occur when initializing the conflict buffer }
  1080.   end;
  1081.   if Assigned(Provider.OnUpdateError) then
  1082.     Provider.OnUpdateError(Provider, Tree.Delta, E, UpdateKind, Response);
  1083.   if Response in [rrSkip, rrAbort] then
  1084.   begin
  1085.     Inc(ErrorCount);
  1086.     if ErrorCount > MaxErrors then
  1087.       Response := rrAbort;
  1088.     if (Response = rrAbort) then
  1089.       MaxErrors := ErrorCount - 1;
  1090.     if Response in [rrSkip, rrAbort] then
  1091.       LogUpdateError(Tree, E, Response);
  1092.   end;
  1093.   FPrevResponse := Response;
  1094.   Result := Response in [rrMerge, rrApply];
  1095. end;
  1096. procedure TCustomResolver.LogUpdateRecord(Tree: TUpdateTree);
  1097. var
  1098.   I: Integer;
  1099.   CurVal: Variant;
  1100. begin
  1101.   Tree.InitErrorPacket(nil, rrApply);
  1102.   for I := 0 to Tree.Delta.FieldCount - 1 do
  1103.   begin
  1104.     { Blobs, Bytes and VarBytes are not included in result packet }
  1105.     if (Tree.Delta.Fields[I].IsBlob) or
  1106.        (Tree.Delta.Fields[I].DataType in [ftBytes, ftVarBytes]) then
  1107.       continue;
  1108.     CurVal := Tree.Delta.Fields[I].NewValue;
  1109.     if not VarIsClear(CurVal) then
  1110.       Tree.ErrorDS.FieldByName(Tree.Delta.Fields[I].FieldName).Value := CurVal;
  1111.   end;
  1112.   Tree.ErrorDS.Post;
  1113. end;
  1114. procedure TCustomResolver.LogUpdateError(Tree: TUpdateTree;
  1115.   E: EUpdateError; Response: TResolverResponse);
  1116. var
  1117.   I: Integer;
  1118.   CurVal: Variant;
  1119. begin
  1120.   Tree.InitErrorPacket(E, Response);
  1121.   if Tree.Delta.HasCurValues then
  1122.     for I := 0 to Tree.Delta.FieldCount - 1 do
  1123.     begin
  1124.       { Blobs, Bytes and VarBytes are not included in result packet }
  1125.       if (Tree.Delta.Fields[I].IsBlob) or
  1126.          (Tree.Delta.Fields[I].DataType in [ftBytes, ftVarBytes]) then
  1127.         continue;
  1128.       CurVal := Tree.Delta.Fields[I].CurValue;
  1129.       if not VarIsClear(CurVal) then
  1130.         Tree.ErrorDS.FieldByName(Tree.Delta.Fields[I].FieldName).Value := CurVal;
  1131.     end;
  1132.   Tree.ErrorDS.Post;
  1133. end;
  1134. { TDataSetResolver }
  1135. constructor TDataSetResolver.Create(AProvider: TDataSetProvider);
  1136. begin
  1137.   inherited Create(AProvider);
  1138.   FOpened := False;
  1139. end;
  1140. function TDataSetResolver.GetProvider: TDataSetProvider;
  1141. begin
  1142.   Result := TDataSetProvider(inherited Provider);
  1143. end;
  1144. procedure TDataSetResolver.BeginUpdate;
  1145. begin
  1146.   FOpened := not Provider.DataSet.Active;
  1147.   if FOpened then
  1148.   begin
  1149.     Provider.DataSet.Open;
  1150.     FBookmark := '';
  1151.   end else
  1152.     FBookmark := Provider.DataSet.Bookmark;
  1153. end;
  1154. procedure TDataSetResolver.EndUpdate;
  1155. begin
  1156.   if FOpened then
  1157.   begin
  1158.     Provider.DataSet.Close;
  1159.     FOpened := False;
  1160.   end else
  1161.   begin
  1162.     if (Length(FBookmark) > 0) and
  1163.        Provider.DataSet.BookmarkValid(@FBookmark[1]) then
  1164.     Provider.DataSet.Bookmark := FBookmark;
  1165.   end;
  1166. end;
  1167. procedure TDataSetResolver.InitializeConflictBuffer(Tree: TUpdateTree);
  1168. begin
  1169.   { Set the conflict buffer to the current values of the data }
  1170.   if Provider.FindRecord(Tree.Source, Tree.Delta, upWhereKeyOnly) then
  1171.     Tree.Delta.AssignCurValues(Tree.Source);
  1172. end;
  1173. procedure TDataSetResolver.InternalBeforeResolve(Tree: TUpdateTree);
  1174. begin
  1175.   Provider.FindRecord(Tree.Source, Tree.Delta, Provider.UpdateMode);
  1176. end;
  1177. procedure TDataSetResolver.PutRecord(Tree: TUpdateTree);
  1178.   procedure PutField(Src, Dest: TField); forward;
  1179.   procedure PutObjectField(Src, Dest: TObjectField);
  1180.   var
  1181.     i: Integer;
  1182.   begin
  1183.     if VarIsNull(Src.NewValue) then
  1184.       Dest.Clear else
  1185.       for i := 0 to Src.FieldCount - 1 do
  1186.         if (not VarIsClear(Src.Fields[i].NewValue)) and
  1187.            (pfInUpdate in Src.Fields[i].ProviderFlags) then
  1188.           PutField(Src.Fields[i], Dest.Fields[i]);
  1189.   end;
  1190.   procedure PutField(Src, Dest: TField);
  1191.   begin
  1192.     if (Src.DataType in [ftArray, ftADT]) then
  1193.       PutObjectField(TObjectField(Src), TObjectField(Dest)) else
  1194.     if (Src.DataType in [ftDataSet, ftReference]) then
  1195.       raise Exception.CreateRes(@SNoDataSets) else
  1196.     if (not VarIsClear(Src.NewValue)) and
  1197.        (pfInUpdate in Src.ProviderFlags) then
  1198.       Dest.Assign(Src);
  1199.   end;
  1200. var
  1201.   i: Integer;
  1202.   Field: TField;
  1203. begin
  1204.   with Tree do
  1205.   try
  1206.     for i := 0 to Delta.FieldCount - 1 do
  1207.     begin
  1208.       Field := Source.FindField(Delta.Fields[i].FieldName);
  1209.       if (Field <> nil) and (Delta.Fields[i].DataType <> ftDataSet) then
  1210.         PutField(Delta.Fields[i], Field);
  1211.     end;
  1212.     Source.Post;
  1213.   except
  1214.     Source.Cancel;
  1215.     raise;
  1216.   end;
  1217. end;
  1218. procedure TDataSetResolver.DoUpdate(Tree: TUpdateTree);
  1219. begin
  1220.   with Tree do
  1221.   begin
  1222.     if not Provider.FindRecord(Source, Delta, Provider.UpdateMode) then
  1223.       DatabaseError(SRecordChanged);
  1224.     Source.Edit;
  1225.     PutRecord(Tree);
  1226.   end;
  1227. end;
  1228. procedure TDataSetResolver.DoDelete(Tree: TUpdateTree);
  1229. begin
  1230.   with Tree do
  1231.   begin
  1232.     if Provider.FindRecord(Tree.Source, Tree.Delta, Provider.UpdateMode) then
  1233.       Source.Delete else
  1234.       DatabaseError(SRecordChanged);
  1235.   end;
  1236. end;
  1237. procedure TDataSetResolver.DoInsert(Tree: TUpdateTree);
  1238. begin
  1239.   Tree.Source.Append;
  1240.   PutRecord(Tree);
  1241. end;
  1242. { TSQLResolver }
  1243. constructor TSQLResolver.Create(AProvider: TDataSetProvider);
  1244. begin
  1245.   inherited Create(AProvider);
  1246.   FSQL := TStringList.Create;
  1247.   FParams := TParams.Create(nil);
  1248. end;
  1249. destructor TSQLResolver.Destroy;
  1250. begin
  1251.   FSQL.Free;
  1252.   FParams.Free;
  1253.   inherited Destroy;
  1254. end;
  1255. function TSQLResolver.GetProvider: TDataSetProvider;
  1256. begin
  1257.   Result := TDataSetProvider(inherited Provider);
  1258. end;
  1259. procedure TSQLResolver.InitTreeData(Tree: TUpdateTree);
  1260.   function GetQuotedTableName(SQLBased: Boolean;
  1261.     const QuoteChar, TableName: string): string;
  1262.   var
  1263.     DotPos, DotPos2: Integer;
  1264.   begin
  1265.     Result := '';
  1266.     if Length(TableName) > 0 then
  1267.     begin
  1268.       if (TableName[1] in ['''','"','`']) or (TableName[strlen(PChar(TableName))] in ['''','"','`']) then
  1269.         Result := TableName else
  1270.       begin
  1271.         if SQLBased then
  1272.         begin
  1273.           Result := TableName;
  1274.           DotPos := Pos('.', Result);
  1275.           DotPos2 := Pos('.',PChar(Result) + DotPos);
  1276.           if DotPos2 <> 0 then
  1277.             DotPos2 := DotPos2 + DotPos;
  1278.           if (DotPos <> 0) and (DotPos2 <> 0 ) then
  1279.           begin
  1280.             System.Insert(QuoteChar, Result, DotPos2);
  1281.             System.Insert(QuoteChar, Result, DotPos2 + 2);
  1282.             System.Insert(QuoteChar, Result, DotPos + 1);
  1283.             System.Insert(QuoteChar, Result, DotPos);
  1284.           end
  1285.           else
  1286.           if DotPos <> 0 then
  1287.           begin
  1288.             System.Insert(QuoteChar, Result, DotPos + 1);
  1289.             System.Insert(QuoteChar, Result, DotPos);
  1290.           end;
  1291.           Result := QuoteChar + Result + QuoteChar;
  1292.         end else
  1293.           Result := QuoteChar + TableName + QuoteChar;
  1294.       end;
  1295.     end;
  1296.   end;
  1297. var
  1298.   Info: PSQLInfo;
  1299.   i: Integer;
  1300.   TableName: string;
  1301. begin
  1302.   if Tree.Data <> nil then
  1303.     Dispose(PSQLInfo(Tree.Data));
  1304.   New(Info);
  1305.   Tree.Data := Info;
  1306.   Info.IsSQLBased := IProviderSupport(Tree.Source).PSIsSQLBased;
  1307.   Info.QuoteChar := IProviderSupport(Tree.Source).PSGetQuoteChar;
  1308.   TableName := VarToStr(Tree.Delta.GetOptionalParam(szTABLE_NAME));
  1309.   if TableName = '' then
  1310.     TableName := IProviderSupport(Tree.Source).PSGetTableName;
  1311.   Provider.DoGetTableName(Tree.Source, TableName);
  1312.   if TableName <> '' then
  1313.     Info.QuotedTable := GetQuotedTableName(Info.IsSQLBased, Info.QuoteChar, TableName);
  1314.   if Info.IsSQLBased then
  1315.     Info.QuotedTableDot := '' else
  1316.     Info.QuotedTableDot := Info.QuotedTable + '.';
  1317.   Info.HasObjects := False;
  1318.   for i := 0 to Tree.Delta.FieldCount - 1 do
  1319.     if (Tree.Delta.Fields[i] is TObjectField) and
  1320.        (TObjectField(Tree.Delta.Fields[i]).ObjectType <> '') then
  1321.     begin
  1322.       Info.HasObjects := True;
  1323.       break;
  1324.     end;
  1325. end;
  1326. procedure TSQLResolver.FreeTreeData(Tree: TUpdateTree);
  1327. begin
  1328.   Dispose(PSQLInfo(Tree.Data));
  1329.   Tree.Data := nil;
  1330. end;
  1331. procedure TSQLResolver.DoExecSQL(SQL: TStringList; Params: TParams);
  1332. var
  1333.   RowsAffected: Integer;
  1334. begin
  1335.   RowsAffected := IProviderSupport(Provider.DataSet).PSExecuteStatement(SQL.Text, Params);
  1336.   if not (poAllowMultiRecordUpdates in Provider.Options) and (RowsAffected > 1) then
  1337.   begin
  1338.     IProviderSupport(Provider.DataSet).PSEndTransaction(False);
  1339.     Provider.FTransactionStarted := False;
  1340.     DatabaseError(STooManyRecordsModified);
  1341.   end;
  1342.   if RowsAffected < 1 then
  1343.     DatabaseError(SRecordChanged);
  1344. end;
  1345. procedure TSQLResolver.DoGetValues(SQL: TStringList; Params: TParams;
  1346.   DataSet: TDataSet);
  1347. var
  1348.   DS: TDataSet;
  1349. begin
  1350.   DS := nil;
  1351.   IProviderSupport(Provider.DataSet).PSExecuteStatement(SQL.Text, Params, @DS);
  1352.   if Assigned(DS) then
  1353.   try
  1354.     TPacketDataSet(DataSet).AssignCurValues(DS)
  1355.   finally
  1356.     DS.Free;
  1357.   end;
  1358. end;
  1359. procedure TSQLResolver.InitializeConflictBuffer(Tree: TUpdateTree);
  1360. var
  1361.   Alias: string;
  1362. begin
  1363.   if PSQLInfo(Tree.Data)^.HasObjects then Alias := DefAlias else Alias := '';
  1364.   FSQL.Clear;
  1365.   FParams.Clear;
  1366.   GenSelectSQL(Tree, FSQL, FParams, Alias);
  1367.   DoGetValues(FSQL, FParams, Tree.Delta);
  1368. end;
  1369. procedure TSQLResolver.InternalDoUpdate(Tree: TUpdateTree; UpdateKind: TUpdateKind);
  1370. var
  1371.   Alias: string;
  1372. begin
  1373.   if not IProviderSupport(Tree.Source).PSUpdateRecord(UpdateKind, Tree.Delta) then
  1374.   begin
  1375.     if (PSQLInfo(Tree.Data)^.QuotedTable = '') and not Tree.IsNested then
  1376.       DatabaseError(SNoTableName);
  1377.     if PSQLInfo(Tree.Data)^.HasObjects then Alias := DefAlias else Alias := '';
  1378.     FSQL.Clear;
  1379.     FParams.Clear;
  1380.     case UpdateKind of
  1381.       ukModify: GenUpdateSQL(Tree, FSQL, FParams, Alias);
  1382.       ukInsert: GenInsertSQL(Tree, FSQL, FParams);
  1383.       ukDelete: GenDeleteSQL(Tree, FSQL, FParams, Alias);
  1384.     end;
  1385.     DoExecSQL(FSQL, FParams);
  1386.   end;
  1387. end;
  1388. procedure TSQLResolver.DoUpdate(Tree: TUpdateTree);
  1389. begin
  1390.   InternalDoUpdate(Tree, ukModify);
  1391. end;
  1392. procedure TSQLResolver.DoDelete(Tree: TUpdateTree);
  1393. begin
  1394.   InternalDoUpdate(Tree, ukDelete);
  1395. end;
  1396. procedure TSQLResolver.DoInsert(Tree: TUpdateTree);
  1397. begin
  1398.   InternalDoUpdate(Tree, ukInsert);
  1399. end;
  1400. { SQL generation }
  1401. function QuoteFullName(const FullName, QuoteChar: string): string;
  1402. var
  1403.   i: Integer;
  1404.   p: PChar;
  1405. begin
  1406.   if (Length(FullName) > 1) and (FullName[1] in [#0, #1]) then
  1407.     p := @FullName[2] else
  1408.     p := PChar(FullName);
  1409.   Result := Format('%s%s%0:s',[QuoteChar, p]);
  1410.   for i := Length(Result) downto 1 do
  1411.     if Result[i] = '.' then
  1412.     begin
  1413.       System.Insert(QuoteChar, Result, i + 1);
  1414.       System.Insert(QuoteChar, Result, i);
  1415.     end;
  1416. end;
  1417. function TSQLResolver.UseFieldInUpdate(Field: TField): Boolean;
  1418. const
  1419.   ExcludedTypes = [ftAutoInc, ftDataSet, ftADT, ftArray, ftReference, ftCursor, ftUnknown];
  1420. begin
  1421.   with Field do
  1422.   begin
  1423.     Result := (pfInUpdate in ProviderFlags) and not (DataType in ExcludedTypes) and
  1424.       not ReadOnly and (FieldKind = fkData) and not (pfHidden in ProviderFlags) and
  1425.       not VarIsClear(NewValue) and (Tag <> tagSERVERCALC);
  1426.   end;
  1427. end;
  1428. function TSQLResolver.UseFieldInWhere(Field: TField; Mode: TUpdateMode): Boolean;
  1429. const
  1430.   ExcludedTypes = [ftDataSet, ftADT, ftArray, ftReference, ftCursor, ftUnknown];
  1431. begin
  1432.   with Field do
  1433.   begin
  1434.     Result := not (DataType in ExcludedTypes) and not IsBlob and
  1435.       (FieldKind = fkData) and (Tag <> tagSERVERCALC);
  1436.     if Result then
  1437.       case Mode of
  1438.         upWhereAll:
  1439.           Result := pfInWhere in ProviderFlags;
  1440.         upWhereChanged:
  1441.           Result := ((pfInWhere in ProviderFlags) and not VarIsClear(NewValue)) or
  1442.             (pfInKey in ProviderFlags);
  1443.         upWhereKeyOnly:
  1444.           Result := pfInKey in ProviderFlags;
  1445.       end;
  1446.   end;
  1447. end;
  1448. procedure TSQLResolver.GenWhereSQL(Tree: TUpdateTree; SQL: TStrings; Params: TParams;
  1449.   GenUpdateMode: TUpdateMode; Alias: string);
  1450.   function AddField(Field: TField; InObject: Boolean): Boolean;
  1451.   var
  1452.     i: Integer;
  1453.     BindText: string;
  1454.     s:string;
  1455.     oP:TParam;
  1456.   begin
  1457.     Result := False;
  1458.     with PSQLInfo(Tree.Data)^ do
  1459.     begin
  1460.       if Field.DataType = ftADT then
  1461.       begin
  1462.         for i := 0 to TObjectField(Field).FieldCount - 1 do
  1463.           if AddField(TObjectField(Field).Fields[i], True) then
  1464.             Result := True;
  1465.       end else
  1466.       if UseFieldInWhere(Field, GenUpdateMode) and (Field.DataSize < dsMaxStringSize) then
  1467.       begin
  1468.         Result := True;
  1469.         if InObject then
  1470.         begin
  1471.           if VarIsNull(Field.OldValue) then
  1472.             BindText := Format(' %s.%s is null and', [Alias,   { Do not localize }
  1473.               QuoteFullName(Field.FullName, QuoteChar)])
  1474.           else
  1475.           begin
  1476.             BindText := Format(' %s.%s = ? and',[Alias,        { Do not localize }
  1477.               QuoteFullName(Field.FullName, QuoteChar)]);
  1478.             TParam(Params.Add).AssignFieldValue(Field, Field.OldValue);
  1479.           end;
  1480.         end else
  1481.         begin
  1482.           if VarIsNull(Field.OldValue) or (not IsSQLBased and
  1483.              (Field.DataType = ftString) and (Length(Field.OldValue) = 0)) then
  1484.             BindText := Format(' %s%s%s%1:s is null and',       { Do not localize }
  1485.               [PSQLInfo(Tree.Data)^.QuotedTableDot, QuoteChar, Field.Origin])
  1486.           else
  1487.           begin
  1488.             BindText := Format(' %s%s%s%1:s = ? and',           { Do not localize }
  1489.                 [PSQLInfo(Tree.Data)^.QuotedTableDot, QuoteChar, Field.Origin]);
  1490.             IF (Field.DataType = ftDateTime) then
  1491.             begin
  1492.               //***********************唐荨荨于2005-07-21调整****************************
  1493.               s:=SQLTimeStampToStr('yyyy-mm-dd hh:mm:ss.zzz',VarToSQLTimeStamp(Field.OldValue));
  1494.               if rightstr(s,4)='.000' then
  1495.               begin
  1496.                 TParam(Params.Add).AssignFieldValue(Field, Field.OldValue);
  1497.               end
  1498.               else
  1499.               begin
  1500.                 oP:=TParam(Params.Add);
  1501.                 oP.DataType:=ftString;
  1502.                 oP.Size:=length(s);
  1503.                 oP.Value:=s;
  1504.                 oP.Bound:=true;
  1505.               end;
  1506.               //***********************************************************************
  1507.             end
  1508.             else
  1509.               TParam(Params.Add).AssignFieldValue(Field, Field.OldValue);
  1510.           end;
  1511.         end;
  1512.         SQL.Add(BindText);
  1513.       end;
  1514.     end;
  1515.   end;
  1516. var
  1517.   I: Integer;
  1518.   TempStr: string;
  1519.   Added: Boolean;
  1520. begin
  1521.   with PSQLInfo(Tree.Data)^ do
  1522.   begin
  1523.     SQL.Add('where');
  1524.     Added := False;
  1525.     for I := 0 to Tree.Delta.FieldCount - 1 do
  1526.       if AddField(Tree.Delta.Fields[I], Alias = NestAlias) then
  1527.         Added := True;
  1528.     if not Added then
  1529.       DatabaseError(SNoKeySpecified);
  1530.     { Remove last ' and'}
  1531.     TempStr := SQL[SQL.Count-1];
  1532.     SQL[SQL.Count-1] := Copy(TempStr, 1, Length(TempStr) - 4);
  1533.   end;
  1534. end;
  1535. procedure TSQLResolver.GenInsertSQL(Tree: TUpdateTree; SQL: TStrings;
  1536.   Params: TParams);
  1537.   procedure AddField(Field: TField; var FieldLine, ParamLine: string);
  1538.   var
  1539.     i: Integer;
  1540.     TempStr: string;
  1541.     Value: Variant;
  1542.   begin
  1543.     with PSQLInfo(Tree.Data)^ do
  1544.     begin
  1545.       if Field.DataType in [ftADT, ftArray] then
  1546.       begin
  1547.         FieldLine := Format('%s%s%s%s%2:s, ', [FieldLine, PSQLInfo(Tree.Data)^.QuotedTableDot,
  1548.           QuoteChar, Field.Origin]);
  1549.         ParamLine := Format('%s%s(', [ParamLine, TObjectField(Field).ObjectType]);
  1550.         for i := 0 to TObjectField(Field).FieldCount - 1 do
  1551.           AddField(TObjectField(Field).Fields[i], TempStr, ParamLine);
  1552.         ParamLine := Copy(ParamLine, 1, Length(ParamLine) - 2) + '), ';
  1553.       end else
  1554.       if (Field.DataType = ftDataSet) and (TObjectField(Field).ObjectType <> '') then
  1555.       begin
  1556.         FieldLine := Format('%s%s%s%s%2:s, ', [FieldLine, PSQLInfo(Tree.Data)^.QuotedTableDot,
  1557.           QuoteChar, Field.Origin]);
  1558.         ParamLine := Format('%s%s(), ', [ParamLine, TDataSetField(Field).ObjectType]);
  1559.       end else
  1560.       if (UseFieldInUpdate(Field)) or ((Field.ParentField <> nil) and (Field.ParentField.DataType in [ftADT, ftArray, ftReference]) and VarIsNull(Field.Value)) then
  1561.       begin
  1562.         if (Field.DataType = ftOraBlob) and (not InformixLob) then
  1563.         begin
  1564.           FieldLine := Format('%s%s%s%s%2:s, ', [FieldLine, PSQLInfo(Tree.Data)^.QuotedTableDot,
  1565.                     QuoteChar, Field.Origin]);
  1566.           ParamLine := ParamLine + 'EMPTY_BLOB(), '    { Do not localize }
  1567.         end 
  1568.         else if (Field.DataType = ftOraClob) and (not InformixLob) then
  1569.         begin
  1570.           FieldLine := Format('%s%s%s%s%2:s, ', [FieldLine, PSQLInfo(Tree.Data)^.QuotedTableDot,
  1571.                     QuoteChar, Field.Origin]);
  1572.           ParamLine := ParamLine + 'EMPTY_CLOB(), '    { Do not localize }
  1573.         end else  
  1574.         if (Field.ParentField <> nil) and VarIsNull(Field.Value) then
  1575.         begin
  1576.           FieldLine := Format('%s%s%s%s%2:s, ', [FieldLine, PSQLInfo(Tree.Data)^.QuotedTableDot,
  1577.              QuoteChar, Field.Origin]);
  1578.           ParamLine := ParamLine + 'null, ';
  1579.         end else
  1580.         begin
  1581.           FieldLine := Format('%s%s%s%s%2:s, ', [FieldLine, PSQLInfo(Tree.Data)^.QuotedTableDot,
  1582.           QuoteChar, Field.Origin]);
  1583.           ParamLine := ParamLine + '?, ';
  1584.           Value := Field.NewValue;
  1585.           if VarIsClear(Value) then Value := Field.OldValue;
  1586.           TParam(Params.Add).AssignFieldValue(Field, Value);
  1587.         end;
  1588.       end;
  1589.     end;
  1590.   end;
  1591. var
  1592.   I, J: Integer;
  1593.   FieldLine, ParamLine: string;
  1594.   OraLobs: Integer;
  1595.   Value: Variant;
  1596. begin
  1597.   OraLobs := 0;
  1598.   with PSQLInfo(Tree.Data)^ do
  1599.   begin
  1600.     SQL.Clear;
  1601.     if Tree.IsNested then
  1602.     begin
  1603.       SQL.Add(Format('insert into the (select %s FROM %s %s',[QuoteFullName(Tree.Name, QuoteChar),
  1604.         PSQLInfo(Tree.Parent.Data).QuotedTable, DefAlias]));   { Do not localize }
  1605.       GenWhereSQL(Tree.Parent, SQL, Params, upWhereKeyOnly, DefAlias);
  1606.       SQL.Add(')');
  1607.     end else
  1608.       SQL.Add(Format('insert into %s', [QuotedTable]));        { Do not localize }
  1609.     FieldLine := '  (';
  1610.     ParamLine := FieldLine;
  1611.     for I := 0 to Tree.Delta.FieldCount - 1 do
  1612.     begin
  1613.       AddField(Tree.Delta.Fields[I], FieldLine, ParamLine);
  1614.       if Tree.Delta.Fields[I].DataType in [ftOraClob, ftOraBlob] then
  1615.         if (not InformixLob) then
  1616.           Inc(OraLobs);
  1617.     end;
  1618.     if not Tree.IsNested then
  1619.       SQL.Add(Copy(FieldLine, 1, Length(FieldLine)-2)+')');
  1620.     SQL.Add('values');
  1621.     SQL.Add(Copy(ParamLine, 1, Length(ParamLine)-2)+')');
  1622.     if OraLobs > 0 then
  1623.     begin
  1624.       SQL.Add(' RETURNING ');              { Do not localize }
  1625.       J := OraLobs;
  1626.       for I := 0 to Tree.Delta.FieldCount - 1 do
  1627.         if (Tree.Delta.Fields[I].DataType in [ftOraClob, ftOraBlob] )
  1628.            and UseFieldInUpdate(Tree.Delta.Fields[I])  then
  1629.            begin
  1630.              Dec(J);
  1631.              SQL.Add(Format('%s ', [Tree.Delta.Fields[I].FullName]));
  1632.              if J > 0 then SQL.Add(', ');
  1633.              Value := Tree.Delta.Fields[I].NewValue;
  1634.              if VarIsClear(Value) then Value := Tree.Delta.Fields[I].OldValue;
  1635.              TParam(Params.Add).AssignFieldValue(Tree.Delta.Fields[I], Value)
  1636.            end;
  1637.       SQL.Add('INTO ');                    { Do not localize }
  1638.       while OraLobs > 0 do
  1639.       begin
  1640.         SQL.Add('? ');
  1641.         Dec(OraLobs);
  1642.         if OraLobs > 0 then SQL.Add(', ');
  1643.       end;
  1644.     end;
  1645.   end;
  1646. end;
  1647. procedure TSQLResolver.GenDeleteSQL(Tree: TUpdateTree; SQL: TStrings;
  1648.   Params: TParams; Alias: string);
  1649. begin
  1650.   with PSQLInfo(Tree.Data)^ do
  1651.   begin
  1652.     SQL.Clear;
  1653.     if Tree.IsNested then
  1654.     begin
  1655.       Alias := NestAlias;
  1656.       SQL.Add(Format('delete the (select %s FROM %s %s',[QuoteFullName(Tree.Name, QuoteChar),
  1657.         PSQLInfo(Tree.Parent.Data).QuotedTable, DefAlias]));       { Do not localize }
  1658.       GenWhereSQL(Tree.Parent, SQL, Params, upWhereKeyOnly, DefAlias);
  1659.       SQL.Add(Format(') %s',[Alias]));
  1660.     end else
  1661.       SQL.Add(Format('delete from %s %s', [QuotedTable, Alias]));  { Do not localize } 
  1662.     GenWhereSQL(Tree, SQL, Params, Provider.UpdateMode, Alias);
  1663.   end;
  1664. end;
  1665. procedure TSQLResolver.GenUpdateSQL(Tree: TUpdateTree; SQL: TStrings;
  1666.   Params: TParams; Alias: string);
  1667.   procedure AddField(Field: TField; InObject, InArray: Boolean);
  1668.   var
  1669.     i: Integer;
  1670.     TempStr: string;
  1671.     Value: Variant;
  1672.     NoParam: Boolean;
  1673.   begin
  1674.     NoParam := False;
  1675.     with PSQLInfo(Tree.Data)^ do
  1676.     begin
  1677.       if Field.DataType = ftADT then
  1678.       begin
  1679.         if InArray then
  1680.           SQL.Add(Format(' %s(',[TObjectField(Field).ObjectType]));
  1681.         for i := 0 to TObjectField(Field).FieldCount - 1 do
  1682.           AddField(TObjectField(Field).Fields[i], True, InArray);
  1683.         if InArray then
  1684.         begin
  1685.           TempStr := SQL[SQL.Count-1];
  1686.           SQL[SQL.Count-1] := Copy(TempStr, 1, Length(TempStr) - 1);
  1687.           SQL.Add('),');
  1688.         end;
  1689.       end
  1690.       else if Field.DataType = ftArray then
  1691.       begin
  1692.         SQL.Add(Format('%s = %s(',[Field.FullName, TObjectField(Field).ObjectType]));
  1693.         for i := 0 to TObjectField(Field).FieldCount - 1 do
  1694.           AddField(TObjectField(Field).Fields[i], InObject, True);
  1695.         TempStr := SQL[SQL.Count-1];
  1696.         SQL[SQL.Count-1] := Copy(TempStr, 1, Length(TempStr) - 1);
  1697.         SQL.Add('),');
  1698.       end
  1699.       else if InArray then
  1700.       begin
  1701.         SQL.Add(' ?,');
  1702.         Value := Field.NewValue;
  1703.         if VarIsClear(Value) then Value := Field.OldValue;
  1704.         TParam(Params.Add).AssignFieldValue(Field, Value);
  1705.       end
  1706.       else if UseFieldInUpdate(Field) then
  1707.       begin
  1708.         if (Field.DataType = ftOraClob) and (not InformixLob) then
  1709.         begin
  1710.           NoParam := True;
  1711.           if InObject then
  1712.             SQL.Add(Format(' %s.%s = EMPTY_CLOB(),', [Alias, QuoteFullName(Field.FullName, QuoteChar),   { Do not localize }
  1713.               Field.FullName])) else 
  1714.             SQL.Add(Format(' %s%s%s%1:s = EMPTY_CLOB(),', [PSQLInfo(Tree.Data)^.QuotedTableDot,          { Do not localize }
  1715.                QuoteChar, Field.Origin]));
  1716.         end
  1717.         else if (Field.DataType = ftOraBlob) and (not InformixLob) then
  1718.         begin
  1719.           NoParam := True;
  1720.           if InObject then
  1721.             SQL.Add(Format(' %s.%s = EMPTY_BLOB(),', [Alias, QuoteFullName(Field.FullName, QuoteChar),   { Do not localize }
  1722.                Field.FullName])) else
  1723.             SQL.Add(Format(' %s%s%s%1:s = EMPTY_BLOB(),', [PSQLInfo(Tree.Data)^.QuotedTableDot,          { Do not localize }
  1724.                QuoteChar, Field.Origin]));
  1725.         end
  1726.         else if InObject then
  1727.           SQL.Add(Format(' %s.%s = ?,', [Alias, QuoteFullName(Field.FullName, QuoteChar),
  1728.             Field.FullName])) else
  1729.           SQL.Add(Format(' %s%s%s%1:s = ?,', [PSQLInfo(Tree.Data)^.QuotedTableDot,
  1730.             QuoteChar, Field.Origin]));
  1731.         if not NoParam then
  1732.         begin
  1733.           Value := Field.NewValue;
  1734.           if VarIsClear(Value) then Value := Field.OldValue;
  1735.           TParam(Params.Add).AssignFieldValue(Field, Value);
  1736.         end;
  1737.       end;
  1738.     end;
  1739.   end;
  1740. var
  1741.   I, J: integer;
  1742.   TempStr: string;
  1743.   OraLobs: Integer;
  1744.   Value: Variant;
  1745. begin
  1746.   OraLobs := 0;
  1747.   with PSQLInfo(Tree.Data)^ do
  1748.   begin
  1749.     if Tree.IsNested then
  1750.     begin
  1751.       Alias := NestAlias;
  1752.       SQL.Add(Format('update the (select %s FROM %s %s',[QuoteFullName(Tree.Name, QuoteChar),   { Do not localize }
  1753.         PSQLInfo(Tree.Parent.Data).QuotedTable, DefAlias]));
  1754.       GenWhereSQL(Tree.Parent, SQL, Params, upWhereKeyOnly, DefAlias);
  1755.       SQL.Add(Format(') %s set',[Alias]));                                                      { Do not localize }
  1756.     end else
  1757.       SQL.Add(Format('update %s %s set', [QuotedTable, Alias]));                                { Do not localize }
  1758.                                                                                                 
  1759.     for I := 0 to Tree.Delta.FieldCount - 1 do
  1760.     begin
  1761.       if (Tree.Delta.Fields[i].DataType in [ftOraClob, ftOraBlob]) and
  1762.           UseFieldInUpdate(Tree.Delta.Fields[I]) then
  1763.           if (not InformixLob) then
  1764.             Inc(OraLobs);
  1765.       AddField(Tree.Delta.Fields[i], Alias = NestAlias, False);
  1766.     end;
  1767.     { Remove last ',' }
  1768.     TempStr := SQL[SQL.Count-1];
  1769.     SQL[SQL.Count-1] := Copy(TempStr, 1, Length(TempStr) - 1);
  1770.     GenWhereSQL(Tree, SQL, Params, Provider.UpdateMode, Alias);
  1771.     if OraLobs > 0 then
  1772.     begin
  1773.       SQL.Add(' RETURNING ');       { Do not localize }
  1774.       J := OraLobs;
  1775.       for I := 0 to Tree.Delta.FieldCount - 1 do
  1776.         if (Tree.Delta.Fields[I].DataType in [ftOraClob, ftOraBlob]) 
  1777.            and UseFieldInUpdate(Tree.Delta.Fields[I])  then
  1778.            begin
  1779.              Dec(J);
  1780.              SQL.Add(Format('%s ', [Tree.Delta.Fields[I].FullName]));
  1781.              if J > 0 then SQL.Add(', ');
  1782.              Value := Tree.Delta.Fields[I].NewValue;
  1783.              if VarIsClear(Value) then Value := Tree.Delta.Fields[I].OldValue;
  1784.              TParam(Params.Add).AssignFieldValue(Tree.Delta.Fields[I], Value)
  1785.            end;
  1786.       SQL.Add('INTO ');         { Do not localize }
  1787.       while OraLobs > 0 do
  1788.       begin
  1789.         SQL.Add('? ');
  1790.         Dec(OraLobs);
  1791.         if OraLobs > 0 then SQL.Add(', ');
  1792.       end;
  1793.     end;
  1794.   end;
  1795. end;
  1796. procedure TSQLResolver.GenSelectSQL(Tree: TUpdateTree; SQL: TStrings;
  1797.   Params: TParams; Alias: string; Mode: TUpdateMode = upWhereKeyOnly);
  1798. var
  1799.   i: Integer;
  1800.   Temp: string;
  1801. begin
  1802.   with PSQLInfo(Tree.Data)^ do
  1803.   begin
  1804.     SQL.Add('select');
  1805.     for i := 0 to Tree.Delta.FieldCount - 1 do
  1806.       with Tree.Delta.Fields[i] do
  1807.         if not (DataType in [ftDataSet, ftReference]) and (FieldKind = fkData)
  1808.            and (pfInWhere in ProviderFlags) then
  1809.           SQL.Add(Format(' %s%s%s%1:s,',[QuotedTableDot, QuoteChar, Origin]));
  1810.     { Remove last ',' }
  1811.     Temp := SQL[SQL.Count-1];
  1812.     SQL[SQL.Count-1] := Copy(Temp, 1, Length(Temp) - 1);
  1813.     SQL.Add(Format(' from %s %s',[QuotedTable, Alias]));     { Do not localize }
  1814.     GenWhereSQL(Tree, SQL, Params, Mode, Alias);
  1815.   end;
  1816. end;
  1817. { TLocalAppServer }
  1818. constructor TLocalAppServer.Create(AProvider: TCustomProvider);
  1819. begin
  1820.   inherited Create;
  1821.   FProvider := AProvider;
  1822. end;
  1823. destructor TLocalAppServer.Destroy; 
  1824. begin
  1825.   if FProviderCreated then FProvider.Free;
  1826.   inherited Destroy;
  1827. end;
  1828. constructor TLocalAppServer.Create(ADataset: TDataset);
  1829. begin
  1830.   inherited Create;
  1831.   FProvider := TDatasetProvider.Create(nil);
  1832.   TDatasetProvider(FProvider).Dataset := ADataset;
  1833.   FProviderCreated := True;
  1834. end;
  1835. function TLocalAppServer.GetTypeInfoCount(out Count: Integer): HResult;
  1836. begin
  1837.   Result := E_NOTIMPL;
  1838. end;
  1839. function TLocalAppServer.GetTypeInfo(Index, LocaleID: Integer; out TypeInfo): HResult;
  1840. begin
  1841.   Result := E_NOTIMPL;
  1842. end;
  1843. function TLocalAppServer.GetIDsOfNames(const IID: TGUID; Names: Pointer;
  1844.   NameCount, LocaleID: Integer; DispIDs: Pointer): HResult;
  1845. begin
  1846.   Result := E_NOTIMPL;
  1847. end;
  1848. function TLocalAppServer.Invoke(DispID: Integer; const IID: TGUID; LocaleID: Integer;
  1849.   Flags: Word; var Params; VarResult, ExcepInfo, ArgErr: Pointer): HResult;
  1850. begin
  1851.   Result := E_NOTIMPL;
  1852. end;
  1853. function TLocalAppServer.AS_ApplyUpdates(const ProviderName: WideString;
  1854.   Delta: OleVariant; MaxErrors: Integer; out ErrorCount: Integer;
  1855.   var OwnerData: OleVariant): OleVariant;
  1856. begin
  1857.   Result := FProvider.ApplyUpdates(Delta, MaxErrors, ErrorCount, OwnerData);
  1858. end;
  1859. function TLocalAppServer.AS_GetRecords(const ProviderName: WideString; Count: Integer;
  1860.   out RecsOut: Integer; Options: Integer; const CommandText: WideString;
  1861.   var Params, OwnerData: OleVariant): OleVariant;
  1862. begin
  1863.   Result := FProvider.GetRecords(Count, RecsOut, Options, CommandText, Params,
  1864.     OwnerData);
  1865. end;
  1866. function TLocalAppServer.AS_GetProviderNames: OleVariant;
  1867. begin
  1868.   Result := NULL;
  1869. end;
  1870. function TLocalAppServer.AS_DataRequest(const ProviderName: WideString;
  1871.   Data: OleVariant): OleVariant;
  1872. begin
  1873.   Result := FProvider.DataRequest(Data);
  1874. end;
  1875. function TLocalAppServer.AS_GetParams(const ProviderName: WideString;
  1876.   var OwnerData: OleVariant): OleVariant;
  1877. begin
  1878.   Result := FProvider.GetParams(OwnerData);
  1879. end;
  1880. function TLocalAppServer.AS_RowRequest(const ProviderName: WideString;
  1881.   Row: OleVariant; RequestType: Integer; var OwnerData: OleVariant): OleVariant;
  1882. begin
  1883.   Result := FProvider.RowRequest(Row, RequestType, OwnerData);
  1884. end;
  1885. procedure TLocalAppServer.AS_Execute(const ProviderName: WideString;
  1886.    const CommandText: WideString; var Params, OwnerData: OleVariant);
  1887. begin
  1888.   FProvider.Execute(CommandText, Params, OwnerData);
  1889. end;
  1890. function TLocalAppServer.InterfaceSupportsErrorInfo(const iid: TGUID): HResult;
  1891. begin
  1892.   if IsEqualGUID(IAppServer, iid) then
  1893.     Result := S_OK else
  1894.     Result := S_FALSE;
  1895. end;
  1896. function TLocalAppServer.SafeCallException(ExceptObject: TObject;
  1897.   ExceptAddr: Pointer): HResult;
  1898. begin
  1899. {$IFDEF MSWINDOWS}
  1900.   Result := HandleSafeCallException(ExceptObject, ExceptAddr, IAppServer, '', '');
  1901. {$ENDIF}
  1902. {$IFDEF LINUX}
  1903. if ExceptObject is Exception then
  1904. begin
  1905. SetSafeCallExceptionMsg(Exception(ExceptObject).Message);
  1906. SetSafeCallExceptionAddr(ExceptAddr);
  1907. Result := HResult($8000FFFF);
  1908. end
  1909. else
  1910.     Result := inherited SafeCallException(ExceptObject, ExceptAddr);
  1911. {$ENDIF}
  1912. end;
  1913. end.