mirror of
https://github.com/levinsv/pgadmin3.git
synced 2026-05-15 06:05:49 -06:00
Для удобного поиска серверов к параметрам сервера добавлен Keywords параметр. Это текстовый параметр в котором через пробел можно перечислить слова по которым будет проводиться поиск сервера при нажатии F4. Тут можно например указать IP сервера для соединения использующего туннель putty. GUI интерфейса для настройки параметра нет. Если ключевые слова заданы то отображаются в [].
2365 lines
No EOL
66 KiB
C++
2365 lines
No EOL
66 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;
|
|
wxString keywords;
|
|
|
|
#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("Keywords"), &keywords, wxEmptyString);
|
|
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));
|
|
server->iSetKeywords(keywords);
|
|
|
|
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)
|
|
{
|
|
wxString msg=_("Disconnec&t server")+"\tCtrl-W";
|
|
mnu->Append(id, msg, _("Disconnect from the selected server."));
|
|
}
|
|
|
|
|
|
wxWindow *disconnectServerFactory::StartDialog(frmMain *form, pgObject *obj)
|
|
{
|
|
{
|
|
pgServer *server=NULL;
|
|
wxTreeItemId idserver;
|
|
if (obj) {
|
|
if (!obj->IsCreatedBy(serverFactory)) {
|
|
server=obj->GetServer();
|
|
if (server) {
|
|
idserver=server->GetId();
|
|
form->execSelChange(idserver, false);
|
|
form->GetBrowser()->SelectItem(idserver);
|
|
} else return 0;
|
|
} else {
|
|
idserver=obj->GetId();
|
|
server = (pgServer *)obj;
|
|
}
|
|
if (server->CheckOpenDialogs(form->GetBrowser(), idserver))
|
|
{
|
|
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->Disconnect(form);
|
|
server->UpdateIcon(form->GetBrowser());
|
|
form->GetBrowser()->DeleteChildren(idserver);
|
|
form->execSelChange(idserver, true);
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
bool disconnectServerFactory::CheckEnable(pgObject *obj)
|
|
{
|
|
if (obj) {
|
|
pgServer *pgs=obj->GetServer();
|
|
if (pgs) return pgs->GetConnected();
|
|
}
|
|
// 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;
|
|
} |