1 //////////////////////////////////////////////////////////////////////////
2 //
3 // pgAdmin III - PostgreSQL Tools
4 //
5 // Copyright (C) 2002 - 2016, The pgAdmin Development Team
6 // This software is released under the PostgreSQL Licence
7 //
8 // pgServer.cpp - PostgreSQL Server
9 //
10 //////////////////////////////////////////////////////////////////////////
11
12 #include "pgAdmin3.h"
13
14 // wxWindows headers
15 #include <wx/wx.h>
16 #include <wx/busyinfo.h>
17 #include <wx/dir.h>
18 #include <wx/fileconf.h>
19 #include <wx/wfstream.h>
20
21 // App headers
22 #include "ctl/ctlMenuToolbar.h"
23 #include "frm/menu.h"
24 #include "utils/misc.h"
25 #include "frm/frmMain.h"
26 #include "frm/frmHint.h"
27 #include "dlg/dlgConnect.h"
28 #include "schema/pgDatabase.h"
29 #include "schema/pgTablespace.h"
30 #include "schema/pgGroup.h"
31 #include "schema/pgUser.h"
32 #include "schema/pgRole.h"
33 #include "schema/gpResQueue.h"
34 #include "agent/pgaJob.h"
35 #include "utils/utffile.h"
36 #include "utils/pgfeatures.h"
37 #include "utils/registry.h"
38 #include "frm/frmReport.h"
39 #include "dlg/dlgServer.h"
40 #include "schema/edbResourceGroup.h"
41
42 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
43 #include "utils/sshTunnel.h"
44 #endif
45
46 #define DEFAULT_PG_DATABASE wxT("postgres")
47
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,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)48 pgServer::pgServer(const wxString &newName, const wxString &newHostAddr, const wxString &newDescription, const wxString &newService,
49 const wxString &newDatabase, const wxString &newUsername, int newPort, bool _storePwd, const wxString &newRolename, bool _restore,
50 int _ssl, const wxString &_colour, const wxString &_group, bool _sshTunnel, const wxString &newTunnelHost, const wxString &newTunnelUserName,
51 bool _authModePwd, const wxString &newTunnelPassword, const wxString &newPublicKey, const wxString &newIdentity, const int &sshPort)
52 : pgObject(serverFactory, newName)
53 {
54 description = newDescription;
55 hostaddr = newHostAddr;
56 service = newService;
57 database = newDatabase;
58 username = newUsername;
59 port = newPort;
60 ssl = _ssl;
61 colour = _colour;
62 group = _group;
63
64 serverIndex = 0;
65
66 connected = false;
67 lastSystemOID = 0;
68
69 conn = NULL;
70 passwordValid = true;
71 storePwd = _storePwd;
72 rolename = newRolename;
73 restore = _restore;
74 superUser = false;
75 createPrivilege = false;
76 sshTunnel = _sshTunnel;
77
78 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
79 // SSH Tunnel
80 tunnelObj = NULL;
81 tunnelHost = newTunnelHost;
82 tunnelUserName = newTunnelUserName;
83 authModePwd = _authModePwd;
84 tunnelPassword = newTunnelPassword;
85 publicKeyFile = newPublicKey;
86 identityFile = newIdentity;
87 tunnelPort = sshPort;
88 #endif
89
90 #ifdef WIN32
91 scmHandle = 0;
92 serviceHandle = 0;
93 #endif
94 }
95
~pgServer()96 pgServer::~pgServer()
97 {
98 if (conn)
99 delete conn;
100
101 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
102 if(tunnelObj)
103 {
104 if(tunnelObj->IsAlive())
105 {
106 tunnelObj->Cleanup();
107 }
108 tunnelObj = NULL;
109 }
110 #endif
111
112 #ifdef WIN32
113 if (serviceHandle)
114 CloseServiceHandle(serviceHandle);
115 if (scmHandle)
116 CloseServiceHandle(scmHandle);
117 #endif
118 }
119
120
GetTranslatedMessage(int kindOfMessage) const121 wxString pgServer::GetTranslatedMessage(int kindOfMessage) const
122 {
123 wxString message = wxEmptyString;
124
125 switch (kindOfMessage)
126 {
127 case RETRIEVINGDETAILS:
128 message = _("Retrieving details on server");
129 message += wxT(" ") + GetName();
130 break;
131 case REFRESHINGDETAILS:
132 message = _("Refreshing server");
133 message += wxT(" ") + GetName();
134 break;
135 case BACKUPGLOBALS:
136 message = _("Backup globals of server");
137 message += wxT(" ") + GetName();
138 break;
139 case BACKUPSERVERTITLE:
140 message = _("Backup server");
141 message += wxT(" ") + GetName();
142 break;
143 case DROPTITLE:
144 message = _("Drop server?");
145 break;
146 case PROPERTIESREPORT:
147 message = _("Server properties report");
148 message += wxT(" - ") + GetName();
149 break;
150 case PROPERTIES:
151 message = _("Server properties");
152 break;
153 case STATISTICSREPORT:
154 message = _("Server statistics report");
155 message += wxT(" - ") + GetName();
156 break;
157 case OBJSTATISTICS:
158 message = _("Server statistics");
159 break;
160 }
161
162 return message;
163 }
164
165
GetIconId()166 int pgServer::GetIconId()
167 {
168 if (GetConnected())
169 return serverFactory.GetIconId();
170 else
171 return serverFactory.GetClosedIconId();
172 }
173
174
GetNewMenu()175 wxMenu *pgServer::GetNewMenu()
176 {
177 wxMenu *menu = 0;
178 if (connected && (GetSuperUser() || GetCreateRole()))
179 {
180 menu = new wxMenu();
181 if (settings->GetDisplayOption(_("Tablespaces")))
182 tablespaceFactory.AppendMenu(menu);
183 if (GetConnection()->BackendMinimumVersion(8, 1))
184 {
185 if (settings->GetDisplayOption(_("Groups/group Roles")))
186 groupRoleFactory.AppendMenu(menu);
187 if (settings->GetDisplayOption(_("Users/login Roles")))
188 loginRoleFactory.AppendMenu(menu);
189 if (GetConnection()->GetIsGreenplum())
190 {
191 if (settings->GetDisplayOption(_("Resource Queues")))
192 resQueueFactory.AppendMenu(menu);
193 }
194 }
195 else
196 {
197 if (settings->GetDisplayOption(_("Groups/group Roles")))
198 groupFactory.AppendMenu(menu);
199 if (settings->GetDisplayOption(_("Users/login Roles")))
200 userFactory.AppendMenu(menu);
201 }
202 // Added Resource Group only for PPAS 9.4 and above
203 if (conn->GetIsEdb() && conn->EdbMinimumVersion(9, 4))
204 {
205 if (settings->GetDisplayOption(_("Resource Groups")))
206 resourceGroupFactory.AppendMenu(menu);
207 }
208 }
209 return menu;
210 }
211
GetServer() const212 pgServer *pgServer::GetServer() const
213 {
214 if (connected)
215 return (pgServer *)this;
216 return 0;
217 }
218
219
CreateConn(wxString dbName,OID oid,wxString applicationname)220 pgConn *pgServer::CreateConn(wxString dbName, OID oid, wxString applicationname)
221 {
222 if (!connected)
223 return 0;
224
225 if (dbName.IsEmpty())
226 {
227 dbName = GetDatabaseName();
228 oid = dbOid;
229 }
230
231 pgConn *conn = NULL;
232 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
233 if(sshTunnel)
234 {
235 conn = new pgConn(local_listenhost, service, hostaddr, dbName, username, password, local_listenport, rolename, ssl, oid, applicationname, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
236 }
237 else
238 #endif
239 {
240 conn = new pgConn(GetName(), service, hostaddr, dbName, username, password, port, rolename, ssl, oid, applicationname, sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
241 }
242
243 if (conn && conn->GetStatus() != PGCONN_OK)
244 {
245 wxLogError(wxT("%s"), conn->GetLastError().c_str());
246 delete conn;
247 return 0;
248 }
249 return conn;
250 }
251
252
GetFullName()253 wxString pgServer::GetFullName()
254 {
255 if (GetDescription().Length() > 0)
256 return GetDescription() + wxT(" (") + GetIdentifier() + wxT(")");
257 else
258 return wxT("(") + GetIdentifier() + wxT(")");
259 }
260
GetFullIdentifier()261 wxString pgServer::GetFullIdentifier()
262 {
263 return GetFullName();
264 }
265
Disconnect(frmMain * form)266 bool pgServer::Disconnect(frmMain *form)
267 {
268 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
269 if(tunnelObj)
270 {
271 if(tunnelObj->IsAlive())
272 {
273 tunnelObj->Cleanup();
274 }
275 tunnelObj = NULL;
276 }
277 #endif
278
279 if (conn)
280 {
281 delete conn;
282 conn = 0;
283 connected = false;
284 expandedKids = false;
285 ver = wxT("");
286 versionNum = wxT("");
287 lastSystemOID = 0;
288 }
289
290 if (form)
291 UpdateIcon(form->GetBrowser());
292
293 return true;
294 }
295
296
GetCanHint()297 bool pgServer::GetCanHint()
298 {
299 return connected && conn->BackendMinimumVersion(8, 1) && !autovacuumRunning;
300 }
301
302
ShowHint(frmMain * form,bool force)303 void pgServer::ShowHint(frmMain *form, bool force)
304 {
305 wxArrayString hints;
306
307 if (!autovacuumRunning)
308 hints.Add(HINT_AUTOVACUUM);
309
310 if (force || !hintShown)
311 frmHint::ShowHint(form, hints, GetFullIdentifier(), force);
312 hintShown = true;
313 }
314
315
316 #define SERVICEBUFSIZE 10000
317 #define QUERYBUFSIZE 256
318
319 #ifdef WIN32
GetDependentServices(SC_HANDLE handle)320 wxArrayString pgServer::GetDependentServices(SC_HANDLE handle)
321 {
322 wxArrayString services;
323 LPENUM_SERVICE_STATUS sbuf = (LPENUM_SERVICE_STATUS) new char[SERVICEBUFSIZE];
324
325 DWORD servicesReturned = 0, bytesNeeded;
326 ::EnumDependentServices(handle, SERVICE_STATE_ALL, sbuf, SERVICEBUFSIZE, &bytesNeeded, &servicesReturned);
327
328
329 DWORD i;
330 for (i = 0 ; i < servicesReturned ; i++)
331 {
332 SC_HANDLE h =::OpenService(scmHandle, sbuf[i].lpServiceName, SERVICE_QUERY_CONFIG);
333 if (h)
334 {
335 char buffer[QUERYBUFSIZE];
336 LPQUERY_SERVICE_CONFIG qsc = (LPQUERY_SERVICE_CONFIG)buffer;
337 if(::QueryServiceConfig(h, qsc, QUERYBUFSIZE, &bytesNeeded))
338 {
339 if (qsc->dwStartType != SERVICE_DISABLED)
340 services.Add(sbuf[i].lpServiceName);
341 }
342
343 ::CloseServiceHandle(h);
344 }
345 }
346 delete[] sbuf;
347
348 return services;
349 }
350 #endif
351
352
StartService()353 bool pgServer::StartService()
354 {
355 bool done = false;
356 #ifdef WIN32
357 if (serviceHandle)
358 {
359 done = (::StartService(serviceHandle, 0, 0) != 0);
360 if (!done)
361 {
362 DWORD rc = ::GetLastError();
363 if (rc == ERROR_SERVICE_ALREADY_RUNNING)
364 {
365 GetServerRunning();
366 return true;
367 }
368 // report error
369 wxLogError(__("Failed to start server %s: Errcode=%d\nCheck event log for details."),
370 serviceId.c_str(), rc);
371 }
372 else
373 {
374 GetServerRunning(); // ignore result, just to wait for startup
375
376 wxArrayString services = GetDependentServices(serviceHandle);
377
378 if (services.GetCount() > 0)
379 {
380 size_t i;
381 wxString serviceString;
382 for (i = 0 ; i < services.GetCount() ; i++)
383 serviceString += wxT(" ") + services.Item(i) + wxT("\n");
384
385 wxMessageDialog msg(0, _("There are dependent services configured:\n\n")
386 + serviceString + _("\nStart dependent services too?"), _("Dependent services"),
387 wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
388
389 if (msg.ShowModal() == wxID_YES)
390 {
391 for (i = 0 ; i < services.GetCount() ; i++)
392 {
393 SC_HANDLE h =::OpenService(scmHandle, services.Item(i), GENERIC_EXECUTE | GENERIC_READ);
394 if (h)
395 {
396 if (!::StartService(h, 0, 0))
397 done = false;
398 CloseServiceHandle(h);
399 }
400 else
401 done = false;
402 }
403 if (!done)
404 {
405 wxMessageDialog msg(0, _("One or more dependent services didn't start; see the eventlog for details."), _("Service start problem"),
406 wxICON_EXCLAMATION | wxOK);
407 msg.ShowModal();
408 done = true;
409 }
410 }
411 }
412 }
413 }
414 #else
415 wxString res = ExecProcess(serviceId + wxT(" start"));
416 done = (res.Find(wxT("tarting")) > 0);
417 #endif
418 return done;
419 }
420
421
StopService()422 bool pgServer::StopService()
423 {
424 bool done = false;
425 #ifdef WIN32
426 if (serviceHandle)
427 {
428 SERVICE_STATUS st;
429
430 done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
431 if (!done)
432 {
433 if (::GetLastError() == ERROR_DEPENDENT_SERVICES_RUNNING)
434 {
435 LPENUM_SERVICE_STATUS sbuf = (LPENUM_SERVICE_STATUS) new char[SERVICEBUFSIZE];
436 DWORD bytesNeeded, servicesReturned = 0;
437 ::EnumDependentServices(serviceHandle, SERVICE_ACTIVE, sbuf, SERVICEBUFSIZE, &bytesNeeded, &servicesReturned);
438
439 done = true;
440
441 if (servicesReturned)
442 {
443 DWORD i;
444 wxString services;
445 for (i = 0 ; i < servicesReturned ; i++)
446 services += wxT(" ") + wxString(sbuf[i].lpDisplayName) + wxT("\n");
447
448 wxMessageDialog msg(0, _("There are dependent services running:\n\n")
449 + services + _("\nStop dependent services?"), _("Dependent services"),
450 wxICON_EXCLAMATION | wxYES_NO | wxYES_DEFAULT);
451 if (msg.ShowModal() != wxID_YES)
452 return false;
453
454 for (i = 0 ; done && i < servicesReturned ; i++)
455 {
456 SC_HANDLE h =::OpenService(scmHandle, sbuf[i].lpServiceName, GENERIC_EXECUTE | GENERIC_READ);
457 if (h)
458 {
459 done = (::ControlService(h, SERVICE_CONTROL_STOP, &st) != 0);
460 CloseServiceHandle(h);
461 }
462 else
463 done = false;
464 }
465 if (done)
466 {
467 done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
468
469 int retries = 10;
470 while (!done && retries > 0)
471 {
472 done = (::ControlService(serviceHandle, SERVICE_CONTROL_STOP, &st) != 0);
473 retries--;
474
475 wxSleep(5);
476 }
477
478 }
479 }
480 }
481 // report error
482
483 if (!done)
484 wxLogError(__("Failed to stop server %s: Errcode=%d\nCheck event log for details."),
485 serviceId.c_str(), ::GetLastError());
486 }
487 }
488 #else
489 wxString res = ExecProcess(serviceId + wxT(" stop"));
490 done = (res.Find(wxT("stopped")) > 0);
491 #endif
492 return done;
493 }
494
495
GetServerRunning()496 bool pgServer::GetServerRunning()
497 {
498 bool done = false;
499 #ifdef WIN32
500 if (serviceHandle)
501 {
502 SERVICE_STATUS st;
503 int loops;
504
505 for (loops = 0 ; loops < 20 ; loops++)
506 {
507 if (::QueryServiceStatus(serviceHandle, &st) == 0)
508 {
509 DWORD rc = ::GetLastError();
510 CloseServiceHandle(serviceHandle);
511 CloseServiceHandle(scmHandle);
512 serviceHandle = 0;
513 scmHandle = 0;
514
515 return false;
516 }
517 done = (st.dwCurrentState == SERVICE_RUNNING);
518 if (st.dwCurrentState == SERVICE_START_PENDING)
519 Sleep(100);
520 else
521 break;
522 }
523 }
524 #else
525
526 wxString res = ExecProcess(serviceId + wxT(" status"));
527 done = (res.Find(wxT("PID: ")) > 0);
528
529 #endif
530 return done;
531 }
532
533
iSetServiceID(const wxString & s)534 void pgServer::iSetServiceID(const wxString &s)
535 {
536 serviceId = s;
537 #ifdef WIN32
538 if (serviceId.Find('\\') < 0)
539 scmHandle = OpenSCManager(0, SERVICES_ACTIVE_DATABASE, GENERIC_EXECUTE);
540 else
541 scmHandle = OpenSCManager(wxT("\\\\") + serviceId.BeforeFirst('\\'), SERVICES_ACTIVE_DATABASE, GENERIC_EXECUTE | GENERIC_READ);
542
543 if (scmHandle)
544 serviceHandle = OpenService(scmHandle, serviceId.AfterLast('\\'), GENERIC_EXECUTE | GENERIC_READ);
545 #endif
546 }
547
548
GetServerControllable()549 bool pgServer::GetServerControllable()
550 {
551 #ifdef WIN32
552 return serviceHandle != 0;
553 #else
554 return !serviceId.IsEmpty();
555 #endif
556 }
557
558
passwordFilename()559 wxString pgServer::passwordFilename()
560 {
561 wxString fname = sysSettings::GetConfigFile(sysSettings::PGPASS);
562
563 wxLogInfo(wxT("Using password file %s"), fname.c_str());
564 return fname;
565 }
566
567
568
GetPasswordIsStored()569 bool pgServer::GetPasswordIsStored()
570 {
571 wxString fname = passwordFilename();
572
573
574 if (!wxFile::Exists(fname))
575 return false;
576
577 wxUtfFile file(fname, wxFile::read, wxFONTENCODING_SYSTEM);
578
579 if (file.IsOpened())
580 {
581 wxString before;
582 file.Read(before);
583
584 wxStringTokenizer lines(before, wxT("\n\r"));
585
586 wxString seekStr = GetName() + wxT(":")
587 + NumToStr((long)GetPort()) + wxT(":*:")
588 + username + wxT(":") ;
589
590 wxString seekStr2 = wxString(GetName().mb_str(wxConvUTF8), wxConvLibc) + wxT(":")
591 + NumToStr((long)GetPort()) + wxT(":*:")
592 + wxString(username.mb_str(wxConvUTF8), wxConvLibc) + wxT(":") ;
593
594 while (lines.HasMoreTokens())
595 {
596 wxString str = lines.GetNextToken();
597 if (str.Left(seekStr.Length()) == seekStr)
598 return true;
599
600 if (str.Left(seekStr2.Length()) == seekStr2)
601 return true;
602 }
603 }
604
605 return false;
606 }
607
608
StorePassword()609 void pgServer::StorePassword()
610 {
611 wxString fname = passwordFilename();
612
613 if (!wxFile::Exists(fname))
614 {
615 return;
616 }
617 wxUtfFile file;
618 // Don't try to read and write in one OP - it doesn't work well
619 wxString before;
620 file.Open(fname, wxFile::read, wxFONTENCODING_SYSTEM);
621 file.Read(before);
622 file.Close();
623
624 file.Open(fname, wxFile::write, wxFONTENCODING_SYSTEM);
625
626 if (file.IsOpened())
627 {
628 wxString after;
629
630 wxString passwd;
631 wxString seekStr;
632
633 if (GetConnection()->GetNeedUtfConnectString())
634 {
635 passwd = wxString(password.mb_str(wxConvUTF8), wxConvLibc);
636 seekStr = wxString(GetName().mb_str(wxConvUTF8), wxConvLibc) + wxT(":")
637 + NumToStr((long)GetPort()) + wxT(":*:")
638 + wxString(username.mb_str(wxConvUTF8), wxConvLibc) + wxT(":") ;
639 }
640 else
641 {
642 passwd = password;
643 seekStr = GetName() + wxT(":")
644 + NumToStr((long)GetPort()) + wxT(":*:")
645 + username + wxT(":") ;
646 }
647
648 // Escape ":" and "\" from the password field
649 if (!passwd.IsEmpty())
650 {
651 passwd.Replace(wxT("\\"), wxT("\\\\"));
652 passwd.Replace(wxT(":") , wxT("\\:"));
653 }
654
655 file.Read(before);
656 wxStringTokenizer lines(before, wxT("\n\r"));
657
658 file.Seek(0);
659 bool found = false;
660 while (lines.HasMoreTokens())
661 {
662 wxString str = lines.GetNextToken();
663 if (str.Left(seekStr.Length()) == seekStr && !passwd.IsEmpty())
664 {
665 // entry found
666 found = true;
667 if (storePwd)
668 file.Write(seekStr + passwd + END_OF_LINE);
669 }
670 else
671 file.Write(str + END_OF_LINE);
672 }
673 if (!found && storePwd && !passwd.IsEmpty())
674 file.Write(seekStr + passwd + END_OF_LINE);
675
676 file.Close();
677 }
678 }
679
680
Connect(frmMain * form,bool askPassword,const wxString & pwd,bool forceStorePassword,bool askTunnelPassword)681 int pgServer::Connect(frmMain *form, bool askPassword, const wxString &pwd, bool forceStorePassword, bool askTunnelPassword)
682 {
683 wxLogInfo(wxT("Attempting to create a connection object..."));
684
685 bool storePassword = false;
686
687 if (!conn || conn->GetStatus() != PGCONN_OK)
688 {
689 if (conn)
690 {
691 delete conn;
692 conn = 0;
693 }
694 if (askPassword)
695 {
696 if ((sshTunnel || !passwordValid || !GetPasswordIsStored() || !GetStorePwd()) && GetSSLCert() == wxEmptyString)
697 {
698 wxString txt;
699 txt.Printf(_("Please enter password for user %s\non server %s (%s)"), username.c_str(), description.c_str(), GetName().c_str());
700 dlgConnect *dlg = NULL;
701 // if sshTunnel is true then we have to hide 'Stored Password' option
702 if(sshTunnel)
703 dlg = new dlgConnect(NULL, txt, false);
704 else
705 dlg = new dlgConnect(form, txt, GetStorePwd());
706
707 dlg->SetWindowStyleFlag( dlg->GetWindowStyleFlag() | wxSTAY_ON_TOP);
708
709 switch (dlg->Go())
710 {
711 case wxID_OK:
712 // Give the UI a chance to redraw
713 wxSafeYield();
714 wxMilliSleep(100);
715 wxSafeYield();
716 break;
717 case wxID_CANCEL:
718 case -1:
719 // Give the UI a chance to redraw
720 wxSafeYield();
721 wxMilliSleep(100);
722 wxSafeYield();
723 return PGCONN_ABORTED;
724 default:
725 // Give the UI a chance to redraw
726 wxSafeYield();
727 wxMilliSleep(100);
728 wxSafeYield();
729 wxLogError(__("Couldn't create a connection dialogue!"));
730 return PGCONN_BAD;
731 }
732
733 iSetStorePwd(dlg->GetStorePwd());
734 password = dlg->GetPassword();
735 storePassword = true;
736 if(dlg)
737 {
738 delete dlg;
739 dlg = NULL;
740 }
741 }
742 }
743 else
744 iSetPassword(pwd);
745
746 form->StartMsg(_("Connecting to database"));
747
748 wxString host;
749 int iPort;
750 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
751 if(sshTunnel)
752 {
753 //Ask Tunnel Password
754 if(askTunnelPassword)
755 {
756 wxString txt;
757 if(GetAuthModePwd())
758 {
759 txt.Printf(_("Please enter the SSH tunnel password for user %s\non server %s"), tunnelUserName.c_str(), tunnelHost.c_str());
760 }
761 else
762 {
763 txt.Printf(_("Please enter the pass phrase for the identity file\n%s"), identityFile.c_str());
764 }
765 dlgConnect dlg(NULL, txt, false);
766
767 switch (dlg.Go())
768 {
769 case wxID_OK:
770 // Give the UI a chance to redraw
771 wxSafeYield();
772 wxMilliSleep(100);
773 wxSafeYield();
774 tunnelPassword = dlg.GetPassword();
775 break;
776 case wxID_CANCEL:
777 case -1:
778 default:
779 // Give the UI a chance to redraw
780 wxSafeYield();
781 wxMilliSleep(100);
782 wxSafeYield();
783 form->EndMsg(false);
784 return PGCONN_ABORTED;
785 }
786 }
787 // Create SSH Tunnel if required
788 if(!tunnelObj)
789 {
790 if(!createSSHTunnel())
791 {
792 form->EndMsg(false);
793 return PGCONN_SSHTUNNEL_ERROR;
794 }
795 }
796
797 host = local_listenhost;
798 iPort = local_listenport;
799 }
800 else
801 #endif
802 {
803 host = GetName();
804 iPort = port;
805 }
806
807 if (database.IsEmpty())
808 {
809 conn = new pgConn(host, service, hostaddr, DEFAULT_PG_DATABASE, username, password, iPort, rolename, ssl, 0, appearanceFactory->GetLongAppName() + _(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
810 if (conn->GetStatus() == PGCONN_OK)
811 database = DEFAULT_PG_DATABASE;
812 else if (conn->GetStatus() == PGCONN_BAD && conn->GetLastError().Find(
813 wxT("database \"") DEFAULT_PG_DATABASE wxT("\" does not exist")) >= 0)
814 {
815 delete conn;
816 conn = new pgConn(host, service, hostaddr, wxT("template1"), username, password, iPort, rolename, ssl, 0, appearanceFactory->GetLongAppName() + _(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
817 if (conn && conn->GetStatus() == PGCONN_OK)
818 database = wxT("template1");
819 }
820 }
821 else
822 {
823 conn = new pgConn(host, service, hostaddr, database, username, password, iPort, rolename, ssl, 0, appearanceFactory->GetLongAppName() + _(" - Browser"), sslcert, sslkey, sslrootcert, sslcrl, sslcompression);
824 if (!conn)
825 {
826 form->EndMsg(false);
827 wxLogError(__("Couldn't create a connection object!"));
828 return PGCONN_BAD;
829 }
830 }
831 }
832 int status = conn->GetStatus();
833 if (status == PGCONN_OK)
834 {
835 dbOid = conn->GetDbOid();
836
837 // Check the server version
838 if (conn->GetIsGreenplum())
839 {
840 // Greenplum HAWQ (SQL on Hadoop) is not supported by this pgAdmin version
841 if (conn->GetIsHawq())
842 {
843 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."),
844 appearanceFactory->GetLongAppName().c_str(),
845 appearanceFactory->GetLongAppName().c_str());
846 }
847 else
848 {
849 // Check for Greenplum specific version
850 // Greenplum always shows PG version "8.2.15" for now
851 // this might change once the merge with recent PG versions makes progress
852 // therefore also check for the max version
853 if (!(conn->BackendMinimumVersion(GP_MIN_VERSION_N >> 8, GP_MIN_VERSION_N & 0x00FF)) ||
854 (conn->BackendMinimumVersion(GP_MAX_VERSION_N >> 8, (GP_MAX_VERSION_N & 0x00FF) + 1)))
855 {
856 if (GP_MIN_VERSION_N == GP_MAX_VERSION_N)
857 {
858 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."),
859 appearanceFactory->GetLongAppName().c_str(),
860 appearanceFactory->GetLongAppName().c_str(),
861 wxString(GP_MIN_VERSION_T).c_str());
862 }
863 else
864 {
865 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."),
866 appearanceFactory->GetLongAppName().c_str(),
867 appearanceFactory->GetLongAppName().c_str(),
868 wxString(GP_MIN_VERSION_T).c_str(),
869 wxString(GP_MAX_VERSION_T).c_str());
870 }
871 }
872 }
873 }
874 else
875 {
876 if (!(conn->BackendMinimumVersion(SERVER_MIN_VERSION_N >> 8, SERVER_MIN_VERSION_N & 0x00FF)) ||
877 (conn->BackendMinimumVersion(SERVER_MAX_VERSION_N >> 8, (SERVER_MAX_VERSION_N & 0x00FF) + 1)))
878 {
879 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."),
880 appearanceFactory->GetLongAppName().c_str(),
881 appearanceFactory->GetLongAppName().c_str(),
882 wxString(SERVER_MIN_VERSION_T).c_str(),
883 wxString(SERVER_MAX_VERSION_T).c_str());
884 }
885 }
886
887 connected = true;
888 bool hasUptime = false;
889
890 wxString sql = wxT("SELECT usecreatedb, usesuper");
891 if (conn->BackendMinimumVersion(8, 1))
892 {
893 hasUptime = true;
894 sql += wxT(", CASE WHEN usesuper THEN pg_postmaster_start_time() ELSE NULL END as upsince");
895 }
896 else if (conn->HasFeature(FEATURE_POSTMASTER_STARTTIME))
897 {
898 hasUptime = true;
899 sql += wxT(", CASE WHEN usesuper THEN pg_postmaster_starttime() ELSE NULL END as upsince");
900 }
901 if (conn->BackendMinimumVersion(8, 4))
902 {
903 sql += wxT(", CASE WHEN usesuper THEN pg_conf_load_time() ELSE NULL END as confloadedsince");
904 }
905 if (conn->BackendMinimumVersion(8, 5))
906 {
907 sql += wxT(", CASE WHEN usesuper THEN pg_is_in_recovery() ELSE NULL END as inrecovery");
908 if (conn->BackendMinimumVersion(10, 0))
909 {
910 sql += wxT(", CASE WHEN usesuper THEN pg_last_wal_receive_lsn() ELSE NULL END as receiveloc");
911 sql += wxT(", CASE WHEN usesuper THEN pg_last_wal_replay_lsn() ELSE NULL END as replayloc");
912 }
913 else
914 {
915 sql += wxT(", CASE WHEN usesuper THEN pg_last_xlog_receive_location() ELSE NULL END as receiveloc");
916 sql += wxT(", CASE WHEN usesuper THEN pg_last_xlog_replay_location() ELSE NULL END as replayloc");
917 }
918 }
919 if (conn->BackendMinimumVersion(9, 1))
920 {
921 sql += wxT(", CASE WHEN usesuper THEN pg_last_xact_replay_timestamp() ELSE NULL END as replay_timestamp");
922 if (conn->BackendMinimumVersion(10, 0))
923 sql += wxT(", CASE WHEN usesuper AND pg_is_in_recovery() THEN pg_is_wal_replay_paused() ELSE NULL END as isreplaypaused");
924 else
925 sql += wxT(", CASE WHEN usesuper AND pg_is_in_recovery() THEN pg_is_xlog_replay_paused() ELSE NULL END as isreplaypaused");
926 }
927
928 pgSet *set = ExecuteSet(sql + wxT("\n FROM pg_user WHERE usename=current_user"));
929 if (set)
930 {
931 iSetCreatePrivilege(set->GetBool(wxT("usecreatedb")));
932 iSetSuperUser(set->GetBool(wxT("usesuper")));
933 if (hasUptime)
934 iSetUpSince(set->GetDateTime(wxT("upsince")));
935 if (conn->BackendMinimumVersion(8, 4))
936 iSetConfLoadedSince(set->GetDateTime(wxT("confloadedsince")));
937 if (conn->BackendMinimumVersion(8, 5))
938 {
939 iSetInRecovery(set->GetBool(wxT("inrecovery")));
940 iSetReplayLoc(set->GetVal(wxT("replayloc")));
941 iSetReceiveLoc(set->GetVal(wxT("receiveloc")));
942 }
943 if (conn->BackendMinimumVersion(9, 1))
944 {
945 iSetReplayTimestamp(set->GetVal(wxT("replay_timestamp")));
946 SetReplayPaused(set->GetBool(wxT("isreplaypaused")));
947 }
948 delete set;
949 }
950
951 if (conn->BackendMinimumVersion(8, 1))
952 {
953 set = ExecuteSet(wxT("SELECT rolcreaterole, rolcreatedb FROM pg_roles WHERE rolname = current_user;"));
954
955 if (set)
956 {
957 iSetCreatePrivilege(set->GetBool(wxT("rolcreatedb")));
958 iSetCreateRole(set->GetBool(wxT("rolcreaterole")));
959 delete set;
960 }
961 }
962 else
963 iSetCreateRole(false);
964
965 wxString version, allVersions;
966 version.Printf(wxT("%d.%d"), conn->GetMajorVersion(), conn->GetMinorVersion());
967 allVersions = settings->Read(wxT("Updates/pgsql-Versions"), wxEmptyString);
968 if (allVersions.Find(version) < 0)
969 {
970 if (!allVersions.IsEmpty())
971 allVersions += wxT(", ");
972 allVersions += version;
973 settings->Write(wxT("Updates/pgsql-Versions"), allVersions);
974 }
975 if (conn->IsSSLconnected())
976 settings->WriteBool(wxT("Updates/UseSSL"), true);
977
978 UpdateIcon(form->GetBrowser());
979 if (storePassword || forceStorePassword)
980 StorePassword();
981 }
982 else
983 {
984 connected = false;
985 }
986
987 form->EndMsg(connected && status == PGCONN_OK);
988
989 passwordValid = connected;
990 return status;
991 }
992
993
GetIdentifier() const994 wxString pgServer::GetIdentifier() const
995 {
996 wxString idstr;
997 if (GetService().IsEmpty())
998 {
999 if (GetName().IsEmpty())
1000 idstr.Printf(wxT("local:.s.PGSQL.%d"), port);
1001 else if (GetName().StartsWith(wxT("/")))
1002 idstr.Printf(wxT("local:%s/.s.PGSQL.%d"), GetName().c_str(), port);
1003 else
1004 idstr.Printf(wxT("%s:%d"), GetName().c_str(), port);
1005 }
1006 else
1007 idstr.Printf(_("service %s"), GetService().c_str());
1008 return idstr;
1009 }
1010
1011
GetVersionString()1012 wxString pgServer::GetVersionString()
1013 {
1014 if (connected)
1015 {
1016 if (ver.IsEmpty())
1017 ver = wxString(conn->GetVersionString());
1018 return ver;
1019 }
1020 else
1021 return wxEmptyString;
1022 }
1023
1024
GetVersionNumber()1025 wxString pgServer::GetVersionNumber()
1026 {
1027 if (connected)
1028 {
1029 if (versionNum.IsEmpty())
1030 {
1031 int major = 0, minor = 0;
1032 sscanf(GetVersionString().ToAscii(), "%*s %d.%d", &major, &minor);
1033 versionNum.Printf(wxT("%d.%d"), major, minor);
1034 }
1035
1036 }
1037 return versionNum;
1038 }
1039
1040
GetLastSystemOID()1041 OID pgServer::GetLastSystemOID()
1042 {
1043 if (connected)
1044 {
1045 if (lastSystemOID == 0)
1046 lastSystemOID = conn->GetLastSystemOID();
1047 return lastSystemOID;
1048 }
1049 else
1050 return 0;
1051 }
1052
1053
SetPassword(const wxString & newVal)1054 bool pgServer::SetPassword(const wxString &newVal)
1055 {
1056 wxString sql;
1057 sql.Printf(wxT("ALTER USER %s WITH ENCRYPTED PASSWORD %s;"), qtIdent(username).c_str(), qtDbString(conn->EncryptPassword(username, newVal)).c_str());
1058 bool executed = conn->ExecuteVoid(sql);
1059 if (executed)
1060 {
1061 password = newVal;
1062 StorePassword();
1063 return true;
1064 }
1065 else
1066 return false;
1067 }
1068
1069
GetLastError() const1070 wxString pgServer::GetLastError() const
1071 {
1072 wxString msg;
1073 if (conn)
1074 {
1075 if (error != wxT(""))
1076 {
1077 if (conn->GetLastError() != wxT(""))
1078 {
1079 msg.Printf(wxT("%s\n%s"), error.c_str(), conn->GetLastError().c_str());
1080 }
1081 else
1082 {
1083 msg = error;
1084 }
1085 }
1086 else
1087 {
1088 msg = conn->GetLastError();
1089 }
1090 }
1091 return msg;
1092 }
1093
1094
1095
ShowTreeDetail(ctlTree * browser,frmMain * form,ctlListView * properties,ctlSQLBox * sqlPane)1096 void pgServer::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
1097 {
1098 // Add child nodes if necessary
1099 if (GetConnected())
1100 {
1101 // Reset password menu option
1102 // form->fileMenu->Enable(MNU_PASSWORD, true);
1103
1104 if (!expandedKids)
1105 {
1106 expandedKids = true;
1107 // Log
1108
1109 wxLogInfo(wxT("Adding child object to server %s"), GetIdentifier().c_str());
1110
1111 if (settings->GetDisplayOption(_("Databases")))
1112 browser->AppendCollection(this, databaseFactory);
1113
1114 if (conn->BackendMinimumVersion(8, 0) && settings->GetDisplayOption(_("Tablespaces")))
1115 browser->AppendCollection(this, tablespaceFactory);
1116
1117 // Jobs
1118 // We only add the Jobs node if the appropriate objects are the initial DB.
1119 if (settings->GetDisplayOption(_("pgAgent Jobs")))
1120 {
1121 wxString exists = conn->ExecuteScalar(
1122 wxT("SELECT cl.oid FROM pg_class cl JOIN pg_namespace ns ON ns.oid=relnamespace\n")
1123 wxT(" WHERE relname='pga_job' AND nspname='pgagent'"));
1124
1125 if (!exists.IsNull())
1126 {
1127 exists = conn->ExecuteScalar(wxT("SELECT has_schema_privilege('pgagent', 'USAGE')"));
1128
1129 if (exists == wxT("t"))
1130 browser->AppendCollection(this, jobFactory);
1131 }
1132 }
1133
1134 if (conn->BackendMinimumVersion(8, 1))
1135 {
1136 if (settings->GetDisplayOption(_("Groups/group Roles")))
1137 browser->AppendCollection(this, groupRoleFactory);
1138 if (settings->GetDisplayOption(_("Users/login Roles")))
1139 browser->AppendCollection(this, loginRoleFactory);
1140 if (GetConnection()->GetIsGreenplum())
1141 {
1142 if (settings->GetDisplayOption(_("Resource Queues")))
1143 browser->AppendCollection(this, resQueueFactory);
1144 }
1145 }
1146 else
1147 {
1148 if (settings->GetDisplayOption(_("Groups/group Roles")))
1149 browser->AppendCollection(this, groupFactory);
1150 if (settings->GetDisplayOption(_("Users/login Roles")))
1151 browser->AppendCollection(this, userFactory);
1152 }
1153
1154 // Added Resource Group only for PPAS 9.4 and above
1155 if (conn->GetIsEdb() && conn->EdbMinimumVersion(9, 4))
1156 {
1157 if (settings->GetDisplayOption(_("Resource Groups")))
1158 browser->AppendCollection(this, resourceGroupFactory);
1159 }
1160
1161 autovacuumRunning = true;
1162
1163 wxString qry;
1164 if (conn->BackendMinimumVersion(8, 3))
1165 qry = wxT("SELECT setting FROM pg_settings WHERE name IN ('autovacuum', 'track_counts')");
1166 else
1167 qry = wxT("SELECT setting FROM pg_settings WHERE name IN ('autovacuum', 'stats_start_collector', 'stats_row_level')");
1168
1169 pgSetIterator set(conn, qry);
1170
1171 while (autovacuumRunning && set.RowsLeft())
1172 autovacuumRunning = set.GetBool(wxT("setting"));
1173 }
1174 }
1175
1176
1177 if (properties)
1178 {
1179 // Add the properties view columns
1180 CreateListColumns(properties);
1181
1182 // Display the Server properties
1183
1184 properties->AppendItem(_("Description"), GetDescription());
1185 properties->AppendItem(_("Service"), GetService());
1186 if (GetName().IsEmpty() || GetName().StartsWith(wxT("/")))
1187 {
1188 if (GetName().IsEmpty() && !GetService().IsEmpty())
1189 properties->AppendItem(_("Hostname"), wxEmptyString);
1190 else
1191 properties->AppendItem(_("Hostname"), wxT("local:") + GetName());
1192
1193 if (GetPort() == 0 && !GetService().IsEmpty())
1194 properties->AppendItem(_("Port"), wxEmptyString);
1195 else
1196 properties->AppendItem(_("Port"), (long)GetPort());
1197 }
1198 else
1199 {
1200 properties->AppendItem(_("Hostname"), GetName());
1201 properties->AppendItem(_("Host Address"), GetHostAddr());
1202 if (GetPort() == 0 && !GetService().IsEmpty())
1203 properties->AppendItem(_("Port"), wxEmptyString);
1204 else
1205 properties->AppendItem(_("Port"), (long)GetPort());
1206 #ifdef PG_SSL
1207 if (GetConnected())
1208 {
1209 properties->AppendItem(_("Encryption"),
1210 conn->IsSSLconnected() ? _("SSL encrypted") : _("not encrypted"));
1211 }
1212 else
1213 {
1214 if (ssl > 0)
1215 {
1216 wxString sslMode;
1217 switch (ssl)
1218 {
1219 case 1:
1220 sslMode = _("require");
1221 break;
1222 case 2:
1223 sslMode = _("prefer");
1224 break;
1225 case 3:
1226 sslMode = _("allow");
1227 break;
1228 case 4:
1229 sslMode = _("disable");
1230 break;
1231 case 5:
1232 sslMode = _("verify-ca");
1233 break;
1234 case 6:
1235 sslMode = _("verify-full");
1236 break;
1237 }
1238 properties->AppendItem(_("SSL Mode"), sslMode);
1239 }
1240 }
1241 properties->AppendItem(_("SSL Certificate File"), GetSSLCert());
1242 properties->AppendItem(_("SSL Key File"), GetSSLKey());
1243 properties->AppendItem(_("SSL Root Certificate File"), GetSSLRootCert());
1244 properties->AppendItem(_("SSL Certificate Revocation List"), GetSSLCrl());
1245 properties->AppendItem(_("SSL Compression?"), (GetSSLCompression() ? _("yes") : _("no")));
1246 #endif
1247 }
1248 if (!serviceId.IsEmpty())
1249 properties->AppendItem(_("Service ID"), serviceId);
1250
1251 properties->AppendItem(_("Maintenance database"), GetDatabaseName());
1252 properties->AppendItem(_("Username"), GetUsername());
1253 if (!GetRolename().IsEmpty())
1254 properties->AppendItem(_("Default role"), GetRolename());
1255
1256 properties->AppendYesNoItem(_("Store password?"), GetStorePwd());
1257 properties->AppendYesNoItem(_("Restore environment?"), GetRestore());
1258 if (GetConnected())
1259 {
1260 properties->AppendItem(_("Version string"), GetVersionString());
1261 properties->AppendItem(_("Version number"), GetVersionNumber());
1262 properties->AppendItem(_("Last system OID"), GetLastSystemOID());
1263 }
1264 properties->AppendYesNoItem(_("Connected?"), GetConnected());
1265 if (GetConnected())
1266 {
1267 if (GetUpSince().IsValid())
1268 properties->AppendItem(_("Up since"), GetUpSince());
1269 if (GetConfLoadedSince().IsValid())
1270 properties->AppendItem(_("Configuration loaded since"), GetConfLoadedSince());
1271 if (conn->BackendMinimumVersion(8, 1))
1272 properties->AppendItem(wxT("Autovacuum"), (autovacuumRunning ? _("running") : _("not running")));
1273 if (conn->BackendMinimumVersion(8, 5))
1274 {
1275 properties->AppendItem(_("In recovery"), (GetInRecovery() ? _("yes") : _("no")));
1276 properties->AppendItem(_("Last XLOG receive location"), GetReceiveLoc());
1277 properties->AppendItem(_("Last XLOG replay location"), GetReplayLoc());
1278 }
1279 if (conn->BackendMinimumVersion(9, 1))
1280 {
1281 properties->AppendItem(_("Last XACT replay timestamp"), GetReplayTimestamp());
1282 if (GetInRecovery())
1283 properties->AppendItem(_("Replay paused"), (GetReplayPaused() ? _("paused") : _("running")));
1284 else
1285 properties->AppendItem(_("Replay paused"), wxEmptyString);
1286 }
1287 }
1288 if (GetServerControllable())
1289 properties->AppendYesNoItem(_("Running?"), GetServerRunning());
1290
1291 if (!GetDbRestriction().IsEmpty())
1292 properties->AppendItem(_("DB restriction"), GetDbRestriction());
1293
1294 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1295 if(sshTunnel)
1296 {
1297 properties->AppendItem(_("SSH tunneling?"), (sshTunnel ? _("Yes") : _("No")));
1298 properties->AppendItem(_("Tunnel host"), GetTunnelHost());
1299 properties->AppendItem(_("Tunnel username"), GetTunnelUserName());
1300 properties->AppendItem(_("Authentication mode"), (GetAuthModePwd() ? _("Password") : _("Identity file")));
1301 if(!GetAuthModePwd())
1302 {
1303 properties->AppendItem(_("Identity file path"), GetIdentityFile());
1304 }
1305 }
1306 #endif
1307 }
1308
1309 if(!GetConnected())
1310 return;
1311
1312 if (form && GetCanHint() && !hintShown)
1313 {
1314 ShowHint(form, false);
1315 }
1316 }
1317
1318 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1319
createSSHTunnel()1320 bool pgServer::createSSHTunnel()
1321 {
1322 bool retVal = false;
1323
1324 tunnelObj = new CSSHTunnelThread(tunnelHost, GetName(), port, tunnelUserName, tunnelPassword, publicKeyFile,
1325 identityFile, authModePwd ? AUTH_PASSWORD : AUTH_PUBLICKEY, tunnelPort);
1326
1327 if(tunnelObj)
1328 {
1329 if(tunnelObj->Initialize())
1330 {
1331 if ( tunnelObj->Create() != wxTHREAD_NO_ERROR )
1332 {
1333 delete tunnelObj;
1334 tunnelObj = NULL;
1335 wxLogError(_("SSH Error: Unable to create SSH Tunnling Thread"));
1336 }
1337 else
1338 {
1339 if (tunnelObj->Run() != wxTHREAD_NO_ERROR )
1340 {
1341 delete tunnelObj;
1342 tunnelObj = NULL;
1343 wxLogError(_("SSH Error: Unable to start SSH Tunnling Thread"));
1344 }
1345
1346 SetLocalListenHost(tunnelObj->GetLocalListenIP());
1347 SetLocalListenPort(tunnelObj->GetLocalListenPort());
1348 retVal = true;
1349 }
1350 }
1351 else
1352 {
1353 delete tunnelObj;
1354 tunnelObj = NULL;
1355 }
1356 }
1357
1358 return retVal;
1359 }
1360 #endif
1361
ShowStatistics(frmMain * form,ctlListView * statistics)1362 void pgServer::ShowStatistics(frmMain *form, ctlListView *statistics)
1363 {
1364 if (conn)
1365 {
1366 wxString pidcol = GetConnection()->BackendMinimumVersion(9, 2) ? wxT("pid") : wxT("procpid");
1367 wxString querycol = GetConnection()->BackendMinimumVersion(9, 2) ? wxT("query") : wxT("current_query");
1368 wxString sql;
1369 wxString replication_query;
1370 if (conn->BackendMinimumVersion(10, 0))
1371 replication_query = wxT("state || ' (' || sent_lsn || ' sent, ' || write_lsn || ' written, ' || flush_lsn || ' flushed, ' || replay_lsn || ' applied)'");
1372 else
1373 replication_query = wxT("state || ' (' || sent_location || ' sent, ' || write_location || ' written, ' || flush_location || ' flushed, ' || replay_location || ' applied)'");
1374 wxLogInfo(wxT("Displaying statistics for server %s"), GetIdentifier().c_str());
1375
1376 // Add the statistics view columns
1377 statistics->ClearAll();
1378 statistics->AddColumn(wxT("PID"), 35);
1379 statistics->AddColumn(_("User"), 70);
1380 statistics->AddColumn(_("Database"), 70);
1381 if (GetConnection()->BackendMinimumVersion(8, 1))
1382 {
1383 statistics->AddColumn(_("Backend start"), 70);
1384 statistics->AddColumn(_("Client"), 70);
1385 }
1386 statistics->AddColumn(_("Current Query"), 300);
1387
1388 sql = wxT("SELECT ") + pidcol + wxT(" AS pid, usename, datname, backend_start, client_addr, ");
1389 if (GetConnection()->BackendMinimumVersion(9, 1))
1390 sql += wxT("client_hostname, ");
1391 sql += wxT("client_port, ") + querycol + wxT(" AS query FROM pg_stat_activity\n");
1392 if (GetConnection()->BackendMinimumVersion(9, 1))
1393 {
1394 sql += wxT("UNION\n")
1395 wxT("SELECT ") + pidcol + wxT(", usename, '' AS datname, backend_start, client_addr, client_hostname, client_port, ")
1396 + replication_query + wxT(" AS query FROM pg_stat_replication");
1397 }
1398
1399 pgSet *stats = ExecuteSet(sql);
1400 if (stats)
1401 {
1402 int pos = 0;
1403 while (!stats->Eof())
1404 {
1405 statistics->InsertItem(pos, stats->GetVal(wxT("pid")), 0);
1406 int colpos = 1;
1407 statistics->SetItem(pos, colpos++, stats->GetVal(wxT("usename")));
1408 statistics->SetItem(pos, colpos++, stats->GetVal(wxT("datname")));
1409 if (GetConnection()->BackendMinimumVersion(8, 1))
1410 {
1411 statistics->SetItem(pos, colpos++, stats->GetVal(wxT("backend_start")));
1412 wxString client;
1413 if (GetConnection()->BackendMinimumVersion(9, 1) && !stats->GetVal(wxT("client_hostname")).IsEmpty())
1414 client = stats->GetVal(wxT("client_hostname")) + wxT(":") + stats->GetVal(wxT("client_port"));
1415 else
1416 client = stats->GetVal(wxT("client_addr")) + wxT(":") + stats->GetVal(wxT("client_port"));
1417 if (client == wxT(":-1"))
1418 client = _("local pipe");
1419 statistics->SetItem(pos, colpos++, client);
1420 }
1421 statistics->SetItem(pos, colpos++, stats->GetVal(wxT("query")));
1422
1423 stats->MoveNext();
1424 pos++;
1425 }
1426
1427 delete stats;
1428 }
1429 }
1430 }
1431
ShowDependencies(frmMain * form,ctlListView * Dependencies,const wxString & wh)1432 void pgServer::ShowDependencies(frmMain *form, ctlListView *Dependencies, const wxString &wh)
1433 {
1434 }
1435
1436
ShowDependents(frmMain * form,ctlListView * referencedBy,const wxString & wh)1437 void pgServer::ShowDependents(frmMain *form, ctlListView *referencedBy, const wxString &wh)
1438 {
1439 }
1440
1441
ReloadConfiguration()1442 bool pgServer::ReloadConfiguration()
1443 {
1444 wxString sql = wxT("select pg_reload_conf()");
1445 return conn->ExecuteVoid(sql);
1446 }
1447
1448
PauseReplay()1449 bool pgServer::PauseReplay()
1450 {
1451 SetReplayPaused(true);
1452 wxString sql;
1453 if (conn->BackendMinimumVersion(10, 0))
1454 sql = wxT("SELECT pg_wal_replay_pause()");
1455 else
1456 sql = wxT("SELECT pg_xlog_replay_pause()");
1457 return conn->ExecuteVoid(sql);
1458 }
1459
1460
ResumeReplay()1461 bool pgServer::ResumeReplay()
1462 {
1463 SetReplayPaused(false);
1464 wxString sql;
1465 if (conn->BackendMinimumVersion(10, 0))
1466 sql = wxT("SELECT pg_wal_replay_resume()");
1467 else
1468 sql = wxT("SELECT pg_xlog_replay_resume()");
1469 return conn->ExecuteVoid(sql);
1470 }
1471
1472
AddNamedRestorePoint()1473 bool pgServer::AddNamedRestorePoint()
1474 {
1475 wxString namedrestorepoint = wxGetTextFromUser(_("Enter the name of the restore point to add"), _("Restore point name"));
1476 if (!namedrestorepoint.IsEmpty())
1477 {
1478 wxString sql = wxT("select pg_create_restore_point(") + qtDbString(namedrestorepoint) + wxT(")");
1479 return conn->ExecuteVoid(sql);
1480 }
1481 return false;
1482 }
1483
pgServerCollection(pgaFactory * factory)1484 pgServerCollection::pgServerCollection(pgaFactory *factory)
1485 : pgCollection(factory)
1486 {
1487 }
1488
1489
GetTranslatedMessage(int kindOfMessage) const1490 wxString pgServerCollection::GetTranslatedMessage(int kindOfMessage) const
1491 {
1492 wxString message = wxEmptyString;
1493
1494 switch (kindOfMessage)
1495 {
1496 case RETRIEVINGDETAILS:
1497 message = _("Retrieving details on servers");
1498 break;
1499 case REFRESHINGDETAILS:
1500 message = _("Refreshing servers");
1501 break;
1502 case OBJECTSLISTREPORT:
1503 message = _("Servers list report");
1504 break;
1505 }
1506
1507 return message;
1508 }
1509
1510
pgServerObjCollection(pgaFactory * factory,pgServer * sv)1511 pgServerObjCollection::pgServerObjCollection(pgaFactory *factory, pgServer *sv)
1512 : pgCollection(factory)
1513 {
1514 server = sv;
1515 }
1516
1517
CanCreate()1518 bool pgServerObjCollection::CanCreate()
1519 {
1520 // We can't create resource queues on Greenplum yet.
1521 if (IsCollectionForType(GP_RESOURCE_QUEUE))
1522 return false;
1523
1524 // We can't create tablespaces on Greenplum
1525 if (server->GetConnection()->GetIsGreenplum() && IsCollectionForType(PGM_TABLESPACE))
1526 return false;
1527
1528 if (server->GetMetaType() == PGM_DATABASE)
1529 return (GetServer()->GetCreatePrivilege() || GetServer()->GetSuperUser());
1530 else
1531 {
1532 if (server->GetConnection()->BackendMinimumVersion(8, 1) && GetMetaType() == PGM_ROLE)
1533 return (server->GetCreateRole() || server->GetSuperUser());
1534 else if (server->GetConnection()->BackendMinimumVersion(8, 1) && GetMetaType() == PGM_DATABASE)
1535 return (server->GetCreatePrivilege() || server->GetSuperUser());
1536 else if (GetMetaType() == PGM_JOB)
1537 return true;
1538 else
1539 return server->GetSuperUser();
1540 }
1541 }
1542
1543
CreateObjects(pgCollection * obj,ctlTree * browser,const wxString & restr)1544 pgObject *pgServerFactory::CreateObjects(pgCollection *obj, ctlTree *browser, const wxString &restr)
1545 {
1546 wxTreeItemId groupitem, serveritem;
1547 wxTreeItemIdValue groupcookie;
1548 bool found;
1549
1550 long numServers = settings->Read(wxT("Servers/Count"), 0L);
1551
1552 long loop, port, ssl = 0;
1553 wxString key, servername, hostaddr, description, service, database, username, lastDatabase, lastSchema;
1554 wxString storePwd, rolename, restore, serviceID, discoveryID, dbRestriction, colour;
1555 wxString group, sslcert, sslkey, sslrootcert, sslcrl, sslcompression;
1556
1557 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1558 wxString sshTunnel, authModePwd, tunnelHost, tunnelUserName, tunnelPassword, publicKeyFile, identityFile;
1559 long tunnelPort;
1560 #endif
1561 pgServer *server = 0;
1562
1563 wxArrayString discoveredServers;
1564
1565 // Get the hostname for later...
1566 char buf[255];
1567 gethostname(buf, 255);
1568 wxString hostname = wxString(buf, wxConvUTF8);
1569
1570 //wxLogError(wxT("Loading previously registered servers"));
1571 wxLogInfo(wxT("Loading previously registered servers"));
1572
1573 for (loop = 1; loop <= numServers; ++loop)
1574 {
1575 key.Printf(wxT("Servers/%d/"), (int)loop);
1576
1577 settings->Read(key + wxT("Server"), &servername, wxEmptyString);
1578 settings->Read(key + wxT("HostAddr"), &hostaddr, wxEmptyString);
1579 settings->Read(key + wxT("Service"), &service, wxEmptyString);
1580 settings->Read(key + wxT("ServiceID"), &serviceID, wxEmptyString);
1581 settings->Read(key + wxT("DiscoveryID"), &discoveryID, serviceID);
1582 settings->Read(key + wxT("Description"), &description, wxEmptyString);
1583 settings->Read(key + wxT("StorePwd"), &storePwd, wxEmptyString);
1584 settings->Read(key + wxT("Rolename"), &rolename, wxEmptyString);
1585 settings->Read(key + wxT("Restore"), &restore, wxT("true"));
1586 settings->Read(key + wxT("Port"), &port, 0);
1587 settings->Read(key + wxT("Database"), &database, wxEmptyString);
1588 settings->Read(key + wxT("Username"), &username, wxEmptyString);
1589 settings->Read(key + wxT("LastDatabase"), &lastDatabase, wxEmptyString);
1590 settings->Read(key + wxT("LastSchema"), &lastSchema, wxEmptyString);
1591 settings->Read(key + wxT("DbRestriction"), &dbRestriction, wxEmptyString);
1592 settings->Read(key + wxT("Colour"), &colour, wxEmptyString);
1593 settings->Read(key + wxT("Group"), &group, wxT("Servers"));
1594 settings->Read(key + wxT("SSLCert"), &sslcert, wxEmptyString);
1595 settings->Read(key + wxT("SSLKey"), &sslkey, wxEmptyString);
1596 settings->Read(key + wxT("SSLRootCert"), &sslrootcert, wxEmptyString);
1597 settings->Read(key + wxT("SSLCrl"), &sslcrl, wxEmptyString);
1598 settings->Read(key + wxT("SSLCompression"), &sslcompression, wxT("true"));
1599 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1600 settings->Read(key + wxT("SSHTunnel"), &sshTunnel, wxT("false"));
1601 settings->Read(key + wxT("TunnelHost"), &tunnelHost, wxEmptyString);
1602 settings->Read(key + wxT("TunnelUserName"), &tunnelUserName, wxEmptyString);
1603 settings->Read(key + wxT("TunnelModePwd"), &authModePwd, wxT("true"));
1604 settings->Read(key + wxT("PublicKeyFile"), &publicKeyFile, wxEmptyString);
1605 settings->Read(key + wxT("IdentityFile"), &identityFile, wxEmptyString);
1606 settings->Read(key + wxT("TunnelPort"), &tunnelPort, DEFAULT_SSH_PORT);
1607 #endif
1608 // Sanitize the colour
1609 colour = colour.Trim();
1610
1611 if (!colour.IsEmpty())
1612 {
1613 wxColour cColour;
1614
1615 if (cColour.Set(colour))
1616 colour = cColour.GetAsString(wxC2S_HTML_SYNTAX);
1617 else
1618 colour = wxEmptyString;
1619 }
1620
1621 if (colour.IsEmpty())
1622 {
1623 wxColour cColour;
1624 cColour.Set(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW).GetAsString(wxC2S_HTML_SYNTAX));
1625 colour = cColour.GetAsString(wxC2S_HTML_SYNTAX);
1626 }
1627
1628 // SSL mode
1629 #ifdef PG_SSL
1630 settings->Read(key + wxT("SSL"), &ssl, 0);
1631 #endif
1632
1633 // Sanitize the group
1634 if (group.IsEmpty())
1635 {
1636 group = _("Servers");
1637 }
1638
1639 // Add the Server node
1640 #if defined(HAVE_OPENSSL_CRYPTO) || defined(HAVE_GCRYPT)
1641 server = new pgServer(servername, hostaddr, description, service, database, username, port, StrToBool(storePwd), rolename, StrToBool(restore), ssl,
1642 colour, group, StrToBool(sshTunnel), tunnelHost, tunnelUserName, StrToBool(authModePwd), tunnelPassword, publicKeyFile, identityFile, tunnelPort);
1643 #else
1644 server = new pgServer(servername, hostaddr, description, service, database, username, port, StrToBool(storePwd), rolename, StrToBool(restore), ssl,
1645 colour, group);
1646 #endif
1647 server->iSetLastDatabase(lastDatabase);
1648 server->iSetLastSchema(lastSchema);
1649 server->iSetService(service);
1650 server->iSetServiceID(serviceID);
1651 server->iSetDiscoveryID(discoveryID);
1652 server->iSetDiscovered(false);
1653 server->iSetDbRestriction(dbRestriction);
1654 server->iSetServerIndex(loop);
1655 server->SetSSLCert(sslcert);
1656 server->SetSSLKey(sslkey);
1657 server->SetSSLRootCert(sslrootcert);
1658 server->SetSSLCrl(sslcrl);
1659 server->iSetSSLCompression(StrToBool(sslcompression));
1660
1661 found = false;
1662 if (browser->ItemHasChildren(obj->GetId()))
1663 {
1664 groupitem = browser->GetFirstChild(obj->GetId(), groupcookie);
1665 while (!found && groupitem)
1666 {
1667 if (browser->GetItemText(groupitem).StartsWith(group))
1668 found = true;
1669 else
1670 groupitem = browser->GetNextChild(obj->GetId(), groupcookie);
1671 }
1672 }
1673
1674 if (!found)
1675 {
1676 groupitem = browser->AppendItem(obj->GetId(), group, obj->GetIconId());
1677 }
1678
1679 serveritem = browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1680 browser->SortChildren(groupitem);
1681 if (!server->GetColour().IsEmpty())
1682 browser->SetItemBackgroundColour(serveritem, wxColour(server->GetColour()));
1683
1684 // Note if we're reloading a discovered server
1685 if (!discoveryID.IsEmpty())
1686 discoveredServers.Add(discoveryID);
1687 }
1688
1689 group = _("Servers");
1690
1691 #ifdef __WXMSW__
1692
1693 // Add local servers. Will currently only work on Win32 with >= BETA3
1694 // of the Win32 PostgreSQL installer.
1695 wxLogInfo(wxT("Loading servers registered on the local machine"));
1696
1697 pgRegKey::PGREGWOWMODE wowMode = pgRegKey::PGREG_WOW_DEFAULT;
1698 if (::wxIsPlatform64Bit())
1699 wowMode = pgRegKey::PGREG_WOW32;
1700
1701 pgRegKey *pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
1702
1703 if (pgKey == NULL)
1704 {
1705 wowMode = pgRegKey::PGREG_WOW64;
1706 pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
1707 }
1708
1709 while (pgKey != NULL)
1710 {
1711 pgRegKey *svcKey = NULL;
1712 wxString svcName;
1713 long cookie = 0;
1714 DWORD tmpport = 0;
1715 bool flag = false;
1716
1717 flag = pgKey->GetFirstKey(svcKey, cookie);
1718
1719 while (flag != false)
1720 {
1721 svcName = svcKey->GetKeyName();
1722 // On Windows, the discovery ID is always the service name.
1723 // Only load the server if we didn't load it with all the others.
1724 if (discoveredServers.Index(svcName, false) < 0)
1725 {
1726 servername = wxT("localhost");
1727 database = wxEmptyString;
1728 svcKey->QueryValue(wxT("Display Name"), description);
1729 svcKey->QueryValue(wxT("Database Superuser"), username);
1730 svcKey->QueryValue(wxT("Port"), &tmpport);
1731
1732 // Add the Server node
1733 server = new pgServer(servername, wxEmptyString, description, wxEmptyString, database, username, (long)tmpport, false, wxEmptyString, false);
1734 server->iSetDiscoveryID(svcName);
1735 server->iSetDiscovered(true);
1736 server->iSetServiceID(svcName);
1737 server->iSetGroup(group);
1738
1739 found = false;
1740
1741 if (browser->ItemHasChildren(browser->GetRootItem()))
1742 {
1743 groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1744 while (!found && groupitem)
1745 {
1746 if (browser->GetItemText(groupitem).StartsWith(group))
1747 found = true;
1748 else
1749 groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1750 }
1751 }
1752
1753 if (!found)
1754 {
1755 groupitem = browser->AppendItem(browser->GetRootItem(), group, obj->GetIconId());
1756 browser->SortChildren(browser->GetRootItem());
1757 }
1758
1759 browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1760 browser->SortChildren(groupitem);
1761 }
1762 // Release the current registry key
1763 delete svcKey;
1764
1765 // Get the next one...
1766 flag = pgKey->GetNextKey(svcKey, cookie);
1767 }
1768
1769 /* Release current registry key */
1770 delete pgKey;
1771 pgKey = NULL;
1772 /*
1773 * If wowMode is equal to WOW32, that means this machine is a 64 bit machine and we need to read now 64 bit registry
1774 */
1775 if (wowMode == pgRegKey::PGREG_WOW32)
1776 {
1777 wowMode = pgRegKey::PGREG_WOW64;
1778 pgKey = pgRegKey::OpenRegKey(HKEY_LOCAL_MACHINE, wxT("Software\\PostgreSQL\\Services"), pgRegKey::PGREG_READ, wowMode);
1779 }
1780 }
1781 #endif // __WXMSW__
1782
1783 // Add local servers on non-Win32 platforms (on Win32, they will be picked up above)
1784 #ifndef WIN32
1785
1786 // On Unix/Mac, the discovery ID can be anything. We use the PostgreSQL
1787 // package config filename if it's present, as that is the only thing vaguely
1788 // discoverable and unique to a given installation. We can do the same for
1789 // other distros in the future if they drop a suitable file someplace.
1790 // Look for any files that match the basic postgres*.ini pattern.
1791
1792 wxLogInfo(wxT("Loading servers registered on the local machine"));
1793
1794 if (wxFile::Exists(REGISTRY_FILE))
1795 {
1796 wxString version, locale;
1797 long cookie;
1798
1799 wxFileInputStream fst(REGISTRY_FILE);
1800 wxFileConfig *cnf = new wxFileConfig(fst);
1801
1802 // PostgreSQL servers
1803 cnf->SetPath(wxT("/PostgreSQL"));
1804 bool flag = cnf->GetFirstGroup(version, cookie);
1805 while (flag)
1806 {
1807 // If there is no Version entry, this is probably an uninstalled server
1808 if (cnf->Read(version + wxT("/Version"), wxEmptyString) != wxEmptyString)
1809 {
1810 // Only load this server if we haven't read it from the pgAdmin config
1811 if (discoveredServers.Index(cnf->GetPath() + wxT("/") + version, false) < 0)
1812 {
1813
1814 // Basic details
1815 servername = wxT("localhost");
1816 cnf->Read(version + wxT("/Description"), &description, wxT("PostgreSQL ") + version);
1817 cnf->Read(version + wxT("/Superuser"), &username, wxEmptyString);
1818 cnf->Read(version + wxT("/Port"), &port, 0);
1819
1820 // Add the item, if it looks sane
1821 if (port != 0 && username != wxEmptyString)
1822 {
1823 server = new pgServer(servername, wxEmptyString, description, wxEmptyString, wxT("postgres"), username, port, false, rolename, 0);
1824 server->iSetDiscoveryID(cnf->GetPath() + wxT("/") + version);
1825 server->iSetDiscovered(true);
1826 server->iSetGroup(group);
1827 found = false;
1828 if (browser->ItemHasChildren(browser->GetRootItem()))
1829 {
1830 groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1831 while (!found && groupitem)
1832 {
1833 if (browser->GetItemText(groupitem).StartsWith(group))
1834 found = true;
1835 else
1836 groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1837 }
1838 }
1839
1840 if (!found)
1841 {
1842 groupitem = browser->AppendItem(browser->GetRootItem(), group, obj->GetIconId());
1843 browser->SortChildren(browser->GetRootItem());
1844 }
1845
1846 browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1847 browser->SortChildren(groupitem);
1848 }
1849 }
1850 }
1851
1852 flag = cnf->GetNextGroup(version, cookie);
1853 }
1854
1855 // EnterpriseDB servers
1856 cnf->SetPath(wxT("/EnterpriseDB"));
1857 flag = cnf->GetFirstGroup(version, cookie);
1858 while (flag)
1859 {
1860 // If there is no Version entry, this is probably an uninstalled server
1861 if (cnf->Read(version + wxT("/Version"), wxEmptyString) != wxEmptyString)
1862 {
1863 // Only load this server if we haven't read it from the pgAdmin config
1864 if (discoveredServers.Index(cnf->GetPath() + wxT("/") + version, false) < 0)
1865 {
1866
1867 // Basic details
1868 servername = wxT("localhost");
1869 cnf->Read(version + wxT("/Description"), &description, wxT("EnterpriseDB ") + version);
1870 cnf->Read(version + wxT("/Superuser"), &username, wxEmptyString);
1871 cnf->Read(version + wxT("/Port"), &port, 0);
1872
1873 // Add the item, if it looks sane
1874 if (port != 0 && username != wxEmptyString)
1875 {
1876 server = new pgServer(servername, wxEmptyString, description, wxEmptyString, wxT("edb"), username, port, false, rolename, 0);
1877 server->iSetDiscoveryID(cnf->GetPath() + wxT("/") + version);
1878 server->iSetDiscovered(true);
1879 groupitem = browser->GetFirstChild(obj->GetId(), groupcookie);
1880 if (!groupitem.IsOk())
1881 groupitem = browser->AppendItem(obj->GetId(), group, obj->GetIconId());
1882 browser->AppendItem(groupitem, server->GetFullName(), server->GetIconId(), -1, server);
1883 }
1884 }
1885 }
1886
1887 flag = cnf->GetNextGroup(version, cookie);
1888 }
1889
1890 delete cnf;
1891 browser->SortChildren(obj->GetId());
1892 }
1893
1894 #endif // !WIN32
1895
1896 return server;
1897 }
1898
1899 #include "images/servers.pngc"
1900 #include "images/server.pngc"
1901 #include "images/server-sm.pngc"
1902 #include "images/serverbad.pngc"
1903 #include "images/serverbad-sm.pngc"
1904
pgServerFactory()1905 pgServerFactory::pgServerFactory()
1906 : pgaFactory(__("Server"), __("New Server Registration"), __("Create a new Server registration."), server_png_img, server_sm_png_img)
1907 {
1908 metaType = PGM_SERVER;
1909 closedId = addIcon(serverbad_png_img);
1910 smallClosedId = addIcon(serverbad_sm_png_img);
1911 }
1912
CreateCollection(pgObject * obj)1913 pgCollection *pgServerFactory::CreateCollection(pgObject *obj)
1914 {
1915 return new pgCollection(GetCollectionFactory());
1916 }
1917
CreateCollection(pgObject * obj)1918 pgCollection *pgServerObjFactory::CreateCollection(pgObject *obj)
1919 {
1920 return new pgServerObjCollection(GetCollectionFactory(), (pgServer *)obj);
1921 }
1922
1923 pgServerFactory serverFactory;
1924 static pgaCollectionFactory cf(&serverFactory, __("Servers"), servers_png_img);
1925
1926 #include "images/connect.pngc"
addServerFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)1927 addServerFactory::addServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
1928 {
1929 mnu->Append(id, _("&Add Server..."), _("Add a connection to a server."));
1930 toolbar->AddTool(id, _("Add Server"), *connect_png_bmp, _("Add a connection to a server."), wxITEM_NORMAL);
1931 }
1932
1933
StartDialog(frmMain * form,pgObject * obj)1934 wxWindow *addServerFactory::StartDialog(frmMain *form, pgObject *obj)
1935 {
1936 int rc = PGCONN_BAD;
1937
1938 dlgServer dlg(&serverFactory, form, 0);
1939 dlg.CenterOnParent();
1940
1941 while (rc != PGCONN_OK)
1942 {
1943 if (dlg.GoNew() != wxID_OK)
1944 return 0;
1945
1946 pgServer *server = (pgServer *)dlg.CreateObject(0);
1947
1948 if (dlg.GetTryConnect())
1949 {
1950 wxBusyInfo waiting(wxString::Format(_("Connecting to server %s (%s:%d)"),
1951 server->GetDescription().c_str(), server->GetName().c_str(), server->GetPort()), form);
1952
1953 // Give the UI a chance to redraw
1954 wxSafeYield();
1955 wxMilliSleep(100);
1956 wxSafeYield();
1957
1958 rc = server->Connect(form, false, dlg.GetPassword(), true);
1959 }
1960 else
1961 {
1962 rc = PGCONN_OK;
1963 server->InvalidatePassword();
1964 }
1965 switch (rc)
1966 {
1967 case PGCONN_OK:
1968 {
1969 int icon;
1970 ctlTree *browser = form->GetBrowser();
1971 wxTreeItemId groupitem, parentitem;
1972 wxTreeItemIdValue groupcookie;
1973 int total;
1974 wxString label;
1975
1976 if (server->GetConnected())
1977 icon = serverFactory.GetIconId();
1978 else
1979 icon = serverFactory.GetClosedIconId();
1980 wxLogInfo(wxT("pgServer object initialised as required."));
1981
1982 // Add the new server in its group
1983 wxString group = server->GetGroup();
1984 if (group.Length() == 0)
1985 group = _("Servers");
1986
1987 // Get the parent group
1988 groupitem = browser->GetFirstChild(browser->GetRootItem(), groupcookie);
1989 while (!parentitem && groupitem)
1990 {
1991 if (browser->GetItemText(groupitem).StartsWith(group))
1992 parentitem = groupitem;
1993 groupitem = browser->GetNextChild(browser->GetRootItem(), groupcookie);
1994 }
1995
1996 if (!parentitem)
1997 parentitem = browser->AppendItem(browser->GetRootItem(), group, icon, -1);
1998
1999 browser->AppendItem(parentitem, server->GetFullName(), icon, -1, server);
2000 browser->SortChildren(parentitem);
2001 browser->Expand(parentitem);
2002
2003 total = browser->GetChildrenCount(parentitem, false);
2004 label = group + wxT(" (") + NumToStr((long)total) + wxT(")");
2005 browser->SetItemText(parentitem, label);
2006
2007 form->StoreServers();
2008 return 0;
2009 }
2010 case PGCONN_DNSERR:
2011 {
2012 delete server;
2013 break;
2014 }
2015 case PGCONN_BAD:
2016 case PGCONN_BROKEN:
2017 {
2018 form->ReportConnError(server);
2019 delete server;
2020
2021 break;
2022 }
2023 case PGCONN_SSHTUNNEL_ERROR:
2024 {
2025 delete server;
2026 break;
2027 }
2028 default:
2029 {
2030 wxLogInfo(__("pgServer object didn't initialise because the user aborted."));
2031 delete server;
2032 return 0;
2033 }
2034 }
2035 }
2036 return 0;
2037 }
2038
2039
startServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2040 startServiceFactory::startServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2041 {
2042 mnu->Append(id, _("Start Service"), _("Start PostgreSQL Service"));
2043 }
2044
2045
StartDialog(frmMain * form,pgObject * obj)2046 wxWindow *startServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2047 {
2048 pgServer *server = (pgServer *)obj;
2049 form->StartMsg(_("Starting Service"));
2050 bool rc = server->StartService();
2051 if (rc)
2052 form->execSelChange(server->GetId(), true);
2053 form->EndMsg(rc);
2054 return 0;
2055 }
2056
2057
CheckEnable(pgObject * obj)2058 bool startServiceFactory::CheckEnable(pgObject *obj)
2059 {
2060 if (obj && obj->IsCreatedBy(serverFactory))
2061 {
2062 pgServer *server = (pgServer *)obj;
2063 return server->GetServerControllable() && !server->GetServerRunning();
2064 }
2065 return false;
2066 }
2067
2068
stopServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2069 stopServiceFactory::stopServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2070 {
2071 mnu->Append(id, _("Stop Service"), _("Stop PostgreSQL Service"));
2072 }
2073
2074
StartDialog(frmMain * form,pgObject * obj)2075 wxWindow *stopServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2076 {
2077 pgServer *server = (pgServer *)obj;
2078 wxMessageDialog msg(form, _("Are you sure you wish to shutdown this server?"),
2079 _("Stop Service"), wxYES_NO | wxICON_QUESTION);
2080 if (msg.ShowModal() == wxID_YES)
2081 {
2082 form->StartMsg(_("Stopping service"));
2083
2084 bool done = server->StopService();
2085
2086 if (done)
2087 {
2088 if (server->Disconnect(form))
2089 {
2090 form->GetBrowser()->DeleteChildren(server->GetId());
2091 form->execSelChange(server->GetId(), true);
2092 }
2093 }
2094 form->EndMsg(done);
2095 }
2096
2097 return 0;
2098 }
2099
2100
CheckEnable(pgObject * obj)2101 bool stopServiceFactory::CheckEnable(pgObject *obj)
2102 {
2103 if (obj && obj->IsCreatedBy(serverFactory))
2104 {
2105 pgServer *server = (pgServer *)obj;
2106 return server->GetServerControllable() && server->GetServerRunning();
2107 }
2108 return false;
2109 }
2110
2111
connectServerFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2112 connectServerFactory::connectServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2113 {
2114 mnu->Append(id, _("&Connect"), _("Connect to the selected server."));
2115 }
2116
2117
StartDialog(frmMain * form,pgObject * obj)2118 wxWindow *connectServerFactory::StartDialog(frmMain *form, pgObject *obj)
2119 {
2120 pgServer *server = (pgServer *)obj;
2121 form->ReconnectServer(server);
2122 return 0;
2123 }
2124
2125
CheckEnable(pgObject * obj)2126 bool connectServerFactory::CheckEnable(pgObject *obj)
2127 {
2128 if (obj && obj->IsCreatedBy(serverFactory))
2129 return !((pgServer *)obj)->GetConnected();
2130
2131 return false;
2132 }
2133
2134
disconnectServerFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2135 disconnectServerFactory::disconnectServerFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2136 {
2137 mnu->Append(id, _("Disconnec&t server"), _("Disconnect from the selected server."));
2138 }
2139
2140
StartDialog(frmMain * form,pgObject * obj)2141 wxWindow *disconnectServerFactory::StartDialog(frmMain *form, pgObject *obj)
2142 {
2143 if (obj->CheckOpenDialogs(form->GetBrowser(), form->GetBrowser()->GetSelection()))
2144 {
2145 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.");
2146 wxMessageBox(msg, _("Cannot disconnect database"), wxICON_WARNING | wxOK);
2147 }
2148 else
2149 {
2150 pgServer *server = (pgServer *)obj;
2151 server->Disconnect(form);
2152 server->UpdateIcon(form->GetBrowser());
2153 form->GetBrowser()->DeleteChildren(obj->GetId());
2154 form->execSelChange(obj->GetId(), true);
2155 }
2156
2157 return 0;
2158 }
2159
2160
CheckEnable(pgObject * obj)2161 bool disconnectServerFactory::CheckEnable(pgObject *obj)
2162 {
2163 if (obj && obj->IsCreatedBy(serverFactory))
2164 return ((pgServer *)obj)->GetConnected();
2165
2166 return false;
2167 }
2168
reloadconfServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2169 reloadconfServiceFactory::reloadconfServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2170 {
2171 mnu->Append(id, _("Reload configuration"), _("Reload configuration"));
2172 }
2173
2174
StartDialog(frmMain * form,pgObject * obj)2175 wxWindow *reloadconfServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2176 {
2177 pgServer *server = (pgServer *)obj;
2178 form->StartMsg(_("Reloading configuration"));
2179 bool rc = server->ReloadConfiguration();
2180 form->EndMsg(rc);
2181 return 0;
2182 }
2183
2184
CheckEnable(pgObject * obj)2185 bool reloadconfServiceFactory::CheckEnable(pgObject *obj)
2186 {
2187 if (obj && obj->IsCreatedBy(serverFactory))
2188 {
2189 pgServer *server = (pgServer *)obj;
2190 return server->GetConnected() && server->connection()->BackendMinimumVersion(8, 1);
2191 }
2192 return false;
2193 }
2194
2195
pausereplayServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2196 pausereplayServiceFactory::pausereplayServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2197 {
2198 mnu->Append(id, _("Pause replay of WAL"), _("Pause replay of WAL"));
2199 }
2200
2201
StartDialog(frmMain * form,pgObject * obj)2202 wxWindow *pausereplayServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2203 {
2204 pgServer *server = (pgServer *)obj;
2205 form->StartMsg(_("Pausing replay of WAL"));
2206 bool rc = server->PauseReplay();
2207 form->EndMsg(rc);
2208 return 0;
2209 }
2210
2211
CheckEnable(pgObject * obj)2212 bool pausereplayServiceFactory::CheckEnable(pgObject *obj)
2213 {
2214 if (obj && obj->IsCreatedBy(serverFactory))
2215 {
2216 pgServer *server = (pgServer *)obj;
2217 return server->GetConnected() &&
2218 server->connection()->BackendMinimumVersion(9, 1) &&
2219 server->GetInRecovery() &&
2220 !server->GetReplayPaused();
2221 }
2222 return false;
2223 }
2224
2225
resumereplayServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2226 resumereplayServiceFactory::resumereplayServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2227 {
2228 mnu->Append(id, _("Resume replay of WAL"), _("Resume replay of WAL"));
2229 }
2230
2231
StartDialog(frmMain * form,pgObject * obj)2232 wxWindow *resumereplayServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2233 {
2234 pgServer *server = (pgServer *)obj;
2235 form->StartMsg(_("Resuming replay of WAL"));
2236 bool rc = server->ResumeReplay();
2237 form->EndMsg(rc);
2238 return 0;
2239 }
2240
2241
CheckEnable(pgObject * obj)2242 bool resumereplayServiceFactory::CheckEnable(pgObject *obj)
2243 {
2244 if (obj && obj->IsCreatedBy(serverFactory))
2245 {
2246 pgServer *server = (pgServer *)obj;
2247 return server->GetConnected() &&
2248 server->connection()->BackendMinimumVersion(9, 1) &&
2249 server->GetInRecovery() &&
2250 server->GetReplayPaused();
2251 }
2252 return false;
2253 }
2254
2255
addnamedrestorepointServiceFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2256 addnamedrestorepointServiceFactory::addnamedrestorepointServiceFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2257 {
2258 mnu->Append(id, _("Add named restore point"), _("Add named restore point"));
2259 }
2260
2261
StartDialog(frmMain * form,pgObject * obj)2262 wxWindow *addnamedrestorepointServiceFactory::StartDialog(frmMain *form, pgObject *obj)
2263 {
2264 pgServer *server = (pgServer *)obj;
2265 form->StartMsg(_("Add named restore point"));
2266 bool rc = server->AddNamedRestorePoint();
2267 form->EndMsg(rc);
2268 return 0;
2269 }
2270
2271
CheckEnable(pgObject * obj)2272 bool addnamedrestorepointServiceFactory::CheckEnable(pgObject *obj)
2273 {
2274 if (obj && obj->IsCreatedBy(serverFactory))
2275 {
2276 pgServer *server = (pgServer *)obj;
2277 return server->GetConnected() && server->connection()->BackendMinimumVersion(9, 1) && !server->GetInRecovery();
2278 }
2279 return false;
2280 }
2281