Browse Source

--- Merging r21252 into '.':
U packages/fcl-db/tests/testdbbasics.pas
U packages/fcl-db/src/dbase/dbf_prscore.pas
--- Merging r21253 into '.':
A packages/fcl-db/tests/dbtestframework_gui.lpi
A packages/fcl-db/tests/dbtestframework_gui.lpr
--- Merging r21254 into '.':
G packages/fcl-db/tests/testdbbasics.pas
U packages/fcl-db/src/sqldb/sqldb.pp
U packages/fcl-db/src/base/bufdataset.pas
--- Merging r21256 into '.':
G packages/fcl-db/tests/testdbbasics.pas
G packages/fcl-db/src/base/bufdataset.pas
--- Merging r21267 into '.':
U packages/fcl-db/tests/testbufdatasetstreams.pas
G packages/fcl-db/src/base/bufdataset.pas
--- Merging r21641 into '.':
G packages/fcl-db/tests/testdbbasics.pas
U packages/fcl-db/src/base/dataset.inc

# revisions: 21252,21253,21254,21256,21267,21641
r21252 | joost | 2012-05-08 11:33:21 +0200 (Tue, 08 May 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/dbase/dbf_prscore.pas
M /trunk/packages/fcl-db/tests/testdbbasics.pas

* Fixed case-insensitive filtering on filters like *blah*
r21253 | joost | 2012-05-08 12:22:39 +0200 (Tue, 08 May 2012) | 1 line
Changed paths:
A /trunk/packages/fcl-db/tests/dbtestframework_gui.lpi
A /trunk/packages/fcl-db/tests/dbtestframework_gui.lpr

* Added Lazarus gui-frontend for db unit-tests.
r21254 | joost | 2012-05-08 14:21:50 +0200 (Tue, 08 May 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/bufdataset.pas
M /trunk/packages/fcl-db/src/sqldb/sqldb.pp
M /trunk/packages/fcl-db/tests/testdbbasics.pas

* Moved .ReadOnly property from TSQLQuery to TBufDataset
r21256 | joost | 2012-05-08 16:16:28 +0200 (Tue, 08 May 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/bufdataset.pas
M /trunk/packages/fcl-db/tests/testdbbasics.pas

* Implemented TBufDataset.MergeChangelog
r21267 | joost | 2012-05-09 16:49:53 +0200 (Wed, 09 May 2012) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/bufdataset.pas
M /trunk/packages/fcl-db/tests/testbufdatasetstreams.pas

* fixed the recognition of xml-files using the TBufDataset.filename property
r21641 | joost | 2012-06-18 12:39:34 +0200 (Mon, 18 Jun 2012) | 6 lines
Changed paths:
M /trunk/packages/fcl-db/src/base/dataset.inc
M /trunk/packages/fcl-db/tests/testdbbasics.pas

* Set Field.FieldNo to 0 for fields that are not bound to a fielddef, so that
they are distinguisable from calculated fields with a FieldNo of -1.
* Added test to check for an exception when the Fields do not correspond to
the underlying data.
* Improved exception message when the Fields do not correspond with the data

git-svn-id: branches/fixes_2_6@22439 -

marco 13 years ago
parent
commit
266117c624

+ 2 - 0
.gitattributes

@@ -2005,6 +2005,8 @@ packages/fcl-db/tests/dbfexporttest.lpr svneol=native#text/plain
 packages/fcl-db/tests/dbfexporttestcase1.pas svneol=native#text/plain
 packages/fcl-db/tests/dbftoolsunit.pas svneol=native#text/plain
 packages/fcl-db/tests/dbtestframework.pas svneol=native#text/plain
+packages/fcl-db/tests/dbtestframework_gui.lpi svneol=native#text/plain
+packages/fcl-db/tests/dbtestframework_gui.lpr svneol=native#text/plain
 packages/fcl-db/tests/memdstoolsunit.pas svneol=native#text/plain
 packages/fcl-db/tests/sdfdstoolsunit.pas svneol=native#text/plain
 packages/fcl-db/tests/sqldbtoolsunit.pas svneol=native#text/plain

+ 61 - 35
packages/fcl-db/src/base/bufdataset.pas

@@ -407,6 +407,7 @@ type
 
     FFilterBuffer   : TRecordBuffer;
     FBRecordCount   : integer;
+    FReadOnly       : Boolean;
 
     FSavedState     : TDatasetState;
     FPacketRecords  : integer;
@@ -436,6 +437,7 @@ type
     function GetIndexFieldNames: String;
     function GetIndexName: String;
     function GetBufUniDirectional: boolean;
+    function GetPacketReader(const Format: TDataPacketFormat; const AStream: TStream): TDataPacketReader;
     function LoadBuffer(Buffer : TRecordBuffer): TGetResult;
     function GetFieldSize(FieldDef : TFieldDef) : longint;
     function GetRecordUpdateBuffer(const ABookmark : TBufBookmark; IncludePrior : boolean = false; AFindNext : boolean = false) : boolean;
@@ -495,6 +497,7 @@ type
     procedure DataEvent(Event: TDataEvent; Info: Ptrint); override;
     procedure BeforeRefreshOpenCursor; virtual;
     procedure DoFilterRecord(out Acceptable: Boolean); virtual;
+    procedure SetReadOnly(AValue: Boolean); virtual;
   {abstracts, must be overidden by descendents}
     function Fetch : boolean; virtual;
     function LoadField(FieldDef : TFieldDef;buffer : pointer; out CreateBlob : boolean) : boolean; virtual;
@@ -511,6 +514,7 @@ type
     procedure SetFieldData(Field: TField; Buffer: Pointer); override;
     procedure ApplyUpdates; virtual; overload;
     procedure ApplyUpdates(MaxErrors: Integer); virtual; overload;
+    procedure MergeChangeLog;
     procedure CancelUpdates; virtual;
     destructor Destroy; override;
     function Locate(const keyfields: string; const keyvalues: Variant; options: TLocateOptions) : boolean; override;
@@ -532,6 +536,7 @@ type
 
     property ChangeCount : Integer read GetChangeCount;
     property MaxIndexesCount : Integer read FMaxIndexesCount write SetMaxIndexesCount default 2;
+    property ReadOnly : Boolean read FReadOnly write SetReadOnly default false;
   published
     property FileName : string read FFileName write FFileName;
     property PacketRecords : Integer read FPacketRecords write SetPacketRecords default 10;
@@ -551,6 +556,7 @@ type
     Property AutoCalcFields;
     Property Filter;
     Property Filtered;
+    Property Readonly;
     Property AfterCancel;
     Property AfterClose;
     Property AfterDelete;
@@ -1080,7 +1086,7 @@ end;
 
 Function TCustomBufDataset.GetCanModify: Boolean;
 begin
-  Result:= True;
+  Result:=not (UniDirectional or ReadOnly);
 end;
 
 function TCustomBufDataset.IntAllocRecordBuffer: TRecordBuffer;
@@ -1117,7 +1123,7 @@ begin
   if not Assigned(FDatasetReader) and (FileName<>'') then
     begin
     FFileStream := TFileStream.Create(FileName,fmOpenRead);
-    FDatasetReader := TFpcBinaryDatapacketReader.Create(FFileStream);
+    FDatasetReader := GetPacketReader(dfAny, FFileStream);
     FReadFromFile := True;
     end;
   if assigned(FDatasetReader) then IntLoadFielddefsFromFile;
@@ -1484,6 +1490,11 @@ begin
     end;
 end;
 
+procedure TCustomBufDataset.SetReadOnly(AValue: Boolean);
+begin
+  FReadOnly:=AValue;
+end;
+
 function TCustomBufDataset.GetRecord(Buffer: TRecordBuffer; GetMode: TGetMode; DoCheck: Boolean): TGetResult;
 
 var Acceptable : Boolean;
@@ -2103,28 +2114,7 @@ begin
       end;
   finally
     if failedcount = 0 then
-      begin
-      SetLength(FUpdateBuffer,0);
-
-      if assigned(FUpdateBlobBuffers) then for r:=0 to length(FUpdateBlobBuffers)-1 do
-       if assigned(FUpdateBlobBuffers[r]) then
-        begin
-        if FUpdateBlobBuffers[r]^.OrgBufID >= 0 then
-          begin
-          Freemem(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]^.Buffer);
-          Dispose(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]);
-          FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID] :=FUpdateBlobBuffers[r];
-          end
-        else
-          begin
-          setlength(FBlobBuffers,length(FBlobBuffers)+1);
-          FUpdateBlobBuffers[r]^.OrgBufID := high(FBlobBuffers);
-          FBlobBuffers[high(FBlobBuffers)] := FUpdateBlobBuffers[r];
-          
-          end;
-        end;
-      SetLength(FUpdateBlobBuffers,0);
-      end;
+      MergeChangeLog;
 
     InternalGotoBookmark(@StoreCurrRec);
     Resync([]);
