I have problems with TMemDataSet.BookmarkValid function. Sometimes it returns wrong values but sometimes cases it raises Access Violation exception. Earlier I have used version 7.1.0 and there everything worked correctly. I have check sources and in version 7.1.0 bookmark validating code is:
Code: Select all
if IntPtr(Bookmark) <> nil then
Result := (Bookmark.Order <> -1) or (IntPtr(Bookmark.Item) <> nil)
else
Result := False;
if Result and Filtered then
Result := not OmitRecord(Bookmark.Item);
Code: Select all
if IntPtr(Bookmark) <> nil then
Result := ((Bookmark.Order <> -1) and (Bookmark.Order <= FRecordCount)) or
((Bookmark.RefreshIteration = FRefreshIteration) and (IntPtr(Bookmark.Item) <> nil) and (Bookmark.Item.Order <= FRecordCount))
else
Result := False;
if Result and Filtered then
Result := not OmitRecord(Bookmark.Item);
How to reproduce problem? Create the simplest table in Oracle:
Code: Select all
create table T_TEST
(
test_id INTEGER
)
Code: Select all
insert into t_test values(1)
Code: Select all
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Form1'
ClientHeight = 449
ClientWidth = 745
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
OldCreateOrder = False
PixelsPerInch = 96
TextHeight = 13
object dbg1: TDBGrid
Left = 0
Top = 0
Width = 745
Height = 408
Align = alClient
DataSource = DataSource1
Options = [dgEditing, dgTitles, dgIndicator, dgColumnResize, dgColLines, dgRowLines, dgTabs, dgConfirmDelete, dgCancelOnExit, dgMultiSelect, dgTitleClick, dgTitleHotTrack]
TabOrder = 0
TitleFont.Charset = DEFAULT_CHARSET
TitleFont.Color = clWindowText
TitleFont.Height = -11
TitleFont.Name = 'Tahoma'
TitleFont.Style = []
end
object pnl1: TPanel
Left = 0
Top = 408
Width = 745
Height = 41
Align = alBottom
Caption = 'pnl1'
TabOrder = 1
object lblError: TLabel
Left = 512
Top = 8
Width = 3
Height = 13
Font.Charset = DEFAULT_CHARSET
Font.Color = clRed
Font.Height = -11
Font.Name = 'Tahoma'
Font.Style = []
ParentFont = False
end
object Button1: TButton
Left = 9
Top = 6
Width = 75
Height = 25
Caption = 'Problem'
TabOrder = 0
OnClick = Button1Click
end
end
object OraSession: TOraSession
Username = 'system'
Server = 'xe'
LoginPrompt = False
Left = 224
Top = 184
EncryptedPassword = '98FF96FF9BFF9AFF87FF'
end
object OraQuery1: TOraQuery
Session = OraSession
SQL.Strings = (
'select * from t_test where test_id = 1')
CachedUpdates = True
Options.StrictUpdate = False
Options.PrepareUpdateSQL = True
Left = 320
Top = 200
end
object DataSource1: TDataSource
DataSet = OraQuery1
OnDataChange = DataSource1DataChange
Left = 176
Top = 104
end
object OraSQL1: TOraSQL
Session = OraSession
SQL.Strings = (
'delete from t_test where test_id = 1')
Left = 400
Top = 248
end
end
Code: Select all
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Data.DB, MemDS, DBAccess, Ora, OraCall, Vcl.Grids, Vcl.DBGrids, Vcl.ExtCtrls,
Vcl.StdCtrls, DASQLMonitor, OraSQLMonitor;
type
TForm1 = class(TForm)
OraSession: TOraSession;
OraQuery1: TOraQuery;
dbg1: TDBGrid;
DataSource1: TDataSource;
pnl1: TPanel;
Button1: TButton;
OraSQL1: TOraSQL;
lblError: TLabel;
procedure Button1Click(Sender: TObject);
procedure DataSource1DataChange(Sender: TObject; Field: TField);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
OraSession.Connect;
OraQuery1.Open;
dbg1.SelectedRows.CurrentRowSelected := True;
OraQuery1.DisableControls;
try
OraSQL1.Execute;
finally
OraQuery1.EnableControls;
end;
OraQuery1.RefreshRecord;
OraSession.Rollback; // For testing only - we don't row deleting
try
if OraQuery1.BookmarkValid(dbg1.SelectedRows.Items[0]) then
raise Exception.Create('Bookmark valid, for non existing record.');
finally
OraSession.Disconnect;
end;
end;
procedure TForm1.DataSource1DataChange(Sender: TObject; Field: TField);
begin
if dbg1.SelectedRows.Count > 0 then
if not OraQuery1.BookmarkValid(dbg1.SelectedRows[0]) then
dbg1.SelectedRows.Clear
else
lblError.Caption := 'Bookmark valid for non existing record';
end;
end.
1. Exception "Bookmark valid for non existing record" will be raised
2. Exception Access Violation is raised.
Kind of result depends on memory value which will be used to the bookmark creation. Sometime it will be wrong result sometime it will be Access Violation.
best regards Adam Siwon