oraservicesuni.pas

来自「CrLab UniDAC 1.0 include sources」· PAS 代码 · 共 1,991 行 · 第 1/5 页

PAS
1,991
字号
      for i := 0 to High(KeyAndDataFields.DataFieldDescs) do begin
        FieldDesc := KeyAndDataFields.DataFieldDescs[i];
        if (FDataSetService.IsDMLRefresh and
          not (FieldDesc.DataType in [dtMemo, dtWideMemo, dtBlob])) or
          (LobReturning and (FieldDesc.DataType in [dtOraBlob, dtOraClob, dtWideOraClob]) and
          (not ModifiedFieldsOnly or not FieldIsNull(FieldDesc, False))) or
          ((FSeqFieldDesc = FieldDesc) and FSeqReturning)
        then begin
          if ReturnSB.Length > 0 then begin
            ReturnSB.Append(', ');
            IntoSB.Append(', ');
          end;
          RecordSet := TOCIRecordSet(FDataSetService.GetIRecordSet);
          ReturnSB.Append(FieldDesc.ActualNameQuoted(RecordSet, FDataSet.Options.QuoteNames));
          AddParam(IntoSB, FieldDesc, stInsert, Index);
        end;
      end;
    end;

    if ReturnSB.Length > 0 then begin
      FFooterSB.Append(#$D#$A'RETURNING'#$D#$A'  ');
      FFooterSB.Append(ReturnSB);
    end;

    if IntoSB.Length > 0 then begin
      FFooterSB.Append(#$D#$A'INTO'#$D#$A'  ');
      FFooterSB.Append(IntoSB);
    end;

    if Sequenced and not FSeqReturning then
      FFooterSB.Append(';'#$D#$A'end;');
  finally
    FSeqFieldDesc := nil;
    FSeqReturning := False;
    ReturnSB.Free;
    IntoSB.Free;
  end;
end;

procedure TCustomOraSQLGenerator.AddFieldToUpdateSQL(FieldDesc: TCRFieldDesc;
  const ModifiedFieldsOnly: boolean; const Index: integer = -1);
begin
  if (FieldDesc.DataType in [dtOraBlob, dtOraClob, dtWideOraClob]) and not (FDataSetService.GetTemporaryLobUpdate) then begin
    if FFldSB.Length > 0 then
      FFldSB.Append(', ');

    FFldSB.Append(FieldDesc.ActualNameQuoted(FDataSetService.GetIRecordSet, FDataSet.Options.QuoteNames));
    FFldSB.Append('=');

    if ModifiedFieldsOnly and FieldIsNull(FieldDesc, False) then
      FFldSB.Append('NULL')
    else begin
      if FieldDesc.DataType = dtOraBlob then
        FFldSB.Append('EMPTY_BLOB()')
      else
        FFldSB.Append('EMPTY_CLOB()');
    end;
  end
  else
    inherited;
end;

procedure TCustomOraSQLGenerator.GenerateUpdateSQL(const KeyAndDataFields: TKeyAndDataFields;
  const ModifiedFieldsOnly: boolean; const Index: integer = -1);
var
  i: integer;
  LobReturning: boolean;
  FieldDesc: TCRFieldDesc;

  ReturnSB: StringBuilder;
  IntoSB: StringBuilder;
  RecordSet: TOCIRecordSet;
begin
  inherited GenerateUpdateSQL(KeyAndDataFields, ModifiedFieldsOnly, Index);

  if FFldSB.Length = 0 then
    Exit;

  LobReturning := False;
  if not FDataSetService.GetTemporaryLobUpdate then
    for i := 0 to High(KeyAndDataFields.DataFieldDescs) do
      if KeyAndDataFields.DataFieldDescs[i].DataType in [dtOraBlob, dtOraClob, dtWideOraClob] then
        LobReturning := True;

  ReturnSB := StringBuilder.Create(100);
  IntoSB := StringBuilder.Create(100);
  try
    if FDataSetService.IsDMLRefresh or LobReturning then begin
      for i := 0 to High(KeyAndDataFields.DataFieldDescs) do begin
        FieldDesc := KeyAndDataFields.DataFieldDescs[i];
        if (FDataSetService.IsDMLRefresh and
          not (FieldDesc.DataType in [dtMemo, dtWideMemo, dtBlob, dtOraBlob, dtOraClob, dtWideOraClob])) or
          (LobReturning and (FieldDesc.DataType in [dtOraBlob,dtOraClob,dtWideOraClob]) and
          (not ModifiedFieldsOnly or FieldModified(FieldDesc)))
        then begin
            if ReturnSB.Length > 0 then begin
              ReturnSB.Append(', ');
              IntoSB.Append(', ');
            end;
            RecordSet := TOCIRecordSet(GetIRecordSet);
            ReturnSB.Append(FieldDesc.ActualNameQuoted(RecordSet, FDataSet.Options.QuoteNames));
            AddParam(IntoSB, FieldDesc, stUpdate, Index);
        end;
      end;

      if ReturnSB.Length <> 0 then begin
        FFooterSB.Append(#$D#$A'RETURNING'#$D#$A'  ');
        FFooterSB.Append(ReturnSB);
      end;

      if IntoSB.Length > 0 then
        FFooterSB.Append(#$D#$A'INTO'#$D#$A'  ');
        FFooterSB.Append(IntoSB);
      end;
  finally
    ReturnSB.Free;
    IntoSB.Free;
  end;
end;

procedure TCustomOraSQLGenerator.GenerateLockSQL(const KeyAndDataFields: TKeyAndDataFields;
  const Index: integer = -1);
begin
  FHeaderSB.Append('SELECT * FROM ');
  FHeaderSB.Append(FTableInfo.NormalizeName(FTableInfo.TableNameFull, FDataSet.Options.QuoteNames));
  FMiddleSB.Append(#$D#$A'WHERE'#$D#$A'  ');
  GenerateConditions(FCondSB, stLock, False, KeyAndDataFields, Index);
  FFooterSB.Append(#$D#$A'FOR UPDATE NOWAIT');
end;

procedure TCustomOraSQLGenerator.GenerateRefreshSQL(const KeyAndDataFields: TKeyAndDataFields;
  const ModifiedFieldsOnly: boolean);
begin
  if (csDesigning in FDataSet.ComponentState) and
    FDataSetService.IsFullRefresh or FDataSet.ReadOnly
  then begin
    GenerateConditions(FHeaderSB, stRefresh, ModifiedFieldsOnly, KeyAndDataFields);
    FHeaderSB.Insert(0, 'WHERE'#$D#$A'  ');
  end
  else
    inherited GenerateRefreshSQL(KeyAndDataFields, ModifiedFieldsOnly);
end;

function TCustomOraSQLGenerator.GenerateSQL(const StatementType: TStatementType;
  const ModifiedFieldsOnly: boolean;
  Params: TDAParams;
  const Index: Integer = -1): string;
begin
  if FDataSetService.CompatibilityMode then
    Result := ''
  else
    Result := inherited GenerateSQL(StatementType, ModifiedFieldsOnly, Params, Index);
end;

function TCustomOraSQLGenerator.GenerateTableSQL(const TableName, OrderFields: string): string;
var
  QuotedTableName, St1: string;
  i: integer;
  KeyFields: string;
begin
  QuotedTableName := TOCITableInfo.NormalizeName(TableName, FDataSet.Options.QuoteNames);

  KeyFields := FDataSetService.GetKeyFields;
  if (KeyFields = '') and not FDataSet.ReadOnly then begin
    KeyFields := FDataSetService.GetDBKeyList(TableName);
    TDBAccessUtils.SetKeyFields(FDataSet, KeyFields);
  end;

  if (KeyFields = '') or (AnsiUpperCase(KeyFields) = 'ROWID') then
    Result := 'SELECT T.RowId, T.*'#13#10'FROM ' + QuotedTableName + ' T'#13#10
  else
    Result := 'SELECT T.*'#13#10'FROM ' + QuotedTableName + ' T'#13#10;

  if OrderFields <> '' then begin
    St1 := OrderFields;

    for i := 1 to Length(St1) do
      if St1[i] = ';' then
        St1[i] := ',';

    Result := Result + 'ORDER BY ' + St1 + #13#10;
  end;
end;

function TCustomOraSQLGenerator.GenerateSelectValues(const ValuesList: string): string;
begin
  Result := 'SELECT ' + ValuesList + ' FROM Dual';
end;

{ TCustomOraUpdater }

constructor TCustomOraDataSetUpdater.Create(AOwner: TDataSetService);
begin
  inherited Create(AOwner);

  FDataSetService := TCustomOraDataSetService(AOwner);
end;

function TCustomOraDataSetUpdater.GetIdentityFieldValue(var Value: variant): boolean;
var
  Command: TOCICommand;
  RowId: string;
begin
  Command := TOCICommand(TDBAccessUtils.GetICommand(TCustomDADataSet(FUpdateQuery)));
  Assert(Command <> nil);
  RowId := Command.GetRowId;
  Result := RowID <> '';
  if Result then
    Value := RowID;
end;

procedure TCustomOraDataSetUpdater.CheckUpdateQuery(const StatementType: TStatementType);
begin
  inherited;

  TDBAccessUtils.GetICommand(FUpdateQuery as TCustomDADataSet).SetProp(prStoreRowId, True);
end;

procedure TCustomOraDataSetUpdater.SetUpdateQueryOptions(const StatementType: TStatementType);
var
  DestCommand, SourceCommand: TCRCommand;

  procedure CopyPropC(Prop: integer);
  var
    v: variant;
  begin
    SourceCommand.GetProp(Prop, v);
    DestCommand.SetProp(Prop, v);
  end;

begin
  SourceCommand := GetICommand;
  DestCommand := TDBAccessUtils.GetICommand(FUpdateQuery as TCustomDADataSet);

  CopyPropC(prCacheLobs);
  CopyPropC(prFieldsAsString);
  CopyPropC(prRawAsString);
  CopyPropC(prTemporaryLobUpdate);
end;

procedure TCustomOraDataSetUpdater.UpdateExecute(const StatementTypes: TStatementTypes);
var
  i: integer;
  Param: TParam;
begin
  if (NeedReturnParams or (stRefresh in StatementTypes)) then 
    for i := 0 to TDBAccessUtils.GetParams(FUpdateQuery).Count - 1 do begin
      if not (TDBAccessUtils.GetParams(FUpdateQuery)[i].DataType in [ftOraBlob, ftOraClob]) then
        TDBAccessUtils.GetParams(FUpdateQuery)[i].ParamType := ptInputOutput;
    end;
  // Update ROWID value for successful Refresh after Update on Post or on
  // ApplyUpdaes (UROWID)
  if (stRefresh in StatementTypes) and ((FDataSet.State = dsEdit) or FDataSetService.IsInCacheProcessing)
    and (FDataSetService.IdentityField <> nil)
  then begin
    Param := TDBAccessUtils.GetParams(FUpdateQuery).FindParam('OLD_ROWID');
    if Param <> nil then
      Param.Value := FDataSetService.IdentityField.Value;
  end;
  inherited;
end;

function TCustomOraDataSetUpdater.PerformSQL(const SQL: string; const StatementTypes: TStatementTypes): boolean;
var
  RowId: string;
  Command: TOCICommand;
  Connection: TOCIConnection;
begin
  Result := inherited PerformSQL(SQL, StatementTypes);

  if Result and (stUpdate in StatementTypes) then begin
    RowId := TOCICommand(TDBAccessUtils.GetICommand(TCustomDADataSet(FUpdateQuery))).GetRowId;
    if (RowId <> '') and (RowId[1] = '*') then // UROWID was returned
      SetIdentityFieldValue; // for correct updates when UROWID was changed
  end;

  if Result and (OCIVersion >= 8150) and (OCIVersion < 9000)
    and (stInsert in StatementTypes) and (FDataSetService.IdentityField <> nil)
  then begin
    Command := TOCICommand(TDBAccessUtils.GetICommand(TCustomDADataSet(FUpdateQuery)));
    Connection := TOCIConnection(TDBAccessUtils.GetIConnection(UsedConnection));
    if (Command.GetRowId = '')
      and (Connection.GetOracleVersion > 8000) and (Connection.GetOracleVersion < 8100)
    then begin
      TCustomDADataSet(FUpdateQuery).SQL.Text := 'select 1 from dual where 1=0';
      TCustomDADataSet(FUpdateQuery).Execute;
      TCustomDADataSet(FUpdateQuery).Close;
    end;
  end;
end;

procedure TCustomOraDataSetUpdater.PrepareAppend;
begin
  if (FDataSetService.KeyGeneratorField <> nil) and (FDataSetService.FSequenceMode = _smInsert) then
    GetSequenceNextVal;
end;

function TCustomOraDataSetUpdater.PerformAppend: boolean;
var
  OldReturnParams: boolean;
begin
  OldReturnParams := FDataSet.Options.ReturnParams;
  if FDataSetService.KeyGeneratorField <> nil then
    if ((FDataSet.SQLInsert.Count > 0) or ((GetUpdateObject <> nil)
      and (GetUpdateObject.InsertSQL.Count > 0))) and
      (FDataSetService.FSequenceMode = _smPost)
    then
      GetSequenceNextVal
    else
      FDataSet.Options.ReturnParams := True;

  try
    Result := inherited PerformAppend;
  finally
    FDataSet.Options.ReturnParams := OldReturnParams;
  end;
end;

procedure TCustomOraDataSetUpdater.GetSequenceNextVal;
var
  OldReturnParams: boolean;
  KeyFieldDescs: TFieldDescArray;
begin
  FDataSetService.GetKeyFieldDescs(KeyFieldDescs);
  if Length(KeyFieldDescs) > 0 then begin
    OldReturnParams := FDataSet.Options.ReturnParams;
    FDataSet.Options.ReturnParams := True;
    try
      PerformSQL('begin' + LineSeparator + '  SELECT ' + FDataSetService.FKeySequence + '.NEXTVAL INTO :' +
        KeyFieldDescs[0].Name +' FROM Dual;' + LineSeparator + 'end;', [stCustom]);
    finally
      FDataSet.Options.ReturnParams := OldReturnParams;
    end;
  end;
end;

function TCustomOraDataSetUpdater.PrepareBatch(SQL: string): string;
begin
  Result := 'BEGIN' + #13#10 + SQL + #13#10 + 'END;'
end;

function TCustomOraDataSetUpdater.IsNeedEditPreconnect: boolean;
var
  vHasObjectFields: variant;
begin
  Result := not FDataSet.CachedUpdates and (GetLockMode = lmPessimistic);
  if not Result then begin
    GetIRecordSet.GetProp(prHasObjectFields, vHasObjectFields);
    Result := (vHasObjectFields = True);
  end;
end;

function TCustomOraDataSetUpdater.IsPreconnected: boolean;
var
  vHasObjectFields: variant;
begin
  Result := inherited IsPreconnected;
  if UsedConnection.Options.DisconnectedMode then begin         //in case of Object fields there is pre-connection during
    GetIRecordSet.GetProp(prHasObjectFields, vHasObjectFields); //InitRecord, so we should call EndConnection after post or cancel
    Result := Result or (vHasObjectFields = True);
  end;
end;

function TCustomOraDataSetUpdater.IsNeedInsertPreconnect: boolean;
begin
  Result := (FDataSetService.FSequenceMode = _smInsert);
end;

function TCustomOraDataSetUpdater.NeedReturnParams: boolean;
begin
  Result := inherited NeedReturnParams or FDataSetService.IsDMLRefresh;
end;

function TCustomOraDataSetUpdater.RefreshAfterInsertAllowed: boolean;
begin
  Result := FDataSetService.IsFullRefresh or not FDataSetService.IsDMLRefresh;
end;

{ TCustomOraDataSetService }

procedure TCustomOraDataSetService.CreateDataSetUpdater;
begin
  SetDataSetUpdater(TCustomOraDataSetUpdater.Create(Self));
end;

procedure TCustomOraDataSetService.CreateSQLGenerator;
begin
  SetSQLGenerator(TCustomOraSQLGenerator.Create(Self));
end;

procedure TCustomOraDataSetService.SetDataSetUpdater(Value: TDataSetUpdater);
begin
  inherited;

  FUpdater := TCustomOraDataSetUpdater(Value);
end;

function TCustomOraDataSetService.GetTemporaryLobUpdate: boolean;
var

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?