@@ -2132,6 +2122,33 @@ begin
   end;
 end;
 
+procedure TCustomBufDataset.MergeChangeLog;
+
+var r            : Integer;
+
+begin
+  SetLength(FUpdateBuffer,0);
+
+  if assigned(FUpdateBlobBuffers) then for r:=0 to length(FUpdateBlobBuffers)-1 do
+   if assigned(FUpdateBlobBuffers[r]) then
+    begin
+    if FUpdateBlobBuffers[r]^.OrgBufID >= 0 then
+      begin
+      Freemem(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]^.Buffer);
+      Dispose(FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID]);
+      FBlobBuffers[FUpdateBlobBuffers[r]^.OrgBufID] :=FUpdateBlobBuffers[r];
+      end
+    else
+      begin
+      setlength(FBlobBuffers,length(FBlobBuffers)+1);
+      FUpdateBlobBuffers[r]^.OrgBufID := high(FBlobBuffers);
+      FBlobBuffers[high(FBlobBuffers)] := FUpdateBlobBuffers[r];
+
+      end;
+    end;
+  SetLength(FUpdateBlobBuffers,0);
+end;
+
 
 procedure TCustomBufDataset.InternalCancel;
 
@@ -2277,6 +2294,24 @@ begin
   result := IsUniDirectional;
 end;
 
