From ee16571c11390916ae6b693122edecda2d78c687 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Wed, 11 Mar 2026 08:55:55 +0100 Subject: [PATCH 01/45] fix: crash after canceling query Refs #2426 --- source/dbconnection.pas | 6 +++++- source/main.pas | 1 + 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 88fdccbbd..94bc1f08e 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -426,6 +426,7 @@ TDBConnection = class(TComponent) FServerUptime: Integer; FServerDateTimeOnStartup: String; FParameters: TConnectionParameters; + FOwnsParameters: Boolean; FSecureShellCmd: TSecureShellCmd; FDatabase: String; FAllDatabases: TStringList; @@ -552,6 +553,7 @@ TDBConnection = class(TComponent) function ApplyLimitClause(QueryType, QueryBody: String; Limit, Offset: Int64): String; function LikeClauseTail: String; property Parameters: TConnectionParameters read FParameters write FParameters; + property OwnsParameters: Boolean read FOwnsParameters write FOwnsParameters; property ThreadId: Int64 read GetThreadId; property ConnectionUptime: Int64 read GetConnectionUptime; property ServerUptime: Int64 read GetServerUptime; @@ -2017,6 +2019,7 @@ constructor TDBConnection.Create(AOwner: TComponent); begin inherited; FParameters := TConnectionParameters.Create; + FOwnsParameters := True; FRowsFound := 0; FRowsAffected := 0; FWarningCount := 0; @@ -2138,7 +2141,8 @@ destructor TDBConnection.Destroy; FKeepAliveTimer.Free; FFavorites.Free; FInformationSchemaObjects.Free; - FParameters.Free; + if FOwnsParameters then + FParameters.Free; inherited; end; diff --git a/source/main.pas b/source/main.pas index de2f7158a..67aaf4c8a 100644 --- a/source/main.pas +++ b/source/main.pas @@ -13797,6 +13797,7 @@ procedure TMainForm.actCancelOperationExecute(Sender: TObject); Tab.ExecutionThread.Aborted := True; Killer := ActiveConnection.Parameters.CreateConnection(Self); Killer.Parameters := ActiveConnection.Parameters; + Killer.OwnsParameters := False; Killer.LogPrefix := _('Helper connection'); Killer.OnLog := LogSQL; try From 950e2ca28a9661e6a90d577d4396c4a0c607a66e Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Wed, 11 Mar 2026 11:52:29 +0100 Subject: [PATCH 02/45] feat: allow setting database to in PostgreSQL connections, and show and in the pulldown selector Refs #2424 --- source/connections.pas | 40 ++++++++++++++++++++++++++++++++-------- source/dbconnection.pas | 10 ++++++++-- 2 files changed, 40 insertions(+), 10 deletions(-) diff --git a/source/connections.pas b/source/connections.pas index d02177da2..93dd882d2 100644 --- a/source/connections.pas +++ b/source/connections.pas @@ -1304,7 +1304,7 @@ procedure Tconnform.editDatabasesRightButtonClick(Sender: TObject); // Try to connect and lookup database names Params := CurrentParams; Connection := Params.CreateConnection(Self); - Connection.Parameters.AllDatabasesStr := ''; + Connection.Parameters.AllDatabasesStr := TPgConnection.DBNAME_EMPTY; Connection.LogPrefix := SelectedSessionPath; Connection.OnLog := Mainform.LogSQL; FPopupDatabases := TPopupMenu.Create(Self); @@ -1312,16 +1312,29 @@ procedure Tconnform.editDatabasesRightButtonClick(Sender: TObject); Screen.Cursor := crHourglass; try Connection.Active := True; - if Params.NetTypeGroup = ngPgSQL then - Databases := Connection.GetCol('SELECT datname FROM pg_database WHERE datistemplate=FALSE') - else + if Params.IsAnyPostgreSQL then begin + Databases := Connection.GetCol('SELECT datname FROM pg_database WHERE datistemplate=FALSE'); + Item := TMenuItem.Create(FPopupDatabases); + Item.Caption := TPgConnection.DBNAME_EMPTY + ' (' + _('No database') + ')'; + Item.Tag := TPgConnection.DBTAG_EMPTY; + Item.OnClick := MenuDatabasesClick; + Item.AutoCheck := True; + Item.RadioItem := True; + FPopupDatabases.Items.Add(Item); + end + else begin Databases := Connection.AllDatabases; + end; for DB in Databases do begin Item := TMenuItem.Create(FPopupDatabases); Item.Caption := DB; + if Params.IsAnyPostgreSQL and (DB = TPgConnection.DBNAME_DEFAULT) then begin + Item.Caption := Item.Caption + ' (' + _('Default') + ')'; + Item.Tag := TPgConnection.DBTAG_DEFAULT; + end; Item.OnClick := MenuDatabasesClick; Item.AutoCheck := True; - Item.RadioItem := Params.NetTypeGroup = ngPgSQL; + Item.RadioItem := Params.IsAnyPostgreSQL; FPopupDatabases.Items.Add(Item); end; Databases.Free; @@ -1334,7 +1347,14 @@ procedure Tconnform.editDatabasesRightButtonClick(Sender: TObject); // Check/uncheck items, based on semicolon list Databases := Explode(';', editDatabases.Text); for Item in FPopupDatabases.Items do begin - Item.Checked := Databases.IndexOf(Item.Caption) > -1; + case Item.Tag of + TPgConnection.DBTAG_EMPTY: + Item.Checked := Databases.Contains(TPgConnection.DBNAME_EMPTY); + TPgConnection.DBTAG_DEFAULT: + Item.Checked := Databases.Contains(TPgConnection.DBNAME_DEFAULT) or Databases.IsEmpty; + else + Item.Checked := Databases.IndexOf(Item.Caption) > -1; + end; end; Databases.Free; @@ -1351,8 +1371,12 @@ procedure Tconnform.MenuDatabasesClick(Sender: TObject); begin Databases := TStringList.Create; for Item in FPopupDatabases.Items do begin - if Item.Checked then - Databases.Add(Item.Caption); + if Item.Checked then begin + if Item.Tag in [TPgConnection.DBTAG_EMPTY, TPgConnection.DBTAG_DEFAULT] then // Remove hint + Databases.Add(ReplaceRegExpr('\s\(.+$', Item.Caption, '')) + else + Databases.Add(Item.Caption); + end; end; SelStart := editDatabases.SelStart; editDatabases.Text := Implode(';', Databases); diff --git a/source/dbconnection.pas b/source/dbconnection.pas index 94bc1f08e..e4964c46f 100644 --- a/source/dbconnection.pas +++ b/source/dbconnection.pas @@ -690,6 +690,11 @@ TSqlSrvConnection = class(TDBConnection) TPGRawResults = Array of PPGresult; TPQerrorfields = (PG_DIAG_SEVERITY, PG_DIAG_SQLSTATE, PG_DIAG_MESSAGE_PRIMARY, PG_DIAG_MESSAGE_DETAIL, PG_DIAG_MESSAGE_HINT, PG_DIAG_STATEMENT_POSITION, PG_DIAG_INTERNAL_POSITION, PG_DIAG_INTERNAL_QUERY, PG_DIAG_CONTEXT, PG_DIAG_SOURCE_FILE, PG_DIAG_SOURCE_LINE, PG_DIAG_SOURCE_FUNCTION); TPgConnection = class(TDBConnection) + const + DBNAME_DEFAULT = 'postgres'; + DBNAME_EMPTY = '!'; + DBTAG_EMPTY = 1; + DBTAG_DEFAULT = 2; private FHandle: PPGconn; FLib: TPostgreSQLLib; @@ -2740,7 +2745,7 @@ procedure TPgConnection.SetActive(Value: Boolean); // "You should connect as "postgres" database by default, with an option to change. Don't use template1" dbname := FParameters.AllDatabasesStr; if dbname = '' then - dbname := 'postgres'; + dbname := DBNAME_DEFAULT; // Prepare special stuff for SSH tunnel FinalHost := FParameters.Hostname; @@ -2756,9 +2761,10 @@ procedure TPgConnection.SetActive(Value: Boolean); .AddPair('port', IntToStr(FinalPort)) .AddPair('user', FParameters.Username) .AddPair('password', FParameters.Password) - .AddPair('dbname', dbname) .AddPair('application_name', APPNAME) .AddPair('sslmode', 'disable'); + if dbname <> DBNAME_EMPTY then + ConnectOptions.AddPair('dbname', dbname); if FParameters.WantSSL then begin // Be aware .AddPair would add duplicates case FParameters.SSLVerification of From dc046e9cda46c7d22f3423429656106e28cb7328 Mon Sep 17 00:00:00 2001 From: Ansgar Becker Date: Wed, 11 Mar 2026 15:14:45 +0100 Subject: [PATCH 03/45] feat: make HTML export dark/light mode aware Refs #2418 --- source/exportgrid.pas | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/source/exportgrid.pas b/source/exportgrid.pas index 40ffc24aa..1105a5ef8 100644 --- a/source/exportgrid.pas +++ b/source/exportgrid.pas @@ -724,15 +724,15 @@ procedure TfrmExportGrid.btnOKClick(Sender: TObject); CodeIndent(2) + '' + TableName + '' + sLineBreak + CodeIndent(2) + '' + sLineBreak + CodeIndent(2) + '' + sLineBreak + + CodeIndent(2) + '' + sLineBreak + CodeIndent(2) + '