TOracleDataSet.RefreshRecord incorrectly works at specified property UniqueFields.
It is critical at work with partitioned tables since rowid changes after update.
Variant of correction:
function TOracleDataSet.FetchRecord(
...
{+}
NotUniqueFields: Boolean;
{+.}
begin
...
if CheckIt then CheckIt := not ApplyRecord('C', NewRowId);
// If no action remains, exit
if not (LockIt or RefreshIt or CheckIt) then Exit;
{+}
NotUniqueFields := TrimRight(FUniqueFields) = '';
{+.}
// One or more actions remain, check if there is a rowid
{+}
if NotUniqueFields then
{+.}
CheckRowId(ARowId, 'A lock, refresh or check');
// OK, continue
OpenDMLQuery(False);
DMLQuery.StringFieldsOnly := Self.StringFieldsOnly;
with DMLQuery do
begin
Clear;
{+}
// Declare the RowId variable
if NotUniqueFields then
begin
DeclareVariable('doa__rowid', otString);
SetVariable('doa__rowid', ARowId);
end;
{+.}
if not AllFields then
begin
// If just data fields, execute 'select * from UpdatingTable'
{+}
if NotUniqueFields then
SQL.Text := 'select * from ' + GetUpdatingTable + ' where rowid = :doa__rowid'
else
begin
SQL.Text := 'select * from ' + GetUpdatingTable + ' ';
AddRecordIdWhereClause(DMLQuery, not RefreshIt);
end;
{+.}
// Lock it if requested
if LockIt then SQL.Add('for update nowait');
CopyUpdatingTableVariables(DMLQuery);
end else begin
// If all fields, re-execute the original SQL with rowid in where clause
OldSQL := Self.SubstitutedSQL;
// Check if the SQL is changed for QBE, if so, take the original
if Pos(QBEComment, OldSQL) > 0 then
begin
s := Self.SQL.Text;
Self.SQL.Text := QBEOldSQL;
OldSQL := Self.SubstitutedSQL;
Self.SQL.Text := s;
end;
// Trim after the EndRefreshComment in the where clause
pn := Pos(EndRefreshComment, AnsiUpperCase(OldSQL));
if pn > 0 then OldSQL := TrimRight(Copy(OldSQL, 1, pn - 1));
// Split the SQL so that we can modify it
SplitSelect(OldSQL, False, BeforeWhere, WhereClause, AfterWhere, WhereWord);
// Take the part before the where-clause
SQL.Add(BeforeWhere);
// Add the new where clause and the rowid bit
{+}
if NotUniqueFields then
begin
{+.}
NewWhere := GetUpdatingAlias + '.rowid = :doa__rowid';
if WhereClause '' then
SQL.Add(WhereWord + ' (' + WhereClause + ')' + #13#10 + 'and' + #13#10 + '(' + NewWhere + ')')
else
SQL.Add(WhereWord + ' ' + NewWhere);
{+}
end
else
begin
AddRecordIdWhereClause(DMLQuery, not RefreshIt);
if WhereClause '' then
SQL.Add('and (' + WhereClause + ')');
end;
{+.}
...
// Refresh the record
if RefreshIt and not Eof then
begin
if RefreshData = nil then GetActiveRecBuf(RefreshData);
if RefreshData nil then
{+}
begin
if not NotUniqueFields then
begin
f := FindRowIdIndex(DMLQuery);
if f >= 0 then
Self.SetRowId(RefreshData, PChar(DMLQuery.FieldAsString(f)));
end;
Result := InternalRefreshRecord(DMLQuery, RefreshData);
end;
{+.}
end;
...
end;
It is critical at work with partitioned tables since rowid changes after update.
Variant of correction:
function TOracleDataSet.FetchRecord(
...
{+}
NotUniqueFields: Boolean;
{+.}
begin
...
if CheckIt then CheckIt := not ApplyRecord('C', NewRowId);
// If no action remains, exit
if not (LockIt or RefreshIt or CheckIt) then Exit;
{+}
NotUniqueFields := TrimRight(FUniqueFields) = '';
{+.}
// One or more actions remain, check if there is a rowid
{+}
if NotUniqueFields then
{+.}
CheckRowId(ARowId, 'A lock, refresh or check');
// OK, continue
OpenDMLQuery(False);
DMLQuery.StringFieldsOnly := Self.StringFieldsOnly;
with DMLQuery do
begin
Clear;
{+}
// Declare the RowId variable
if NotUniqueFields then
begin
DeclareVariable('doa__rowid', otString);
SetVariable('doa__rowid', ARowId);
end;
{+.}
if not AllFields then
begin
// If just data fields, execute 'select * from UpdatingTable'
{+}
if NotUniqueFields then
SQL.Text := 'select * from ' + GetUpdatingTable + ' where rowid = :doa__rowid'
else
begin
SQL.Text := 'select * from ' + GetUpdatingTable + ' ';
AddRecordIdWhereClause(DMLQuery, not RefreshIt);
end;
{+.}
// Lock it if requested
if LockIt then SQL.Add('for update nowait');
CopyUpdatingTableVariables(DMLQuery);
end else begin
// If all fields, re-execute the original SQL with rowid in where clause
OldSQL := Self.SubstitutedSQL;
// Check if the SQL is changed for QBE, if so, take the original
if Pos(QBEComment, OldSQL) > 0 then
begin
s := Self.SQL.Text;
Self.SQL.Text := QBEOldSQL;
OldSQL := Self.SubstitutedSQL;
Self.SQL.Text := s;
end;
// Trim after the EndRefreshComment in the where clause
pn := Pos(EndRefreshComment, AnsiUpperCase(OldSQL));
if pn > 0 then OldSQL := TrimRight(Copy(OldSQL, 1, pn - 1));
// Split the SQL so that we can modify it
SplitSelect(OldSQL, False, BeforeWhere, WhereClause, AfterWhere, WhereWord);
// Take the part before the where-clause
SQL.Add(BeforeWhere);
// Add the new where clause and the rowid bit
{+}
if NotUniqueFields then
begin
{+.}
NewWhere := GetUpdatingAlias + '.rowid = :doa__rowid';
if WhereClause '' then
SQL.Add(WhereWord + ' (' + WhereClause + ')' + #13#10 + 'and' + #13#10 + '(' + NewWhere + ')')
else
SQL.Add(WhereWord + ' ' + NewWhere);
{+}
end
else
begin
AddRecordIdWhereClause(DMLQuery, not RefreshIt);
if WhereClause '' then
SQL.Add('and (' + WhereClause + ')');
end;
{+.}
...
// Refresh the record
if RefreshIt and not Eof then
begin
if RefreshData = nil then GetActiveRecBuf(RefreshData);
if RefreshData nil then
{+}
begin
if not NotUniqueFields then
begin
f := FindRowIdIndex(DMLQuery);
if f >= 0 then
Self.SetRowId(RefreshData, PChar(DMLQuery.FieldAsString(f)));
end;
Result := InternalRefreshRecord(DMLQuery, RefreshData);
end;
{+.}
end;
...
end;