+function TCustomBufDataset.GetPacketReader(const Format: TDataPacketFormat; const AStream: TStream): TDataPacketReader;
+
+var APacketReader: TDataPacketReader;
+    APacketReaderReg: TDatapacketReaderRegistration;
+
+begin
+  if GetRegisterDatapacketReader(AStream, format, APacketReaderReg) then
+    APacketReader := APacketReaderReg.ReaderClass.create(AStream)
+  else if TFpcBinaryDatapacketReader.RecognizeStream(AStream) then
+    begin
+    AStream.Seek(0, soFromBeginning);
+    APacketReader := TFpcBinaryDatapacketReader.create(AStream)
+    end
+  else
+    DatabaseError(SStreamNotRecognised);
+  Result:=APacketReader;
+end;
+
 function TCustomBufDataset.GetRecordSize : Word;
 
 begin
@@ -2631,19 +2666,10 @@ begin
 end;
 
 procedure TCustomBufDataset.LoadFromStream(AStream: TStream; Format: TDataPacketFormat);
-var APacketReaderReg : TDatapacketReaderRegistration;
-    APacketReader : TDataPacketReader;
+var APacketReader : TDataPacketReader;
 begin
   CheckBiDirectional;
-  if GetRegisterDatapacketReader(AStream,format,APacketReaderReg) then
-    APacketReader := APacketReaderReg.ReaderClass.create(AStream)
-  else if TFpcBinaryDatapacketReader.RecognizeStream(AStream) then
-    begin
-    AStream.Seek(0,soFromBeginning);
-    APacketReader := TFpcBinaryDatapacketReader.create(AStream)
-    end
-  else
-    DatabaseError(SStreamNotRecognised);
+  APacketReader:=GetPacketReader(Format, AStream);
   try
     SetDatasetPacket(APacketReader);
   finally

+ 3 - 9
packages/fcl-db/src/base/dataset.inc

@@ -85,14 +85,8 @@ Procedure TDataset.BindFields(Binding: Boolean);
 var i, FieldIndex: Integer;
     FieldDef: TFieldDef;
 begin
-  {
-     Here some magic will be needed later; for now just simply set
-     Just set fieldno from listindex...
-     Later we should take it from the fielddefs.
-     // ATM Set by CreateField ...
-  For I:=0 to FFieldList.Count-1 do
-    FFieldList[i].FFieldNo:=I;
-  }
+  { FieldNo is set to -1 for calculated/lookup fields, to 0 for unbound field
+    and for bound fields it is set to FieldDef.FieldNo }
   FCalcFieldsSize := 0;
   FBlobFieldCount := 0;
   for i := 0 to Fields.Count - 1 do
@@ -124,7 +118,7 @@ begin
               FOffset := FBlobFieldCount;
               Inc(FBlobFieldCount);
             end;
-          end else FFieldNo := FieldIndex;
+          end else FFieldNo := 0;
         end;
       end else FFieldNo := 0;
     end;

+ 1 - 1
packages/fcl-db/src/dbase/dbf_prscore.pas

