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, ¤tAcl);
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