Browse Source

--- Merging r25099 into '.':
U packages/fcl-db/src/sqldb/postgres/pqconnection.pp
--- Merging r25248 into '.':
G packages/fcl-db/src/sqldb/postgres/pqconnection.pp
--- Merging r25249 into '.':
G packages/fcl-db/src/sqldb/postgres/pqconnection.pp
--- Merging r25250 into '.':
G packages/fcl-db/src/sqldb/postgres/pqconnection.pp
--- Merging r25251 into '.':
U packages/fcl-db/src/sqldb/sqldb.pp
--- Merging r25252 into '.':
G packages/fcl-db/src/sqldb/sqldb.pp
--- Merging r25293 into '.':
U packages/fcl-db/src/base/db.pas
--- Merging r25294 into '.':
G packages/fcl-db/src/base/db.pas
U packages/fcl-db/src/base/fields.inc
--- Merging r25313 into '.':
U packages/fcl-db/src/base/bufdataset.pas
--- Merging r25314 into '.':
G packages/fcl-db/src/base/bufdataset.pas
--- Merging r25326 into '.':
U packages/fcl-db/tests/bufdatasettoolsunit.pas
U packages/fcl-db/tests/testdbbasics.pas
--- Merging r25327 into '.':
U packages/fcl-db/tests/dbtestframework_gui.lpi
U packages/fcl-db/tests/dbtestframework_gui.lpr
U packages/fcl-db/tests/inieditor.lfm
A packages/fcl-db/tests/dbguitestrunner.pas
U packages/fcl-db/tests/inieditor.pas
U packages/fcl-db/tests/sqldbtoolsunit.pas