@@ -1679,7 +1679,7 @@ begin
         str0 := AnsiStrUpper(Args[0]);
         str1 := AnsiStrUpper(Args[1]+1);
         setlength(str1, arg1len-2);
-        match := AnsiPos(str0, str1) = 0;
+        match := AnsiPos(str1, str0) <> 0;
       end else begin
         arg0len := StrLen(Args[0]);
         // at least length without asterisk

+ 3 - 6
packages/fcl-db/src/sqldb/sqldb.pp

@@ -212,7 +212,6 @@ type
     FDeleteSQL           : TStringList;
     FIsEOF               : boolean;
     FLoadingFieldDefs    : boolean;
-    FReadOnly            : boolean;
     FUpdateMode          : TUpdateMode;
     FParams              : TParams;
     FusePrimaryKeyAsKey  : Boolean;
@@ -241,7 +240,6 @@ type
     function GetStatementType : TStatementType;
     procedure SetDeleteSQL(const AValue: TStringlist);
     procedure SetInsertSQL(const AValue: TStringlist);
-    procedure SetReadOnly(AValue : Boolean);
     procedure SetParseSQL(AValue : Boolean);
     procedure SetSQL(const AValue: TStringlist);
     procedure SetUpdateSQL(const AValue: TStringlist);
@@ -275,6 +273,7 @@ type
     Procedure SetDataSource(AValue : TDatasource);
     procedure LoadBlobIntoBuffer(FieldDef: TFieldDef;ABlobBuf: PBufBlobField); override;
     procedure BeforeRefreshOpenCursor; override;
+    procedure SetReadOnly(AValue : Boolean); override;
     Function LogEvent(EventType : TDBEventType) : Boolean;
     Procedure Log(EventType : TDBEventType; Const Msg : String); virtual;
   public
@@ -322,7 +321,6 @@ type
   // protected
     property SchemaType : TSchemaType read FSchemaType default stNoSchema;
     property Transaction;
-    property ReadOnly : Boolean read FReadOnly write SetReadOnly default false;
     property SQL : TStringlist read FSQL write SetSQL;
     property UpdateSQL : TStringlist read FUpdateSQL write SetUpdateSQL;
     property InsertSQL : TStringlist read FInsertSQL write SetInsertSQL;
@@ -1482,7 +1480,6 @@ begin
 
   FServerIndexDefs := TServerIndexDefs.Create(Self);
 
-  FReadOnly := false;
   FParseSQL := True;
 
   FServerFiltered := False;
@@ -1517,7 +1514,7 @@ procedure TCustomSQLQuery.SetReadOnly(AValue : Boolean);
 
 begin
   CheckInactive;
-  FReadOnly:=AValue;
+  inherited SetReadOnly(AValue);
 end;
 
 procedure TCustomSQLQuery.SetParseSQL(AValue : Boolean);
@@ -1707,7 +1704,7 @@ Function TCustomSQLQuery.GetCanModify: Boolean;
 begin
   // the test for assigned(FCursor) is needed for the case that the dataset isn't opened
   if assigned(FCursor) and (FCursor.FStatementType = stSelect) then
-    Result:= FUpdateable and (not FReadOnly) and (not IsUniDirectional)
+    Result:= FUpdateable and (not ReadOnly) and (not IsUniDirectional)
   else
     Result := False;
 end;

+ 79 - 0
packages/fcl-db/tests/dbtestframework_gui.lpi

