mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
2342 lines
No EOL
65 KiB
C++
2342 lines
No EOL
65 KiB
C++
//////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// pgAdmin III - PostgreSQL Tools
|
|
//
|
|
// Copyright (C) 2002 - 2016, The pgAdmin Development Team
|
|
// This software is released under the PostgreSQL Licence
|
|
//
|
|
// pgServer.cpp - PostgreSQL Server
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#include "pgAdmin3.h"
|
|
|
|
// wxWindows headers
|
|
#include <wx/wx.h>
|
|
#include <wx/busyinfo.h>
|
|
#include <wx/dir.h>
|
|
#include <wx/fileconf.h>
|
|
#include <wx/wfstream.h>
|
|
|
|
// App headers
|
|
#include "ctl/ctlMenuToolbar.h"
|
|
#include "frm/menu.h"
|
|
#include "utils/misc.h"
|
|
#include "frm/frmMain.h"
|
|
#include "frm/frmHint.h"
|
|
#include "dlg/dlgConnect.h"
|
|
#include "schema/pgDatabase.h"
|
|
#include "schema/pgTablespace.h"
|
|
#include "schema/pgGroup.h"
|
|
#include "schema/pgUser.h"
|
|
#include "schema/pgRole.h"
|
|
#include "schema/gpResQueue.h"
|
|
#include "agent/pgaJob.h"
|
|
#include "utils/utffile.h"
|
|
#include "utils/pgfeatures.h"
|
|
#include "utils/registry.h"
|
|
#include "frm/frmReport.h"
|
|
#include "dlg/dlgServer.h"
|
|
#include "schema/edbResourceGroup.h"
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
#include "utils/sshTunnel.h"
|
|
#endif
|
|
|
|
#define DEFAULT_PG_DATABASE wxT("postgres")
|
|
|
|
pgServer::pgServer(const wxString &newName, const wxString &newHostAddr, const wxString &newDescription, const wxString &newService,
|
|
const wxString &newDatabase, const wxString &newUsername, int newPort, bool _storePwd, const wxString &newRolename, const wxString& newConnStr, bool _restore,
|
|
int _ssl, const wxString &_colour, const wxString &_group, bool _sshTunnel, const wxString &newTunnelHost, const wxString &newTunnelUserName,
|
|
bool _authModePwd, const wxString &newTunnelPassword, const wxString &newPublicKey, const wxString &newIdentity, const int &sshPort)
|
|
: pgObject(serverFactory, newName)
|
|
{
|
|
description = newDescription;
|
|
hostaddr = newHostAddr;
|
|
service = newService;
|
|
database = newDatabase;
|
|
username = newUsername;
|
|
port = newPort;
|
|
ssl = _ssl;
|
|
colour = _colour;
|
|
group = _group;
|
|
|
|
serverIndex = 0;
|
|
|
|
connected = false;
|
|
lastSystemOID = 0;
|
|
|
|
conn = NULL;
|
|
passwordValid = true;
|
|
storePwd = _storePwd;
|
|
rolename = newRolename;
|
|
connstr = newConnStr;
|
|
restore = _restore;
|
|
superUser = false;
|
|
createPrivilege = false;
|
|
sshTunnel = _sshTunnel;
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
// SSH Tunnel
|
|
tunnelObj = NULL;
|
|
tunnelHost = newTunnelHost;
|
|
tunnelUserName = newTunnelUserName;
|
|
authModePwd = _authModePwd;
|
|
tunnelPassword = newTunnelPassword;
|
|
publicKeyFile = newPublicKey;
|
|
identityFile = newIdentity;
|
|
tunnelPort = sshPort;
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
scmHandle = 0;
|
|
serviceHandle = 0;
|
|
#endif
|
|
}
|
|
|
|
pgServer::~pgServer()
|
|
{
|
|
if (conn)
|
|
delete conn;
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
if(tunnelObj)
|
|
{
|
|
if(tunnelObj->IsAlive())
|
|
{
|
|
tunnelObj->Cleanup();
|
|
}
|
|
tunnelObj = NULL;
|
|
}
|
|
#endif
|
|
|
|
#ifdef WIN32
|
|
if (serviceHandle)
|
|
CloseServiceHandle(serviceHandle);
|
|
if (scmHandle)
|
|
CloseServiceHandle(scmHandle);
|
|
#endif
|
|
}
|
|
|
|
|
|
wxString pgServer::GetTranslatedMessage(int kindOfMessage) const
|
|
{
|
|
wxString message = wxEmptyString;
|
|
|
|
switch (kindOfMessage)
|
|
{
|
|
case RETRIEVINGDETAILS:
|
|
message = _("Retrieving details on server");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case REFRESHINGDETAILS:
|
|
message = _("Refreshing server");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case BACKUPGLOBALS:
|
|
message = _("Backup globals of server");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case BACKUPSERVERTITLE:
|
|
message = _("Backup server");
|
|
message += wxT(" ") + GetName();
|
|
break;
|
|
case DROPTITLE:
|
|
message = _("Drop server?");
|
|
break;
|
|
case PROPERTIESREPORT:
|
|
message = _("Server properties report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case PROPERTIES:
|
|
message = _("Server properties");
|
|
break;
|
|
case STATISTICSREPORT:
|
|
message = _("Server statistics report");
|
|
message += wxT(" - ") + GetName();
|
|
break;
|
|
case OBJSTATISTICS:
|
|
message = _("Server statistics");
|
|
break;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
|
|
int pgServer::GetIconId()
|
|
{
|
|
if (GetConnected())
|
|
return serverFactory.GetIconId();
|
|
else
|
|
return serverFactory.GetClosedIconId();
|
|
}
|
|
|
|
|
|
wxMenu *pgServer::GetNewMenu()
|
|
{
|
|
wxMenu *menu = 0;
|
|
if (connected && (GetSuperUser() || GetCreateRole()))
|
|
{
|
|
menu = new wxMenu();
|
|
if (settings->GetDisplayOption(_("Tablespaces")))
|
|
tablespaceFactory.AppendMenu(menu);
|
|
if (GetConnection()->BackendMinimumVersion(8, 1))
|
|
{
|
|
if (settings->GetDisplayOption(_("Groups/group Roles")))
|
|
groupRoleFactory.AppendMenu(menu);
|
|
if (settings->GetDisplayOption(_("Users/login Roles")))
|
|
loginRoleFactory.AppendMenu(menu);
|
|
if (GetConnection()->GetIsGreenplum())
|
|
{
|
|
if (settings->GetDisplayOption(_("Resource Queues")))
|
|
resQueueFactory.AppendMenu(menu);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (settings->GetDisplayOption(_("Groups/group Roles")))
|
|
groupFactory.AppendMenu(menu);
|
|
if (settings->GetDisplayOption(_("Users/login Roles")))
|
|
userFactory.AppendMenu(menu);
|
|
}
|
|
// Added Resource Group only for PPAS 9.4 and above
|
|
if (conn->GetIsEdb() && conn->EdbMinimumVersion(9, 4))
|
|
{
|
|
if (settings->GetDisplayOption(_("Resource Groups")))
|
|
resourceGroupFactory.AppendMenu(menu);
|
|
}
|
|
}
|
|
return menu;
|
|
}
|
|
|
|
pgServer *pgServer::GetServer() const
|
|
{
|
|
if (connected)
|
|
return (pgServer *)this;
|
|
return 0;
|
|
}
|
|
|
|
|
|
pgConn *pgServer::CreateConn(wxString dbName, OID oid, wxString applicationname)
|
|
{
|
|
if (!connected)
|
|
return 0;
|
|
|
|
if (dbName.IsEmpty())
|
|
{
|
|
dbName = GetDatabaseName();
|
|
oid = dbOid;
|
|
}
|
|
|
|
pgConn *conn = NULL;
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
if(sshTunnel)
|
|
{
|
|
conn = new pgConn(local_listenhost, service, hostaddr, dbName, username, password, local_listenport, rolename,connstr, ssl, oid, applicationname, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
conn = new pgConn(GetName(), service, hostaddr, dbName, username, password, port, rolename,connstr, ssl, oid, applicationname, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
|
|
}
|
|
|
|
if (conn && conn->GetStatus() != PGCONN_OK)
|
|
{
|
|
wxLogError(wxT("%s"), conn->GetLastError().c_str());
|
|
delete conn;
|
|
return 0;
|
|
}
|
|
return conn;
|
|
}
|
|
|
|
|
|
wxString pgServer::GetFullName()
|
|
{
|
|
if (GetDescription().Length() > 0)
|
|
return GetDescription() + wxT(" (") + GetIdentifier() + wxT(")");
|
|
else
|
|
return wxT("(") + GetIdentifier() + wxT(")");
|
|
}
|
|
|
|
wxString pgServer::GetFullIdentifier()
|
|
{
|
|
return GetFullName();
|
|
}
|
|
|
|
bool pgServer::Disconnect(frmMain *form)
|
|
{
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
if(tunnelObj)
|
|
{
|
|
if(tunnelObj->IsAlive())
|
|
{
|
|
tunnelObj->Cleanup();
|
|
}
|
|
tunnelObj = NULL;
|
|
}
|
|
#endif
|
|
|
|
if (conn)
|
|
{
|
|
delete conn;
|
|
conn = 0;
|
|
connected = false;
|
|
expandedKids = false;
|
|
ver = wxT("");
|
|
versionNum = wxT("");
|
|
lastSystemOID = 0;
|
|
}
|
|
|
|
if (form)
|
|
UpdateIcon(form->GetBrowser());
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool pgServer::GetCanHint()
|
|
{
|
|
return connected && conn->BackendMinimumVersion(8, 1) && !autovacuumRunning;
|
|
}
|
|
|
|
|
|
void pgServer::ShowHint(frmMain *form, bool force)
|
|
{
|
|
wxArrayString hints;
|
|
|
|
if (!autovacuumRunning)
|
|
hints.Add(HINT_AUTOVACUUM);
|
|
|
|
if (force || !hintShown)
|
|
frmHint::ShowHint(form, hints, GetFullIdentifier(), force);
|
|
hintShown = true;
|
|
}
|
|
|
|
|
|
#define SERVICEBUFSIZE 10000
|
|
#define QUERYBUFSIZE 256
|
|
|
|
#ifdef WIN32
|
|
wxArrayString pgServer::GetDependentServices(SC_HANDLE handle)
|
|
{
|
|
wxArrayString services;
|
|
LPENUM_SERVICE_STATUS sbuf = (LPENUM_SERVICE_STATUS) new char[SERVICEBUFSIZE];
|
|
|
|
DWORD servicesReturned = 0, bytesNeeded;
|
|
::EnumDependentServices(handle, SERVICE_STATE_ALL, sbuf, SERVICEBUFSIZE, &bytesNeeded, &servicesReturned);
|
|
|
|
|
|
DWORD i;
|
|
for (i = 0 ; i < servicesReturned ; i++)
|
|
{
|
|
SC_HANDLE h =::OpenService(scmHandle, sbuf[i].lpServiceName, SERVICE_QUERY_CONFIG);
|
|
if (h)
|
|
{
|
|
char buffer[QUERYBUFSIZE];
|
|
LPQUERY_SERVICE_CONFIG qsc = (LPQUERY_SERVICE_CONFIG)buffer;
|
|
if(::QueryServiceConfig(h, qsc, QUERYBUFSIZE, &bytesNeeded))
|
|
{
|
|
if (qsc->dwStartType != SERVICE_DISABLED)
|
|
services.Add(sbuf[i].lpServiceName);
|
|
}
|
|
|
|
::CloseServiceHandle(h);
|
|
}
|
|
}
|
|
delete[] sbuf;
|
|
|
|
return services;
|
|
}
|
|
#endif
|
|
|
|
|
|
bool pgServer::StartService()
|
|
{
|
|
bool done = false;
|
|
#ifdef WIN32
|
|
if (serviceHandle)
|
|
{
|
|
done = (::StartService(serviceHandle, 0, 0) != 0);
|
|
if (!done)
|
|
{
|
|
DWORD rc = ::GetLastError();
|
|
if (rc == ERROR_SERVICE_ALREADY_RUNNING)
|
|
{
|
|
GetServerRunning();
|
|
return true;
|
|
}
|
|
// report error
|
|
wxLogError(__("Failed to start server %s: Errcode=%d\nCheck event log for details."),
|
|
serviceId.c_str(), rc);
|
|
}
|
|
else
|
|
{
|
|
GetServerRunning(); // ignore result, just to wait for startup
|
|
|
|
wxArrayString services = GetDependentServices(serviceHandle);
|
|
|
|
if (services.GetCount() > 0)
|
|
{
|
|
size_t i;
|
|
wxString serviceString;
|
|
for (i = 0 ; i < services.GetCount() ; i++)
|
|
serviceString += wxT(" ") + services.Item(i) + wxT("\n");
|
|
|
|
wxMessageDialog msg(0, _("There are dependent services configured:\n\n")
|
|
+ serviceString + _("\nStart dependent services too?"), _("Dependent services"),
|
|
wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
|
|
|
|
if (msg.ShowModal() == wxID_YES)
|
|
{
|
|
for (i = 0 ; i < services.GetCount() ; i++)
|
|
{
|
|
SC_HANDLE h =::OpenService(scmHandle, services.Item(i), GENERIC_EXECUTE | GENERIC_READ);
|
|
if (h)
|
|
{
|
|
if (!::StartService(h, 0, 0))
|
|
done = false;
|
|
CloseServiceHandle(h);
|
|
}
|
|
else
|
|
done = false;
|
|
}
|
|
if (!done)
|
|
{
|
|
wxMessageDialog msg(0, _("One or more dependent services didn't start; see the eventlog for details."), _("Service start problem"),
|
|
wxICON_EXCLAMATION | wxOK);
|
|
msg.ShowModal();
|
|
done = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
#else
|
|
wxString res = ExecProcess(serviceId + wxT(" start"));
|
|
done = (res.Find(wxT("tarting")) > 0);
|
|
#endif
|
|
return done;
|
|
}
|
|
|
|
|
|
bool pgServer::StopService()
|
|
{
|
|
bool done = false;
|
|
#ifdef WIN32
|
|
if (serviceHandle)
|
|
{
|
|
SERVICE_STATUS st;
|
|
|
|
done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
|
|
if (!done)
|
|
{
|
|
if (::GetLastError() == ERROR_DEPENDENT_SERVICES_RUNNING)
|
|
{
|
|
LPENUM_SERVICE_STATUS sbuf = (LPENUM_SERVICE_STATUS) new char[SERVICEBUFSIZE];
|
|
DWORD bytesNeeded, servicesReturned = 0;
|
|
::EnumDependentServices(serviceHandle, SERVICE_ACTIVE, sbuf, SERVICEBUFSIZE, &bytesNeeded, &servicesReturned);
|
|
|
|
done = true;
|
|
|
|
if (servicesReturned)
|
|
{
|
|
DWORD i;
|
|
wxString services;
|
|
for (i = 0 ; i < servicesReturned ; i++)
|
|
services += wxT(" ") + wxString(sbuf[i].lpDisplayName) + wxT("\n");
|
|
|
|
wxMessageDialog msg(0, _("There are dependent services running:\n\n")
|
|
+ services + _("\nStop dependent services?"), _("Dependent services"),
|
|
wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
|
|
if (msg.ShowModal() != wxID_YES)
|
|
return false;
|
|
|
|
for (i = 0 ; done && i < servicesReturned ; i++)
|
|
{
|
|
SC_HANDLE h =::OpenService(scmHandle, sbuf[i].lpServiceName, GENERIC_EXECUTE | GENERIC_READ);
|
|
if (h)
|
|
{
|
|
done = (::ControlService(h, SERVICE_CONTROL_STOP, &st) != 0);
|
|
CloseServiceHandle(h);
|
|
}
|
|
else
|
|
done = false;
|
|
}
|
|
if (done)
|
|
{
|
|
done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
|
|
|
|
int retries = 10;
|
|
while (!done && retries > 0)
|
|
{
|
|
done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
|
|
retries--;
|
|
|
|
wxSleep(5);
|
|
}
|
|
|
|
}
|
|
}
|
|
}
|
|
// report error
|
|
|
|
if (!done)
|
|
wxLogError(__("Failed to stop server %s: Errcode=%d\nCheck event log for details."),
|
|
serviceId.c_str(), ::GetLastError());
|
|
}
|
|
}
|
|
#else
|
|
wxString res = ExecProcess(serviceId + wxT(" stop"));
|
|
done = (res.Find(wxT("stopped")) > 0);
|
|
#endif
|
|
return done;
|
|
}
|
|
|
|
|
|
bool pgServer::GetServerRunning()
|
|
{
|
|
bool done = false;
|
|
#ifdef WIN32
|
|
if (serviceHandle)
|
|
{
|
|
SERVICE_STATUS st;
|
|
int loops;
|
|
|
|
for (loops = 0 ; loops < 20 ; loops++)
|
|
{
|
|
if (::QueryServiceStatus(serviceHandle, &st) == 0)
|
|
{
|
|
DWORD rc = ::GetLastError();
|
|
CloseServiceHandle(serviceHandle);
|
|
CloseServiceHandle(scmHandle);
|
|
serviceHandle = 0;
|
|
scmHandle = 0;
|
|
|
|
return false;
|
|
}
|
|
done = (st.dwCurrentState == SERVICE_RUNNING);
|
|
if (st.dwCurrentState == SERVICE_START_PENDING)
|
|
Sleep(100);
|
|
else
|
|
break;
|
|
}
|
|
}
|
|
#else
|
|
|
|
wxString res = ExecProcess(serviceId + wxT(" status"));
|
|
done = (res.Find(wxT("PID: ")) > 0);
|
|
|
|
#endif
|
|
return done;
|
|
}
|
|
|
|
|
|
void pgServer::iSetServiceID(const wxString &s)
|
|
{
|
|
serviceId = s;
|
|
#ifdef WIN32
|
|
if (serviceId.Find('\\') < 0)
|
|
scmHandle = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, GENERIC_EXECUTE);
|
|
else
|
|
scmHandle = OpenSCManager(wxT("\\\\") + serviceId.BeforeFirst('\\'), SERVICES_ACTIVE_DATABASE, GENERIC_EXECUTE | GENERIC_READ);
|
|
|
|
if (scmHandle)
|
|
serviceHandle = OpenService(scmHandle, serviceId.AfterLast('\\'), GENERIC_EXECUTE | GENERIC_READ);
|
|
#endif
|
|
}
|
|
|
|
|
|
bool pgServer::GetServerControllable()
|
|
{
|
|
#ifdef WIN32
|
|
return serviceHandle != 0;
|
|
#else
|
|
return !serviceId.IsEmpty();
|
|
#endif
|
|
}
|
|
|
|
|
|
wxString pgServer::passwordFilename()
|
|
{
|
|
wxString fname = sysSettings::GetConfigFile(sysSettings::PGPASS);
|
|
|
|
wxLogInfo(wxT("Using password file %s"), fname.c_str());
|
|
return fname;
|
|
}
|
|
|
|
|
|
|
|
bool pgServer::GetPasswordIsStored()
|
|
{
|
|
wxString fname = passwordFilename();
|
|
|
|
|
|
if (!wxFile::Exists(fname))
|
|
return false;
|
|
|
|
wxUtfFile file(fname, wxFile::read, wxFONTENCODING_SYSTEM);
|
|
|
|
if (file.IsOpened())
|
|
{
|
|
wxString before;
|
|
file.Read(before);
|
|
|
|
wxStringTokenizer lines(before, wxT("\n\r"));
|
|
|
|
wxString seekStr = GetName() + wxT(":")
|
|
+ NumToStr((long)GetPort()) + wxT(":*:")
|
|
+ username + wxT(":") ;
|
|
|
|
wxString seekStr2 = wxString(GetName().mb_str(wxConvUTF8), wxConvLibc) + wxT(":")
|
|
+ NumToStr((long)GetPort()) + wxT(":*:")
|
|
+ wxString(username.mb_str(wxConvUTF8), wxConvLibc) + wxT(":") ;
|
|
|
|
while (lines.HasMoreTokens())
|
|
{
|
|
wxString str = lines.GetNextToken();
|
|
if (str.Left(seekStr.Length()) == seekStr)
|
|
return true;
|
|
|
|
if (str.Left(seekStr2.Length()) == seekStr2)
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
void pgServer::StorePassword()
|
|
{
|
|
wxString fname = passwordFilename();
|
|
|
|
if (!wxFile::Exists(fname))
|
|
{
|
|
return;
|
|
}
|
|
wxUtfFile file;
|
|
// Don't try to read and write in one OP - it doesn't work well
|
|
wxString before;
|
|
file.Open(fname, wxFile::read, wxFONTENCODING_SYSTEM);
|
|
file.Read(before);
|
|
file.Close();
|
|
|
|
file.Open(fname, wxFile::write, wxFONTENCODING_SYSTEM);
|
|
|
|
if (file.IsOpened())
|
|
{
|
|
wxString after;
|
|
|
|
wxString passwd;
|
|
wxString seekStr;
|
|
|
|
if (GetConnection()->GetNeedUtfConnectString())
|
|
{
|
|
passwd = wxString(password.mb_str(wxConvUTF8), wxConvLibc);
|
|
seekStr = wxString(GetName().mb_str(wxConvUTF8), wxConvLibc) + wxT(":")
|
|
+ NumToStr((long)GetPort()) + wxT(":*:")
|
|
+ wxString(username.mb_str(wxConvUTF8), wxConvLibc) + wxT(":") ;
|
|
}
|
|
else
|
|
{
|
|
passwd = password;
|
|
seekStr = GetName() + wxT(":")
|
|
+ NumToStr((long)GetPort()) + wxT(":*:")
|
|
+ username + wxT(":") ;
|
|
}
|
|
|
|
// Escape ":" and "\" from the password field
|
|
if (!passwd.IsEmpty())
|
|
{
|
|
passwd.Replace(wxT("\\"), wxT("\\\\"));
|
|
passwd.Replace(wxT(":") , wxT("\\:"));
|
|
}
|
|
|
|
file.Read(before);
|
|
wxStringTokenizer lines(before, wxT("\n\r"));
|
|
|
|
file.Seek(0);
|
|
bool found = false;
|
|
while (lines.HasMoreTokens())
|
|
{
|
|
wxString str = lines.GetNextToken();
|
|
if (str.Left(seekStr.Length()) == seekStr && !passwd.IsEmpty())
|
|
{
|
|
// entry found
|
|
found = true;
|
|
if (storePwd)
|
|
file.Write(seekStr + passwd + END_OF_LINE);
|
|
}
|
|
else
|
|
file.Write(str + END_OF_LINE);
|
|
}
|
|
if (!found && storePwd && !passwd.IsEmpty())
|
|
file.Write(seekStr + passwd + END_OF_LINE);
|
|
|
|
file.Close();
|
|
}
|
|
}
|
|
|
|
|
|
int pgServer::Connect(frmMain *form, bool askPassword, const wxString &pwd, bool forceStorePassword, bool askTunnelPassword)
|
|
{
|
|
wxLogInfo(wxT("Attempting to create a connection object..."));
|
|
|
|
bool storePassword = false;
|
|
|
|
if (!conn || conn->GetStatus() != PGCONN_OK)
|
|
{
|
|
if (conn)
|
|
{
|
|
delete conn;
|
|
conn = 0;
|
|
}
|
|
if (askPassword)
|
|
{
|
|
if ((sshTunnel || !passwordValid || !GetPasswordIsStored() || !GetStorePwd()) && GetSSLCert() == wxEmptyString)
|
|
{
|
|
wxString txt;
|
|
txt.Printf(_("Please enter password for user %s\non server %s (%s)"), username.c_str(), description.c_str(), GetName().c_str());
|
|
dlgConnect *dlg = NULL;
|
|
// if sshTunnel is true then we have to hide 'Stored Password' option
|
|
if(sshTunnel)
|
|
dlg = new dlgConnect(NULL, txt, false);
|
|
else
|
|
dlg = new dlgConnect(form, txt, GetStorePwd());
|
|
|
|
dlg->SetWindowStyleFlag( dlg->GetWindowStyleFlag() | wxSTAY_ON_TOP);
|
|
|
|
switch (dlg->Go())
|
|
{
|
|
case wxID_OK:
|
|
// Give the UI a chance to redraw
|
|
wxSafeYield();
|
|
wxMilliSleep(100);
|
|
wxSafeYield();
|
|
break;
|
|
case wxID_CANCEL:
|
|
case -1:
|
|
// Give the UI a chance to redraw
|
|
wxSafeYield();
|
|
wxMilliSleep(100);
|
|
wxSafeYield();
|
|
return PGCONN_ABORTED;
|
|
default:
|
|
// Give the UI a chance to redraw
|
|
wxSafeYield();
|
|
wxMilliSleep(100);
|
|
wxSafeYield();
|
|
wxLogError(__("Couldn't create a connection dialogue!"));
|
|
return PGCONN_BAD;
|
|
}
|
|
|
|
iSetStorePwd(dlg->GetStorePwd());
|
|
password = dlg->GetPassword();
|
|
storePassword = true;
|
|
if(dlg)
|
|
{
|
|
delete dlg;
|
|
dlg = NULL;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
iSetPassword(pwd);
|
|
|
|
form->StartMsg(_("Connecting to database"));
|
|
|
|
wxString host;
|
|
int iPort;
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
if(sshTunnel)
|
|
{
|
|
//Ask Tunnel Password
|
|
if(askTunnelPassword)
|
|
{
|
|
wxString txt;
|
|
if(GetAuthModePwd())
|
|
{
|
|
txt.Printf(_("Please enter the SSH tunnel password for user %s\non server %s"), tunnelUserName.c_str(), tunnelHost.c_str());
|
|
}
|
|
else
|
|
{
|
|
txt.Printf(_("Please enter the pass phrase for the identity file\n%s"), identityFile.c_str());
|
|
}
|
|
dlgConnect dlg(NULL, txt, false);
|
|
|
|
switch (dlg.Go())
|
|
{
|
|
case wxID_OK:
|
|
// Give the UI a chance to redraw
|
|
wxSafeYield();
|
|
wxMilliSleep(100);
|
|
wxSafeYield();
|
|
tunnelPassword = dlg.GetPassword();
|
|
break;
|
|
case wxID_CANCEL:
|
|
case -1:
|
|
default:
|
|
// Give the UI a chance to redraw
|
|
wxSafeYield();
|
|
wxMilliSleep(100);
|
|
wxSafeYield();
|
|
form->EndMsg(false);
|
|
return PGCONN_ABORTED;
|
|
}
|
|
}
|
|
// Create SSH Tunnel if required
|
|
if(!tunnelObj)
|
|
{
|
|
if(!createSSHTunnel())
|
|
{
|
|
form->EndMsg(false);
|
|
return PGCONN_SSHTUNNEL_ERROR;
|
|
}
|
|
}
|
|
|
|
host = local_listenhost;
|
|
iPort = local_listenport;
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
host = GetName();
|
|
iPort = port;
|
|
}
|
|
wxString usr=wxEmptyString;
|
|
#ifndef __WXMSW__
|
|
wxGetEnv(wxT("USER"), &usr);
|
|
#else
|
|
wxGetEnv(wxT("USERNAME"), &usr);
|
|
#endif
|
|
if (database.IsEmpty())
|
|
{
|
|
conn = new pgConn(host, service, hostaddr, DEFAULT_PG_DATABASE, username, password, iPort, rolename,connstr, ssl, 0, appearanceFactory->GetLongAppName() +wxT(" - ")+ usr, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
|
|
if (conn->GetStatus() == PGCONN_OK)
|
|
database = DEFAULT_PG_DATABASE;
|
|
else if (conn->GetStatus() == PGCONN_BAD && conn->GetLastError().Find(
|
|
wxT("database \"") DEFAULT_PG_DATABASE wxT("\" does not exist")) >= 0)
|
|
{
|
|
delete conn;
|
|
conn = new pgConn(host, service, hostaddr, wxT("template1"), username, password, iPort, rolename,connstr, ssl, 0, appearanceFactory->GetLongAppName() + wxT(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
|
|
if (conn && conn->GetStatus() == PGCONN_OK)
|
|
database = wxT("template1");
|
|
}
|
|
}
|
|
else
|
|
{
|
|
conn = new pgConn(host, service, hostaddr, database, username, password, iPort, rolename,connstr, ssl, 0, appearanceFactory->GetLongAppName() + " "+usr, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
|
|
if (!conn)
|
|
{
|
|
form->EndMsg(false);
|
|
wxLogError(__("Couldn't create a connection object!"));
|
|
return PGCONN_BAD;
|
|
}
|
|
}
|
|
}
|
|
int status = conn->GetStatus();
|
|
if (status == PGCONN_OK)
|
|
{
|
|
dbOid = conn->GetDbOid();
|
|
|
|
// Check the server version
|
|
if (conn->GetIsGreenplum())
|
|
{
|
|
// Greenplum HAWQ (SQL on Hadoop) is not supported by this pgAdmin version
|
|
if (conn->GetIsHawq())
|
|
{
|
|
wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected."),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
appearanceFactory->GetLongAppName().c_str());
|
|
}
|
|
else
|
|
{
|
|
// Check for Greenplum specific version
|
|
// Greenplum always shows PG version "8.2.15" for now
|
|
// this might change once the merge with recent PG versions makes progress
|
|
// therefore also check for the max version
|
|
if (!(conn->BackendMinimumVersion(GP_MIN_VERSION_N >> 8, GP_MIN_VERSION_N & 0x00FF)) ||
|
|
(conn->BackendMinimumVersion(GP_MAX_VERSION_N >> 8, (GP_MAX_VERSION_N & 0x00FF) + 1)))
|
|
{
|
|
if (GP_MIN_VERSION_N == GP_MAX_VERSION_N)
|
|
{
|
|
wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected.\n\nSupported server version is %s."),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
wxString(GP_MIN_VERSION_T).c_str());
|
|
}
|
|
else
|
|
{
|
|
wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected.\n\nSupported server versions are %s to %s."),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
wxString(GP_MIN_VERSION_T).c_str(),
|
|
wxString(GP_MAX_VERSION_T).c_str());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (!(conn->BackendMinimumVersion(SERVER_MIN_VERSION_N >> 8, SERVER_MIN_VERSION_N & 0x00FF)) ||
|
|
(conn->BackendMinimumVersion(SERVER_MAX_VERSION_N >> 8, (SERVER_MAX_VERSION_N & 0x00FF) + 1))) {
|
|
wxLogWarning(_("The server you are connecting to is not a version that is supported by this release of %s.\n\n%s may not function as expected.\n\nSupported server versions are %s to %s."),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
appearanceFactory->GetLongAppName().c_str(),
|
|
wxString(SERVER_MIN_VERSION_T).c_str(),
|
|
wxString(SERVER_MAX_VERSION_T).c_str());
|
|
}
|
|
}
|
|
|
|
connected = true;
|
|
bool hasUptime = false;
|
|
|
|
wxString sql = wxT("SELECT usecreatedb, usesuper");
|
|
if (conn->BackendMinimumVersion(8, 1))
|
|
{
|
|
hasUptime = true;
|
|
sql += wxT(", pg_postmaster_start_time() as upsince");
|
|
}
|
|
else if (conn->HasFeature(FEATURE_POSTMASTER_STARTTIME))
|
|
{
|
|
hasUptime = true;
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_postmaster_starttime() ELSE NULL END as upsince");
|
|
}
|
|
if (conn->BackendMinimumVersion(8, 4))
|
|
{
|
|
sql += wxT(", pg_conf_load_time() as confloadedsince");
|
|
}
|
|
if (conn->BackendMinimumVersion(8, 5))
|
|
{
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_is_in_recovery() ELSE NULL END as inrecovery");
|
|
if (conn->BackendMinimumVersion(10, 0))
|
|
{
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_last_wal_receive_lsn() ELSE NULL END as receiveloc");
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_last_wal_replay_lsn() ELSE NULL END as replayloc");
|
|
}
|
|
else
|
|
{
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_last_xlog_receive_location() ELSE NULL END as receiveloc");
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_last_xlog_replay_location() ELSE NULL END as replayloc");
|
|
}
|
|
}
|
|
if (conn->BackendMinimumVersion(9, 1))
|
|
{
|
|
sql += wxT(", CASE WHEN usesuper THEN pg_last_xact_replay_timestamp() ELSE NULL END as replay_timestamp");
|
|
if (conn->BackendMinimumVersion(10, 0))
|
|
sql += wxT(", CASE WHEN usesuper AND pg_is_in_recovery() THEN pg_is_wal_replay_paused() ELSE NULL END as isreplaypaused");
|
|
else
|
|
sql += wxT(", CASE WHEN usesuper AND pg_is_in_recovery() THEN pg_is_xlog_replay_paused() ELSE NULL END as isreplaypaused");
|
|
}
|
|
|
|
pgSet *set = ExecuteSet(sql + wxT("\n FROM pg_user WHERE usename=current_user"));
|
|
if (set)
|
|
{
|
|
iSetCreatePrivilege(set->GetBool(wxT("usecreatedb")));
|
|
iSetSuperUser(set->GetBool(wxT("usesuper")));
|
|
if (hasUptime)
|
|
iSetUpSince(set->GetDateTime(wxT("upsince")));
|
|
if (conn->BackendMinimumVersion(8, 4))
|
|
iSetConfLoadedSince(set->GetDateTime(wxT("confloadedsince")));
|
|
if (conn->BackendMinimumVersion(8, 5))
|
|
{
|
|
iSetInRecovery(set->GetBool(wxT("inrecovery")));
|
|
iSetReplayLoc(set->GetVal(wxT("replayloc")));
|
|
iSetReceiveLoc(set->GetVal(wxT("receiveloc")));
|
|
}
|
|
if (conn->BackendMinimumVersion(9, 1))
|
|
{
|
|
iSetReplayTimestamp(set->GetVal(wxT("replay_timestamp")));
|
|
SetReplayPaused(set->GetBool(wxT("isreplaypaused")));
|
|
}
|
|
delete set;
|
|
}
|
|
|
|
if (conn->BackendMinimumVersion(8, 1))
|
|
{
|
|
set = ExecuteSet(wxT("SELECT rolcreaterole, rolcreatedb FROM pg_roles WHERE rolname = current_user;"));
|
|
|
|
if (set)
|
|
{
|
|
iSetCreatePrivilege(set->GetBool(wxT("rolcreatedb")));
|
|
iSetCreateRole(set->GetBool(wxT("rolcreaterole")));
|
|
delete set;
|
|
}
|
|
}
|
|
else
|
|
iSetCreateRole(false);
|
|
|
|
wxString version, allVersions;
|
|
version.Printf(wxT("%d.%d"), conn->GetMajorVersion(), conn->GetMinorVersion());
|
|
allVersions = settings->Read(wxT("Updates/pgsql-Versions"), wxEmptyString);
|
|
if (allVersions.Find(version) < 0)
|
|
{
|
|
if (!allVersions.IsEmpty())
|
|
allVersions += wxT(", ");
|
|
allVersions += version;
|
|
settings->Write(wxT("Updates/pgsql-Versions"), allVersions);
|
|
}
|
|
if (conn->IsSSLconnected())
|
|
settings->WriteBool(wxT("Updates/UseSSL"), true);
|
|
|
|
UpdateIcon(form->GetBrowser());
|
|
if (storePassword || forceStorePassword)
|
|
StorePassword();
|
|
}
|
|
else
|
|
{
|
|
connected = false;
|
|
}
|
|
|
|
form->EndMsg(connected && status == PGCONN_OK);
|
|
|
|
passwordValid = connected;
|
|
return status;
|
|
}
|
|
|
|
|
|
wxString pgServer::GetIdentifier() const
|
|
{
|
|
wxString idstr;
|
|
if (GetService().IsEmpty())
|
|
{
|
|
if (GetName().IsEmpty())
|
|
idstr.Printf(wxT("local:.s.PGSQL.%d"), port);
|
|
else if (GetName().StartsWith(wxT("/")))
|
|
idstr.Printf(wxT("local:%s/.s.PGSQL.%d"), GetName().c_str(), port);
|
|
else
|
|
idstr.Printf(wxT("%s:%d"), GetName().c_str(), port);
|
|
}
|
|
else
|
|
idstr.Printf(_("service %s"), GetService().c_str());
|
|
return idstr;
|
|
}
|
|
|
|
|
|
wxString pgServer::GetVersionString()
|
|
{
|
|
if (connected)
|
|
{
|
|
if (ver.IsEmpty())
|
|
ver = wxString(conn->GetVersionString());
|
|
return ver;
|
|
}
|
|
else
|
|
return wxEmptyString;
|
|
}
|
|
|
|
|
|
wxString pgServer::GetVersionNumber()
|
|
{
|
|
if (connected)
|
|
{
|
|
if (versionNum.IsEmpty())
|
|
{
|
|
int major = 0, minor = 0;
|
|
sscanf(GetVersionString().ToAscii(), "%*s %d.%d", &major, &minor);
|
|
versionNum.Printf(wxT("%d.%d"), major, minor);
|
|
}
|
|
|
|
}
|
|
return versionNum;
|
|
}
|
|
|
|
|
|
OID pgServer::GetLastSystemOID()
|
|
{
|
|
if (connected)
|
|
{
|
|
if (lastSystemOID == 0)
|
|
lastSystemOID = conn->GetLastSystemOID();
|
|
return lastSystemOID;
|
|
}
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool pgServer::SetPassword(const wxString &newVal)
|
|
{
|
|
wxString sql;
|
|
sql.Printf(wxT("ALTER USER %s WITH ENCRYPTED PASSWORD %s;"), qtIdent(username).c_str(), qtDbString(conn->EncryptPassword(username, newVal)).c_str());
|
|
bool executed = conn->ExecuteVoid(sql);
|
|
if (executed)
|
|
{
|
|
password = newVal;
|
|
StorePassword();
|
|
return true;
|
|
}
|
|
else
|
|
return false;
|
|
}
|
|
|
|
|
|
wxString pgServer::GetLastError() const
|
|
{
|
|
wxString msg;
|
|
if (conn)
|
|
{
|
|
if (error != wxT(""))
|
|
{
|
|
if (conn->GetLastError() != wxT(""))
|
|
{
|
|
msg.Printf(wxT("%s\n%s"), error.c_str(), conn->GetLastError().c_str());
|
|
}
|
|
else
|
|
{
|
|
msg = error;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
msg = conn->GetLastError();
|
|
}
|
|
}
|
|
return msg;
|
|
}
|
|
|
|
|
|
|
|
void pgServer::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
|
|
{
|
|
// Add child nodes if necessary
|
|
if (GetConnected())
|
|
{
|
|
// Reset password menu option
|
|
// form->fileMenu->Enable(MNU_PASSWORD, true);
|
|
|
|
if (!expandedKids)
|
|
{
|
|
expandedKids = true;
|
|
// Log
|
|
|
|
wxLogInfo(wxT("Adding child object to server %s"), GetIdentifier().c_str());
|
|
|
|
if (settings->GetDisplayOption(_("Databases")))
|
|
browser->AppendCollection(this, databaseFactory);
|
|
|
|
if (conn->BackendMinimumVersion(8, 0) && settings->GetDisplayOption(_("Tablespaces")))
|
|
browser->AppendCollection(this, tablespaceFactory);
|
|
|
|
// Jobs
|
|
// We only add the Jobs node if the appropriate objects are the initial DB.
|
|
if (settings->GetDisplayOption(_("pgAgent Jobs")))
|
|
{
|
|
wxString exists = conn->ExecuteScalar(
|
|
wxT("SELECT cl.oid FROM pg_class cl JOIN pg_namespace ns ON ns.oid=relnamespace\n")
|
|
wxT(" WHERE relname='pga_job' AND nspname='pgagent'"));
|
|
|
|
if (!exists.IsNull())
|
|
{
|
|
exists = conn->ExecuteScalar(wxT("SELECT has_schema_privilege('pgagent', 'USAGE')"));
|
|
|
|
if (exists == wxT("t"))
|
|
browser->AppendCollection(this, jobFactory);
|
|
}
|
|
}
|
|
|
|
if (conn->BackendMinimumVersion(8, 1))
|
|
{
|
|
if (settings->GetDisplayOption(_("Groups/group Roles")))
|
|
browser->AppendCollection(this, groupRoleFactory);
|
|
if (settings->GetDisplayOption(_("Users/login Roles")))
|
|
browser->AppendCollection(this, loginRoleFactory);
|
|
if (GetConnection()->GetIsGreenplum())
|
|
{
|
|
if (settings->GetDisplayOption(_("Resource Queues")))
|
|
browser->AppendCollection(this, resQueueFactory);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (settings->GetDisplayOption(_("Groups/group Roles")))
|
|
browser->AppendCollection(this, groupFactory);
|
|
if (settings->GetDisplayOption(_("Users/login Roles")))
|
|
browser->AppendCollection(this, userFactory);
|
|
}
|
|
|
|
// Added Resource Group only for PPAS 9.4 and above
|
|
if (conn->GetIsEdb() && conn->EdbMinimumVersion(9, 4))
|
|
{
|
|
if (settings->GetDisplayOption(_("Resource Groups")))
|
|
browser->AppendCollection(this, resourceGroupFactory);
|
|
}
|
|
|
|
autovacuumRunning = true;
|
|
|
|
wxString qry;
|
|
if (conn->BackendMinimumVersion(8, 3))
|
|
qry = wxT("SELECT setting FROM pg_settings WHERE name IN ('autovacuum', 'track_counts')");
|
|
else
|
|
qry = wxT("SELECT setting FROM pg_settings WHERE name IN ('autovacuum', 'stats_start_collector', 'stats_row_level')");
|
|
|
|
pgSetIterator set(conn, qry);
|
|
|
|
while (autovacuumRunning && set.RowsLeft())
|
|
autovacuumRunning = set.GetBool(wxT("setting"));
|
|
}
|
|
}
|
|
|
|
|
|
if (properties)
|
|
{
|
|
// Add the properties view columns
|
|
CreateListColumns(properties);
|
|
|
|
// Display the Server properties
|
|
|
|
properties->AppendItem(_("Description"), GetDescription());
|
|
properties->AppendItem(_("Service"), GetService());
|
|
if (GetName().IsEmpty() || GetName().StartsWith(wxT("/")))
|
|
{
|
|
if (GetName().IsEmpty() && !GetService().IsEmpty())
|
|
properties->AppendItem(_("Hostname"), wxEmptyString);
|
|
else
|
|
properties->AppendItem(_("Hostname"), wxT("local:") + GetName());
|
|
|
|
if (GetPort() == 0 && !GetService().IsEmpty())
|
|
properties->AppendItem(_("Port"), wxEmptyString);
|
|
else
|
|
properties->AppendItem(_("Port"), (long)GetPort());
|
|
}
|
|
else
|
|
{
|
|
properties->AppendItem(_("Hostname"), GetName());
|
|
properties->AppendItem(_("Host Address"), GetHostAddr());
|
|
if (GetPort() == 0 && !GetService().IsEmpty())
|
|
properties->AppendItem(_("Port"), wxEmptyString);
|
|
else
|
|
properties->AppendItem(_("Port"), (long)GetPort());
|
|
#ifdef PG_SSL
|
|
if (GetConnected())
|
|
{
|
|
properties->AppendItem(_("Encryption"),
|
|
conn->IsSSLconnected() ? _("SSL encrypted") : _("not encrypted"));
|
|
}
|
|
else
|
|
{
|
|
if (ssl > 0)
|
|
{
|
|
wxString sslMode;
|
|
switch (ssl)
|
|
{
|
|
case 1:
|
|
sslMode = _("require");
|
|
break;
|
|
case 2:
|
|
sslMode = _("prefer");
|
|
break;
|
|
case 3:
|
|
sslMode = _("allow");
|
|
break;
|
|
case 4:
|
|
sslMode = _("disable");
|
|
break;
|
|
case 5:
|
|
sslMode = _("verify-ca");
|
|
break;
|
|
case 6:
|
|
sslMode = _("verify-full");
|
|
break;
|
|
}
|
|
properties->AppendItem(_("SSL Mode"), sslMode);
|
|
}
|
|
}
|
|
properties->AppendItem(_("SSL Certificate File"), GetSSLCert());
|
|
properties->AppendItem(_("SSL Key File"), GetSSLKey());
|
|
properties->AppendItem(_("SSL Root Certificate File"), GetSSLRootCert());
|
|
properties->AppendItem(_("SSL Certificate Revocation List"), GetSSLCrl());
|
|
properties->AppendItem(_("SSL Compression?"), (GetSSLCompression() ? _("yes") : _("no")));
|
|
#endif
|
|
}
|
|
if (!serviceId.IsEmpty())
|
|
properties->AppendItem(_("Service ID"), serviceId);
|
|
|
|
properties->AppendItem(_("Maintenance database"), GetDatabaseName());
|
|
properties->AppendItem(_("Username"), GetUsername());
|
|
if (!GetRolename().IsEmpty())
|
|
properties->AppendItem(_("Default role"), GetRolename());
|
|
if (!GetConnStr().IsEmpty())
|
|
properties->AppendItem(_("Add connect str"), GetConnStr());
|
|
|
|
properties->AppendYesNoItem(_("Store password?"), GetStorePwd());
|
|
properties->AppendYesNoItem(_("Restore environment?"), GetRestore());
|
|
if (GetConnected())
|
|
{
|
|
properties->AppendItem(_("Version string"), GetVersionString());
|
|
properties->AppendItem(_("Version number"), GetVersionNumber());
|
|
properties->AppendItem(_("Last system OID"), GetLastSystemOID());
|
|
}
|
|
properties->AppendYesNoItem(_("Connected?"), GetConnected());
|
|
if (GetConnected())
|
|
{
|
|
if (GetUpSince().IsValid())
|
|
properties->AppendItem(_("Up since"), GetUpSince());
|
|
if (GetConfLoadedSince().IsValid())
|
|
properties->AppendItem(_("Configuration loaded since"), GetConfLoadedSince());
|
|
if (conn->BackendMinimumVersion(8, 1))
|
|
properties->AppendItem(wxT("Autovacuum"), (autovacuumRunning ? _("running") : _("not running")));
|
|
if (conn->BackendMinimumVersion(8, 5))
|
|
{
|
|
properties->AppendItem(_("In recovery"), (GetInRecovery() ? _("yes") : _("no")));
|
|
properties->AppendItem(_("Last XLOG receive location"), GetReceiveLoc());
|
|
properties->AppendItem(_("Last XLOG replay location"), GetReplayLoc());
|
|
}
|
|
if (conn->BackendMinimumVersion(9, 1))
|
|
{
|
|
properties->AppendItem(_("Last XACT replay timestamp"), GetReplayTimestamp());
|
|
if (GetInRecovery())
|
|
properties->AppendItem(_("Replay paused"), (GetReplayPaused() ? _("paused") : _("running")));
|
|
else
|
|
properties->AppendItem(_("Replay paused"), wxEmptyString);
|
|
}
|
|
}
|
|
if (GetServerControllable())
|
|
properties->AppendYesNoItem(_("Running?"), GetServerRunning());
|
|
|
|
if (!GetDbRestriction().IsEmpty())
|
|
properties->AppendItem(_("DB restriction"), GetDbRestriction());
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
if(sshTunnel)
|
|
{
|
|
properties->AppendItem(_("SSH tunneling?"), (sshTunnel ? _("Yes") : _("No")));
|
|
properties->AppendItem(_("Tunnel host"), GetTunnelHost());
|
|
properties->AppendItem(_("Tunnel username"), GetTunnelUserName());
|
|
properties->AppendItem(_("Authentication mode"), (GetAuthModePwd() ? _("Password") : _("Identity file")));
|
|
if(!GetAuthModePwd())
|
|
{
|
|
properties->AppendItem(_("Identity file path"), GetIdentityFile());
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
if(!GetConnected())
|
|
return;
|
|
|
|
if (form && GetCanHint() && !hintShown)
|
|
{
|
|
ShowHint(form, false);
|
|
}
|
|
}
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
|
|
bool pgServer::createSSHTunnel()
|
|
{
|
|
bool retVal = false;
|
|
|
|
tunnelObj = new CSSHTunnelThread(tunnelHost, GetName(), port, tunnelUserName, tunnelPassword, publicKeyFile,
|
|
identityFile, authModePwd ? AUTH_PASSWORD : AUTH_PUBLICKEY, tunnelPort);
|
|
|
|
if(tunnelObj)
|
|
{
|
|
if(tunnelObj->Initialize())
|
|
{
|
|
if ( tunnelObj->Create() != wxTHREAD_NO_ERROR )
|
|
{
|
|
delete tunnelObj;
|
|
tunnelObj = NULL;
|
|
wxLogError(_("SSH Error: Unable to create SSH Tunnling Thread"));
|
|
}
|
|
else
|
|
{
|
|
if (tunnelObj->Run() != wxTHREAD_NO_ERROR )
|
|
{
|
|
delete tunnelObj;
|
|
tunnelObj = NULL;
|
|
wxLogError(_("SSH Error: Unable to start SSH Tunnling Thread"));
|
|
}
|
|
|
|
SetLocalListenHost(tunnelObj->GetLocalListenIP());
|
|
SetLocalListenPort(tunnelObj->GetLocalListenPort());
|
|
retVal = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
delete tunnelObj;
|
|
tunnelObj = NULL;
|
|
}
|
|
}
|
|
|
|
return retVal;
|
|
}
|
|
#endif
|
|
|
|
void pgServer::ShowStatistics(frmMain *form, ctlListView *statistics)
|
|
{
|
|
if (conn)
|
|
{
|
|
wxString pidcol = GetConnection()->BackendMinimumVersion(9, 2) ? wxT("pid") : wxT("procpid");
|
|
wxString querycol = GetConnection()->BackendMinimumVersion(9, 2) ? wxT("query") : wxT("current_query");
|
|
wxString sql;
|
|
wxString replication_query = wxT("state || ' (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)'");
|
|
if (GetConnection()->BackendMinimumVersion(10, 0)) {
|
|
replication_query = wxT("state || ' (' || sent_lsn || ' sent, ' || write_lsn || ' written, ' || flush_lsn || ' flushed, ' || replay_lsn || ' applied)'");
|
|
}
|
|
wxLogInfo(wxT("Displaying statistics for server %s"), GetIdentifier().c_str());
|
|
|
|
// Add the statistics view columns
|
|
statistics->ClearAll();
|
|
statistics->AddColumn(wxT("PID"), 35);
|
|
statistics->AddColumn(_("User"), 70);
|
|
statistics->AddColumn(_("Database"), 70);
|
|
if (GetConnection()->BackendMinimumVersion(8, 1))
|
|
{
|
|
statistics->AddColumn(_("Backend start"), 70);
|
|
statistics->AddColumn(_("Client"), 70);
|
|
}
|
|
statistics->AddColumn(_("Current Query"), 300);
|
|
|
|
sql = wxT("SELECT ") + pidcol + wxT(" AS pid, usename, datname, backend_start, client_addr, ");
|
|
if (GetConnection()->BackendMinimumVersion(9, 1))
|
|
sql += wxT("client_hostname, ");
|
|
sql += wxT("client_port, ") + querycol + wxT(" AS query FROM pg_stat_activity\n");
|
|
if (GetConnection()->BackendMinimumVersion(9, 1))
|
|
{
|
|
sql += wxT("UNION\n")
|
|
wxT("SELECT ") + pidcol + wxT(", usename, '' AS datname, backend_start, client_addr, client_hostname, client_port, ")
|
|
+ replication_query + wxT(" AS query FROM pg_stat_replication");
|
|
}
|
|
|
|
pgSet *stats = ExecuteSet(sql);
|
|
if (stats)
|
|
{
|
|
int pos = 0;
|
|
while (!stats->Eof())
|
|
{
|
|
statistics->InsertItem(pos, stats->GetVal(wxT("pid")), 0);
|
|
int colpos = 1;
|
|
statistics->SetItem(pos, colpos++, stats->GetVal(wxT("usename")));
|
|
statistics->SetItem(pos, colpos++, stats->GetVal(wxT("datname")));
|
|
if (GetConnection()->BackendMinimumVersion(8, 1))
|
|
{
|
|
statistics->SetItem(pos, colpos++, stats->GetVal(wxT("backend_start")));
|
|
wxString client;
|
|
if (GetConnection()->BackendMinimumVersion(9, 1) && !stats->GetVal(wxT("client_hostname")).IsEmpty())
|
|
client = stats->GetVal(wxT("client_hostname")) + wxT(":") + stats->GetVal(wxT("client_port"));
|
|
else
|
|
client = stats->GetVal(wxT("client_addr")) + wxT(":") + stats->GetVal(wxT("client_port"));
|
|
if (client == wxT(":-1"))
|
|
client = _("local pipe");
|
|
statistics->SetItem(pos, colpos++, client);
|
|
}
|
|
statistics->SetItem(pos, colpos++, stats->GetVal(wxT("query")));
|
|
|
|
stats->MoveNext();
|
|
pos++;
|
|
}
|
|
|
|
delete stats;
|
|
}
|
|
}
|
|
}
|
|
|
|
void pgServer::ShowDependencies(frmMain *form, ctlListView *Dependencies, const wxString &wh)
|
|
{
|
|
}
|
|
|
|
|
|
void pgServer::ShowDependents(frmMain *form, ctlListView *referencedBy, const wxString &wh)
|
|
{
|
|
}
|
|
|
|
|
|
bool pgServer::ReloadConfiguration()
|
|
{
|
|
wxString sql = wxT("select pg_reload_conf()");
|
|
return conn->ExecuteVoid(sql);
|
|
}
|
|
|
|
|
|
bool pgServer::PauseReplay()
|
|
{
|
|
SetReplayPaused(true);
|
|
wxString sql = wxT("SELECT pg_xlog_replay_pause()");
|
|
if (conn->BackendMinimumVersion(10, 0)) sql = wxT("SELECT pg_wal_replay_pause()");
|
|
return conn->ExecuteVoid(sql);
|
|
}
|
|
|
|
|
|
bool pgServer::ResumeReplay()
|
|
{
|
|
SetReplayPaused(false);
|
|
wxString sql = wxT("SELECT pg_xlog_replay_resume()");
|
|
if (conn->BackendMinimumVersion(10, 0)) sql = wxT("SELECT pg_wal_replay_resume()");
|
|
return conn->ExecuteVoid(sql);
|
|
}
|
|
|
|
|
|
bool pgServer::AddNamedRestorePoint()
|
|
{
|
|
wxString namedrestorepoint = wxGetTextFromUser(_("Enter the name of the restore point to add"), _("Restore point name"));
|
|
if (!namedrestorepoint.IsEmpty())
|
|
{
|
|
wxString sql = wxT("select pg_create_restore_point(") + qtDbString(namedrestorepoint) + wxT(")");
|
|
return conn->ExecuteVoid(sql);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
pgServerCollection::pgServerCollection(pgaFactory *factory)
|
|
: pgCollection(factory)
|
|
{
|
|
}
|
|
|
|
|
|
wxString pgServerCollection::GetTranslatedMessage(int kindOfMessage) const
|
|
{
|
|
wxString message = wxEmptyString;
|
|
|
|
switch (kindOfMessage)
|
|
{
|
|
case RETRIEVINGDETAILS:
|
|
message = _("Retrieving details on servers");
|
|
break;
|
|
case REFRESHINGDETAILS:
|
|
message = _("Refreshing servers");
|
|
break;
|
|
case OBJECTSLISTREPORT:
|
|
message = _("Servers list report");
|
|
break;
|
|
}
|
|
|
|
return message;
|
|
}
|
|
|
|
|
|
pgServerObjCollection::pgServerObjCollection(pgaFactory *factory, pgServer *sv)
|
|
: pgCollection(factory)
|
|
{
|
|
server = sv;
|
|
}
|
|
|
|
|
|
bool pgServerObjCollection::CanCreate()
|
|
{
|
|
// We can't create resource queues on Greenplum yet.
|
|
if (IsCollectionForType(GP_RESOURCE_QUEUE))
|
|
return false;
|
|
|
|
// We can't create tablespaces on Greenplum
|
|
if (server->GetConnection()->GetIsGreenplum() && IsCollectionForType(PGM_TABLESPACE))
|
|
return false;
|
|
|
|
if (server->GetMetaType() == PGM_DATABASE)
|
|
return (GetServer()->GetCreatePrivilege() || GetServer()->GetSuperUser());
|
|
else
|
|
{
|
|
if (server->GetConnection()->BackendMinimumVersion(8, 1) && GetMetaType() == PGM_ROLE)
|
|
return (server->GetCreateRole() || server->GetSuperUser());
|
|
else if (server->GetConnection()->BackendMinimumVersion(8, 1) && GetMetaType() == PGM_DATABASE)
|
|
return (server->GetCreatePrivilege() || server->GetSuperUser());
|
|
else if (GetMetaType() == PGM_JOB)
|
|
return true;
|
|
else
|
|
return server->GetSuperUser();
|
|
}
|
|
}
|
|
|
|
|
|
pgObject *pgServerFactory::CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr)
|
|
{
|
|
wxTreeItemId groupitem, serveritem;
|
|
wxTreeItemIdValue groupcookie;
|
|
bool found;
|
|
|
|
long numServers = settings->Read(wxT("Servers/Count"), 0L);
|
|
|
|
long loop, port, ssl = 0;
|
|
wxString key, servername, hostaddr, description, service, database, username, lastDatabase, lastSchema;
|
|
wxString storePwd, rolename, connstr, restore, serviceID, discoveryID, dbRestriction, colour;
|
|
wxString group, sslcert, sslkey, sslrootcert, sslcrl, sslcompression;
|
|
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
wxString sshTunnel, authModePwd, tunnelHost, tunnelUserName, tunnelPassword, publicKeyFile, identityFile;
|
|
long tunnelPort;
|
|
#endif
|
|
pgServer *server = 0;
|
|
|
|
wxArrayString discoveredServers;
|
|
|
|
// Get the hostname for later...
|
|
char buf[255];
|
|
gethostname(buf, 255);
|
|
wxString hostname = wxString(buf, wxConvUTF8);
|
|
|
|
//wxLogError(wxT("Loading previously registered servers"));
|
|
wxLogInfo(wxT("Loading previously registered servers"));
|
|
|
|
for (loop = 1; loop <= numServers; ++loop)
|
|
{
|
|
key.Printf(wxT("Servers/%d/"), (int)loop);
|
|
|
|
settings->Read(key + wxT("Server"), &servername, wxEmptyString);
|
|
settings->Read(key + wxT("HostAddr"), &hostaddr, wxEmptyString);
|
|
settings->Read(key + wxT("Service"), &service, wxEmptyString);
|
|
settings->Read(key + wxT("ServiceID"), &serviceID, wxEmptyString);
|
|
settings->Read(key + wxT("DiscoveryID"), &discoveryID, serviceID);
|
|
settings->Read(key + wxT("Description"), &description, wxEmptyString);
|
|
settings->Read(key + wxT("StorePwd"), &storePwd, wxEmptyString);
|
|
settings->Read(key + wxT("Rolename"), &rolename, wxEmptyString);
|
|
settings->Read(key + wxT("ConnStr"), &connstr, wxEmptyString);
|
|
settings->Read(key + wxT("Restore"), &restore, wxT("true"));
|
|
settings->Read(key + wxT("Port"), &port, 0);
|
|
settings->Read(key + wxT("Database"), &database, wxEmptyString);
|
|
settings->Read(key + wxT("Username"), &username, wxEmptyString);
|
|
settings->Read(key + wxT("LastDatabase"), &lastDatabase, wxEmptyString);
|
|
settings->Read(key + wxT("LastSchema"), &lastSchema, wxEmptyString);
|
|
settings->Read(key + wxT("DbRestriction"), &dbRestriction, wxEmptyString);
|
|
settings->Read(key + wxT("Colour"), &colour, wxEmptyString);
|
|
settings->Read(key + wxT("Group"), &group, wxT("Servers"));
|
|
settings->Read(key + wxT("SSLCert"), &sslcert, wxEmptyString);
|
|
settings->Read(key + wxT("SSLKey"), &sslkey, wxEmptyString);
|
|
settings->Read(key + wxT("SSLRootCert"), &sslrootcert, wxEmptyString);
|
|
settings->Read(key + wxT("SSLCrl"), &sslcrl, wxEmptyString);
|
|
settings->Read(key + wxT("SSLCompression"), &sslcompression, wxT("true"));
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
settings->Read(key + wxT("SSHTunnel"), &sshTunnel, wxT("false"));
|
|
settings->Read(key + wxT("TunnelHost"), &tunnelHost, wxEmptyString);
|
|
settings->Read(key + wxT("TunnelUserName"), &tunnelUserName, wxEmptyString);
|
|
settings->Read(key + wxT("TunnelModePwd"), &authModePwd, wxT("true"));
|
|
settings->Read(key + wxT("PublicKeyFile"), &publicKeyFile, wxEmptyString);
|
|
settings->Read(key + wxT("IdentityFile"), &identityFile, wxEmptyString);
|
|
settings->Read(key + wxT("TunnelPort"), &tunnelPort, DEFAULT_SSH_PORT);
|
|
#endif
|
|
// Sanitize the colour
|
|
colour = colour.Trim();
|
|
|
|
if (!colour.IsEmpty())
|
|
{
|
|
wxColour cColour;
|
|
|
|
if (cColour.Set(colour))
|
|
colour = cColour.GetAsString(wxC2S_HTML_SYNTAX);
|
|
else
|
|
colour = wxEmptyString;
|
|
}
|
|
|
|
if (colour.IsEmpty())
|
|
{
|
|
wxColour cColour;
|
|
cColour.Set(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW).GetAsString(wxC2S_HTML_SYNTAX));
|
|
colour = cColour.GetAsString(wxC2S_HTML_SYNTAX);
|
|
}
|
|
|
|
// SSL mode
|
|
#ifdef PG_SSL
|
|
settings->Read(key + wxT("SSL"), &ssl, 0);
|
|
#endif
|
|
|
|
// Sanitize the group
|
|
if (group.IsEmpty())
|
|
{
|
|
group = _("Servers");
|
|
}
|
|
|
|
// Add the Server node
|
|
#if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
|
|
server = new pgServer(servername, hostaddr, description, service, database, username, port, StrToBool(storePwd), rolename, connstr, StrToBool(restore), ssl,
|
|
colour, group, StrToBool(sshTunnel), tunnelHost, tunnelUserName, StrToBool(authModePwd), tunnelPassword, publicKeyFile, identityFile, tunnelPort);
|
|
#else
|
|
server = new pgServer(servername, hostaddr, description, service, database, username, port, StrToBool(storePwd), rolename, connstr, StrToBool(restore), ssl,
|
|
colour, group);
|
|
#endif
|
|
server->iSetLastDatabase(lastDatabase);
|
|
server->iSetLastSchema(lastSchema);
|
|
server->iSetService(service);
|
|
server->iSetServiceID(serviceID);
|
|
server->iSetDiscoveryID(discoveryID);
|
|
server->iSetDiscovered(false);
|
|
server->iSetDbRestriction(dbRestriction);
|
|
server->iSetServerIndex(loop);
|
|
server->SetSSLCert(sslcert);
|
|
server->SetSSLKey(sslkey);
|
|
server->SetSSLRootCert(sslrootcert);
|
|
server->SetSSLCrl(sslcrl);
|
|
server->iSetSSLCompression(StrToBool(sslcompression));
|
|
|
|
found = false;
|
|
if (browser->ItemHasChildren(obj->GetId()))
|
|
{
|
|
groupitem = browser->GetFirstChild(obj->GetId(), groupcookie);
|
|
while (!found && groupitem)
|
|
{
|
|
if (browser->GetItemText(groupitem).StartsWith(group))
|
|
found = true;
|
|
else
|
|
groupitem = browser->GetNextChild(obj->GetId(), groupcookie);
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
groupitem = browser->AppendItem(obj->GetId(), group, obj->GetIconId());
|
|
}
|
|
|
|
serveritem = browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
|
|
browser->SortChildren(groupitem);
|
|
if (!server->GetColour().IsEmpty())
|
|
browser->SetItemBackgroundColour(serveritem, wxColour(server->GetColour()));
|
|
|
|
// Note if we're reloading a discovered server
|
|
if (!discoveryID.IsEmpty())
|
|
discoveredServers.Add(discoveryID);
|
|
}
|
|
|
|
group = _("Servers");
|
|
|
|
#ifdef __WXMSW__
|
|
|
|
// Add local servers. Will currently only work on Win32 with >= BETA3
|
|
// of the Win32 PostgreSQL installer.
|
|
wxLogInfo(wxT("Loading servers registered on the local machine"));
|
|
|
|
pgRegKey::PGREGWOWMODE wowMode = pgRegKey::PGREG_WOW_DEFAULT;
|
|
if (::wxIsPlatform64Bit())
|
|
wowMode = pgRegKey::PGREG_WOW32;
|
|
|
|
pgRegKey *pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
|
|
|
|
if (pgKey == NULL)
|
|
{
|
|
wowMode = pgRegKey::PGREG_WOW64;
|
|
pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
|
|
}
|
|
|
|
while (pgKey != NULL)
|
|
{
|
|
pgRegKey *svcKey = NULL;
|
|
wxString svcName;
|
|
long cookie = 0;
|
|
DWORD tmpport = 0;
|
|
bool flag = false;
|
|
|
|
flag = pgKey->GetFirstKey(svcKey, cookie);
|
|
|
|
while (flag != false)
|
|
{
|
|
svcName = svcKey->GetKeyName();
|
|
// On Windows, the discovery ID is always the service name.
|
|
// Only load the server if we didn't load it with all the others.
|
|
if (discoveredServers.Index(svcName, false) < 0)
|
|
{
|
|
servername = wxT("localhost");
|
|
database = wxEmptyString;
|
|
svcKey->QueryValue(wxT("Display Name"), description);
|
|
svcKey->QueryValue(wxT("Database Superuser"), username);
|
|
svcKey->QueryValue(wxT("Port"), &tmpport);
|
|
|
|
// Add the Server node
|
|
server = new pgServer(servername, wxEmptyString, description, wxEmptyString, database, username, (long)tmpport, false, wxEmptyString, wxEmptyString, false);
|
|
server->iSetDiscoveryID(svcName);
|
|
server->iSetDiscovered(true);
|
|
server->iSetServiceID(svcName);
|
|
server->iSetGroup(group);
|
|
|
|
found = false;
|
|
|
|
if (browser->ItemHasChildren(browser->GetRootItem()))
|
|
{
|
|
groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
|
|
while (!found && groupitem)
|
|
{
|
|
if (browser->GetItemText(groupitem).StartsWith(group))
|
|
found = true;
|
|
else
|
|
groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
groupitem = browser->AppendItem(browser->GetRootItem(), group, obj->GetIconId());
|
|
browser->SortChildren(browser->GetRootItem());
|
|
}
|
|
|
|
browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
|
|
browser->SortChildren(groupitem);
|
|
}
|
|
// Release the current registry key
|
|
delete svcKey;
|
|
|
|
// Get the next one...
|
|
flag = pgKey->GetNextKey(svcKey, cookie);
|
|
}
|
|
|
|
/* Release current registry key */
|
|
delete pgKey;
|
|
pgKey = NULL;
|
|
/*
|
|
* If wowMode is equal to WOW32, that means this machine is a 64 bit machine and we need to read now 64 bit registry
|
|
*/
|
|
if (wowMode == pgRegKey::PGREG_WOW32)
|
|
{
|
|
wowMode = pgRegKey::PGREG_WOW64;
|
|
pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
|
|
}
|
|
}
|
|
#endif // __WXMSW__
|
|
|
|
// Add local servers on non-Win32 platforms (on Win32, they will be picked up above)
|
|
#ifndef WIN32
|
|
|
|
// On Unix/Mac, the discovery ID can be anything. We use the PostgreSQL
|
|
// package config filename if it's present, as that is the only thing vaguely
|
|
// discoverable and unique to a given installation. We can do the same for
|
|
// other distros in the future if they drop a suitable file someplace.
|
|
// Look for any files that match the basic postgres*.ini pattern.
|
|
|
|
wxLogInfo(wxT("Loading servers registered on the local machine"));
|
|
|
|
if (wxFile::Exists(REGISTRY_FILE))
|
|
{
|
|
wxString version, locale;
|
|
long cookie;
|
|
|
|
wxFileInputStream fst(REGISTRY_FILE);
|
|
wxFileConfig *cnf = new wxFileConfig(fst);
|
|
|
|
// PostgreSQL servers
|
|
cnf->SetPath(wxT("/PostgreSQL"));
|
|
bool flag = cnf->GetFirstGroup(version, cookie);
|
|
while (flag)
|
|
{
|
|
// If there is no Version entry, this is probably an uninstalled server
|
|
if (cnf->Read(version + wxT("/Version"), wxEmptyString) != wxEmptyString)
|
|
{
|
|
// Only load this server if we haven't read it from the pgAdmin config
|
|
if (discoveredServers.Index(cnf->GetPath() + wxT("/") + version, false) < 0)
|
|
{
|
|
|
|
// Basic details
|
|
servername = wxT("localhost");
|
|
cnf->Read(version + wxT("/Description"), &description, wxT("PostgreSQL ") + version);
|
|
cnf->Read(version + wxT("/Superuser"), &username, wxEmptyString);
|
|
cnf->Read(version + wxT("/Port"), &port, 0);
|
|
|
|
// Add the item, if it looks sane
|
|
if (port != 0 && username != wxEmptyString)
|
|
{
|
|
server = new pgServer(servername, wxEmptyString, description, wxEmptyString, wxT("postgres"), username, port, false, rolename, connstr, 0);
|
|
server->iSetDiscoveryID(cnf->GetPath() + wxT("/") + version);
|
|
server->iSetDiscovered(true);
|
|
server->iSetGroup(group);
|
|
found = false;
|
|
if (browser->ItemHasChildren(browser->GetRootItem()))
|
|
{
|
|
groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
|
|
while (!found && groupitem)
|
|
{
|
|
if (browser->GetItemText(groupitem).StartsWith(group))
|
|
found = true;
|
|
else
|
|
groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
|
|
}
|
|
}
|
|
|
|
if (!found)
|
|
{
|
|
groupitem = browser->AppendItem(browser->GetRootItem(), group, obj->GetIconId());
|
|
browser->SortChildren(browser->GetRootItem());
|
|
}
|
|
|
|
browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
|
|
browser->SortChildren(groupitem);
|
|
}
|
|
}
|
|
}
|
|
|
|
flag = cnf->GetNextGroup(version, cookie);
|
|
}
|
|
|
|
// EnterpriseDB servers
|
|
cnf->SetPath(wxT("/EnterpriseDB"));
|
|
flag = cnf->GetFirstGroup(version, cookie);
|
|
while (flag)
|
|
{
|
|
// If there is no Version entry, this is probably an uninstalled server
|
|
if (cnf->Read(version + wxT("/Version"), wxEmptyString) != wxEmptyString)
|
|
{
|
|
// Only load this server if we haven't read it from the pgAdmin config
|
|
if (discoveredServers.Index(cnf->GetPath() + wxT("/") + version, false) < 0)
|
|
{
|
|
|
|
// Basic details
|
|
servername = wxT("localhost");
|
|
cnf->Read(version + wxT("/Description"), &description, wxT("EnterpriseDB ") + version);
|
|
cnf->Read(version + wxT("/Superuser"), &username, wxEmptyString);
|
|
cnf->Read(version + wxT("/Port"), &port, 0);
|
|
|
|
// Add the item, if it looks sane
|
|
if (port != 0 && username != wxEmptyString)
|
|
{
|
|
server = new pgServer(servername, wxEmptyString, description, wxEmptyString, wxT("edb"), username, port, false, rolename, connstr, 0);
|
|
server->iSetDiscoveryID(cnf->GetPath() + wxT("/") + version);
|
|
server->iSetDiscovered(true);
|
|
groupitem = browser->GetFirstChild(obj->GetId(), groupcookie);
|
|
if (!groupitem.IsOk())
|
|
groupitem = browser->AppendItem(obj->GetId(), group, obj->GetIconId());
|
|
browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
|
|
}
|
|
}
|
|
}
|
|
|
|
flag = cnf->GetNextGroup(version, cookie);
|
|
}
|
|
|
|
delete cnf;
|
|
browser->SortChildren(obj->GetId());
|
|
}
|
|
|
|
#endif // !WIN32
|
|
|
|
return server;
|
|
}
|
|
|
|
#include "images/servers.pngc"
|
|
#include "images/server.pngc"
|
|
#include "images/server-sm.pngc"
|
|
#include "images/serverbad.pngc"
|
|
#include "images/serverbad-sm.pngc"
|
|
|
|
pgServerFactory::pgServerFactory()
|
|
: pgaFactory(__("Server"), __("New Server Registration"), __("Create a new Server registration."), server_png_img, server_sm_png_img)
|
|
{
|
|
metaType = PGM_SERVER;
|
|
closedId = addIcon(serverbad_png_img);
|
|
smallClosedId = addIcon(serverbad_sm_png_img);
|
|
}
|
|
|
|
pgCollection *pgServerFactory::CreateCollection(pgObject *obj)
|
|
{
|
|
return new pgCollection(GetCollectionFactory());
|
|
}
|
|
|
|
pgCollection *pgServerObjFactory::CreateCollection(pgObject *obj)
|
|
{
|
|
return new pgServerObjCollection(GetCollectionFactory(), (pgServer *)obj);
|
|
}
|
|
|
|
pgServerFactory serverFactory;
|
|
static pgaCollectionFactory cf(&serverFactory, __("Servers"), servers_png_img);
|
|
|
|
#include "images/connect.pngc"
|
|
addServerFactory::addServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
|
|
{
|
|
mnu->Append(id, _("&Add Server..."), _("Add a connection to a server."));
|
|
toolbar->AddTool(id, _("Add Server"), GetBundleSVG(connect_png_bmp, "connect.svg", wxSize(32, 32)), _("Add a connection to a server."), wxITEM_NORMAL);
|
|
}
|
|
|
|
|
|
wxWindow *addServerFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
int rc = PGCONN_BAD;
|
|
|
|
dlgServer dlg(&serverFactory, form, 0);
|
|
dlg.CenterOnParent();
|
|
|
|
while (rc != PGCONN_OK)
|
|
{
|
|
if (dlg.GoNew() != wxID_OK)
|
|
return 0;
|
|
|
|
pgServer *server = (pgServer *)dlg.CreateObject(0);
|
|
|
|
if (dlg.GetTryConnect())
|
|
{
|
|
wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"),
|
|
server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), form);
|
|
|
|
// Give the UI a chance to redraw
|
|
wxSafeYield();
|
|
wxMilliSleep(100);
|
|
wxSafeYield();
|
|
|
|
rc = server->Connect(form, false, dlg.GetPassword(), true);
|
|
}
|
|
else
|
|
{
|
|
rc = PGCONN_OK;
|
|
server->InvalidatePassword();
|
|
}
|
|
switch (rc)
|
|
{
|
|
case PGCONN_OK:
|
|
{
|
|
int icon;
|
|
ctlTree *browser = form->GetBrowser();
|
|
wxTreeItemId groupitem, parentitem;
|
|
wxTreeItemIdValue groupcookie;
|
|
int total;
|
|
wxString label;
|
|
|
|
if (server->GetConnected())
|
|
icon = serverFactory.GetIconId();
|
|
else
|
|
icon = serverFactory.GetClosedIconId();
|
|
wxLogInfo(wxT("pgServer object initialised as required."));
|
|
|
|
// Add the new server in its group
|
|
wxString group = server->GetGroup();
|
|
if (group.Length() == 0)
|
|
group = _("Servers");
|
|
|
|
// Get the parent group
|
|
groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
|
|
while (!parentitem && groupitem)
|
|
{
|
|
if (browser->GetItemText(groupitem).StartsWith(group))
|
|
parentitem = groupitem;
|
|
groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
|
|
}
|
|
|
|
if (!parentitem)
|
|
parentitem = browser->AppendItem(browser->GetRootItem(), group, icon, -1);
|
|
|
|
browser->AppendItem(parentitem, server->GetFullName(), icon, -1, server);
|
|
browser->SortChildren(parentitem);
|
|
browser->Expand(parentitem);
|
|
|
|
total = browser->GetChildrenCount(parentitem, false);
|
|
label = group + wxT(" (") + NumToStr((long)total) + wxT(")");
|
|
browser->SetItemText(parentitem, label);
|
|
|
|
form->StoreServers();
|
|
return 0;
|
|
}
|
|
case PGCONN_DNSERR:
|
|
{
|
|
delete server;
|
|
break;
|
|
}
|
|
case PGCONN_BAD:
|
|
case PGCONN_BROKEN:
|
|
{
|
|
form->ReportConnError(server);
|
|
delete server;
|
|
|
|
break;
|
|
}
|
|
case PGCONN_SSHTUNNEL_ERROR:
|
|
{
|
|
delete server;
|
|
break;
|
|
}
|
|
default:
|
|
{
|
|
wxLogInfo(__("pgServer object didn't initialise because the user aborted."));
|
|
delete server;
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
startServiceFactory::startServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Start Service"), _("Start PostgreSQL Service"));
|
|
}
|
|
|
|
|
|
wxWindow *startServiceFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
form->StartMsg(_("Starting Service"));
|
|
bool rc = server->StartService();
|
|
if (rc)
|
|
form->execSelChange(server->GetId(), true);
|
|
form->EndMsg(rc);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool startServiceFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
return server->GetServerControllable() && !server->GetServerRunning();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
stopServiceFactory::stopServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Stop Service"), _("Stop PostgreSQL Service"));
|
|
}
|
|
|
|
|
|
wxWindow *stopServiceFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
wxMessageDialog msg(form, _("Are you sure you wish to shutdown this server?"),
|
|
_("Stop Service"), wxYES_NO | wxICON_QUESTION);
|
|
if (msg.ShowModal() == wxID_YES)
|
|
{
|
|
form->StartMsg(_("Stopping service"));
|
|
|
|
bool done = server->StopService();
|
|
|
|
if (done)
|
|
{
|
|
if (server->Disconnect(form))
|
|
{
|
|
form->GetBrowser()->DeleteChildren(server->GetId());
|
|
form->execSelChange(server->GetId(), true);
|
|
}
|
|
}
|
|
form->EndMsg(done);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool stopServiceFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
return server->GetServerControllable() && server->GetServerRunning();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
connectServerFactory::connectServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("&Connect"), _("Connect to the selected server."));
|
|
}
|
|
|
|
|
|
wxWindow *connectServerFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
form->ReconnectServer(server);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool connectServerFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
return !((pgServer *)obj)->GetConnected();
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
disconnectServerFactory::disconnectServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Disconnec&t server"), _("Disconnect from the selected server."));
|
|
}
|
|
|
|
|
|
wxWindow *disconnectServerFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
if (obj->CheckOpenDialogs(form->GetBrowser(), form->GetBrowser()->GetSelection()))
|
|
{
|
|
wxString msg = _("There are properties dialogues open for one or more objects belonging to a database which will be disconnected. Please close the properties dialogues and try again.");
|
|
wxMessageBox(msg, _("Cannot disconnect database"), wxICON_WARNING | wxOK);
|
|
}
|
|
else
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
server->Disconnect(form);
|
|
server->UpdateIcon(form->GetBrowser());
|
|
form->GetBrowser()->DeleteChildren(obj->GetId());
|
|
form->execSelChange(obj->GetId(), true);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool disconnectServerFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
return ((pgServer *)obj)->GetConnected();
|
|
|
|
return false;
|
|
}
|
|
|
|
disconnectServerFactoryAll::disconnectServerFactoryAll(menuFactoryList* list, wxMenu* mnu, ctlMenuToolbar* toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Disconnec&t all servers"), _("Disconnect from all servers."));
|
|
}
|
|
|
|
|
|
wxWindow* disconnectServerFactoryAll::StartDialog(frmMain* form, pgObject* obj)
|
|
{
|
|
|
|
wxTreeItemIdValue foldercookie, servercookie;
|
|
wxTreeItemId folderitem, serveritem;
|
|
pgObject* object;
|
|
pgServer* server;
|
|
folderitem = form->GetBrowser()->GetFirstChild(form->GetBrowser()->GetRootItem(), foldercookie);
|
|
while (folderitem)
|
|
{
|
|
if (form->GetBrowser()->ItemHasChildren(folderitem))
|
|
{
|
|
serveritem = form->GetBrowser()->GetFirstChild(folderitem, servercookie);
|
|
while (serveritem)
|
|
{
|
|
object = form->GetBrowser()->GetObject(serveritem);
|
|
if (object && object->IsCreatedBy(serverFactory))
|
|
{
|
|
if (CheckEnable(object)) {
|
|
if (object->CheckOpenDialogs(form->GetBrowser(), serveritem))
|
|
{
|
|
wxString msg = _("There are properties dialogues open for one or more objects belonging to a database which will be disconnected. Please close the properties dialogues and try again.");
|
|
wxMessageBox(msg, _("Cannot disconnect database"), wxICON_WARNING | wxOK);
|
|
}
|
|
else
|
|
{
|
|
server = (pgServer*)object;
|
|
server->Disconnect(form);
|
|
server->UpdateIcon(form->GetBrowser());
|
|
form->GetBrowser()->DeleteChildren(object->GetId());
|
|
form->execSelChange(object->GetId(), true);
|
|
}
|
|
}
|
|
}
|
|
serveritem = form->GetBrowser()->GetNextChild(folderitem, servercookie);
|
|
}
|
|
}
|
|
folderitem = form->GetBrowser()->GetNextChild(form->GetBrowser()->GetRootItem(), foldercookie);
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool disconnectServerFactoryAll::CheckEnable(pgObject* obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
return ((pgServer*)obj)->GetConnected();
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
reloadconfServiceFactory::reloadconfServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Reload configuration"), _("Reload configuration"));
|
|
}
|
|
|
|
|
|
wxWindow *reloadconfServiceFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
form->StartMsg(_("Reloading configuration"));
|
|
bool rc = server->ReloadConfiguration();
|
|
form->EndMsg(rc);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool reloadconfServiceFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
return server->GetConnected() && server->connection()->BackendMinimumVersion(8, 1);
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
pausereplayServiceFactory::pausereplayServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Pause replay of WAL"), _("Pause replay of WAL"));
|
|
}
|
|
|
|
|
|
wxWindow *pausereplayServiceFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
form->StartMsg(_("Pausing replay of WAL"));
|
|
bool rc = server->PauseReplay();
|
|
form->EndMsg(rc);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool pausereplayServiceFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
return server->GetConnected() &&
|
|
server->connection()->BackendMinimumVersion(9, 1) &&
|
|
server->GetInRecovery() &&
|
|
!server->GetReplayPaused();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
resumereplayServiceFactory::resumereplayServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Resume replay of WAL"), _("Resume replay of WAL"));
|
|
}
|
|
|
|
|
|
wxWindow *resumereplayServiceFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
form->StartMsg(_("Resuming replay of WAL"));
|
|
bool rc = server->ResumeReplay();
|
|
form->EndMsg(rc);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool resumereplayServiceFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
return server->GetConnected() &&
|
|
server->connection()->BackendMinimumVersion(9, 1) &&
|
|
server->GetInRecovery() &&
|
|
server->GetReplayPaused();
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
addnamedrestorepointServiceFactory::addnamedrestorepointServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
|
|
{
|
|
mnu->Append(id, _("Add named restore point"), _("Add named restore point"));
|
|
}
|
|
|
|
|
|
wxWindow *addnamedrestorepointServiceFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
form->StartMsg(_("Add named restore point"));
|
|
bool rc = server->AddNamedRestorePoint();
|
|
form->EndMsg(rc);
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool addnamedrestorepointServiceFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj && obj->IsCreatedBy(serverFactory))
|
|
{
|
|
pgServer *server = (pgServer *)obj;
|
|
return server->GetConnected() && server->connection()->BackendMinimumVersion(9, 1) && !server->GetInRecovery();
|
|
}
|
|
return false;
|
|
} |