# revisions: 25099,25248,25249,25250,25251,25252,25293,25294,25313,25314,25326,25327
r25099 | ludob | 2013-07-14 15:08:06 +0200 (Sun, 14 Jul 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/postgres/pqconnection.pp

pqconnection: changed FCursorCount to dword to avoid 'prepared statement already exists' errors when preparing more than 64k queries in one transaction while keeping one ore more queries open
r25248 | michael | 2013-08-12 09:25:21 +0200 (Mon, 12 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/postgres/pqconnection.pp

* Thread-safe connection pool
r25249 | michael | 2013-08-12 09:48:08 +0200 (Mon, 12 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/postgres/pqconnection.pp

* Reworked pool to a thread list
r25250 | michael | 2013-08-12 10:19:00 +0200 (Mon, 12 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/postgres/pqconnection.pp

* Fixed ROLLBACK : all statements must be unprepared
r25251 | michael | 2013-08-12 14:44:03 +0200 (Mon, 12 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/sqldb.pp

* Mark transaction as closed in caNone case of EndTranscation
r25252 | michael | 2013-08-12 14:56:16 +0200 (Mon, 12 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/sqldb/sqldb.pp

* Restore old behaviour for caNone for Action
r25293 | lacak | 2013-08-19 13:43:16 +0200 (Mon, 19 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/db.pas

fcl-db: base: formatting (char-case)
r25294 | lacak | 2013-08-19 14:06:36 +0200 (Mon, 19 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/db.pas
M /trunk/packages/fcl-db/src/base/fields.inc

fcl-db: base: implements AsBytes for TBlobField
r25313 | lacak | 2013-08-20 08:11:06 +0200 (Tue, 20 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/bufdataset.pas

fcl-db: bufdataset: formatting
r25314 | lacak | 2013-08-20 08:42:09 +0200 (Tue, 20 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/src/base/bufdataset.pas

fcl-db: bufdataset: partialy fixes TestOpeningNonExistingDataset. See also #22030.
r25326 | lacak | 2013-08-22 11:57:45 +0200 (Thu, 22 Aug 2013) | 1 line
Changed paths:
M /trunk/packages/fcl-db/tests/bufdatasettoolsunit.pas
M /trunk/packages/fcl-db/tests/testdbbasics.pas

fcl-db: tests: formatting
r25327 | reiniero | 2013-08-22 13:07:39 +0200 (Thu, 22 Aug 2013) | 2 lines
Changed paths:
A /trunk/packages/fcl-db/tests/dbguitestrunner.pas
M /trunk/packages/fcl-db/tests/dbtestframework_gui.lpi
M /trunk/packages/fcl-db/tests/dbtestframework_gui.lpr
M /trunk/packages/fcl-db/tests/inieditor.lfm
M /trunk/packages/fcl-db/tests/inieditor.pas
M /trunk/packages/fcl-db/tests/sqldbtoolsunit.pas

sqldb: tests: clean up forms so database.ini editor is in main form

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

marco 12 years ago
parent
commit
15b0fada20

+ 1 - 0
.gitattributes

@@ -2013,6 +2013,7 @@ packages/fcl-db/tests/README.txt svneol=native#text/plain
 packages/fcl-db/tests/bufdatasettoolsunit.pas svneol=native#text/plain
 packages/fcl-db/tests/bufdatasettoolsunit.pas svneol=native#text/plain
 packages/fcl-db/tests/database.ini.txt svneol=native#text/plain
 packages/fcl-db/tests/database.ini.txt svneol=native#text/plain
 packages/fcl-db/tests/dbftoolsunit.pas svneol=native#text/plain
 packages/fcl-db/tests/dbftoolsunit.pas svneol=native#text/plain
+packages/fcl-db/tests/dbguitestrunner.pas svneol=native#text/plain
 packages/fcl-db/tests/dbtestframework.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.lpi svneol=native#text/plain
 packages/fcl-db/tests/dbtestframework_gui.lpr svneol=native#text/plain
 packages/fcl-db/tests/dbtestframework_gui.lpr svneol=native#text/plain

+ 29 - 28
packages/fcl-db/src/base/bufdataset.pas

@@ -176,8 +176,6 @@ type
     property BookmarkSize : integer read GetBookmarkSize;
     property BookmarkSize : integer read GetBookmarkSize;
   end;
   end;
   
   
-  TDataPacketFormat = (dfBinary,dfXML,dfXMLUTF8,dfAny);
-
   { TDoubleLinkedBufIndex }
   { TDoubleLinkedBufIndex }
 
 
   TDoubleLinkedBufIndex = class(TBufIndex)
   TDoubleLinkedBufIndex = class(TBufIndex)
@@ -344,6 +342,8 @@ type
 
 
   { TDataPacketReader }
   { TDataPacketReader }
 
 
+  TDataPacketFormat = (dfBinary,dfXML,dfXMLUTF8,dfAny);
+
   TDatapacketReaderClass = class of TDatapacketReader;
   TDatapacketReaderClass = class of TDatapacketReader;
   TDataPacketReader = class(TObject)
   TDataPacketReader = class(TObject)
     FStream : TStream;
     FStream : TStream;
@@ -1129,21 +1129,23 @@ begin
   // If there are less fields then FieldDefs we know for sure that the dataset
   // If there are less fields then FieldDefs we know for sure that the dataset
   // is not (correctly) created.
   // is not (correctly) created.
 
 
-  // commented for now. If there are constant expressions in the select
-  // statement they are ftUnknown, and not created.
+  // If there are constant expressions in the select statement (for PostgreSQL)
+  // they are of type ftUnknown (in FieldDefs), and are not created (in Fields).
+  // So Fields.Count < FieldDefs.Count in this case
   // See mantis #22030
   // See mantis #22030
 
 
   //  if Fields.Count<FieldDefs.Count then
   //  if Fields.Count<FieldDefs.Count then
-  //    DatabaseError(SErrNoDataset);
+  if Fields.Count = 0 then
+    DatabaseError(SErrNoDataset);
 
 
   // If there is a field with FieldNo=0 then the fields are not found to the
   // If there is a field with FieldNo=0 then the fields are not found to the
   // FieldDefs which is a sign that there is no dataset created. (Calculated and
   // FieldDefs which is a sign that there is no dataset created. (Calculated and
   // lookup fields have FieldNo=-1)
   // lookup fields have FieldNo=-1)
   for i := 0 to Fields.Count-1 do
   for i := 0 to Fields.Count-1 do
-    if fields[i].FieldNo=0 then
+    if Fields[i].FieldNo=0 then
       DatabaseError(SErrNoDataset)
       DatabaseError(SErrNoDataset)
-    else if (FAutoIncValue>-1) and (fields[i] is TAutoIncField) and not assigned(FAutoIncField) then
-      FAutoIncField := TAutoIncField(fields[i]);
+    else if (FAutoIncValue>-1) and (Fields[i] is TAutoIncField) and not assigned(FAutoIncField) then
+      FAutoIncField := TAutoIncField(Fields[i]);
 
 
   InitDefaultIndexes;
   InitDefaultIndexes;
   CalcRecordSize;
   CalcRecordSize;
@@ -2662,19 +2664,6 @@ begin
     end;
     end;
 end;
 end;
 
 
-procedure TCustomBufDataset.SaveToFile(AFileName: string;
-  Format: TDataPacketFormat);
-var AFileStream : TFileStream;
-begin
-  if AFileName='' then AFileName := FFileName;
-  AFileStream := TFileStream.Create(AFileName,fmCreate);
-  try
-    SaveToStream(AFileStream, Format);
-  finally
-    AFileStream.Free;
-  end;
-end;
-
 procedure TCustomBufDataset.SetDatasetPacket(AReader: TDataPacketReader);
 procedure TCustomBufDataset.SetDatasetPacket(AReader: TDataPacketReader);
 begin
 begin
   FDatasetReader := AReader;
   FDatasetReader := AReader;
@@ -2828,31 +2817,43 @@ begin
   end;
   end;
 end;
 end;
 
 
-procedure TCustomBufDataset.CreateDataset;
-var AStoreFilename: string;
+procedure TCustomBufDataset.SaveToFile(AFileName: string;
+  Format: TDataPacketFormat);
+var AFileStream : TFileStream;
+begin
+  if AFileName='' then AFileName := FFileName;
+  AFileStream := TFileStream.Create(AFileName,fmCreate);
+  try
+    SaveToStream(AFileStream, Format);
+  finally
+    AFileStream.Free;
+  end;
+end;
 
 
+procedure TCustomBufDataset.CreateDataset;
+var AStoreFileName: string;
 begin
 begin
   CheckInactive;
   CheckInactive;
   if ((FieldCount=0) or (FieldDefs.Count=0)) then
   if ((FieldCount=0) or (FieldDefs.Count=0)) then
     begin
     begin
     if (FieldDefs.Count>0) then
     if (FieldDefs.Count>0) then
       CreateFields
       CreateFields
-    else if (fields.Count>0) then
+    else if (Fields.Count>0) then
       begin
       begin
-      InitFieldDefsFromfields;
+      InitFieldDefsFromFields;
       BindFields(True);
       BindFields(True);
       end
       end
     else
     else
       raise Exception.Create(SErrNoFieldsDefined);
       raise Exception.Create(SErrNoFieldsDefined);
     FAutoIncValue:=1;
     FAutoIncValue:=1;
     end;
     end;
-  // When a filename is set, do not read from this file
-  AStoreFilename:=FFileName;
+  // When a FileName is set, do not read from this file
+  AStoreFileName:=FFileName;
   FFileName := '';
   FFileName := '';
   try
   try
     Open;
     Open;
   finally
   finally
-    FFileName:=AStoreFilename;
+    FFileName:=AStoreFileName;
   end;
   end;
 end;
 end;
 
 

+ 7 - 5
packages/fcl-db/src/base/db.pas

@@ -72,8 +72,8 @@ type
   TFields = Class;
   TFields = Class;
   TDataSet = class;
   TDataSet = class;
   TDataBase = Class;
   TDataBase = Class;
-  TDatasource = Class;
-  TDatalink = Class;
+  TDataSource = Class;
+  TDataLink = Class;
   TDBTransaction = Class;
   TDBTransaction = Class;
 
 
 { Exception classes }
 { Exception classes }
@@ -864,15 +864,17 @@ type
     Function GetBlobStream (Mode : TBlobStreamMode) : TStream;
     Function GetBlobStream (Mode : TBlobStreamMode) : TStream;
   protected
   protected
     procedure FreeBuffers; override;
     procedure FreeBuffers; override;
+    function GetAsBytes: TBytes; override;
     function GetAsString: string; override;
     function GetAsString: string; override;
     function GetAsVariant: Variant; override;
     function GetAsVariant: Variant; override;
+    function GetAsWideString: WideString; override;
     function GetBlobSize: Longint; virtual;
     function GetBlobSize: Longint; virtual;
     function GetIsNull: Boolean; override;
     function GetIsNull: Boolean; override;
     procedure GetText(var TheText: string; ADisplayText: Boolean); override;
     procedure GetText(var TheText: string; ADisplayText: Boolean); override;
+    procedure SetAsBytes(const AValue: TBytes); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetAsString(const AValue: string); override;
     procedure SetText(const AValue: string); override;
     procedure SetText(const AValue: string); override;
     procedure SetVarValue(const AValue: Variant); override;
     procedure SetVarValue(const AValue: Variant); override;
-    function GetAsWideString: WideString; override;
     procedure SetAsWideString(const AValue: WideString); override;
     procedure SetAsWideString(const AValue: WideString); override;
   public
   public
     constructor Create(AOwner: TComponent); override;
     constructor Create(AOwner: TComponent); override;
@@ -1402,7 +1404,7 @@ type
     Procedure DoInternalOpen;
     Procedure DoInternalOpen;
     Function  GetBuffer (Index : longint) : TRecordBuffer;
     Function  GetBuffer (Index : longint) : TRecordBuffer;
     Function  GetField (Index : Longint) : TField;
     Function  GetField (Index : Longint) : TField;
-    Procedure RegisterDataSource(ADatasource : TDataSource);
+    Procedure RegisterDataSource(ADataSource : TDataSource);
     Procedure RemoveField (Field : TField);
     Procedure RemoveField (Field : TField);
     procedure SetConstraints(Value: TCheckConstraints);
     procedure SetConstraints(Value: TCheckConstraints);
     Procedure SetField (Index : Longint;Value : TField);
     Procedure SetField (Index : Longint;Value : TField);
@@ -1410,7 +1412,7 @@ type
     Procedure ShiftBuffersBackward;
     Procedure ShiftBuffersBackward;
     Function  TryDoing (P : TDataOperation; Ev : TDatasetErrorEvent) : Boolean;
     Function  TryDoing (P : TDataOperation; Ev : TDatasetErrorEvent) : Boolean;
     Function GetActive : boolean;
     Function GetActive : boolean;
-    Procedure UnRegisterDataSource(ADatasource : TDatasource);
+    Procedure UnRegisterDataSource(ADataSource : TDataSource);
     Procedure UpdateFieldDefs;
     Procedure UpdateFieldDefs;
     procedure SetBlockReadSize(AValue: Integer); virtual;
     procedure SetBlockReadSize(AValue: Integer); virtual;
     Procedure SetFieldDefs(AFieldDefs: TFieldDefs);
     Procedure SetFieldDefs(AFieldDefs: TFieldDefs);

+ 48 - 15
packages/fcl-db/src/base/fields.inc

@@ -2737,7 +2737,7 @@ end;
 
 
 { TBlobField }
 { TBlobField }
 
 
-Function TBlobField.GetBlobStream(Mode : TBlobStreamMode) : TStream;
+function TBlobField.GetBlobStream(Mode: TBlobStreamMode): TStream;
 
 
 begin
 begin
   Result:=FDataset.CreateBlobStream(Self,Mode);
   Result:=FDataset.CreateBlobStream(Self,Mode);
@@ -2748,6 +2748,24 @@ procedure TBlobField.FreeBuffers;
 begin
 begin
 end;
 end;
 
 
+function TBlobField.GetAsBytes: TBytes;
+var
+  Stream : TStream;
+  Len    : Integer;
+begin
+  Stream := GetBlobStream(bmRead);
+  if Stream <> nil then
+    try
+      Len := Stream.Size;
+      SetLength(Result, Len);
+      if Len > 0 then
+        Stream.ReadBuffer(Result[0], Len);
+    finally
+      Stream.Free;
+    end
+  else
+    SetLength(Result, 0);
+end;
 
 
 function TBlobField.GetAsString: string;
 function TBlobField.GetAsString: string;
 var
 var
@@ -2756,7 +2774,7 @@ var
 begin
 begin
   Stream := GetBlobStream(bmRead);
   Stream := GetBlobStream(bmRead);
   if Stream <> nil then
   if Stream <> nil then
-    With Stream do
+    with Stream do
       try
       try
         Len := Size;
         Len := Size;
         SetLength(Result, Len);
         SetLength(Result, Len);
@@ -2776,7 +2794,7 @@ var
 begin
 begin
   Stream := GetBlobStream(bmRead);
   Stream := GetBlobStream(bmRead);
   if Stream <> nil then
   if Stream <> nil then
-    With Stream do
+    with Stream do
       try
       try
         Len := Size;
         Len := Size;
         SetLength(Result, (Len+1) div 2);
         SetLength(Result, (Len+1) div 2);
@@ -2799,7 +2817,8 @@ begin
     s := GetAsString;
     s := GetAsString;
     result := s;
     result := s;
     end
     end
-  else result := Null;
+  else
+    result := Null;
 end;
 end;
 
 
 
 
@@ -2807,29 +2826,29 @@ function TBlobField.GetBlobSize: Longint;
 var
 var
   Stream: TStream;
   Stream: TStream;
 begin
 begin
-  Stream := GetBlobStream(bmread);
+  Stream := GetBlobStream(bmRead);
   if Stream <> nil then
   if Stream <> nil then
-    With Stream do
+    with Stream do
       try
       try
         Result:=Size;
         Result:=Size;
       finally
       finally
         Free;
         Free;
       end
       end
   else
   else
-    result := 0;
+    Result := 0;
 end;
 end;
 
 
 
 
 function TBlobField.GetIsNull: Boolean;
 function TBlobField.GetIsNull: Boolean;
 
 
 begin
 begin
-  If Not Modified then
-    result:= inherited GetIsnull
+  if Not Modified then
+    Result:= inherited GetIsNull
   else
   else
-    With GetBlobStream(bmread) do
+    with GetBlobStream(bmRead) do
       try
       try
         Result:=(Size=0);
         Result:=(Size=0);
-      Finally
+      finally
         Free;
         Free;
       end;
       end;
 end;
 end;
@@ -2841,12 +2860,26 @@ begin
   TheText:=inherited GetAsString;
   TheText:=inherited GetAsString;
 end;
 end;
 
 
+procedure TBlobField.SetAsBytes(const AValue: TBytes);
+var
+  Len : Integer;
+begin
+  with GetBlobStream(bmWrite) do
+    try
+      Len := Length(AValue);
+      if Len > 0 then
+        WriteBuffer(AValue[0], Len);
+    finally
+      Free;
+    end;
+end;
+
 
 
 procedure TBlobField.SetAsString(const AValue: string);
 procedure TBlobField.SetAsString(const AValue: string);
 var
 var
   Len : Integer;
   Len : Integer;
 begin
 begin
-  With GetBlobStream(bmwrite) do
+  with GetBlobStream(bmWrite) do
     try
     try
       Len := Length(AValue);
       Len := Length(AValue);
       if Len > 0 then
       if Len > 0 then
@@ -2861,7 +2894,7 @@ procedure TBlobField.SetAsWideString(const AValue: WideString);
 var
 var
   Len : Integer;
   Len : Integer;
 begin
 begin
-  With GetBlobStream(bmwrite) do
+  with GetBlobStream(bmWrite) do
     try
     try
       Len := Length(AValue) * 2;
       Len := Length(AValue) * 2;
       if Len > 0 then
       if Len > 0 then
@@ -2923,8 +2956,8 @@ end;
 procedure TBlobField.LoadFromStream(Stream: TStream);
 procedure TBlobField.LoadFromStream(Stream: TStream);
 
 
 begin
 begin
-  With GetBlobStream(bmWrite) do
-    Try
+  with GetBlobStream(bmWrite) do
+    try
       CopyFrom(Stream,0);
       CopyFrom(Stream,0);
     finally
     finally
       Free;
       Free;

+ 217 - 87
packages/fcl-db/src/sqldb/postgres/pqconnection.pp

@@ -15,19 +15,33 @@ uses
 {$EndIf}
 {$EndIf}
 
 
 type
 type
+  TPQCursor = Class;
+
+  { TPQTrans }
+
   TPQTrans = Class(TSQLHandle)
   TPQTrans = Class(TSQLHandle)
-    protected
+  protected
     PGConn        : PPGConn;
     PGConn        : PPGConn;
+    FList : TThreadList;
+    Procedure RegisterCursor(S : TPQCursor);
+    Procedure UnRegisterCursor(S : TPQCursor);
+  Public
+    Constructor Create;
+    Destructor Destroy; override;
   end;
   end;
 
 
+  { TPQCursor }
+
   TPQCursor = Class(TSQLCursor)
   TPQCursor = Class(TSQLCursor)
-    protected
+  protected
     Statement    : string;
     Statement    : string;
     StmtName     : string;
     StmtName     : string;
     tr           : TPQTrans;
     tr           : TPQTrans;
     res          : PPGresult;
     res          : PPGresult;
     CurTuple     : integer;
     CurTuple     : integer;
     FieldBinding : array of integer;
     FieldBinding : array of integer;
+   Public
+    Destructor Destroy; override;
   end;
   end;
 
 
   EPQDatabaseError = class(EDatabaseError)
   EPQDatabaseError = class(EDatabaseError)
@@ -50,8 +64,8 @@ type
 
 
   TPQConnection = class (TSQLConnection)
   TPQConnection = class (TSQLConnection)
   private
   private
-    FConnectionPool      : array of TPQTranConnection;
-    FCursorCount         : word;
+    FConnectionPool      : TThreadList;
+    FCursorCount         : dword;
     FConnectString       : string;
     FConnectString       : string;
     FIntegerDateTimes    : boolean;
     FIntegerDateTimes    : boolean;
     FVerboseErrors       : Boolean;
     FVerboseErrors       : Boolean;
@@ -60,6 +74,11 @@ type
     function TranslateFldType(res : PPGresult; Tuple : integer; out Size : integer) : TFieldType;
     function TranslateFldType(res : PPGresult; Tuple : integer; out Size : integer) : TFieldType;
     procedure ExecuteDirectPG(const Query : String);
     procedure ExecuteDirectPG(const Query : String);
   protected
   protected
+    // Add connection to pool.
+    procedure AddConnection(T: TPQTranConnection);
+    // Release connection in pool.
+    procedure ReleaseConnection(Conn: PPGConn; DoClear : Boolean);
+
     procedure DoInternalConnect; override;
     procedure DoInternalConnect; override;
     procedure DoInternalDisconnect; override;
     procedure DoInternalDisconnect; override;
     function GetHandle : pointer; override;
     function GetHandle : pointer; override;
@@ -86,6 +105,7 @@ type
     function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
     function RowsAffected(cursor: TSQLCursor): TRowsCount; override;
   public
   public
     constructor Create(AOwner : TComponent); override;
     constructor Create(AOwner : TComponent); override;
+    destructor destroy; override;
     function GetConnectionInfo(InfoType:TConnInfoType): string; override;
     function GetConnectionInfo(InfoType:TConnInfoType): string; override;
     procedure CreateDB; override;
     procedure CreateDB; override;
     procedure DropDB; override;
     procedure DropDB; override;
@@ -152,6 +172,53 @@ const Oid_Bool     = 16;
       oid_numeric   = 1700;
       oid_numeric   = 1700;
       Oid_uuid      = 2950;
       Oid_uuid      = 2950;
 
 
+{ TPQTrans }
+
+procedure TPQTrans.RegisterCursor(S: TPQCursor);
+begin
+  FList.Add(S);
+  S.tr:=Self;
+end;
+
+procedure TPQTrans.UnRegisterCursor(S: TPQCursor);
+begin
+  S.tr:=Nil;
+  FList.Remove(S);
+end;
+
+constructor TPQTrans.Create;
+begin
+  Flist:=TThreadList.Create;
+  FList.Duplicates:=dupIgnore;
+end;
+
+destructor TPQTrans.Destroy;
+
+Var
+  L : TList;
+  I : integer;
+
+begin
+  L:=Flist.LockList;
+  try
+    For I:=0 to L.Count-1 do
+      TPQCursor(L[i]).tr:=Nil;
+  finally
+    Flist.UnlockList;
+  end;
+  FreeAndNil(FList);
+  inherited Destroy;
+end;
+
+{ TPQCursor }
+
+destructor TPQCursor.Destroy;
+begin
+  if Assigned(tr) then
+    Tr.UnRegisterCursor(Self);
+  inherited Destroy;
+end;
+
 
 
 constructor TPQConnection.Create(AOwner : TComponent);
 constructor TPQConnection.Create(AOwner : TComponent);
 
 
@@ -160,6 +227,15 @@ begin
   FConnOptions := FConnOptions + [sqSupportParams] + [sqEscapeRepeat] + [sqEscapeSlash];
   FConnOptions := FConnOptions + [sqSupportParams] + [sqEscapeRepeat] + [sqEscapeSlash];
   FieldNameQuoteChars:=DoubleQuotes;
   FieldNameQuoteChars:=DoubleQuotes;
   VerboseErrors:=True;
   VerboseErrors:=True;
+  FConnectionPool:=TThreadlist.Create;
+end;
+
+destructor TPQConnection.destroy;
+begin
+  // We must disconnect here. If it is done in inherited, then connection pool is gone.
+  Connected:=False;
+  FreeAndNil(FConnectionPool);
+  inherited destroy;
 end;
 end;
 
 
 procedure TPQConnection.CreateDB;
 procedure TPQConnection.CreateDB;
@@ -174,7 +250,7 @@ begin
   ExecuteDirectPG('DROP DATABASE ' +DatabaseName);
   ExecuteDirectPG('DROP DATABASE ' +DatabaseName);
 end;
 end;
 
 
-procedure TPQConnection.ExecuteDirectPG(const query : string);
+procedure TPQConnection.ExecuteDirectPG(const Query: String);
 
 
 var ASQLDatabaseHandle    : PPGConn;
 var ASQLDatabaseHandle    : PPGConn;
     res                   : PPGresult;
     res                   : PPGresult;
@@ -207,6 +283,39 @@ begin
 {$EndIf}
 {$EndIf}
 end;
 end;
 
 
+procedure TPQConnection.AddConnection(T: TPQTranConnection);
+
+begin
+  FConnectionPool.Add(T);
+end;
+
+procedure TPQConnection.ReleaseConnection(Conn: PPGConn; DoClear: Boolean);
+
+Var
+  I : Integer;
+  L : TList;
+  T : TPQTranConnection;
+
+begin
+  L:=FConnectionPool.LockList;
+  // make connection available in pool
+  try
+    for i:=0 to L.Count-1 do
+      begin
+      T:=TPQTranConnection(L[i]);
+      if (T.FPGConn=Conn) then
+        begin
+        T.FTranActive:=false;
+        if DoClear then
+          T.FPGConn:=Nil;
+        break;
+        end;
+      end
+  finally
+    FConnectionPool.UnlockList;
+  end;
+end;
+
 
 
 function TPQConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
 function TPQConnection.GetTransactionHandle(trans : TSQLHandle): pointer;
 begin
 begin
@@ -218,23 +327,26 @@ var
   res : PPGresult;
   res : PPGresult;
   tr  : TPQTrans;
   tr  : TPQTrans;
   i   : Integer;
   i   : Integer;
+  L   : TList;
+
 begin
 begin
   result := false;
   result := false;
-
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
-
+  L:=tr.FList.LockList;
+  try
+    For I:=0 to L.Count-1 do
+      begin
+      UnprepareStatement(TPQCursor(L[i]));
+      TPQCursor(L[i]).tr:=Nil;
+      end;
+    L.Clear;
+  finally
+    tr.flist.UnlockList;
+  end;
   res := PQexec(tr.PGConn, 'ROLLBACK');
   res := PQexec(tr.PGConn, 'ROLLBACK');
-
   CheckResultError(res,tr.PGConn,SErrRollbackFailed);
   CheckResultError(res,tr.PGConn,SErrRollbackFailed);
-
   PQclear(res);
   PQclear(res);
-  //make connection available in pool
-  for i:=0 to length(FConnectionPool)-1 do
-    if FConnectionPool[i].FPGConn=tr.PGConn then
-      begin
-      FConnectionPool[i].FTranActive:=false;
-      break;
-      end;
+  ReleaseConnection(tr.PGCOnn,false);
   result := true;
   result := true;
 end;
 end;
 
 
@@ -245,20 +357,12 @@ var
   i   : Integer;
   i   : Integer;
 begin
 begin
   result := false;
   result := false;
-
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
-
   res := PQexec(tr.PGConn, 'COMMIT');
   res := PQexec(tr.PGConn, 'COMMIT');
   CheckResultError(res,tr.PGConn,SErrCommitFailed);
   CheckResultError(res,tr.PGConn,SErrCommitFailed);
-
   PQclear(res);
   PQclear(res);
   //make connection available in pool
   //make connection available in pool
-  for i:=0 to length(FConnectionPool)-1 do
-    if FConnectionPool[i].FPGConn=tr.PGConn then
-      begin
-      FConnectionPool[i].FTranActive:=false;
-      break;
-      end;
+  ReleaseConnection(tr.PGConn,false);
   result := true;
   result := true;
 end;
 end;
 
 
@@ -267,35 +371,47 @@ var
   res : PPGresult;
   res : PPGresult;
   tr  : TPQTrans;
   tr  : TPQTrans;
   i   : Integer;
   i   : Integer;
+  t : TPQTranConnection;
+  L : TList;
 begin
 begin
   result:=false;
   result:=false;
   tr := trans as TPQTrans;
   tr := trans as TPQTrans;
 
 
   //find an unused connection in the pool
   //find an unused connection in the pool
   i:=0;
   i:=0;
-  while i<length(FConnectionPool) do
-    if (FConnectionPool[i].FPGConn=nil) or not FConnectionPool[i].FTranActive then
-      break
-    else
+  t:=Nil;
+  L:=FConnectionPool.LockList;
+  try
+    while (I<L.Count-1) do
+      begin
+      T:=TPQTranConnection(L[i]);
+      if (T.FPGConn=nil) or not T.FTranActive then
+        break
+      else
+        T:=Nil;
       i:=i+1;
       i:=i+1;
-  if i=length(FConnectionPool) then //create a new connection
+      end;
+    // set to active now, so when we exit critical section,
+    // it will be marked active and will not be found.
+    if Assigned(T) then
+      T.FTranActive:=true;
+  finally
+    FConnectionPool.UnLockList;
+  end;
+  if (T=Nil) then
+    begin
+    T:=TPQTranConnection.Create;
+    T.FTranActive:=True;
+    AddConnection(T);
+    end;
+  if (T.FPGConn<>nil) then
+    tr.PGConn:=T.FPGConn
+  else
     begin
     begin
     tr.PGConn := PQconnectdb(pchar(FConnectString));
     tr.PGConn := PQconnectdb(pchar(FConnectString));
     CheckConnectionStatus(tr.PGConn);
     CheckConnectionStatus(tr.PGConn);
-
     if CharSet <> '' then
     if CharSet <> '' then
       PQsetClientEncoding(tr.PGConn, pchar(CharSet));
       PQsetClientEncoding(tr.PGConn, pchar(CharSet));
-
-    //store the new connection
-    SetLength(FConnectionPool,i+1);
-    FConnectionPool[i]:=TPQTranConnection.Create;
-    FConnectionPool[i].FPGConn:=tr.PGConn;
-    FConnectionPool[i].FTranActive:=true;
-    end
-  else //re-use existing connection
-    begin
-    tr.PGConn:=FConnectionPool[i].FPGConn;
-    FConnectionPool[i].FTranActive:=true;
     end;
     end;
 
 
   res := PQexec(tr.PGConn, 'BEGIN');
   res := PQexec(tr.PGConn, 'BEGIN');
@@ -339,7 +455,10 @@ end;
 
 
 
 
 procedure TPQConnection.DoInternalConnect;
 procedure TPQConnection.DoInternalConnect;
-var ASQLDatabaseHandle   : PPGConn;
+var
+  ASQLDatabaseHandle   : PPGConn;
+  T : TPQTranConnection;
+
 begin
 begin
 {$IfDef LinkDynamically}
 {$IfDef LinkDynamically}
   InitialisePostgres3;
   InitialisePostgres3;
@@ -365,24 +484,33 @@ begin
   // This only works for pg>=8.0, so timestamps won't work with earlier versions of pg which are compiled with integer_datetimes on
   // This only works for pg>=8.0, so timestamps won't work with earlier versions of pg which are compiled with integer_datetimes on
   if PQparameterStatus<>nil then
   if PQparameterStatus<>nil then
     FIntegerDateTimes := PQparameterStatus(ASQLDatabaseHandle,'integer_datetimes') = 'on';
     FIntegerDateTimes := PQparameterStatus(ASQLDatabaseHandle,'integer_datetimes') = 'on';
-
-  SetLength(FConnectionPool,1);
-  FConnectionPool[0]:=TPQTranConnection.Create;
-  FConnectionPool[0].FPGConn:=ASQLDatabaseHandle;
-  FConnectionPool[0].FTranActive:=false;
+  T:=TPQTranConnection.Create;
+  T.FPGConn:=ASQLDatabaseHandle;
+  T.FTranActive:=false;
+  AddConnection(T);
 end;
 end;
 
 
 procedure TPQConnection.DoInternalDisconnect;
 procedure TPQConnection.DoInternalDisconnect;
-var i:integer;
+var
+  i:integer;
+  L : TList;
+  T : TPQTranConnection;
+
 begin
 begin
   Inherited;
   Inherited;
-  for i:=0 to length(FConnectionPool)-1 do
-    begin
-    if assigned(FConnectionPool[i].FPGConn) then
-      PQfinish(FConnectionPool[i].FPGConn);
-    FConnectionPool[i].Free;
-    end;
-  Setlength(FConnectionPool,0);
+  L:=FConnectionPool.LockList;
+  try
+    for i:=0 to L.Count-1 do
+      begin
+      T:=TPQTranConnection(L[i]);
+      if assigned(T.FPGConn) then
+        PQfinish(T.FPGConn);
+      T.Free;
+      end;
+    L.Clear;
+  finally
+    FConnectionPool.UnLockList;
+  end;
 {$IfDef LinkDynamically}
 {$IfDef LinkDynamically}
   ReleasePostgres3;
   ReleasePostgres3;
 {$EndIf}
 {$EndIf}
@@ -396,13 +524,7 @@ begin
     begin
     begin
     sErr := PQerrorMessage(conn);
     sErr := PQerrorMessage(conn);
     //make connection available in pool
     //make connection available in pool
-    for i:=0 to length(FConnectionPool)-1 do
-      if FConnectionPool[i].FPGConn=conn then
-        begin
-        FConnectionPool[i].FPGConn:=nil;
-        FConnectionPool[i].FTranActive:=false;
-        break;
-        end;
+    ReleaseConnection(Conn,True);
     PQfinish(conn);
     PQfinish(conn);
     DatabaseError(sErrConnectionFailed + ' (PostgreSQL: ' + sErr + ')', Self);
     DatabaseError(sErrConnectionFailed + ' (PostgreSQL: ' + sErr + ')', Self);
     end;
     end;
@@ -463,14 +585,7 @@ begin
     if assigned(conn) then
     if assigned(conn) then
       begin
       begin
       PQFinish(conn);
       PQFinish(conn);
-      //make connection available in pool
-      for i:=0 to length(FConnectionPool)-1 do
-        if FConnectionPool[i].FPGConn=conn then
-          begin
-          FConnectionPool[i].FPGConn:=nil;
-          FConnectionPool[i].FTranActive:=false;
-          break;
-          end;
+      ReleaseConnection(Conn,True);
       end;
       end;
     raise E;
     raise E;
     end;
     end;
@@ -549,18 +664,18 @@ begin
   end;
   end;
 end;
 end;
 
 
-Function TPQConnection.AllocateCursorHandle : TSQLCursor;
+function TPQConnection.AllocateCursorHandle: TSQLCursor;
 
 
 begin
 begin
   result := TPQCursor.create;
   result := TPQCursor.create;
 end;
 end;
 
 
-Procedure TPQConnection.DeAllocateCursorHandle(var cursor : TSQLCursor);
+procedure TPQConnection.DeAllocateCursorHandle(var cursor: TSQLCursor);
 begin
 begin
   FreeAndNil(cursor);
   FreeAndNil(cursor);
 end;
 end;
 
 
-Function TPQConnection.AllocateTransactionHandle : TSQLHandle;
+function TPQConnection.AllocateTransactionHandle: TSQLHandle;
 
 
 begin
 begin
   result := TPQTrans.create;
   result := TPQTrans.create;
@@ -625,8 +740,9 @@ begin
     if FStatementType in [stInsert,stUpdate,stDelete, stSelect] then
     if FStatementType in [stInsert,stUpdate,stDelete, stSelect] then
       begin
       begin
       StmtName := 'prepst'+inttostr(FCursorCount);
       StmtName := 'prepst'+inttostr(FCursorCount);
-      inc(FCursorCount);
-      tr := TPQTrans(aTransaction.Handle);
+      InterlockedIncrement(FCursorCount);
+      TPQTrans(aTransaction.Handle).RegisterCursor(Cursor as TPQCursor);
+
       // Only available for pq 8.0, so don't use it...
       // Only available for pq 8.0, so don't use it...
       // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar(''));
       // Res := pqprepare(tr,'prepst'+name+nr,pchar(buf),params.Count,pchar(''));
       s := 'prepare '+StmtName+' ';
       s := 'prepare '+StmtName+' ';
@@ -755,7 +871,8 @@ begin
       end
       end
     else
     else
       begin
       begin
-      tr := TPQTrans(aTransaction.Handle);
+      // Registercursor sets tr
+      TPQTrans(aTransaction.Handle).RegisterCursor(Cursor as TPQCursor);
 
 
       if Assigned(AParams) and (AParams.Count > 0) then
       if Assigned(AParams) and (AParams.Count > 0) then
         begin
         begin
@@ -816,26 +933,39 @@ end;
 function TPQConnection.GetHandle: pointer;
 function TPQConnection.GetHandle: pointer;
 var
 var
   i:integer;
   i:integer;
+  L : TList;
+  T : TPQTranConnection;
+
 begin
 begin
   result:=nil;
   result:=nil;
   if not Connected then
   if not Connected then
     exit;
     exit;
   //Get any handle that is (still) connected
   //Get any handle that is (still) connected
-  for i:=0 to length(FConnectionPool)-1 do
-    if assigned(FConnectionPool[i].FPGConn) and (PQstatus(FConnectionPool[i].FPGConn)<>CONNECTION_BAD) then
+  L:=FConnectionPool.LockList;
+  try
+    I:=L.Count-1;
+    While (I>=0) and (Result=Nil) do
       begin
       begin
-      Result :=FConnectionPool[i].FPGConn;
-      exit;
+      T:=TPQTranConnection(L[i]);
+      if assigned(T.FPGConn) and (PQstatus(T.FPGConn)<>CONNECTION_BAD) then
+        Result:=T.FPGConn;
+      Dec(I);
       end;
       end;
+  finally
+    FConnectionPool.UnLockList;
+  end;
+  if Result<>Nil then
+     exit;
   //Nothing connected!! Reconnect
   //Nothing connected!! Reconnect
-  if assigned(FConnectionPool[0].FPGConn) then
-    PQreset(FConnectionPool[0].FPGConn)
+  // T is element 0 after loop
+  if assigned(T.FPGConn) then
+    PQreset(T.FPGConn)
   else
   else
-    FConnectionPool[0].FPGConn := PQconnectdb(pchar(FConnectString));
-  CheckConnectionStatus(FConnectionPool[0].FPGConn);
+    T.FPGConn := PQconnectdb(pchar(FConnectString));
+  CheckConnectionStatus(T.FPGConn);
   if CharSet <> '' then
   if CharSet <> '' then
-    PQsetClientEncoding(FConnectionPool[0].FPGConn, pchar(CharSet));
-  result:=FConnectionPool[0].FPGConn;
+    PQsetClientEncoding(T.FPGConn, pchar(CharSet));
+  result:=T.FPGConn;
 end;
 end;
 
 
 function TPQConnection.Fetch(cursor : TSQLCursor) : boolean;
 function TPQConnection.Fetch(cursor : TSQLCursor) : boolean;

+ 2 - 1
packages/fcl-db/src/sqldb/sqldb.pp

@@ -1248,11 +1248,11 @@ procedure TSQLTransaction.EndTransaction;
 
 
 begin
 begin
   Case Action of
   Case Action of
-    caNone : ;
     caCommit :
     caCommit :
       Commit;
       Commit;
     caCommitRetaining :
     caCommitRetaining :
       CommitRetaining;
       CommitRetaining;
+    caNone,
     caRollback :
     caRollback :
       RollBack;
       RollBack;
     caRollbackRetaining :
     caRollbackRetaining :
@@ -1350,6 +1350,7 @@ end;
 destructor TSQLTransaction.Destroy;
 destructor TSQLTransaction.Destroy;
 begin
 begin
   EndTransaction;
   EndTransaction;
+  FreeAndNil(FTrans);
   FreeAndNil(FParams);
   FreeAndNil(FParams);
   inherited Destroy;
   inherited Destroy;
 end;
 end;

+ 1 - 2
packages/fcl-db/tests/bufdatasettoolsunit.pas

@@ -6,8 +6,8 @@ A closed BufDataset normally has no data, so these tests won't work.
 
 
 To circumvent this, this unit saves the dataset contents to file and reloads them on opening
 To circumvent this, this unit saves the dataset contents to file and reloads them on opening
 using the BufDataset persistence mechanism.
 using the BufDataset persistence mechanism.
-
 }
 }
+
 {$mode objfpc}{$H+}
 {$mode objfpc}{$H+}
 
 
 interface
 interface
@@ -18,7 +18,6 @@ uses
   BufDataset;
   BufDataset;
 
 
 type
 type
-{ TbufdatasetConnector }
 
 
   { TbufdatasetDBConnector }
   { TbufdatasetDBConnector }
 
 

+ 68 - 0
packages/fcl-db/tests/dbguitestrunner.pas

@@ -0,0 +1,68 @@
+unit DBGuiTestRunner;
+// Adds database.ini editing facilities to regular GuiTestRunner form
+
+{$mode objfpc}{$H+}
+
+interface
+
+uses
+  Classes, SysUtils,
+  Interfaces, Forms,
+  StdCtrls,
+  GuiTestRunner, inieditor;
+
+type
+
+  { TDBGuiTestRunnerForm }
+
+  TDBGuiTestRunnerForm=class(TGUITestRunner)
+  private
+    DBEditButton: TButton;
+  public
+    procedure DBEditButtonClick(ASender: TObject);
+    constructor Create(AOwner: TComponent); override;
+  end;
+
+var
+  DBGuiTestRunnerForm: TDBGuiTestRunnerForm;
+
+
+implementation
+
+
+{ TDBGuiTestRunnerForm }
+
+procedure TDBGuiTestRunnerForm.DBEditButtonClick(ASender: TObject);
+var
+  DBSelectForm: TFormIniEditor;
+begin
+  DBSelectForm:=TFormIniEditor.Create(nil);
+  try
+    DBSelectForm.INIFile:='database.ini';
+    DBSelectForm.ProfileSelectSection:='Database';
+    DBSelectForm.ProfileSelectKey:='type';
+    // We can ignore resulting db selection as the file is saved already:
+    DBSelectForm.ShowModal;
+  finally
+    DBSelectForm.Free;
+  end;
+end;
+
+constructor TDBGuiTestRunnerForm.Create(AOwner: TComponent);
+// Add our database.ini edit button to the existing GUI
+begin
+  inherited Create(AOwner);
+  DBEditButton:=TButton.Create(Self);
+  DBEditButton.Top:=7;
+  DBEditButton.Left:=210;
+  DBEditButton.Height:=32;
+  DBEditButton.Width:=100;
+  DBEditButton.Caption:='Edit database.ini...';
+  DBEditButton.Hint:='Edit database selection settings (effective for next start)';
+  DBEditButton.OnClick:=@DBEditButtonClick;
+  // Set this last; now all properties take effect
+  DBEditButton.Parent:=Self.Panel1;
+end;
+
+end.
+

+ 11 - 2
packages/fcl-db/tests/dbtestframework_gui.lpi

@@ -1,10 +1,14 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <CONFIG>
 <CONFIG>
   <ProjectOptions>
   <ProjectOptions>
     <Version Value="9"/>
     <Version Value="9"/>
     <General>
     <General>
+      <Flags>
+        <MainUnitHasCreateFormStatements Value="False"/>
+      </Flags>
       <SessionStorage Value="InProjectDir"/>
       <SessionStorage Value="InProjectDir"/>
       <MainUnit Value="0"/>
       <MainUnit Value="0"/>
+      <Title Value="DBTestFramework"/>
       <ResourceType Value="res"/>
       <ResourceType Value="res"/>
       <UseXPManifest Value="True"/>
       <UseXPManifest Value="True"/>
     </General>
     </General>
@@ -76,12 +80,17 @@
         <PackageName Value="FCL"/>
         <PackageName Value="FCL"/>
       </Item4>
       </Item4>
     </RequiredPackages>
     </RequiredPackages>
-    <Units Count="1">
+    <Units Count="2">
       <Unit0>
       <Unit0>
         <Filename Value="dbtestframework_gui.lpr"/>
         <Filename Value="dbtestframework_gui.lpr"/>
         <IsPartOfProject Value="True"/>
         <IsPartOfProject Value="True"/>
         <UnitName Value="dbtestframework_gui"/>
         <UnitName Value="dbtestframework_gui"/>
       </Unit0>
       </Unit0>
+      <Unit1>
+        <Filename Value="dbguitestrunner.pas"/>
+        <IsPartOfProject Value="True"/>
+        <UnitName Value="DBGuiTestRunner"/>
+      </Unit1>
     </Units>
     </Units>
   </ProjectOptions>
   </ProjectOptions>
   <CompilerOptions>
   <CompilerOptions>

+ 6 - 24
packages/fcl-db/tests/dbtestframework_gui.lpr

@@ -14,10 +14,11 @@ program dbtestframework_gui;
 uses
 uses
   Interfaces, Forms,
   Interfaces, Forms,
   // GUI:
   // GUI:
-  GuiTestRunner, inieditor,
+  StdCtrls {to extend GuiTestRunner},
+  DBGuiTestRunner, inieditor,
   // Generic DB test framework units
   // Generic DB test framework units
   ToolsUnit,
   ToolsUnit,
-  // Connectors for different database-types
+  // Connectors for different database types
   sqldbtoolsunit,
   sqldbtoolsunit,
   dbftoolsunit,
   dbftoolsunit,
   bufdatasettoolsunit,
   bufdatasettoolsunit,
@@ -37,29 +38,10 @@ uses
 
 
 {$R *.res}
 {$R *.res}
 
 
-var
-  DBSelectForm: TFormIniEditor;
-  TestRunForm: TGUITestRunner;
 begin
 begin
+  Application.Title:='DBTestFramework';
   Application.Initialize;
   Application.Initialize;
-  DBSelectForm:=TFormIniEditor.Create(nil);
-  try
-    DBSelectForm.INIFile:='database.ini';
-    DBSelectForm.ProfileSelectSection:='Database';
-    DBSelectForm.ProfileSelectKey:='type';
-    // We can ignore resulting db selection as the file is saved already:
-    DBSelectForm.ShowModal;
-  finally
-    DBSelectForm.Free;
-  end;
-  // Manually run this form because autocreation could have loaded an old
-  // database.ini file (if the user changed it using DBSelectForm)
-  TestRunForm:=TGUITestRunner.Create(nil);
-  try
-    TestRunForm.Show;
-    Application.Run;
-  finally
-    TestRunForm.Free;
-  end;
+  Application.CreateForm(TDBGuiTestRunnerForm, DBGuiTestRunnerForm);
+  Application.Run;
 end.
 end.
 
 

+ 25 - 7
packages/fcl-db/tests/inieditor.lfm

@@ -454,12 +454,14 @@ object FormIniEditor: TFormIniEditor
     Lines.Strings = (
     Lines.Strings = (
       ''
       ''
     )
     )
+    SelectedColor.FrameEdges = sfeAround
     SelectedColor.BackPriority = 50
     SelectedColor.BackPriority = 50
     SelectedColor.ForePriority = 50
     SelectedColor.ForePriority = 50
     SelectedColor.FramePriority = 50
     SelectedColor.FramePriority = 50
     SelectedColor.BoldPriority = 50
     SelectedColor.BoldPriority = 50
     SelectedColor.ItalicPriority = 50
     SelectedColor.ItalicPriority = 50
     SelectedColor.UnderlinePriority = 50
     SelectedColor.UnderlinePriority = 50
+    SelectedColor.StrikeOutPriority = 50
     OnStatusChange = SynMemoStatusChange
     OnStatusChange = SynMemoStatusChange
     inline SynLeftGutterPartList1: TSynGutterPartList
     inline SynLeftGutterPartList1: TSynGutterPartList
       object SynGutterMarks1: TSynGutterMarks
       object SynGutterMarks1: TSynGutterMarks
@@ -471,6 +473,7 @@ object FormIniEditor: TFormIniEditor
         MouseActions = <>
         MouseActions = <>
         MarkupInfo.Background = clBtnFace
         MarkupInfo.Background = clBtnFace
         MarkupInfo.Foreground = clNone
         MarkupInfo.Foreground = clNone
+        MarkupInfo.FrameEdges = sfeAround
         DigitCount = 2
         DigitCount = 2
         ShowOnlyLineNumbersMultiplesOf = 1
         ShowOnlyLineNumbersMultiplesOf = 1
         ZeroStart = False
         ZeroStart = False
@@ -485,11 +488,15 @@ object FormIniEditor: TFormIniEditor
       object SynGutterSeparator1: TSynGutterSeparator
       object SynGutterSeparator1: TSynGutterSeparator
         Width = 2
         Width = 2
         MouseActions = <>
         MouseActions = <>
+        MarkupInfo.Background = clWhite
+        MarkupInfo.Foreground = clGray
+        MarkupInfo.FrameEdges = sfeAround
       end
       end
       object SynGutterCodeFolding1: TSynGutterCodeFolding
       object SynGutterCodeFolding1: TSynGutterCodeFolding
         MouseActions = <>
         MouseActions = <>
         MarkupInfo.Background = clNone
         MarkupInfo.Background = clNone
         MarkupInfo.Foreground = clGray
         MarkupInfo.Foreground = clGray
+        MarkupInfo.FrameEdges = sfeAround
         MouseActionsExpanded = <>
         MouseActionsExpanded = <>
         MouseActionsCollapsed = <>
         MouseActionsCollapsed = <>
       end
       end
@@ -497,7 +504,7 @@ object FormIniEditor: TFormIniEditor
   end
   end
   object FileNameEdit: TFileNameEdit
   object FileNameEdit: TFileNameEdit
     Left = 56
     Left = 56
-    Height = 23
+    Height = 21
     Top = 24
     Top = 24
     Width = 368
     Width = 368
     OnAcceptFileName = FileNameEditAcceptFileName
     OnAcceptFileName = FileNameEditAcceptFileName
@@ -510,28 +517,28 @@ object FormIniEditor: TFormIniEditor
   end
   end
   object INIFileLabel: TLabel
   object INIFileLabel: TLabel
     Left = 8
     Left = 8
-    Height = 15
+    Height = 13
     Top = 24
     Top = 24
-    Width = 34
+    Width = 32
     Caption = 'INI file'
     Caption = 'INI file'
     ParentColor = False
     ParentColor = False
   end
   end
   object ProfileSelect: TComboBox
   object ProfileSelect: TComboBox
     Left = 56
     Left = 56
-    Height = 23
+    Height = 21
     Hint = 'Choose the profile you want to enable'
     Hint = 'Choose the profile you want to enable'
     Top = 61
     Top = 61
     Width = 164
     Width = 164
-    ItemHeight = 15
+    ItemHeight = 13
     OnSelect = ProfileSelectSelect
     OnSelect = ProfileSelectSelect
     Sorted = True
     Sorted = True
     TabOrder = 1
     TabOrder = 1
   end
   end
   object ProfileLabel: TLabel
   object ProfileLabel: TLabel
     Left = 8
     Left = 8
-    Height = 15
+    Height = 13
     Top = 64
     Top = 64
-    Width = 34
+    Width = 30
     Caption = 'Profile'
     Caption = 'Profile'
     ParentColor = False
     ParentColor = False
   end
   end
@@ -556,6 +563,17 @@ object FormIniEditor: TFormIniEditor
     OnClick = CancelButtonClick
     OnClick = CancelButtonClick
     TabOrder = 3
     TabOrder = 3
   end
   end
+  object Label1: TLabel
+    Left = 8
+    Height = 13
+    Top = 0
+    Width = 229
+    Caption = 'Changes need a program restart to load!'
+    Font.Color = clRed
+    Font.Style = [fsBold]
+    ParentColor = False
+    ParentFont = False
+  end
   object SynIniHighlighter: TSynIniSyn
   object SynIniHighlighter: TSynIniSyn
     DefaultFilter = 'INI Files (*.ini)|*.ini'
     DefaultFilter = 'INI Files (*.ini)|*.ini'
     Enabled = False
     Enabled = False

+ 1 - 0
packages/fcl-db/tests/inieditor.pas

@@ -15,6 +15,7 @@ type
 
 
   TFormIniEditor = class(TForm)
   TFormIniEditor = class(TForm)
     GUITimer: TIdleTimer;
     GUITimer: TIdleTimer;
+    Label1: TLabel;
     OKButton: TButton;
     OKButton: TButton;
     CancelButton: TButton;
     CancelButton: TButton;
     ProfileSelect: TComboBox;
     ProfileSelect: TComboBox;

+ 1 - 1
packages/fcl-db/tests/sqldbtoolsunit.pas

@@ -14,7 +14,7 @@ uses
   {$ENDIF WIN64}
   {$ENDIF WIN64}
   ,odbcconn
   ,odbcconn
   {$IFNDEF WIN64}
   {$IFNDEF WIN64}
-  {See packages\fcl-db\fpmake.pp: Oracle connector is not built if PostgreSQL connectoris not built}
+  {See packages\fcl-db\fpmake.pp: Oracle connector not built yet on Win64}
   ,oracleconnection
   ,oracleconnection
   {$ENDIF WIN64}
   {$ENDIF WIN64}
   ,sqlite3conn
   ,sqlite3conn

+ 9 - 10
packages/fcl-db/tests/testdbbasics.pas

@@ -324,11 +324,11 @@ begin
     begin
     begin
     aDatasource.DataSet := ds;
     aDatasource.DataSet := ds;
     DataEvents := '';
     DataEvents := '';
-    open;
-    Fields.add(tfield.Create(DBConnector.GetNDataset(1)));
+    Open;
+    Fields.Add(TField.Create(ds));
     CheckEquals('deUpdateState:0;deFieldListChange:0;',DataEvents);
     CheckEquals('deUpdateState:0;deFieldListChange:0;',DataEvents);
     DataEvents := '';
     DataEvents := '';
-    fields.Clear;
+    Fields.Clear;
     CheckEquals('deFieldListChange:0;',DataEvents)
     CheckEquals('deFieldListChange:0;',DataEvents)
     end;
     end;
   aDatasource.Free;
   aDatasource.Free;
@@ -1319,7 +1319,6 @@ begin
     first;
     first;
     CheckTrue(EOF);
     CheckTrue(EOF);
 
 
-
     Close;
     Close;
     end;
     end;
 end;
 end;
@@ -1327,14 +1326,13 @@ end;
 {$ifdef fpc}
 {$ifdef fpc}
 procedure TTestBufDatasetDBBasics.TestIsEmpty;
 procedure TTestBufDatasetDBBasics.TestIsEmpty;
 begin
 begin
-  with tCustombufdataset(DBConnector.GetNDataset(True,1)) do
+  with DBConnector.GetNDataset(True,1) as TCustomBufDataset do
     begin
     begin
     open;
     open;
     delete;
     delete;
     Resync([]);
     Resync([]);
-    applyupdates;
+    ApplyUpdates;
     CheckTrue(IsEmpty);
     CheckTrue(IsEmpty);
-
     end;
     end;
 end;
 end;
 
 
@@ -2333,7 +2331,6 @@ var i          : byte;
     DbfTableLevel: integer;
     DbfTableLevel: integer;
 
 
 begin
 begin
-  DbfTableLevel:=4;
   if (uppercase(dbconnectorname)='DBF') then
   if (uppercase(dbconnectorname)='DBF') then
   begin
   begin
     DbfTableLevel:=strtointdef(dbconnectorparams,4);
     DbfTableLevel:=strtointdef(dbconnectorparams,4);
@@ -2359,7 +2356,8 @@ var i          : byte;
 
 
 begin
 begin
   if (uppercase(dbconnectorname)='DBF') then
   if (uppercase(dbconnectorname)='DBF') then
-    Ignore('TDBF Smallint support only from -999 to 9999');
+    Ignore('TDBF: Smallint support only from -999 to 9999');
+
   TestfieldDefinition(ftSmallint,2,ds,Fld);
   TestfieldDefinition(ftSmallint,2,ds,Fld);
 
 
   for i := 0 to testValuesCount-1 do
   for i := 0 to testValuesCount-1 do
@@ -2498,7 +2496,8 @@ var i          : byte;
 
 
 begin
 begin
   if (uppercase(dbconnectorname)='DBF') then
   if (uppercase(dbconnectorname)='DBF') then
-    Ignore('This test does not apply to TDDBF as they store currency in BCD fields.');
+    Ignore('This test does not apply to TDBF as they store currency in BCD fields.');
+
   TestfieldDefinition(ftCurrency,8,ds,Fld);
   TestfieldDefinition(ftCurrency,8,ds,Fld);
 
 
   for i := 0 to testValuesCount-1 do
   for i := 0 to testValuesCount-1 do