@@ -0,0 +1,79 @@
+<?xml version="1.0"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="9"/>
+    <General>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <ResourceType Value="res"/>
+      <UseXPManifest Value="True"/>
+      <Icon Value="0"/>
+    </General>
+    <i18n>
+      <EnableI18N LFM="False"/>
+    </i18n>
+    <VersionInfo>
+      <StringTable ProductVersion=""/>
+    </VersionInfo>
+    <BuildModes Count="1">
+      <Item1 Name="Default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
+      <ExcludeFileFilter Value="*.(bak|ppu|o|so);*~;backup"/>
+    </PublishOptions>
+    <RunParams>
+      <local>
+        <FormatVersion Value="1"/>
+      </local>
+    </RunParams>
+    <RequiredPackages Count="3">
+      <Item1>
+        <PackageName Value="FPCUnitTestRunner"/>
+      </Item1>
+      <Item2>
+        <PackageName Value="LCL"/>
+      </Item2>
+      <Item3>
+        <PackageName Value="FCL"/>
+      </Item3>
+    </RequiredPackages>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="dbtestframework_gui.lpr"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="dbtestframework_gui"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <SearchPaths>
+      <IncludeFiles Value="$(ProjOutDir)"/>
+      <OtherUnitFiles Value="../src/base;../src/sqldb/odbc;../src/sqldb/mssql;../src/sqldb/sqlite;../src/sqldb/postgres;../src/sqldb/oracle;../src/memds;../src/sqldb;../src/sqldb/interbase;../src/sqldb/mysql;../src/dbase;../src/sdf"/>
+    </SearchPaths>
+    <Other>
+      <CompilerMessages>
+        <UseMsgFile Value="True"/>
+      </CompilerMessages>
+      <CompilerPath Value="$(CompPath)"/>
+    </Other>
+  </CompilerOptions>
+  <Debugging>
+    <Exceptions Count="4">
+      <Item1>
+        <Name Value="EAbort"/>
+      </Item1>
+      <Item2>
+        <Name Value="ECodetoolError"/>
+      </Item2>
+      <Item3>
+        <Name Value="EFOpenError"/>
+      </Item3>
+      <Item4>
+        <Name Value="EIBDatabaseError"/>
+      </Item4>
+    </Exceptions>
+  </Debugging>
+</CONFIG>

+ 37 - 0
packages/fcl-db/tests/dbtestframework_gui.lpr

@@ -0,0 +1,37 @@
+program dbtestframework_gui;
+
+{$mode objfpc}{$H+}
+
+// Note that this Lazarus project by default re-compiles all DB-units! This eases
+// developing, but asks some attention from the developer.
+// If you want to use the default, installed db-units, simply clear the search path
+// in the compiler-options.
+// It could also be that after compiling this project, you have to manually clean
+// the .ppu files before you can build fcl-db in the regular way. (Using fpmake)
+
+uses
+  Interfaces, Forms, GuiTestRunner,
+  // Generic DB-testframework units
+  ToolsUnit,
+  // Connecors for different database-types
+  sqldbtoolsunit,
+  dbftoolsunit,
+  bufdatasettoolsunit,
+  memdstoolsunit,
+  SdfDSToolsUnit,
+  // DB unittest
+  testbasics,
+  TestFieldTypes,
+  TestDBBasics,
+  TestDatasources,
+  TestBufDatasetStreams,
+  TestSpecificTBufDataset;
+
+{$R *.res}
+
+begin
+  Application.Initialize;
+  Application.CreateForm(TGuiTestRunner, TestRunner);
+  Application.Run;
+end.
+

+ 22 - 0
packages/fcl-db/tests/testbufdatasetstreams.pas

@@ -72,6 +72,7 @@ type
     procedure TestAppendDeleteBIN;
 
     procedure TestFileNameProperty;
+    procedure TestXmlFileRecognition;
     procedure TestCloseDatasetNoConnection; // bug 17623
   end;
 
@@ -469,6 +470,27 @@ begin
   LoadDs.close;
 end;
 
+procedure TTestBufDatasetStreams.TestXmlFileRecognition;
+var ds    : TDataset;
+    LoadDs: TDataset;
+begin
+  ds := DBConnector.GetNDataset(true,5);
+
+  ds.open;
+  TCustomBufDataset(ds).SaveToFile('test.xml',dfXML);
+  ds.close;
+
+  LoadDs := DBConnector.GetNDataset(True,2);
+  TCustomBufDataset(LoadDs).FileName:='test.xml';
+  LoadDs.Open;
+
+  ds := DBConnector.GetNDataset(true,4);
+  ds.Open;
+  CompareDatasets(ds,LoadDs);
+  ds.close;
+  LoadDs.close;
+end;
+
 procedure TTestBufDatasetStreams.TestCloseDatasetNoConnection;
 var SaveDs: TCustomBufDataset;
     LoadDs: TCustomBufDataset;

+ 111 - 3
packages/fcl-db/tests/testdbbasics.pas

@@ -58,6 +58,7 @@ type
     procedure TestdeFieldListChange;
     procedure TestExceptionLocateClosed;    // bug 13938
     procedure TestCanModifySpecialFields;
+    procedure TestDetectionNonMatchingDataset;
   end;
 
   { TTestBufDatasetDBBasics }
@@ -79,6 +80,8 @@ type
     procedure TestBufDatasetCancelUpd1;
     procedure TestMultipleDeleteUpdateBuffer;
     procedure TestDoubleDelete;
+    procedure TestReadOnly;
+    procedure TestMergeChangeLog;
   // index tests
     procedure TestAddIndexInteger;
     procedure TestAddIndexSmallInt;
