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 // dlgQuery.cpp - Property Dialog
9 //
10 //////////////////////////////////////////////////////////////////////////
11 
12 // wxWindows headers
13 #include <wx/wx.h>
14 #include <wx/button.h>
15 
16 // App headers
17 #include "pgAdmin3.h"
18 #include "ctl/ctlMenuToolbar.h"
19 #include "ctl/ctlSQLBox.h"
20 #include "schema/pgCollection.h"
21 #include "schema/pgDatatype.h"
22 #include "utils/misc.h"
23 #include "utils/pgDefs.h"
24 #include "ctl/ctlSecurityPanel.h"
25 #include "ctl/ctlDefaultSecurityPanel.h"
26 
27 // Images
28 #include "images/properties.pngc"
29 
30 #include "frm/frmMain.h"
31 #include "frm/frmHint.h"
32 
33 // Property dialogs
34 #include "dlg/dlgProperty.h"
35 #include "dlg/dlgServer.h"
36 #include "dlg/dlgAggregate.h"
37 #include "dlg/dlgColumn.h"
38 #include "dlg/dlgIndex.h"
39 #include "dlg/dlgIndexConstraint.h"
40 #include "dlg/dlgForeignKey.h"
41 #include "dlg/dlgCheck.h"
42 #include "dlg/dlgRule.h"
43 #include "dlg/dlgTrigger.h"
44 #include "dlg/dlgEventTrigger.h"
45 #include "agent/dlgJob.h"
46 #include "agent/dlgStep.h"
47 #include "agent/dlgSchedule.h"
48 
49 #include "slony/dlgRepCluster.h"
50 #include "slony/dlgRepNode.h"
51 #include "slony/dlgRepPath.h"
52 #include "slony/dlgRepListen.h"
53 #include "slony/dlgRepSet.h"
54 #include "slony/dlgRepSequence.h"
55 #include "slony/dlgRepTable.h"
56 #include "slony/dlgRepSubscription.h"
57 #include "schema/pgTable.h"
58 #include "schema/pgColumn.h"
59 #include "schema/pgTrigger.h"
60 #include "schema/pgGroup.h"
61 #include "schema/pgUser.h"
62 #include "schema/pgEventTrigger.h"
63 
SetOid(OID id)64 void dataType::SetOid(OID id)
65 {
66 	oid = id;
67 }
68 
SetTypename(wxString name)69 void dataType::SetTypename(wxString name)
70 {
71 	typeName = name;
72 }
73 
GetOid()74 OID dataType::GetOid()
75 {
76 	return oid;
77 }
78 
GetTypename()79 wxString dataType::GetTypename()
80 {
81 	return typeName;
82 }
83 
84 #define CTRLID_CHKSQLTEXTFIELD 1000
85 
86 
87 BEGIN_EVENT_TABLE(dlgProperty, DialogWithHelp)
88 	EVT_NOTEBOOK_PAGE_CHANGED(XRCID("nbNotebook"),  dlgProperty::OnPageSelect)
89 
90 	EVT_TEXT(XRCID("txtName"),                      dlgProperty::OnChange)
91 	EVT_TEXT(XRCID("cbOwner"),                      dlgProperty::OnChangeOwner)
92 	EVT_COMBOBOX(XRCID("cbOwner"),                  dlgProperty::OnChange)
93 	EVT_TEXT(XRCID("cbSchema"),                     dlgProperty::OnChange)
94 	EVT_COMBOBOX(XRCID("cbSchema"),                 dlgProperty::OnChange)
95 	EVT_TEXT(XRCID("txtComment"),                   dlgProperty::OnChange)
96 
97 	EVT_CHECKBOX(CTRLID_CHKSQLTEXTFIELD,            dlgProperty::OnChangeReadOnly)
98 
99 	EVT_BUTTON(wxID_HELP,                           dlgProperty::OnHelp)
100 	EVT_BUTTON(wxID_OK,                             dlgProperty::OnOK)
101 END_EVENT_TABLE();
102 
103 
dlgProperty(pgaFactory * f,frmMain * frame,const wxString & resName)104 dlgProperty::dlgProperty(pgaFactory *f, frmMain *frame, const wxString &resName) : DialogWithHelp(frame)
105 {
106 	readOnly = false;
107 	sqlPane = 0;
108 	sqlTextField1 = 0;
109 	sqlTextField2 = 0;
110 	processing = false;
111 	mainForm = frame;
112 	database = 0;
113 	connection = 0;
114 	factory = f;
115 	item = (void *)NULL;
116 	owneritem = (void *)NULL;
117 	chkReadOnly = (wxCheckBox *)NULL;
118 	SetFont(settings->GetSystemFont());
119 	LoadResource(frame, resName);
120 
121 #ifdef __WXMSW__
122 	SetWindowStyleFlag(GetWindowStyleFlag() & ~wxMAXIMIZE_BOX);
123 #endif
124 
125 	nbNotebook = CTRL_NOTEBOOK("nbNotebook");
126 	if (!nbNotebook)
127 	{
128 		wxMessageBox(wxString::Format(_("Problem with resource %s: Notebook not found.\nPrepare to crash!"), resName.c_str()));
129 		return;
130 	}
131 
132 	// Set the icon
133 	wxBitmap bm(factory->GetImage());
134 	wxIcon ico;
135 	ico.CopyFromBitmap(bm);
136 	SetIcon(ico);
137 
138 	txtName = CTRL_TEXT("txtName");
139 	txtOid = CTRL_TEXT("txtOID");
140 	txtComment = CTRL_TEXT("txtComment");
141 	cbOwner = CTRL_COMBOBOX2("cbOwner");
142 	cbSchema = CTRL_COMBOBOX2("cbSchema");
143 	cbClusterSet = CTRL_COMBOBOX1("cbClusterSet");
144 
145 	wxString db = wxT("Database");
146 	wxString ts = wxT("Tablespace");
147 	wxString rg = wxT("Resource Group");
148 	enableSQL2 = db.Cmp(factory->GetTypeName()) == 0
149 	             || ts.Cmp(factory->GetTypeName()) == 0
150 	             || rg.Cmp(factory->GetTypeName()) == 0;
151 
152 	wxNotebookPage *page = nbNotebook->GetPage(0);
153 	wxASSERT(page != NULL);
154 	page->GetClientSize(&width, &height);
155 
156 	numericValidator.SetStyle(wxFILTER_NUMERIC);
157 	btnOK->Disable();
158 
159 	statusBar = XRCCTRL(*this, "unkStatusBar", wxStatusBar);
160 }
161 
162 
~dlgProperty()163 dlgProperty::~dlgProperty()
164 {
165 	wxString prop = wxT("Properties/") + wxString(factory->GetTypeName());
166 	settings->WritePoint(prop, GetPosition());
167 
168 	if (GetWindowStyle() & wxRESIZE_BORDER)
169 		settings->WriteSize(prop, GetSize());
170 
171 	if (obj)
172 		obj->SetWindowPtr(NULL);
173 }
174 
175 
GetHelpPage() const176 wxString dlgProperty::GetHelpPage() const
177 {
178 	wxString page;
179 
180 	pgObject *obj = ((dlgProperty *)this)->GetObject();
181 	if (obj)
182 		page = obj->GetHelpPage(false);
183 	else
184 	{
185 		// Attempt to get he page from the dialogue, otherwise, take a shot at it!
186 		page = this->GetHelpPage(true);
187 		if (page.Length() == 0)
188 		{
189 			page = wxT("pg/sql-create");
190 			page += wxString(factory->GetTypeName()).Lower();
191 		}
192 	}
193 
194 	return page;
195 }
196 
197 
CheckValid(bool & enable,const bool condition,const wxString & msg)198 void dlgProperty::CheckValid(bool &enable, const bool condition, const wxString &msg)
199 {
200 	if (enable)
201 	{
202 		if (!condition)
203 		{
204 			if (statusBar)
205 				statusBar->SetStatusText(msg);
206 			enable = false;
207 		}
208 	}
209 }
210 
211 
SetDatabase(pgDatabase * db)212 void dlgProperty::SetDatabase(pgDatabase *db)
213 {
214 	database = db;
215 	if (db)
216 		connection = db->GetConnection();
217 }
218 
SetDatatypeCache(dataTypeCache cache)219 void dlgProperty::SetDatatypeCache(dataTypeCache cache)
220 {
221 	dtCache = cache;
222 }
223 
EnableOK(bool enable)224 void dlgProperty::EnableOK(bool enable)
225 {
226 	btnOK->Enable(enable);
227 	if (enable)
228 	{
229 		if (statusBar)
230 			statusBar->SetStatusText(wxEmptyString);
231 	}
232 }
233 
234 
SetSqlReadOnly(bool readonly)235 void dlgProperty::SetSqlReadOnly(bool readonly)
236 {
237 	if (chkReadOnly)
238 		chkReadOnly->Enable(!readonly);
239 }
240 
241 
Go(bool modal)242 int dlgProperty::Go(bool modal)
243 {
244 	wxASSERT(factory != 0);
245 
246 	if(GetObject())
247 		obj = GetObject();
248 	else
249 		obj = mainForm->GetBrowser()->GetObject(mainForm->GetBrowser()->GetSelection());
250 
251 	// restore previous position and size, if applicable
252 	wxString prop = wxT("Properties/") + wxString(factory->GetTypeName());
253 
254 	wxSize origSize = GetSize();
255 
256 	if (GetWindowStyle() & wxRESIZE_BORDER)
257 		SetSize(settings->Read(prop, GetSize()));
258 
259 	wxPoint pos = settings->Read(prop, GetPosition());
260 	if (pos.x < 0)
261 		pos.x = 0;
262 	if (pos.y < 0)
263 		pos.y = 0;
264 	Move(pos);
265 
266 	wxSize size = GetSize();
267 	CheckOnScreen(this, pos, size, origSize.GetWidth(), origSize.GetHeight());
268 	Move(pos);
269 
270 	ctlComboBoxFix *cbowner = (ctlComboBoxFix *)cbOwner;
271 	ctlComboBoxFix *cbschema = (ctlComboBoxFix *)cbSchema;
272 
273 	if (cbClusterSet)
274 	{
275 		cbClusterSet->Append(wxEmptyString);
276 		cbClusterSet->SetSelection(0);
277 
278 		if (mainForm && database)
279 		{
280 			wxArrayString clusters = database->GetSlonyClusters(mainForm->GetBrowser());
281 
282 			size_t i;
283 			for (i = 0 ; i < clusters.GetCount() ; i++)
284 			{
285 				wxString cluster = wxT("_") + clusters.Item(i);
286 				pgSetIterator sets(connection,
287 				                   wxT("SELECT set_id, ") + qtIdent(cluster) + wxT(".slonyversionmajor(), ") + qtIdent(cluster) + wxT(".slonyversionminor()\n")
288 				                   wxT("  FROM ") + qtIdent(cluster) + wxT(".sl_set\n")
289 				                   wxT(" WHERE set_origin = ") + qtIdent(cluster) +
290 				                   wxT(".getlocalnodeid(") + qtDbString(cluster) + wxT(");"));
291 
292 				while (sets.RowsLeft())
293 				{
294 					wxString str;
295 					long setId = sets.GetLong(wxT("set_id"));
296 					long majorVer = sets.GetLong(wxT("slonyversionmajor"));
297 					long minorVer = sets.GetLong(wxT("slonyversionminor"));
298 					str.Printf(_("Cluster \"%s\", set %ld"), clusters.Item(i).c_str(), setId);
299 					cbClusterSet->Append(str, static_cast<void *>(new replClientData(cluster, setId, majorVer, minorVer)));
300 				}
301 			}
302 		}
303 		if (cbClusterSet->GetCount() < 2)
304 			cbClusterSet->Disable();
305 	}
306 
307 	if (cbowner && !cbowner->GetCount())
308 	{
309 		if (!GetObject())
310 			cbOwner->Append(wxEmptyString);
311 		AddGroups(cbowner);
312 		AddUsers(cbowner);
313 	}
314 	if (txtOid)
315 		txtOid->Disable();
316 
317 	if (cbschema && !cbschema->GetCount())
318 		AddSchemas(cbschema);
319 
320 	if (GetObject())
321 	{
322 		if (txtName)
323 			txtName->SetValue(GetObject()->GetName());
324 		if (txtOid)
325 			txtOid->SetValue(NumToStr((unsigned long)GetObject()->GetOid()));
326 		if (cbOwner)
327 			cbOwner->SetValue(GetObject()->GetOwner());
328 		if (cbSchema)
329 			cbSchema->SetValue(GetObject()->GetSchema()->GetName());
330 		if (txtComment)
331 			txtComment->SetValue(GetObject()->GetComment());
332 
333 
334 		if (!readOnly && !GetObject()->CanCreate())
335 		{
336 			// users who can't create will usually not be allowed to change either.
337 			readOnly = false;
338 		}
339 
340 		wxString typeName = factory->GetTypeName();
341 		SetTitle(wxString(wxGetTranslation(typeName)) + wxT(" ") + GetObject()->GetFullIdentifier());
342 	}
343 	else
344 	{
345 		if (factory)
346 			SetTitle(wxGetTranslation(factory->GetNewString()));
347 		if (cbSchema)
348 		{
349 			if (obj->GetMetaType() == PGM_SCHEMA)
350 				cbSchema->SetValue(obj->GetName());
351 			else
352 				cbSchema->SetValue(obj->GetSchema()->GetName());
353 		}
354 	}
355 	if (statusBar)
356 		statusBar->SetStatusText(wxEmptyString);
357 
358 	if (nbNotebook)
359 	{
360 		wxNotebookPage *pg = nbNotebook->GetPage(0);
361 		if (pg)
362 			pg->SetFocus();
363 	}
364 
365 	// This fixes a UI glitch on MacOS X and Windows
366 	// Because of the new layout code, the Privileges pane don't size itself properly
367 	SetSize(GetSize().GetWidth() + 1, GetSize().GetHeight());
368 	SetSize(GetSize().GetWidth() - 1, GetSize().GetHeight());
369 
370 	if (modal)
371 		return ShowModal();
372 	else
373 		Show(true);
374 
375 	return 0;
376 }
377 
378 
CreateAdditionalPages()379 void dlgProperty::CreateAdditionalPages()
380 {
381 	if (wxString(factory->GetTypeName()).Cmp(wxT("Server")))
382 	{
383 		// create a panel
384 		sqlPane = new wxPanel(nbNotebook);
385 
386 		// add panel to the notebook
387 		nbNotebook->AddPage(sqlPane, wxT("SQL"));
388 
389 		// create a flex grid sizer
390 		wxFlexGridSizer *fgsizer = new wxFlexGridSizer(1, 5, 5);
391 
392 		// add checkbox to the panel
393 		chkReadOnly = new wxCheckBox(sqlPane, CTRLID_CHKSQLTEXTFIELD, _("Read only"));
394 		chkReadOnly->SetValue(true);
395 		fgsizer->Add(chkReadOnly, 1, wxALL | wxALIGN_LEFT, 5);
396 
397 		// text entry box
398 		sqlTextField1 = new ctlSQLBox(sqlPane, CTL_PROPSQL,
399 		                              wxDefaultPosition, wxDefaultSize,
400 		                              wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_RICH2);
401 		fgsizer->Add(sqlTextField1, 1, wxALL | wxEXPAND, 5);
402 
403 		// text entry box
404 		if (enableSQL2)
405 		{
406 			sqlTextField2 = new ctlSQLBox(sqlPane, CTL_PROPSQL,
407 			                              wxDefaultPosition, wxDefaultSize,
408 			                              wxTE_MULTILINE | wxSUNKEN_BORDER | wxTE_RICH2);
409 			fgsizer->Add(sqlTextField2, 1, wxALL | wxEXPAND, 5);
410 		}
411 
412 		fgsizer->AddGrowableCol(0);
413 		fgsizer->AddGrowableRow(1);
414 		if (fgsizer->GetRows() > 1)
415 		{
416 			fgsizer->AddGrowableRow(2);
417 		}
418 
419 		sqlPane->SetAutoLayout(true);
420 		sqlPane->SetSizer(fgsizer);
421 	}
422 }
423 
424 
GetName()425 wxString dlgProperty::GetName()
426 {
427 	if (txtName)
428 	{
429 		if (GetObject())
430 		{
431 			// If there is an existing object name with a leading or trailing
432 			// space, don't try to remove it.
433 			if (GetObject()->GetName() == txtName->GetValue())
434 				return txtName->GetValue();
435 			else
436 				return txtName->GetValue().Strip(wxString::both);
437 		}
438 		else
439 			return txtName->GetValue().Strip(wxString::both);
440 	}
441 	return wxEmptyString;
442 }
443 
444 
AppendNameChange(wxString & sql,const wxString & objName)445 void dlgProperty::AppendNameChange(wxString &sql, const wxString &objName)
446 {
447 	if (GetObject()->GetName() != GetName())
448 	{
449 		if (objName.Length() > 0)
450 		{
451 			sql += wxT("ALTER ") + objName
452 			       +  wxT("\n  RENAME TO ") + qtIdent(GetName())
453 			       +  wxT(";\n");
454 		}
455 		else
456 		{
457 			sql += wxT("ALTER ") + GetObject()->GetTypeName().MakeUpper()
458 			       +  wxT(" ") + GetObject()->GetQuotedFullIdentifier()
459 			       +  wxT("\n  RENAME TO ") + qtIdent(GetName())
460 			       +  wxT(";\n");
461 		}
462 	}
463 }
464 
465 
AppendOwnerChange(wxString & sql,const wxString & objName)466 void dlgProperty::AppendOwnerChange(wxString &sql, const wxString &objName)
467 {
468 	if (!GetObject() || GetObject()->GetOwner() != cbOwner->GetValue())
469 	{
470 		sql += wxT("ALTER ") + objName
471 		       +  wxT("\n  OWNER TO ") + qtIdent(cbOwner->GetValue())
472 		       +  wxT(";\n");
473 	}
474 }
475 
476 
AppendOwnerNew(wxString & sql,const wxString & objName)477 void dlgProperty::AppendOwnerNew(wxString &sql, const wxString &objName)
478 {
479 	if (cbOwner->GetGuessedSelection() > 0)
480 		sql += wxT("ALTER ") + objName
481 		       +  wxT("\n  OWNER TO ") + qtIdent(cbOwner->GetValue())
482 		       +  wxT(";\n");
483 }
484 
485 
AppendSchemaChange(wxString & sql,const wxString & objName)486 void dlgProperty::AppendSchemaChange(wxString &sql, const wxString &objName)
487 {
488 	wxString currentschema;
489 
490 	if (GetObject()->GetMetaType() == PGM_SCHEMA)
491 	{
492 		currentschema = GetObject()->GetName();
493 	}
494 	else
495 	{
496 		currentschema = GetObject()->GetSchema()->GetName();
497 	}
498 
499 	if (currentschema != cbSchema->GetValue())
500 	{
501 		sql += wxT("ALTER ") + objName
502 		       +  wxT("\n  SET SCHEMA ") + qtIdent(cbSchema->GetValue())
503 		       +  wxT(";\n");
504 	}
505 }
506 
507 
AppendComment(wxString & sql,const wxString & objName,pgObject * obj)508 void dlgProperty::AppendComment(wxString &sql, const wxString &objName, pgObject *obj)
509 {
510 	wxString comment = txtComment->GetValue();
511 	if ((!obj && !comment.IsEmpty()) || (obj && obj->GetComment() != comment))
512 	{
513 		sql += wxT("COMMENT ON ") + objName
514 		       + wxT("\n  IS ") + qtDbString(comment) + wxT(";\n");
515 	}
516 }
517 
518 
AppendComment(wxString & sql,const wxString & objType,pgSchema * schema,pgObject * obj)519 void dlgProperty::AppendComment(wxString &sql, const wxString &objType, pgSchema *schema, pgObject *obj)
520 {
521 	wxString comment = txtComment->GetValue();
522 	if ((!obj && !comment.IsEmpty()) || (obj && obj->GetComment() != comment))
523 	{
524 		sql += wxT("COMMENT ON ") + objType + wxT(" ");
525 		if (schema)
526 			sql += schema->GetQuotedPrefix();
527 		sql += qtIdent(GetName()) + wxT("\n  IS ") + qtDbString(comment) + wxT(";\n");
528 	}
529 }
530 
531 
AppendQuoted(wxString & sql,const wxString & name)532 void dlgProperty::AppendQuoted(wxString &sql, const wxString &name)
533 {
534 	// quick and quite dirty:
535 	// !!! this is unsafe if the name itself contains a dot which isn't meant as separator between schema and object
536 	if (name.First('.') >= 0)
537 	{
538 		sql += qtIdent(name.BeforeFirst('.')) + wxT(".") + qtIdent(name.AfterFirst('.'));
539 	}
540 	else
541 		sql += qtIdent(name);
542 }
543 
AppendQuotedType(wxString & sql,const wxString & name)544 void dlgProperty::AppendQuotedType(wxString &sql, const wxString &name)
545 {
546 	// see AppendQuoted()
547 	if (name.First('.') >= 0)
548 	{
549 		sql += qtIdent(name.BeforeFirst('.')) + wxT(".") + qtTypeIdent(name.AfterFirst('.'));
550 	}
551 	else
552 		sql += qtTypeIdent(name);
553 }
554 
555 
FillCombobox(const wxString & query,ctlComboBoxFix * cb1,ctlComboBoxFix * cb2)556 void dlgProperty::FillCombobox(const wxString &query, ctlComboBoxFix *cb1, ctlComboBoxFix *cb2)
557 {
558 	if (!cb1 && !cb2)
559 		return;
560 
561 	pgSet *set = connection->ExecuteSet(query);
562 	if (set)
563 	{
564 		while (!set->Eof())
565 		{
566 			if (cb1)
567 				cb1->Append(set->GetVal(0));
568 			if (cb2)
569 				cb2->Append(set->GetVal(0));
570 			set->MoveNext();
571 		}
572 		delete set;
573 	}
574 
575 }
576 
577 
AddDatabases(ctlComboBoxFix * cb)578 void dlgProperty::AddDatabases(ctlComboBoxFix *cb)
579 {
580 	FillCombobox(wxT("SELECT datname FROM pg_database ORDER BY 1"), cb);
581 }
582 
583 
AddUsers(ctlComboBoxFix * cb1,ctlComboBoxFix * cb2)584 void dlgProperty::AddUsers(ctlComboBoxFix *cb1, ctlComboBoxFix *cb2)
585 {
586 	if (connection->BackendMinimumVersion(8, 1))
587 	{
588 		FillCombobox(wxT("SELECT rolname FROM pg_roles WHERE rolcanlogin ORDER BY 1"), cb1, cb2);
589 	}
590 	else
591 	{
592 		FillCombobox(wxT("SELECT usename FROM pg_user ORDER BY 1"), cb1, cb2);
593 	}
594 }
595 
596 
AddGroups(ctlComboBoxFix * combo)597 void dlgProperty::AddGroups(ctlComboBoxFix *combo)
598 {
599 	if (connection->BackendMinimumVersion(8, 1))
600 	{
601 		FillCombobox(wxT("SELECT rolname FROM pg_roles WHERE NOT rolcanlogin ORDER BY 1"), combo);
602 	}
603 	else
604 	{
605 		FillCombobox(wxT("SELECT groname FROM pg_group ORDER BY 1"), combo);
606 	}
607 }
608 
609 
AddSchemas(ctlComboBoxFix * combo)610 void dlgProperty::AddSchemas(ctlComboBoxFix *combo)
611 {
612 	if (connection->BackendMinimumVersion(8, 1))
613 	{
614 		FillCombobox(wxT("SELECT nspname FROM pg_namespace WHERE nspname NOT LIKE E'pg\\\\_%' AND nspname != 'information_schema' ORDER BY nspname"),
615 		             combo);
616 	}
617 }
618 
619 
PrepareTablespace(ctlComboBoxFix * cb,const OID current)620 void dlgProperty::PrepareTablespace(ctlComboBoxFix *cb, const OID current)
621 {
622 	wxASSERT(cb != 0);
623 
624 	if (connection->BackendMinimumVersion(8, 0))
625 	{
626 		// Populate the combo
627 		cb->FillOidKey(connection, wxT("SELECT oid, spcname FROM pg_tablespace WHERE spcname <> 'pg_global' ORDER BY spcname"));
628 
629 		if (current)
630 			cb->SetKey(current);
631 		else
632 		{
633 			if (database)
634 				cb->SetValue(database->GetDefaultTablespace());
635 			else
636 			{
637 				wxString def = connection->ExecuteScalar(wxT("SELECT current_setting('default_tablespace');"));
638 				if (def == wxEmptyString || def == wxT("unset"))
639 					def = wxT("pg_default");
640 				cb->SetValue(def);
641 			}
642 		}
643 	}
644 	else
645 		cb->Disable();
646 }
647 
648 
OnChangeStc(wxStyledTextEvent & ev)649 void dlgProperty::OnChangeStc(wxStyledTextEvent &ev)
650 {
651 	CheckChange();
652 }
653 
654 
OnChange(wxCommandEvent & ev)655 void dlgProperty::OnChange(wxCommandEvent &ev)
656 {
657 	CheckChange();
658 }
659 
660 
OnChangeOwner(wxCommandEvent & ev)661 void dlgProperty::OnChangeOwner(wxCommandEvent &ev)
662 {
663 	ctlComboBox *cb = cbOwner;
664 	if (cb)
665 		cb->GuessSelection(ev);
666 	CheckChange();
667 }
668 
669 
OnChangeReadOnly(wxCommandEvent & ev)670 void dlgProperty::OnChangeReadOnly(wxCommandEvent &ev)
671 {
672 	size_t pos;
673 	bool showmessage;
674 
675 	showmessage = chkReadOnly->GetValue()
676 	              && ! (!enableSQL2 && GetSql().Length() == 0 && sqlTextField1->GetText().Cmp(_("-- nothing to change")) == 0)
677 	              && ! (!enableSQL2 && GetSql().Length() == 0 && sqlTextField1->GetText().Cmp(_("-- definition incomplete")) == 0)
678 	              && ! (enableSQL2 && GetSql().Length() == 0 && GetSql2().Length() == 0 && sqlTextField1->GetText().Cmp(_("-- nothing to change")) == 0 && sqlTextField2->GetText().Length() == 0)
679 	              && ! (enableSQL2 && GetSql().Length() == 0 && GetSql2().Length() == 0 && sqlTextField1->GetText().Cmp(_("-- definition incomplete")) == 0 && sqlTextField2->GetText().Length() == 0)
680 	              && (sqlTextField1->GetText().Cmp(GetSql()) != 0 || (enableSQL2 && sqlTextField2->GetText().Cmp(GetSql2()) != 0));
681 
682 	if (showmessage)
683 	{
684 		if (wxMessageBox(_("Are you sure you wish to cancel your edit?"), _("SQL editor"), wxYES_NO | wxNO_DEFAULT) != wxYES)
685 		{
686 			chkReadOnly->SetValue(false);
687 			return;
688 		}
689 	}
690 
691 	sqlTextField1->SetReadOnly(chkReadOnly->GetValue());
692 	if (enableSQL2)
693 	{
694 		sqlTextField2->SetReadOnly(chkReadOnly->GetValue());
695 	}
696 	for (pos = 0; pos < nbNotebook->GetPageCount() - 1; pos++)
697 	{
698 		nbNotebook->GetPage(pos)->Enable(chkReadOnly->GetValue());
699 	}
700 
701 	if (chkReadOnly->GetValue())
702 	{
703 		FillSQLTextfield();
704 	}
705 }
706 
707 
FillSQLTextfield()708 void dlgProperty::FillSQLTextfield()
709 {
710 	// create a function because this is a duplicated code
711 	sqlTextField1->SetReadOnly(false);
712 	if (enableSQL2)
713 	{
714 		sqlTextField2->SetReadOnly(false);
715 	}
716 	if (btnOK->IsEnabled())
717 	{
718 		wxString tmp;
719 		if (cbClusterSet && cbClusterSet->GetSelection() > 0)
720 		{
721 			replClientData *data = (replClientData *)cbClusterSet->wxItemContainer::GetClientData(cbClusterSet->GetSelection());
722 			if(data)
723 				tmp.Printf(_("-- Execute replicated using cluster \"%s\", set %ld\n"), data->cluster.c_str(), data->setId);
724 		}
725 		sqlTextField1->SetText(tmp + GetSql());
726 		if (enableSQL2)
727 		{
728 			sqlTextField2->SetText(GetSql2());
729 		}
730 	}
731 	else
732 	{
733 		if (GetObject())
734 			sqlTextField1->SetText(_("-- nothing to change"));
735 		else
736 			sqlTextField1->SetText(_("-- definition incomplete"));
737 		if (enableSQL2)
738 		{
739 			sqlTextField2->SetText(wxT(""));
740 		}
741 	}
742 	sqlTextField1->SetReadOnly(true);
743 	if (enableSQL2)
744 	{
745 		sqlTextField2->SetReadOnly(true);
746 	}
747 }
748 
749 
tryUpdate(wxTreeItemId collectionItem)750 bool dlgProperty::tryUpdate(wxTreeItemId collectionItem)
751 {
752 	ctlTree *browser = mainForm->GetBrowser();
753 	pgCollection *collection = (pgCollection *)browser->GetObject(collectionItem);
754 	if (collection && collection->IsCollection() && factory->GetCollectionFactory() == collection->GetFactory())
755 	{
756 		pgObject *data = CreateObject(collection);
757 		if (data)
758 		{
759 
760 			wxString nodeName = this->GetDisplayName();
761 			if (nodeName.IsEmpty())
762 				nodeName = data->GetDisplayName();
763 
764 			size_t pos = 0;
765 			wxTreeItemId newItem;
766 
767 			if (!data->IsCreatedBy(columnFactory))
768 			{
769 				// columns should be appended, not inserted alphabetically
770 
771 				wxCookieType cookie;
772 				newItem = browser->GetFirstChild(collectionItem, cookie);
773 				while (newItem)
774 				{
775 					if (browser->GetItemText(newItem) > nodeName)
776 						break;
777 					pos++;
778 					newItem = browser->GetNextChild(collectionItem, cookie);
779 				}
780 			}
781 
782 			if (newItem)
783 				browser->InsertItem(collectionItem, pos, nodeName, data->GetIconId(), -1, data);
784 			else
785 				browser->AppendItem(collectionItem, nodeName, data->GetIconId(), -1, data);
786 
787 			if (data->WantDummyChild())
788 				browser->AppendItem(data->GetId(), wxT("Dummy"));
789 
790 			if (browser->GetSelection() == item)
791 				collection->ShowTreeDetail(browser, 0, mainForm->GetProperties());
792 			else
793 				collection->UpdateChildCount(browser);
794 		}
795 		else
796 		{
797 			// CreateObject didn't return a new pgObject; refresh the complete collection
798 			mainForm->Refresh(collection);
799 		}
800 		return true;
801 	}
802 	return false;
803 }
804 
805 
806 
ShowObject()807 void dlgProperty::ShowObject()
808 {
809 	mainForm->ObjectBrowserRefreshing(true);
810 	pgObject *data = GetObject();
811 
812 	// We might have a parent to refresh. If so, the children will
813 	// inherently get refreshed as well. Yay :-)
814 	if (owneritem)
815 	{
816 		// Get the object node in case we need it later
817 		wxTreeItemId objectnode = mainForm->GetBrowser()->GetItemParent(owneritem);
818 
819 		// Stash the selected items path
820 		wxString currentPath = mainForm->GetCurrentNodePath();
821 
822 		pgObject *tblobj = mainForm->GetBrowser()->GetObject(owneritem);
823 
824 		if (tblobj)
825 		{
826 			dlgProperty *ownDialog = NULL;
827 			if (data)
828 			{
829 				ownDialog = data->GetWindowPtr();
830 				data->SetWindowPtr(NULL);
831 			}
832 			mainForm->Refresh(tblobj);
833 			if (data)
834 			{
835 				data->SetWindowPtr(ownDialog);
836 			}
837 		}
838 
839 		// Restore the previous selection...
840 		mainForm->SetCurrentNode(mainForm->GetBrowser()->GetRootItem(), currentPath);
841 	}
842 	else if (data)
843 	{
844 		pgObject *newData = data->Refresh(mainForm->GetBrowser(), item);
845 		if (newData && newData != data)
846 		{
847 			mainForm->SetCurrentObject(newData);
848 			mainForm->GetBrowser()->SetItemData(item, newData);
849 
850 			newData->SetId(item);
851 			delete data;
852 			SetObject(newData);
853 
854 			newData->UpdateIcon(mainForm->GetBrowser());
855 		}
856 		if (newData)
857 		{
858 			mainForm->GetBrowser()->DeleteChildren(newData->GetId());
859 
860 			if (item == mainForm->GetBrowser()->GetSelection())
861 				newData->ShowTree(mainForm, mainForm->GetBrowser(), mainForm->GetProperties(), 0);
862 			mainForm->GetBrowser()->SetItemText(item, newData->GetFullName());
863 			mainForm->GetSqlPane()->SetReadOnly(false);
864 			mainForm->GetSqlPane()->SetText(newData->GetSql(mainForm->GetBrowser()));
865 			mainForm->GetSqlPane()->SetReadOnly(true);
866 		}
867 	}
868 	else if (item && chkReadOnly->GetValue())
869 	{
870 		wxTreeItemId collectionItem = item;
871 
872 		while (collectionItem)
873 		{
874 			// search up the tree for our collection
875 			if (tryUpdate(collectionItem))
876 				break;
877 			collectionItem = mainForm->GetBrowser()->GetItemParent(collectionItem);
878 		}
879 	}
880 	else // Brute force update the current item
881 	{
882 		pgObject *currobj = mainForm->GetBrowser()->GetObject(mainForm->GetBrowser()->GetSelection());
883 
884 		if (currobj)
885 			mainForm->Refresh(currobj);
886 	}
887 	mainForm->ObjectBrowserRefreshing(false);
888 }
889 
890 
apply(const wxString & sql,const wxString & sql2)891 bool dlgProperty::apply(const wxString &sql, const wxString &sql2)
892 {
893 	wxString tmp;
894 	pgConn *myConn = connection;
895 
896 	if (GetDisconnectFirst())
897 	{
898 		myConn = database->GetServer()->GetConnection();
899 		database->Disconnect();
900 	}
901 
902 	if (!sql.IsEmpty())
903 	{
904 		wxArrayString queries;
905 
906 		if (WannaSplitQueries())
907 			queries = SplitQueries(BuildSql(sql));
908 		else
909 			queries.Add(BuildSql(sql));
910 
911 		for (size_t index = 0; index < queries.GetCount(); index++)
912 		{
913 			tmp = queries.Item(index);
914 			if (!myConn->ExecuteVoid(tmp))
915 			{
916 				// error message is displayed inside ExecuteVoid
917 				return false;
918 			}
919 
920 			if (database)
921 				database->AppendSchemaChange(tmp);
922 		}
923 	}
924 
925 	// Process the second SQL statement. This is primarily only used by
926 	// CREATE DATABASE which cannot be run in a multi-statement query in
927 	// PostgreSQL 8.3+
928 	if (!sql2.IsEmpty())
929 	{
930 		tmp = BuildSql(sql2);
931 
932 		if (!myConn->ExecuteVoid(tmp))
933 		{
934 			// error message is displayed inside ExecuteVoid
935 			// Warn the user about partially applied changes, but don't bail out.
936 			// Carry on as if everything was successful (because the most important
937 			// change was!!
938 			wxMessageBox(_("An error occurred executing the second stage SQL statement.\n\nChanges may have been partially applied."), _("Warning"), wxICON_EXCLAMATION | wxOK, this);
939 		}
940 		else // Only apend schema changes if there was no error.
941 		{
942 			if (database)
943 				database->AppendSchemaChange(tmp);
944 		}
945 	}
946 
947 	ShowObject();
948 
949 	return true;
950 }
951 
952 
BuildSql(const wxString & sql)953 wxString dlgProperty::BuildSql(const wxString &sql)
954 {
955 	wxString tmp;
956 
957 	if (cbClusterSet && cbClusterSet->GetSelection() > 0)
958 	{
959 		replClientData *data = (replClientData *)cbClusterSet->wxItemContainer::GetClientData(cbClusterSet->GetSelection());
960 		if (data)
961 		{
962 			if (data->majorVer > 1 || (data->majorVer == 1 && data->minorVer >= 2))
963 			{
964 				// From slony version 2.2.0 onwards ddlscript_prepare() method is removed and
965 				// ddlscript_complete() method arguments got changed so we have to use ddlcapture() method
966 				// instead of ddlscript_prepare() and changed the argument of ddlscript_complete() method
967 				if ((data->majorVer == 2 && data->minorVer >= 2) || (data->majorVer > 2))
968 				{
969 					tmp = wxT("SELECT ") + qtIdent(data->cluster)
970 					      + wxT(".ddlcapture(") + qtDbString(sql) + wxT(", ") + wxT("NULL::text") + wxT(" );\n")
971 					      + wxT("SELECT ") + qtIdent(data->cluster)
972 					      + wxT(".ddlscript_complete(") + wxT("NULL::text") + wxT(" );\n");
973 				}
974 				else
975 				{
976 					tmp = wxT("SELECT ") + qtIdent(data->cluster)
977 					      + wxT(".ddlscript_prepare(") + NumToStr(data->setId) + wxT(", -1);\n")
978 					      + sql + wxT(";\n")
979 					      + wxT("SELECT ") + qtIdent(data->cluster)
980 					      + wxT(".ddlscript_complete(") + NumToStr(data->setId) + wxT(", ")
981 					      + qtDbString(sql) + wxT(", -1);\n");
982 				}
983 			}
984 			else
985 			{
986 				tmp = wxT("SELECT ") + qtIdent(data->cluster)
987 				      + wxT(".ddlscript(") + NumToStr(data->setId) + wxT(", ")
988 				      + qtDbString(sql) + wxT(", 0);\n");
989 			}
990 		}
991 	}
992 	else
993 		tmp = sql;
994 
995 	return tmp;
996 }
997 
998 
SplitQueries(const wxString & sql)999 wxArrayString dlgProperty::SplitQueries(const wxString &sql)
1000 {
1001 	wxArrayString queries;
1002 	wxString query;
1003 	wxString c;
1004 
1005 	bool antislash = false;
1006 	bool quote_string = false;
1007 	bool doublequote_string = false;
1008 
1009 	for (size_t item = 0; item < sql.Length(); item++)
1010 	{
1011 		c = sql.GetChar(item);
1012 
1013 		if (c == wxT("\\"))
1014 			antislash = true;
1015 
1016 		if (c == wxT("'"))
1017 		{
1018 			if (antislash)
1019 				antislash = false;
1020 			else if (quote_string)
1021 				quote_string = false;
1022 			else if (!doublequote_string)
1023 				quote_string = true;
1024 		}
1025 
1026 		if (c == wxT("\""))
1027 		{
1028 			if (antislash)
1029 				antislash = false;
1030 			else if (doublequote_string)
1031 				doublequote_string = false;
1032 			else if (!quote_string)
1033 				doublequote_string = true;
1034 		}
1035 
1036 		query = query + c;
1037 
1038 		if (c == wxT(";") && !antislash && !quote_string && !doublequote_string)
1039 		{
1040 			queries.Add(query);
1041 			query = wxEmptyString;
1042 		}
1043 	}
1044 
1045 	return queries;
1046 }
1047 
1048 
OnOK(wxCommandEvent & ev)1049 void dlgProperty::OnOK(wxCommandEvent &ev)
1050 {
1051 #ifdef __WXGTK__
1052 	if (!btnOK->IsEnabled())
1053 		return;
1054 #endif
1055 	if (!IsUpToDate())
1056 	{
1057 		if (wxMessageBox(wxT("The object has been changed by another user. Do you wish to continue to try to update it?"), wxT("Overwrite changes?"), wxYES_NO) != wxYES)
1058 			return;
1059 	}
1060 
1061 	EnableOK(false);
1062 
1063 	if (IsModal())
1064 	{
1065 		EndModal(0);
1066 		return;
1067 	}
1068 
1069 	wxString sql;
1070 	wxString sql2;
1071 	if (chkReadOnly->GetValue())
1072 	{
1073 		sql = GetSql();
1074 		sql2 = GetSql2();
1075 	}
1076 	else
1077 	{
1078 		sql = sqlTextField1->GetText();
1079 		if (enableSQL2)
1080 		{
1081 			sql2 = sqlTextField2->GetText();
1082 		}
1083 		else
1084 		{
1085 			sql2 = wxT("");
1086 		}
1087 	}
1088 
1089 	if (!apply(sql, sql2))
1090 	{
1091 		EnableOK(true);
1092 		return;
1093 	}
1094 
1095 	Destroy();
1096 }
1097 
1098 
OnPageSelect(wxNotebookEvent & event)1099 void dlgProperty::OnPageSelect(wxNotebookEvent &event)
1100 {
1101 	if (sqlTextField1 && chkReadOnly->GetValue() &&
1102 	        event.GetSelection() == (int)nbNotebook->GetPageCount() - 1)
1103 	{
1104 		FillSQLTextfield();
1105 	}
1106 }
1107 
1108 
1109 
InitDialog(frmMain * frame,pgObject * node)1110 void dlgProperty::InitDialog(frmMain *frame, pgObject *node)
1111 {
1112 	CenterOnParent();
1113 	if (!connection)
1114 		connection = node->GetConnection();
1115 	database = node->GetDatabase();
1116 
1117 	if (factory != node->GetFactory() && !node->IsCollection())
1118 	{
1119 		wxCookieType cookie;
1120 		wxTreeItemId collectionItem = frame->GetBrowser()->GetFirstChild(node->GetId(), cookie);
1121 		while (collectionItem)
1122 		{
1123 			pgCollection *collection = (pgCollection *)frame->GetBrowser()->GetObject(collectionItem);
1124 			if (collection && collection->IsCollection() && collection->IsCollectionFor(node))
1125 				break;
1126 
1127 			collectionItem = frame->GetBrowser()->GetNextChild(node->GetId(), cookie);
1128 		}
1129 		item = collectionItem;
1130 	}
1131 	else
1132 		item = node->GetId();
1133 
1134 	// Additional hacks to get the table to refresh when modifying sub-objects
1135 	if (!item && (node->GetMetaType() == PGM_TABLE || node->GetMetaType() == PGM_VIEW
1136 	              || node->GetMetaType() == GP_PARTITION || node->GetMetaType() == PGM_DOMAIN))
1137 		owneritem = node->GetId();
1138 
1139 	int metatype = node->GetMetaType();
1140 
1141 	switch (metatype)
1142 	{
1143 		case PGM_COLUMN:
1144 			owneritem = node->GetTable()->GetId();
1145 			break;
1146 
1147 		case PGM_CHECK:
1148 		case PGM_FOREIGNKEY:
1149 		case PGM_CONSTRAINT:
1150 		case PGM_EXCLUDE:
1151 		case PGM_INDEX:
1152 		case PGM_PRIMARYKEY:
1153 		case PGM_UNIQUE:
1154 		case PGM_TRIGGER:
1155 		case PGM_RULE: // Rules are technically table objects! Yeuch
1156 		case EDB_PACKAGEFUNCTION:
1157 		case EDB_PACKAGEVARIABLE:
1158 		case PGM_SCHEDULE:
1159 		case PGM_STEP:
1160 			if (node->IsCollection())
1161 				owneritem = frame->GetBrowser()->GetParentObject(node->GetId())->GetId();
1162 			else
1163 				owneritem = frame->GetBrowser()->GetParentObject(frame->GetBrowser()->GetParentObject(node->GetId())->GetId())->GetId();
1164 			break;
1165 
1166 		default:
1167 			// we want to do this as objects can change schema
1168 			owneritem = node->GetId();
1169 			break;
1170 	}
1171 }
1172 
1173 
CreateDlg(frmMain * frame,pgObject * node,bool asNew,pgaFactory * factory)1174 dlgProperty *dlgProperty::CreateDlg(frmMain *frame, pgObject *node, bool asNew, pgaFactory *factory)
1175 {
1176 	if (!factory)
1177 	{
1178 		factory = node->GetFactory();
1179 		if (node->IsCollection())
1180 			factory = ((pgaCollectionFactory *)factory)->GetItemFactory();
1181 	}
1182 
1183 	pgObject *currentNode, *parentNode;
1184 	if (asNew)
1185 		currentNode = 0;
1186 	else
1187 		currentNode = node;
1188 
1189 	if (factory != node->GetFactory())
1190 		parentNode = node;
1191 	else
1192 		parentNode = frame->GetBrowser()->GetObject(
1193 		                 frame->GetBrowser()->GetItemParent(node->GetId()));
1194 
1195 	if (parentNode && parentNode->IsCollection() && parentNode->GetMetaType() != PGM_SERVER)
1196 		parentNode = frame->GetBrowser()->GetObject(
1197 		                 frame->GetBrowser()->GetItemParent(parentNode->GetId()));
1198 
1199 	dlgProperty *dlg = 0;
1200 
1201 	if (factory)
1202 	{
1203 		dlg = factory->CreateDialog(frame, currentNode, parentNode);
1204 		if (dlg)
1205 		{
1206 			if (factory->IsCollection())
1207 				factory = ((pgaCollectionFactory *)factory)->GetItemFactory();
1208 			wxASSERT(factory);
1209 
1210 			dlg->InitDialog(frame, node);
1211 
1212 			if (currentNode)
1213 				currentNode->SetWindowPtr(dlg);
1214 		}
1215 	}
1216 	return dlg;
1217 }
1218 
1219 
CreateObjectDialog(frmMain * frame,pgObject * node,pgaFactory * factory)1220 bool dlgProperty::CreateObjectDialog(frmMain *frame, pgObject *node, pgaFactory *factory)
1221 {
1222 	if (node->GetMetaType() != PGM_SERVER)
1223 	{
1224 		pgConn *conn = node->GetConnection();
1225 		if (!conn || conn->GetStatus() != PGCONN_OK || !conn->IsAlive())
1226 			return false;
1227 	}
1228 
1229 	dlgProperty *dlg = NULL;
1230 
1231 	if (node)
1232 		dlg = node->GetWindowPtr();
1233 
1234 	if (dlg)
1235 		dlg->Raise();
1236 	else
1237 	{
1238 		dlg = CreateDlg(frame, node, true, factory);
1239 
1240 		if (dlg)
1241 		{
1242 			dlg->SetTitle(wxGetTranslation(dlg->factory->GetNewString()));
1243 
1244 			dlg->CreateAdditionalPages();
1245 			dlg->Go();
1246 			dlg->CheckChange();
1247 		}
1248 		else
1249 			wxMessageBox(_("Not implemented."));
1250 	}
1251 
1252 	return true;
1253 }
1254 
1255 
EditObjectDialog(frmMain * frame,ctlSQLBox * sqlbox,pgObject * node)1256 bool dlgProperty::EditObjectDialog(frmMain *frame, ctlSQLBox *sqlbox, pgObject *node)
1257 {
1258 	if (node->GetMetaType() != PGM_SERVER)
1259 	{
1260 		pgConn *conn = node->GetConnection();
1261 		if (!conn || conn->GetStatus() != PGCONN_OK || !conn->IsAlive())
1262 			return false;
1263 	}
1264 
1265 	// If this is a function or view, hint that the user might want to edit the object in
1266 	// the query tool.
1267 	if (node->GetMetaType() == PGM_FUNCTION || node->GetMetaType() == PGM_VIEW)
1268 	{
1269 		if (frmHint::ShowHint(frame, HINT_OBJECT_EDITING) == wxID_CANCEL)
1270 			return false;
1271 	}
1272 
1273 	dlgProperty *dlg = NULL;
1274 
1275 	if (node)
1276 		dlg = node->GetWindowPtr();
1277 
1278 	if (dlg)
1279 		dlg->Raise();
1280 	else
1281 	{
1282 		dlg = CreateDlg(frame, node, false);
1283 
1284 		if (dlg)
1285 		{
1286 			wxString typeName = dlg->factory->GetTypeName();
1287 			dlg->SetTitle(wxString(wxGetTranslation(typeName)) + wxT(" ") + node->GetFullIdentifier());
1288 
1289 			dlg->CreateAdditionalPages();
1290 			dlg->Go();
1291 
1292 			dlg->CheckChange();
1293 		}
1294 		else
1295 			wxMessageBox(_("Not implemented."));
1296 	}
1297 
1298 	return true;
1299 }
1300 
qtDbString(const wxString & str)1301 wxString dlgProperty::qtDbString(const wxString &str)
1302 {
1303 	// Use the server aware version if possible
1304 	if (connection)
1305 		return connection->qtDbString(str);
1306 	else if (database)
1307 		return database->GetConnection()->qtDbString(str);
1308 	else
1309 	{
1310 		wxString ret = str;
1311 		ret.Replace(wxT("\\"), wxT("\\\\"));
1312 		ret.Replace(wxT("'"), wxT("''"));
1313 		ret.Append(wxT("'"));
1314 		ret.Prepend(wxT("'"));
1315 		return ret;
1316 	}
1317 }
1318 
OnHelp(wxCommandEvent & ev)1319 void dlgProperty::OnHelp(wxCommandEvent &ev)
1320 {
1321 	wxString page = GetHelpPage();
1322 
1323 	if (!page.IsEmpty())
1324 	{
1325 		if (page.StartsWith(wxT("pg/")))
1326 		{
1327 			if (connection)
1328 			{
1329 				if (connection->GetIsEdb())
1330 					DisplayHelp(page.Mid(3), HELP_ENTERPRISEDB);
1331 				else if (connection->GetIsGreenplum())
1332 					DisplayHelp(page.Mid(3), HELP_GREENPLUM);
1333 				else
1334 					DisplayHelp(page.Mid(3), HELP_POSTGRESQL);
1335 			}
1336 			else
1337 				DisplayHelp(page.Mid(3), HELP_POSTGRESQL);
1338 		}
1339 		else if (page.StartsWith(wxT("slony/")))
1340 			DisplayHelp(page.Mid(6), HELP_SLONY);
1341 		else
1342 			DisplayHelp(page, HELP_PGADMIN);
1343 	}
1344 }
1345 
1346 /////////////////////////////////////////////////////////////////////////////
1347 
1348 
dlgTypeProperty(pgaFactory * f,frmMain * frame,const wxString & resName)1349 dlgTypeProperty::dlgTypeProperty(pgaFactory *f, frmMain *frame, const wxString &resName)
1350 	: dlgProperty(f, frame, resName)
1351 {
1352 	isVarLen = false;
1353 	isVarPrec = false;
1354 	if (wxWindow::FindWindow(XRCID("txtLength")))
1355 	{
1356 		txtLength = CTRL_TEXT("txtLength");
1357 		txtLength->SetValidator(numericValidator);
1358 		txtLength->Disable();
1359 	}
1360 	else
1361 		txtLength = 0;
1362 	if (wxWindow::FindWindow(XRCID("txtPrecision")))
1363 	{
1364 		txtPrecision = CTRL_TEXT("txtPrecision");
1365 		txtPrecision->SetValidator(numericValidator);
1366 		txtPrecision->Disable();
1367 	}
1368 	else
1369 		txtPrecision = 0;
1370 }
1371 
1372 
FillDatatype(ctlComboBox * cb,bool withDomains,bool addSerials)1373 void dlgTypeProperty::FillDatatype(ctlComboBox *cb, bool withDomains, bool addSerials)
1374 {
1375 	FillDatatype(cb, 0, withDomains, addSerials);
1376 }
1377 
FillDatatype(ctlComboBox * cb,ctlComboBox * cb2,bool withDomains,bool addSerials)1378 void dlgTypeProperty::FillDatatype(ctlComboBox *cb, ctlComboBox *cb2, bool withDomains, bool addSerials)
1379 {
1380 
1381 	if (dtCache.IsEmpty())
1382 	{
1383 		// A column dialog is directly called, no datatype caching is done.
1384 		// Fetching datatypes from server.
1385 		DatatypeReader tr(database, withDomains, addSerials);
1386 		while (tr.HasMore())
1387 		{
1388 			pgDatatype dt = tr.GetDatatype();
1389 
1390 			AddType(wxT("?"), tr.GetOid(), dt.GetQuotedSchemaPrefix(database) + dt.QuotedFullName());
1391 			cb->Append(dt.GetQuotedSchemaPrefix(database) + dt.QuotedFullName());
1392 			if (cb2)
1393 				cb2->Append(dt.GetQuotedSchemaPrefix(database) + dt.QuotedFullName());
1394 			tr.MoveNext();
1395 		}
1396 	}
1397 	else
1398 	{
1399 		// A column dialog is called from a table dialog where we have already cached the datatypes.
1400 		// Using cached datatypes.
1401 		size_t i;
1402 		for (i = 0; i < dtCache.GetCount(); i++)
1403 		{
1404 			AddType(wxT("?"), dtCache.Item(i)->GetOid(), dtCache.Item(i)->GetTypename());
1405 			cb->Append(dtCache.Item(i)->GetTypename());
1406 			if (cb2)
1407 				cb2->Append(dtCache.Item(i)->GetTypename());
1408 		}
1409 	}
1410 
1411 }
1412 
1413 
Go(bool modal)1414 int dlgTypeProperty::Go(bool modal)
1415 {
1416 	if (GetObject())
1417 	{
1418 		if (txtLength)
1419 			txtLength->SetValidator(numericValidator);
1420 		if (txtPrecision)
1421 			txtPrecision->SetValidator(numericValidator);
1422 	}
1423 	return dlgProperty::Go(modal);
1424 }
1425 
1426 
1427 
AddType(const wxString & typ,const OID oid,const wxString quotedName)1428 void dlgTypeProperty::AddType(const wxString &typ, const OID oid, const wxString quotedName)
1429 {
1430 	wxString vartyp;
1431 	if (typ == wxT("?"))
1432 	{
1433 		switch ((long)oid)
1434 		{
1435 			case PGOID_TYPE_BIT:
1436 			case PGOID_TYPE_BIT_ARRAY:
1437 			case PGOID_TYPE_VARBIT:
1438 			case PGOID_TYPE_VARBIT_ARRAY:
1439 			case PGOID_TYPE_BPCHAR:
1440 			case PGOID_TYPE_BPCHAR_ARRAY:
1441 			case PGOID_TYPE_VARCHAR:
1442 			case PGOID_TYPE_VARCHAR_ARRAY:
1443 				vartyp = wxT("L");
1444 				break;
1445 			case PGOID_TYPE_TIME:
1446 			case PGOID_TYPE_TIME_ARRAY:
1447 			case PGOID_TYPE_TIMETZ:
1448 			case PGOID_TYPE_TIMETZ_ARRAY:
1449 			case PGOID_TYPE_TIMESTAMP:
1450 			case PGOID_TYPE_TIMESTAMP_ARRAY:
1451 			case PGOID_TYPE_TIMESTAMPTZ:
1452 			case PGOID_TYPE_TIMESTAMPTZ_ARRAY:
1453 			case PGOID_TYPE_INTERVAL:
1454 			case PGOID_TYPE_INTERVAL_ARRAY:
1455 				vartyp = wxT("D");
1456 				break;
1457 			case PGOID_TYPE_NUMERIC:
1458 			case PGOID_TYPE_NUMERIC_ARRAY:
1459 				vartyp = wxT("P");
1460 				break;
1461 			default:
1462 				vartyp = wxT(" ");
1463 				break;
1464 		}
1465 	}
1466 	else
1467 		vartyp = typ;
1468 
1469 	types.Add(vartyp + NumToStr(oid) + wxT(":") + quotedName);
1470 }
1471 
1472 
GetTypeInfo(int sel)1473 wxString dlgTypeProperty::GetTypeInfo(int sel)
1474 {
1475 	wxString str;
1476 	if (sel >= 0)
1477 		str = types.Item(sel);
1478 
1479 	return str;
1480 }
1481 
1482 
GetTypeOid(int sel)1483 wxString dlgTypeProperty::GetTypeOid(int sel)
1484 {
1485 	wxString str;
1486 	if (sel >= 0)
1487 		str = types.Item(sel).Mid(1).BeforeFirst(':');
1488 
1489 	return str;
1490 }
1491 
1492 
GetQuotedTypename(int sel)1493 wxString dlgTypeProperty::GetQuotedTypename(int sel)
1494 {
1495 	wxString sql, suffix;
1496 	bool isArray = false;
1497 
1498 	if (sel >= 0)
1499 	{
1500 		sql = types.Item(sel).AfterFirst(':');
1501 
1502 		// Deal with time/timestamp first as they're special cases
1503 		if (sql.Left(19) == wxT("time with time zone"))
1504 		{
1505 			if (sql.Right(2) == wxT("[]"))
1506 				isArray = true;
1507 			sql = wxT("time");
1508 			suffix = wxT("with time zone");
1509 		}
1510 		else if (sql.Left(21) == wxT("time without time zone"))
1511 		{
1512 			if (sql.Right(2) == wxT("[]"))
1513 				isArray = true;
1514 			sql = wxT("time");
1515 			suffix = wxT("without time zone");
1516 		}
1517 		else if (sql.Left(24) == wxT("timestamp with time zone"))
1518 		{
1519 			if (sql.Right(2) == wxT("[]"))
1520 				isArray = true;
1521 			sql = wxT("timestamp");
1522 			suffix = wxT("with time zone");
1523 		}
1524 		else if (sql.Left(27) == wxT("timestamp without time zone"))
1525 		{
1526 			if (sql.Right(2) == wxT("[]"))
1527 				isArray = true;
1528 			sql = wxT("timestamp");
1529 			suffix = wxT("without time zone");
1530 		}
1531 		else if (sql.Right(2) == wxT("[]"))
1532 		{
1533 			sql = sql.SubString(0, sql.Len() - 3);
1534 			isArray = true;
1535 		}
1536 		else if (sql.Right(3) == wxT("[]\""))
1537 		{
1538 			sql = sql.SubString(1, sql.Len() - 4);
1539 			isArray = true;
1540 		}
1541 
1542 		// Stick the length on
1543 		if (isVarLen && txtLength)
1544 		{
1545 			wxString varlen = txtLength->GetValue();
1546 			if (!varlen.IsEmpty() && NumToStr(StrToLong(varlen)) == varlen && StrToLong(varlen) >= minVarLen)
1547 			{
1548 				sql += wxT("(") + varlen;
1549 				if (isVarPrec && txtPrecision)
1550 				{
1551 					wxString varprec = txtPrecision->GetValue();
1552 					if (!varprec.IsEmpty())
1553 						sql += wxT(",") + varprec;
1554 				}
1555 				sql += wxT(")");
1556 			}
1557 		}
1558 	}
1559 
1560 	// Append any post-length suffix
1561 	if (suffix.length())
1562 		sql += wxT(" ") + suffix;
1563 
1564 	// Append any array decoration
1565 	if (isArray)
1566 		sql += wxT("[]");
1567 
1568 	return sql;
1569 }
1570 
1571 
CheckLenEnable()1572 void dlgTypeProperty::CheckLenEnable()
1573 {
1574 	int sel = cbDatatype->GetGuessedSelection();
1575 	if (sel >= 0)
1576 	{
1577 		wxString info = types.Item(sel);
1578 		isVarPrec = info.StartsWith(wxT("P"));
1579 		isVarLen =  isVarPrec || info.StartsWith(wxT("L")) || info.StartsWith(wxT("D"));
1580 		minVarLen = (info.StartsWith(wxT("D")) ? 0 : 1);
1581 		maxVarLen = isVarPrec ? 1000 :
1582 		            minVarLen ? 0x7fffffff : 10;
1583 	}
1584 }
1585 
1586 
1587 /////////////////////////////////////////////////////////////////////////////
1588 
1589 
dlgCollistProperty(pgaFactory * f,frmMain * frame,const wxString & resName,pgTable * parentNode)1590 dlgCollistProperty::dlgCollistProperty(pgaFactory *f, frmMain *frame, const wxString &resName, pgTable *parentNode)
1591 	: dlgProperty(f, frame, resName)
1592 {
1593 	columns = 0;
1594 	table = parentNode;
1595 }
1596 
1597 
dlgCollistProperty(pgaFactory * f,frmMain * frame,const wxString & resName,ctlListView * colList)1598 dlgCollistProperty::dlgCollistProperty(pgaFactory *f, frmMain *frame, const wxString &resName, ctlListView *colList)
1599 	: dlgProperty(f, frame, resName)
1600 {
1601 	columns = colList;
1602 	table = 0;
1603 }
1604 
1605 
Go(bool modal)1606 int dlgCollistProperty::Go(bool modal)
1607 {
1608 	if (columns)
1609 	{
1610 		int pos;
1611 		// iterate cols
1612 		for (pos = 0 ; pos < columns->GetItemCount() ; pos++)
1613 		{
1614 			wxString col = columns->GetItemText(pos);
1615 			if (cbColumns->FindString(col) < 0)
1616 			{
1617 				cbColumns->Append(col, StrToOid(columns->GetText(pos, 7)));
1618 			}
1619 		}
1620 	}
1621 	if (table)
1622 	{
1623 		wxCookieType cookie;
1624 		pgObject *data;
1625 		wxTreeItemId columnsItem = mainForm->GetBrowser()->GetFirstChild(table->GetId(), cookie);
1626 		while (columnsItem)
1627 		{
1628 			data = mainForm->GetBrowser()->GetObject(columnsItem);
1629 			if (data->GetMetaType() == PGM_COLUMN && data->IsCollection())
1630 				break;
1631 			columnsItem = mainForm->GetBrowser()->GetNextChild(table->GetId(), cookie);
1632 		}
1633 
1634 		if (columnsItem)
1635 		{
1636 			wxCookieType cookie;
1637 			pgColumn *column;
1638 			wxTreeItemId item = mainForm->GetBrowser()->GetFirstChild(columnsItem, cookie);
1639 
1640 			// check columns
1641 			while (item)
1642 			{
1643 				column = (pgColumn *)mainForm->GetBrowser()->GetObject(item);
1644 				if (column->IsCreatedBy(columnFactory))
1645 				{
1646 					if (column->GetColNumber() > 0)
1647 					{
1648 						cbColumns->Append(column->GetName(), column->GetAttTypId());
1649 					}
1650 				}
1651 
1652 				item = mainForm->GetBrowser()->GetNextChild(columnsItem, cookie);
1653 			}
1654 		}
1655 	}
1656 
1657 	return dlgProperty::Go(modal);
1658 }
1659 
1660 
1661 
1662 /////////////////////////////////////////////////////////////////////////////
1663 
1664 
1665 BEGIN_EVENT_TABLE(dlgSecurityProperty, dlgProperty)
1666 	EVT_BUTTON(CTL_ADDPRIV,             dlgSecurityProperty::OnAddPriv)
1667 	EVT_BUTTON(CTL_DELPRIV,             dlgSecurityProperty::OnDelPriv)
1668 #ifdef __WXMAC__
1669 	EVT_SIZE(                           dlgSecurityProperty::OnChangeSize)
1670 #endif
1671 END_EVENT_TABLE();
1672 
SetPrivilegesLayout()1673 void dlgSecurityProperty::SetPrivilegesLayout()
1674 {
1675 	securityPage->lbPrivileges->GetParent()->Layout();
1676 }
1677 
dlgSecurityProperty(pgaFactory * f,frmMain * frame,pgObject * obj,const wxString & resName,const wxString & privList,const char * privChar)1678 dlgSecurityProperty::dlgSecurityProperty(pgaFactory *f, frmMain *frame, pgObject *obj, const wxString &resName, const wxString &privList, const char *privChar)
1679 	: dlgProperty(f, frame, resName)
1680 {
1681 	securityChanged = false;
1682 
1683 
1684 	if (!privList.IsEmpty() && (!obj || obj->CanCreate()))
1685 	{
1686 		securityPage = new ctlSecurityPanel(nbNotebook, privList, privChar, frame->GetImageList());
1687 
1688 		if (obj)
1689 		{
1690 
1691 			wxArrayString groups;
1692 			// Fetch Groups Information
1693 			pgSet *setGrp = obj->GetConnection()->ExecuteSet(wxT("SELECT groname FROM pg_group ORDER BY groname"));
1694 
1695 			if (setGrp)
1696 			{
1697 				while (!setGrp->Eof())
1698 				{
1699 					groups.Add(setGrp->GetVal(0));
1700 					setGrp->MoveNext();
1701 				}
1702 				delete setGrp;
1703 			}
1704 
1705 			wxString str = obj->GetAcl();
1706 			if (!str.IsEmpty())
1707 			{
1708 				str = str.Mid(1, str.Length() - 2);
1709 				wxStringTokenizer tokens(str, wxT(","));
1710 
1711 				while (tokens.HasMoreTokens())
1712 				{
1713 					wxString str = tokens.GetNextToken();
1714 					if (str[0U] == '"')
1715 						str = str.Mid(1, str.Length() - 2);
1716 
1717 					wxString name = str.BeforeLast('=');
1718 					wxString value;
1719 
1720 					connection = obj->GetConnection();
1721 					if (connection->BackendMinimumVersion(7, 4))
1722 						value = str.Mid(name.Length() + 1).BeforeLast('/');
1723 					else
1724 						value = str.Mid(name.Length() + 1);
1725 
1726 					int icon = userFactory.GetIconId();
1727 
1728 					if (name.Left(6).IsSameAs(wxT("group "), false))
1729 					{
1730 						icon = groupFactory.GetIconId();
1731 						name = wxT("group ") + qtStrip(name.Mid(6));
1732 					}
1733 					else if (name.IsEmpty())
1734 					{
1735 						icon = PGICON_PUBLIC;
1736 						name = wxT("public");
1737 					}
1738 					else
1739 					{
1740 						name = qtStrip(name);
1741 						for (unsigned int index = 0; index < groups.Count(); index++)
1742 							if (name == groups[index])
1743 							{
1744 								name = wxT("group ") + name;
1745 								icon = groupFactory.GetIconId();
1746 								break;
1747 							}
1748 					}
1749 
1750 					securityPage->lbPrivileges->AppendItem(icon, name, value);
1751 					currentAcl.Add(name + wxT("=") + value);
1752 				}
1753 			}
1754 			else
1755 			{
1756 				int icon = PGICON_PUBLIC;
1757 				wxString name = wxT("public");
1758 				wxString value;
1759 				if (obj->GetMetaType() == PGM_DATABASE)
1760 					value = wxT("Tc");
1761 				else if (obj->GetMetaType() == PGM_FUNCTION)
1762 					value = wxT("X");
1763 				else if (obj->GetMetaType() == PGM_LANGUAGE)
1764 					value = wxT("U");
1765 
1766 				if (value != wxEmptyString)
1767 				{
1768 					securityPage->lbPrivileges->AppendItem(icon, name, value);
1769 					currentAcl.Add(name + wxT("=") + value);
1770 				}
1771 			}
1772 		}
1773 	}
1774 	else
1775 		securityPage = NULL;
1776 }
1777 
1778 
~dlgSecurityProperty()1779 dlgSecurityProperty::~dlgSecurityProperty()
1780 {
1781 }
1782 
1783 
1784 
1785 #ifdef __WXMAC__
OnChangeSize(wxSizeEvent & ev)1786 void dlgSecurityProperty::OnChangeSize(wxSizeEvent &ev)
1787 {
1788 	if (securityPage)
1789 		securityPage->lbPrivileges->SetSize(wxDefaultCoord, wxDefaultCoord,
1790 		                                    ev.GetSize().GetWidth(), ev.GetSize().GetHeight() - 550);
1791 	if (GetAutoLayout())
1792 	{
1793 		Layout();
1794 	}
1795 }
1796 #endif
1797 
1798 
Go(bool modal)1799 int dlgSecurityProperty::Go(bool modal)
1800 {
1801 	if (securityPage)
1802 	{
1803 		if (cbOwner && !cbOwner->GetCount())
1804 		{
1805 			if (!GetObject())
1806 				cbOwner->Append(wxEmptyString);
1807 			AddGroups(cbOwner);
1808 			AddUsers(cbOwner);
1809 		}
1810 
1811 		securityPage->SetConnection(connection);
1812 		//securityPage->Layout();
1813 	}
1814 
1815 	return dlgProperty::Go(modal);
1816 }
1817 
1818 
AddGroups(ctlComboBox * comboBox)1819 void dlgSecurityProperty::AddGroups(ctlComboBox *comboBox)
1820 {
1821 	if (!((securityPage && securityPage->cbGroups) || comboBox))
1822 		return;
1823 
1824 	pgSet *set = connection->ExecuteSet(wxT("SELECT groname FROM pg_group ORDER BY groname"));
1825 
1826 	if (set)
1827 	{
1828 		while (!set->Eof())
1829 		{
1830 			if (securityPage && securityPage->cbGroups)
1831 				securityPage->cbGroups->Append(wxT("group ") + set->GetVal(0));
1832 			if (comboBox)
1833 				comboBox->Append(set->GetVal(0));
1834 			set->MoveNext();
1835 		}
1836 		delete set;
1837 	}
1838 }
1839 
1840 
AddUsers(ctlComboBox * combobox)1841 void dlgSecurityProperty::AddUsers(ctlComboBox *combobox)
1842 {
1843 	if (securityPage && securityPage->cbGroups && settings->GetShowUsersForPrivileges())
1844 	{
1845 		securityPage->stGroup->SetLabel(_("Group/User"));
1846 		dlgProperty::AddUsers(securityPage->cbGroups, combobox);
1847 		Layout();
1848 	}
1849 	else
1850 		dlgProperty::AddUsers(combobox);
1851 }
1852 
1853 
OnAddPriv(wxCommandEvent & ev)1854 void dlgSecurityProperty::OnAddPriv(wxCommandEvent &ev)
1855 {
1856 	securityChanged = true;
1857 	EnableOK(btnOK->IsEnabled());
1858 }
1859 
1860 
OnDelPriv(wxCommandEvent & ev)1861 void dlgSecurityProperty::OnDelPriv(wxCommandEvent &ev)
1862 {
1863 	securityChanged = true;
1864 	EnableOK(btnOK->IsEnabled());
1865 }
1866 
1867 
GetHelpPage() const1868 wxString dlgSecurityProperty::GetHelpPage() const
1869 {
1870 	if (nbNotebook->GetSelection() == (int)nbNotebook->GetPageCount() - 2)
1871 		return wxT("pg/sql-grant");
1872 	else
1873 		return dlgProperty::GetHelpPage();
1874 }
1875 
1876 
EnableOK(bool enable,bool ignoreSql)1877 void dlgSecurityProperty::EnableOK(bool enable, bool ignoreSql)
1878 {
1879 	// Don't enable the OK button if the object isn't yet created,
1880 	// leave that to the object dialog.
1881 	if (securityChanged && GetObject() && !ignoreSql)
1882 	{
1883 		wxString sql = GetSql();
1884 		if (sql.IsEmpty())
1885 		{
1886 			enable = false;
1887 			securityChanged = false;
1888 		}
1889 		else
1890 			enable = true;
1891 	}
1892 	dlgProperty::EnableOK(enable);
1893 }
1894 
1895 
GetGrant(const wxString & allPattern,const wxString & grantObject)1896 wxString dlgSecurityProperty::GetGrant(const wxString &allPattern, const wxString &grantObject)
1897 {
1898 	if (securityPage)
1899 		return securityPage->GetGrant(allPattern, grantObject, &currentAcl);
1900 	else
1901 		return wxString();
1902 }
1903 
DisablePrivilege(const wxString & priv)1904 bool dlgSecurityProperty::DisablePrivilege(const wxString &priv)
1905 {
1906 	if (securityPage)
1907 		return securityPage->DisablePrivilege(priv);
1908 	else
1909 		return true;
1910 }
1911 
AppendCurrentAcl(const wxString & name,const wxString & value)1912 void dlgSecurityProperty::AppendCurrentAcl(const wxString &name, const wxString &value)
1913 {
1914 	if (!(name.IsEmpty() && value.IsEmpty()))
1915 		currentAcl.Add(name + wxT("=") + value);
1916 }
1917 
1918 
1919 /////////////////////////////////////////////////////////////////////////////
1920 
1921 
1922 BEGIN_EVENT_TABLE(dlgDefaultSecurityProperty, dlgSecurityProperty)
1923 	EVT_BUTTON(CTL_DEFADDPRIV, dlgDefaultSecurityProperty::OnAddPriv)
1924 	EVT_BUTTON(CTL_DEFDELPRIV, dlgDefaultSecurityProperty::OnDelPriv)
1925 #ifdef __WXMAC__
1926 	EVT_SIZE(                  dlgDefaultSecurityProperty::OnChangeSize)
1927 #endif
1928 END_EVENT_TABLE();
1929 
1930 
dlgDefaultSecurityProperty(pgaFactory * f,frmMain * frame,pgObject * obj,const wxString & resName,const wxString & privList,const char * privChar,bool createDefPrivPanel)1931 dlgDefaultSecurityProperty::dlgDefaultSecurityProperty(pgaFactory *f, frmMain *frame, pgObject *obj, const wxString &resName, const wxString &privList, const char *privChar, bool createDefPrivPanel)
1932 	: dlgSecurityProperty(f, frame, obj, resName, privList, privChar), defaultSecurityChanged(false)
1933 {
1934 	pgConn *l_conn = obj ? obj->GetConnection() : connection;
1935 	if ((!obj || obj->CanCreate()) && createDefPrivPanel)
1936 		defaultSecurityPage = new ctlDefaultSecurityPanel(l_conn, nbNotebook, frame->GetImageList());
1937 	else
1938 		defaultSecurityPage = NULL;
1939 }
1940 
1941 
AddGroups(ctlComboBox * comboBox)1942 void dlgDefaultSecurityProperty::AddGroups(ctlComboBox *comboBox)
1943 {
1944 	if (!((securityPage && securityPage->cbGroups) || comboBox || defaultSecurityPage))
1945 		return;
1946 
1947 	pgSet *set = connection->ExecuteSet(wxT("SELECT groname FROM pg_group ORDER BY groname"));
1948 
1949 	if (set)
1950 	{
1951 		while (!set->Eof())
1952 		{
1953 			if (securityPage && securityPage->cbGroups)
1954 				securityPage->cbGroups->Append(wxT("group ") + set->GetVal(0));
1955 
1956 			if (comboBox)
1957 				comboBox->Append(set->GetVal(0));
1958 
1959 			if (defaultSecurityPage)
1960 				defaultSecurityPage->m_groups.Add(wxT("group ") + set->GetVal(0));
1961 
1962 			set->MoveNext();
1963 		}
1964 		delete set;
1965 	}
1966 }
1967 
1968 
AddUsers(ctlComboBox * combobox)1969 void dlgDefaultSecurityProperty::AddUsers(ctlComboBox *combobox)
1970 {
1971 	if ((securityPage && securityPage->cbGroups) || defaultSecurityPage || combobox)
1972 	{
1973 		wxString strFetchUserQuery =
1974 		    connection->BackendMinimumVersion(8, 1) ?
1975 		    wxT("SELECT rolname FROM pg_roles WHERE rolcanlogin ORDER BY 1") :
1976 		    wxT("SELECT usename FROM pg_user ORDER BY 1");
1977 
1978 		pgSet *set = connection->ExecuteSet(strFetchUserQuery);
1979 		if (set)
1980 		{
1981 			while (!set->Eof())
1982 			{
1983 				if (settings->GetShowUsersForPrivileges())
1984 				{
1985 					if (securityPage && securityPage->cbGroups)
1986 						securityPage->cbGroups->Append(set->GetVal(0));
1987 
1988 					if (defaultSecurityPage)
1989 						defaultSecurityPage->m_groups.Add(set->GetVal(0));
1990 				}
1991 
1992 				if (combobox)
1993 					combobox->Append(set->GetVal(0));
1994 
1995 				set->MoveNext();
1996 			}
1997 			delete set;
1998 		}
1999 	}
2000 }
2001 
2002 #ifdef __WXMAC__
OnChangeSize(wxSizeEvent & ev)2003 void dlgDefaultSecurityProperty::OnChangeSize(wxSizeEvent &ev)
2004 {
2005 	wxSize l_size = ev.GetSize();
2006 	if (defaultSecurityPage && l_size.GetWidth() > 10 && l_size.GetHeight() > 25)
2007 		defaultSecurityPage->SetSize(l_size.GetWidth() - 10, l_size.GetHeight() - 25);
2008 	dlgSecurityProperty::OnChangeSize(ev);
2009 }
2010 #endif
2011 
2012 
EnableOK(bool enable,bool ignoreSql)2013 void dlgDefaultSecurityProperty::EnableOK(bool enable, bool ignoreSql)
2014 {
2015 	// Don't enable the OK button if the object isn't yet created,
2016 	// leave that to the object dialog.
2017 	if (GetObject() && !ignoreSql)
2018 	{
2019 		wxString sql = GetSql();
2020 		if (sql.IsEmpty())
2021 		{
2022 			enable = false;
2023 		}
2024 		else
2025 			enable = true;
2026 	}
2027 	dlgSecurityProperty::EnableOK(enable, ignoreSql);
2028 }
2029 
2030 
OnAddPriv(wxCommandEvent & ev)2031 void dlgDefaultSecurityProperty::OnAddPriv(wxCommandEvent &ev)
2032 {
2033 	defaultSecurityChanged = true;
2034 	EnableOK(btnOK->IsEnabled());
2035 }
2036 
2037 
OnDelPriv(wxCommandEvent & ev)2038 void dlgDefaultSecurityProperty::OnDelPriv(wxCommandEvent &ev)
2039 {
2040 	defaultSecurityChanged = true;
2041 	EnableOK(btnOK->IsEnabled());
2042 }
2043 
GetDefaultPrivileges(const wxString & schemaName)2044 wxString dlgDefaultSecurityProperty::GetDefaultPrivileges(const wxString &schemaName)
2045 {
2046 	if (defaultSecurityChanged)
2047 		return defaultSecurityPage->GetDefaultPrivileges(schemaName);
2048 	return wxT("");
2049 }
2050 
Go(bool modal,bool createDefPrivs,const wxString & defPrivsOnTables,const wxString & defPrivsOnSeqs,const wxString & defPrivsOnFuncs,const wxString & defPrivsOnTypes)2051 int dlgDefaultSecurityProperty::Go(bool modal, bool createDefPrivs, const wxString &defPrivsOnTables,
2052                                    const wxString &defPrivsOnSeqs, const wxString &defPrivsOnFuncs,
2053                                    const wxString &defPrivsOnTypes)
2054 {
2055 	if (securityPage)
2056 	{
2057 		if (cbOwner && !cbOwner->GetCount())
2058 		{
2059 			if (!GetObject())
2060 				cbOwner->Append(wxEmptyString);
2061 			AddGroups(cbOwner);
2062 			AddUsers(cbOwner);
2063 		}
2064 
2065 		securityPage->SetConnection(connection);
2066 		//securityPage->Layout();
2067 	}
2068 
2069 	int res = dlgSecurityProperty::Go(modal);
2070 
2071 	if (defaultSecurityPage)
2072 	{
2073 		if (createDefPrivs && connection->BackendMinimumVersion(9, 0))
2074 			defaultSecurityPage->UpdatePrivilegePages(createDefPrivs, defPrivsOnTables,
2075 			        defPrivsOnSeqs, defPrivsOnFuncs, defPrivsOnTypes);
2076 		else
2077 			defaultSecurityPage->Enable(false);
2078 	}
2079 
2080 	return res;
2081 }
2082 
GetHelpPage() const2083 wxString dlgDefaultSecurityProperty::GetHelpPage() const
2084 {
2085 	int nDiff      = nbNotebook->GetPageCount() - nbNotebook->GetSelection();
2086 
2087 	switch (nDiff)
2088 	{
2089 		case 3:
2090 			return wxT("pg/sql-grant");
2091 		case 2:
2092 			return wxT("pg/sql-alterdefaultprivileges");
2093 		default:
2094 			return dlgProperty::GetHelpPage();
2095 	}
2096 }
2097 
2098 /////////////////////////////////////////////////////////////////////////////
2099 
2100 
2101 BEGIN_EVENT_TABLE(dlgAgentProperty, dlgProperty)
2102 	EVT_BUTTON (wxID_OK,                            dlgAgentProperty::OnOK)
2103 END_EVENT_TABLE();
2104 
dlgAgentProperty(pgaFactory * f,frmMain * frame,const wxString & resName)2105 dlgAgentProperty::dlgAgentProperty(pgaFactory *f, frmMain *frame, const wxString &resName)
2106 	: dlgProperty(f, frame, resName)
2107 {
2108 	recId = 0;
2109 }
2110 
2111 
GetSql()2112 wxString dlgAgentProperty::GetSql()
2113 {
2114 	wxString str = GetInsertSql();
2115 	if (!str.IsEmpty())
2116 		str += wxT("\n\n");
2117 	return str + GetUpdateSql();
2118 }
2119 
2120 
2121 
executeSql()2122 bool dlgAgentProperty::executeSql()
2123 {
2124 	wxString sql;
2125 	bool dataChanged = false;
2126 
2127 	sql = GetInsertSql();
2128 	if (!sql.IsEmpty())
2129 	{
2130 		int pos;
2131 		long jobId = 0, schId = 0, stpId = 0;
2132 		if (sql.Contains(wxT("<JobId>")))
2133 		{
2134 			recId = jobId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_job_jobid_seq');")));
2135 			while ((pos = sql.Find(wxT("<JobId>"))) >= 0)
2136 				sql = sql.Left(pos) + NumToStr(jobId) + sql.Mid(pos + 7);
2137 		}
2138 
2139 		if (sql.Contains(wxT("<SchId>")))
2140 		{
2141 			// Each schedule ID should be unique. This'll need work if a schedule hits more than
2142 			// one table or anything.
2143 			recId = schId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_schedule_jscid_seq');")));
2144 			while ((pos = sql.Find(wxT("<SchId>"))) >= 0)
2145 			{
2146 				sql = sql.Left(pos) + NumToStr(schId) + sql.Mid(pos + 7);
2147 				recId = schId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_schedule_jscid_seq');")));
2148 			}
2149 		}
2150 
2151 		if (sql.Contains(wxT("<StpId>")))
2152 		{
2153 			// Each step ID should be unique. This'll need work if a step hits more than
2154 			// one table or anything.
2155 			recId = stpId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_jobstep_jstid_seq');")));
2156 			while ((pos = sql.Find(wxT("<StpId>"))) >= 0)
2157 			{
2158 				sql = sql.Left(pos) + NumToStr(stpId) + sql.Mid(pos + 7);
2159 				recId = stpId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_jobstep_jstid_seq');")));
2160 			}
2161 		}
2162 
2163 		pgSet *set = connection->ExecuteSet(sql);
2164 		if (set)
2165 		{
2166 			delete set;
2167 		}
2168 		if (!set)
2169 		{
2170 			return false;
2171 		}
2172 		dataChanged = true;
2173 	}
2174 
2175 	sql = GetUpdateSql();
2176 	if (!sql.IsEmpty())
2177 	{
2178 		int pos;
2179 		while ((pos = sql.Find(wxT("<JobId>"))) >= 0)
2180 			sql = sql.Left(pos) + NumToStr(recId) + sql.Mid(pos + 7);
2181 
2182 		long newId;
2183 		if (sql.Contains(wxT("<SchId>")))
2184 		{
2185 			// Each schedule ID should be unique. This'll need work if a schedule hits more than
2186 			// one table or anything.
2187 			newId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_schedule_jscid_seq');")));
2188 			while ((pos = sql.Find(wxT("<SchId>"))) >= 0)
2189 			{
2190 				sql = sql.Left(pos) + NumToStr(newId) + sql.Mid(pos + 7);
2191 				newId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_schedule_jscid_seq');")));
2192 			}
2193 		}
2194 
2195 		if (sql.Contains(wxT("<StpId>")))
2196 		{
2197 			// Each step ID should be unique. This'll need work if a step hits more than
2198 			// one table or anything.
2199 			newId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_jobstep_jstid_seq');")));
2200 			while ((pos = sql.Find(wxT("<StpId>"))) >= 0)
2201 			{
2202 				sql = sql.Left(pos) + NumToStr(newId) + sql.Mid(pos + 7);
2203 				newId = StrToLong(connection->ExecuteScalar(wxT("SELECT nextval('pgagent.pga_jobstep_jstid_seq');")));
2204 			}
2205 		}
2206 
2207 		if (!connection->ExecuteVoid(sql))
2208 		{
2209 			// error message is displayed inside ExecuteVoid
2210 			return false;
2211 		}
2212 		dataChanged = true;
2213 	}
2214 
2215 	return dataChanged;
2216 }
2217 
2218 
OnOK(wxCommandEvent & ev)2219 void dlgAgentProperty::OnOK(wxCommandEvent &ev)
2220 {
2221 #ifdef __WXGTK__
2222 	if (!btnOK->IsEnabled())
2223 		return;
2224 #endif
2225 	if (!IsUpToDate())
2226 	{
2227 		if (wxMessageBox(wxT("The object has been changed by another user. Do you wish to continue to try to update it?"), wxT("Overwrite changes?"), wxYES_NO) != wxYES)
2228 			return;
2229 	}
2230 
2231 	if (IsModal())
2232 	{
2233 		EndModal(0);
2234 		return;
2235 	}
2236 
2237 	connection->ExecuteVoid(wxT("BEGIN TRANSACTION"));
2238 
2239 	if (executeSql())
2240 	{
2241 		connection->ExecuteVoid(wxT("COMMIT TRANSACTION"));
2242 		ShowObject();
2243 	}
2244 	else
2245 	{
2246 		connection->ExecuteVoid(wxT("ROLLBACK TRANSACTION"));
2247 	}
2248 
2249 	Destroy();
2250 }
2251 
2252 
propertyFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2253 propertyFactory::propertyFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2254 {
2255 	if (mnu)
2256 		mnu->Append(id, _("&Properties...\tCtrl-Alt-Enter"), _("Display/edit the properties of the selected object."));
2257 	else
2258 		context = false;
2259 	if (toolbar)
2260 		toolbar->AddTool(id, wxEmptyString, *properties_png_bmp, _("Display/edit the properties of the selected object."), wxITEM_NORMAL);
2261 }
2262 
2263 
StartDialog(frmMain * form,pgObject * obj)2264 wxWindow *propertyFactory::StartDialog(frmMain *form, pgObject *obj)
2265 {
2266 	if (!dlgProperty::EditObjectDialog(form, form->GetSqlPane(), obj))
2267 		form->CheckAlive();
2268 
2269 	return 0;
2270 }
2271 
2272 
CheckEnable(pgObject * obj)2273 bool propertyFactory::CheckEnable(pgObject *obj)
2274 {
2275 	return obj && ((obj->GetMetaType() == PGM_DATABASE) ? (obj->GetConnection() != NULL) : true) && obj->CanEdit();
2276 }
2277 
2278 
2279 #include "images/create.pngc"
createFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2280 createFactory::createFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : actionFactory(list)
2281 {
2282 	mnu->Append(id, _("&Create..."),  _("Create a new object of the same type as the selected object."));
2283 	toolbar->AddTool(id, wxEmptyString, *create_png_bmp, _("Create a new object of the same type as the selected object."), wxITEM_NORMAL);
2284 }
2285 
2286 
StartDialog(frmMain * form,pgObject * obj)2287 wxWindow *createFactory::StartDialog(frmMain *form, pgObject *obj)
2288 {
2289 	if (!dlgProperty::CreateObjectDialog(form, obj, 0))
2290 		form->CheckAlive();
2291 
2292 	return 0;
2293 }
2294 
2295 
CheckEnable(pgObject * obj)2296 bool createFactory::CheckEnable(pgObject *obj)
2297 {
2298 	return obj && obj->CanCreate();
2299 }
2300 
2301 
2302 #include "images/drop.pngc"
dropFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2303 dropFactory::dropFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2304 {
2305 	mnu->Append(id, _("&Delete/Drop...\tDel"),  _("Delete/Drop the selected object."));
2306 	toolbar->AddTool(id, wxEmptyString, *drop_png_bmp, _("Drop the currently selected object."), wxITEM_NORMAL);
2307 }
2308 
2309 
StartDialog(frmMain * form,pgObject * obj)2310 wxWindow *dropFactory::StartDialog(frmMain *form, pgObject *obj)
2311 {
2312 	form->ExecDrop(false);
2313 	return 0;
2314 }
2315 
2316 
CheckEnable(pgObject * obj)2317 bool dropFactory::CheckEnable(pgObject *obj)
2318 {
2319 	return obj && obj->CanDrop();
2320 }
2321 
2322 
dropCascadedFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2323 dropCascadedFactory::dropCascadedFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2324 {
2325 	mnu->Append(id, _("Drop cascaded..."), _("Drop the selected object and all objects dependent on it."));
2326 }
2327 
2328 
StartDialog(frmMain * form,pgObject * obj)2329 wxWindow *dropCascadedFactory::StartDialog(frmMain *form, pgObject *obj)
2330 {
2331 	form->ExecDrop(true);
2332 	return 0;
2333 }
2334 
2335 
CheckEnable(pgObject * obj)2336 bool dropCascadedFactory::CheckEnable(pgObject *obj)
2337 {
2338 	return obj && obj->CanDrop() && obj->CanDropCascaded();
2339 }
2340 
2341 
2342 #include "images/refresh.pngc"
refreshFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)2343 refreshFactory::refreshFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
2344 {
2345 	if (mnu)
2346 		mnu->Append(id, _("Re&fresh\tF5"), _("Refresh the selected object."));
2347 	else
2348 		context = false;
2349 	if (toolbar)
2350 		toolbar->AddTool(id, wxEmptyString, *refresh_png_bmp, _("Refresh the selected object."), wxITEM_NORMAL);
2351 }
2352 
2353 
StartDialog(frmMain * form,pgObject * obj)2354 wxWindow *refreshFactory::StartDialog(frmMain *form, pgObject *obj)
2355 {
2356 	if (form)
2357 		obj = form->GetBrowser()->GetObject(form->GetBrowser()->GetSelection());
2358 
2359 	if (obj)
2360 		if (CheckEnable(obj))
2361 			form->Refresh(obj);
2362 	return 0;
2363 }
2364 
2365 
CheckEnable(pgObject * obj)2366 bool refreshFactory::CheckEnable(pgObject *obj)
2367 {
2368 	// This isn't really clean... But we don't have a pgObject::CanRefresh() so far,
2369 	// so it's Good Enough (tm) for now.
2370 	return obj != 0 && !obj->IsCreatedBy(serverFactory.GetCollectionFactory());
2371 }
2372 
2373