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 + -
显示快捷键?