@@ -670,6 +673,28 @@ begin
     end;
 end;
 
+procedure TTestDBBasics.TestDetectionNonMatchingDataset;
+var
+  F: TField;
+  ds: tdataset;
+begin
+  // TDataset.Bindfields should detect problems when the underlying data does
+  // not reflect the fields of the dataset. This test is to check if this is
+  // really done.
+  ds := DBConnector.GetNDataset(true,6);
+  with ds do
+    begin
+    open;
+    close;
+
+    F := TStringField.Create(ds);
+    F.FieldName:='DOES_NOT_EXIST';
+    F.DataSet:=ds;
+    F.Size:=50;
+
+    CheckException(open,EDatabaseError);
+    end;
+end;
 
 procedure TTestCursorDBBasics.TestAppendInsertRecord;
 begin
@@ -1147,15 +1172,60 @@ begin
   with DBConnector.GetNDataset(15) do
     begin
     Open;
-    //FilterOptions := [foNoPartialCompare];
-    //FilterOptions := [];
-    Filter := '(name=''*Name3'')';
+    Filter := '(name=''TestName3'')';
     Filtered := True;
     CheckFalse(EOF);
     CheckEquals(3,FieldByName('ID').asinteger);
     CheckEquals('TestName3',FieldByName('NAME').asstring);
     next;
     CheckTrue(EOF);
+
+    // Check partial compare
+    Filter := '(name=''*Name5'')';
+    CheckFalse(EOF);
+    CheckEquals(5,FieldByName('ID').asinteger);
+    CheckEquals('TestName5',FieldByName('NAME').asstring);
+    next;
+    CheckTrue(EOF);
+
+    // Check case-sensitivity
+    Filter := '(name=''*name3'')';
+    first;
+    CheckTrue(EOF);
+
+    FilterOptions:=[foCaseInsensitive];
+    Filter := '(name=''testname3'')';
+    first;
+    CheckFalse(EOF);
+    CheckEquals(3,FieldByName('ID').asinteger);
+    CheckEquals('TestName3',FieldByName('NAME').asstring);
+    next;
+    CheckTrue(EOF);
+
+    // Check case-insensitive partial compare
+    Filter := '(name=''*name3'')';
+    first;
+    CheckFalse(EOF);
+    CheckEquals(3,FieldByName('ID').asinteger);
+    CheckEquals('TestName3',FieldByName('NAME').asstring);
+    next;
+    CheckTrue(EOF);
+
+    Filter := '(name=''*name*'')';
+    first;
+    CheckFalse(EOF);
+    CheckEquals(1,FieldByName('ID').asinteger);
+    CheckEquals('TestName1',FieldByName('NAME').asstring);
+    next;
+    CheckFalse(EOF);
+    CheckEquals(2,FieldByName('ID').asinteger);
+    CheckEquals('TestName2',FieldByName('NAME').asstring);
+
+    Filter := '(name=''*neme*'')';
+    first;
+    CheckTrue(EOF);
+
+
     Close;
     end;
 end;
@@ -1361,6 +1431,44 @@ begin
     end;
 end;
 
+procedure TTestBufDatasetDBBasics.TestReadOnly;
+var
+  ds: TCustomBufDataset;
+begin
+  ds := DBConnector.GetFieldDataset as TCustomBufDataset;
+  with ds do
+    begin
+    ReadOnly:=true;
+    CheckFalse(CanModify);
+    end;
+end;
+
+procedure TTestBufDatasetDBBasics.TestMergeChangeLog;
+var
+  ds: TCustomBufDataset;
+  i: integer;
+  s: string;
+begin
+  ds := DBConnector.GetNDataset(5) as TCustomBufDataset;
+  with ds do
+    begin
+    open;
+    Edit;
+    i := fields[0].AsInteger;
+    s := fields[1].AsString;
+    fields[0].AsInteger:=64;
+    fields[1].AsString:='Changed';
+    Post;
+    checkequals(fields[0].OldValue,i);
+    checkequals(fields[1].OldValue,s);
+    CheckEquals(ChangeCount,1);
+    MergeChangeLog;
+    CheckEquals(ChangeCount,0);
+    checkequals(fields[0].OldValue,64);
+    checkequals(fields[1].OldValue,'Changed');
+    end;
+end;
+
 procedure TTestBufDatasetDBBasics.FTestXMLDatasetDefinition(ADataset: TDataset);
 var i : integer;
 begin