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 // pgDomain.cpp - Domain class
9 //
10 //////////////////////////////////////////////////////////////////////////
11
12 // wxWindows headers
13 #include <wx/wx.h>
14
15 // App headers
16 #include "pgAdmin3.h"
17 #include "frm/frmMain.h"
18 #include "utils/misc.h"
19 #include "schema/pgDomain.h"
20 #include "schema/pgDatatype.h"
21
22 #include "schema/pgTable.h"
23 #include "schema/pgColumn.h"
24 #include "schema/pgIndexConstraint.h"
25 #include "schema/pgForeignKey.h"
26 #include "schema/pgCheck.h"
27 #include "utils/sysSettings.h"
28 #include "utils/pgfeatures.h"
29 #include "schema/pgRule.h"
30 #include "schema/pgTrigger.h"
31 #include "schema/pgConstraints.h"
32 #include "schema/gpPartition.h"
33
34
pgDomain(pgSchema * newSchema,const wxString & newName)35 pgDomain::pgDomain(pgSchema *newSchema, const wxString &newName)
36 : pgSchemaObject(newSchema, domainFactory, newName)
37 {
38 }
39
~pgDomain()40 pgDomain::~pgDomain()
41 {
42 }
43
GetTranslatedMessage(int kindOfMessage) const44 wxString pgDomain::GetTranslatedMessage(int kindOfMessage) const
45 {
46 wxString message = wxEmptyString;
47
48 switch (kindOfMessage)
49 {
50 case RETRIEVINGDETAILS:
51 message = _("Retrieving details on domain");
52 message += wxT(" ") + GetName();
53 break;
54 case REFRESHINGDETAILS:
55 message = _("Refreshing domain");
56 message += wxT(" ") + GetName();
57 break;
58 case DROPINCLUDINGDEPS:
59 message = wxString::Format(_("Are you sure you wish to drop domain \"%s\" including all objects that depend on it?"),
60 GetFullIdentifier().c_str());
61 break;
62 case DROPEXCLUDINGDEPS:
63 message = wxString::Format(_("Are you sure you wish to drop domain \"%s\"?"),
64 GetFullIdentifier().c_str());
65 break;
66 case DROPCASCADETITLE:
67 message = _("Drop domain cascaded?");
68 break;
69 case DROPTITLE:
70 message = _("Drop domain?");
71 break;
72 case PROPERTIESREPORT:
73 message = _("Domain properties report");
74 message += wxT(" - ") + GetName();
75 break;
76 case PROPERTIES:
77 message = _("Domain properties");
78 break;
79 case DDLREPORT:
80 message = _("Domain DDL report");
81 message += wxT(" - ") + GetName();
82 break;
83 case DDL:
84 message = _("Domain DDL");
85 break;
86 case DEPENDENCIESREPORT:
87 message = _("Domain dependencies report");
88 message += wxT(" - ") + GetName();
89 break;
90 case DEPENDENCIES:
91 message = _("Domain dependencies");
92 break;
93 case DEPENDENTSREPORT:
94 message = _("Domain dependents report");
95 message += wxT(" - ") + GetName();
96 break;
97 case DEPENDENTS:
98 message = _("Domain dependents");
99 break;
100 }
101
102 return message;
103 }
104
105
DropObject(wxFrame * frame,ctlTree * browser,bool cascaded)106 bool pgDomain::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
107 {
108 wxString sql = wxT("DROP DOMAIN ") + this->GetSchema()->GetQuotedIdentifier() + wxT(".") + this->GetQuotedIdentifier();
109 if (cascaded)
110 sql += wxT(" CASCADE");
111 return GetDatabase()->ExecuteVoid(sql);
112 }
113
GetSql(ctlTree * browser)114 wxString pgDomain::GetSql(ctlTree *browser)
115 {
116 if (sql.IsNull())
117 {
118 sql = wxT("-- Domain: ") + GetQuotedFullIdentifier() + wxT("\n\n")
119 + wxT("-- DROP DOMAIN ") + GetQuotedFullIdentifier() + wxT(";")
120 + wxT("\n\nCREATE DOMAIN ") + GetQuotedFullIdentifier()
121 + wxT("\n AS ") + GetQuotedBasetype();
122 if (GetCollationOid() > 0)
123 sql += wxT("\n COLLATE ") + GetQuotedCollation();
124 AppendIfFilled(sql, wxT("\n DEFAULT "), GetDefault());
125 // CONSTRAINT Name Dont know where it's stored, may be omitted anyway
126 if (notNull)
127 sql += wxT("\n NOT NULL");
128
129 // Get a count of the constraints.
130 int consCount = 0;
131 pgCollection *constraints = browser->FindCollection(checkFactory, GetId());
132 if (constraints)
133 {
134 constraints->ShowTreeDetail(browser);
135 treeObjectIterator consIt(browser, constraints);
136
137 pgObject *data;
138
139 while ((data = consIt.GetNextObject()) != 0)
140 {
141 data->ShowTreeDetail(browser);
142
143 sql += wxT("\n CONSTRAINT ") + data->GetQuotedIdentifier()
144 + wxT(" ") + data->GetTypeName().Upper()
145 + wxT(" ") ;
146
147 switch (data->GetMetaType())
148 {
149 case PGM_CHECK:
150 sql += wxT("(") + ((pgCheck *)data)->GetDefinition() + wxT(")");
151 if (GetDatabase()->BackendMinimumVersion(9, 2) && !((pgCheck *)data)->GetValid())
152 sql += wxT(" NOT VALID");
153 break;
154 }
155 }
156 }
157
158 sql += wxT(";\n")
159 + GetOwnerSql(7, 4)
160 + GetCommentSql();
161
162 if (GetConnection()->BackendMinimumVersion(9, 1))
163 sql += GetSeqLabelsSql();
164 }
165
166 return sql;
167 }
168
169
GetNewMenu()170 wxMenu *pgDomain::GetNewMenu()
171 {
172 wxMenu *menu = pgObject::GetNewMenu();
173 if (schema->GetCreatePrivilege())
174 {
175 checkFactory.AppendMenu(menu);
176 }
177 return menu;
178 }
179
180
ShowTreeDetail(ctlTree * browser,frmMain * form,ctlListView * properties,ctlSQLBox * sqlPane)181 void pgDomain::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
182 {
183 if (!expandedKids)
184 {
185 expandedKids = true;
186
187 browser->RemoveDummyChild(this);
188
189 // Log
190 wxLogInfo(wxT("Adding child object to domain %s"), GetIdentifier().c_str());
191 if (GetConnection()->BackendMinimumVersion(7, 4))
192 browser->AppendCollection(this, constraintFactory);
193 }
194
195 if (properties)
196 {
197 CreateListColumns(properties);
198
199 properties->AppendItem(_("Name"), GetName());
200 properties->AppendItem(_("OID"), GetOid());
201 properties->AppendItem(_("Owner"), GetOwner());
202 properties->AppendItem(_("Base type"), GetBasetype());
203 if (GetDimensions())
204 properties->AppendItem(_("Dimensions"), GetDimensions());
205 if (GetCollationOid() > 0)
206 properties->AppendItem(_("Collation"), GetQuotedCollation());
207 properties->AppendItem(_("Default"), GetDefault());
208 properties->AppendYesNoItem(_("Not NULL?"), GetNotNull());
209 properties->AppendYesNoItem(_("System domain?"), GetSystemObject());
210 properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
211
212 if (!GetLabels().IsEmpty())
213 {
214 wxArrayString seclabels = GetProviderLabelArray();
215 if (seclabels.GetCount() > 0)
216 {
217 for (unsigned int index = 0 ; index < seclabels.GetCount() - 1 ; index += 2)
218 {
219 properties->AppendItem(seclabels.Item(index), seclabels.Item(index + 1));
220 }
221 }
222 }
223 }
224 }
225
226
227
Refresh(ctlTree * browser,const wxTreeItemId item)228 pgObject *pgDomain::Refresh(ctlTree *browser, const wxTreeItemId item)
229 {
230 pgObject *domain = 0;
231
232 pgCollection *coll = browser->GetParentCollection(item);
233 if (coll)
234 domain = domainFactory.CreateObjects(coll, 0, wxT(" AND d.oid=") + GetOidStr() + wxT("\n"));
235
236 return domain;
237 }
238
239
Validate(frmMain * form)240 void pgDomain::Validate(frmMain *form)
241 {
242 wxString sql = wxT("ALTER DOMAIN ") + GetQuotedFullIdentifier()
243 + wxT("\n VALIDATE CONSTRAINT ") + GetCheckConstraintName();
244 GetDatabase()->ExecuteVoid(sql);
245
246 iSetValid(true);
247 UpdateIcon(form->GetBrowser());
248 }
249
250
251 ////////////////////////////////////////////////////
252
253
254
CreateObjects(pgCollection * collection,ctlTree * browser,const wxString & restriction)255 pgObject *pgDomainFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
256 {
257 wxString sql;
258 pgDomain *domain = 0;
259
260 pgDatabase *db = collection->GetDatabase();
261
262 sql = wxT("SELECT d.oid, d.typname as domname, d.typbasetype, format_type(b.oid,NULL) as basetype, pg_get_userbyid(d.typowner) as domainowner, \n");
263 if (collection->GetDatabase()->BackendMinimumVersion(9, 1))
264 sql += wxT("c.oid AS colloid, c.collname, cn.nspname as collnspname, \n");
265 sql += wxT(" d.typlen, d.typtypmod, d.typnotnull, d.typdefault, d.typndims, d.typdelim, bn.nspname as basensp,\n")
266 wxT(" description, (SELECT COUNT(1) FROM pg_type t2 WHERE t2.typname=d.typname) > 1 AS domisdup,\n")
267 wxT(" (SELECT COUNT(1) FROM pg_type t3 WHERE t3.typname=b.typname) > 1 AS baseisdup");
268 if (collection->GetDatabase()->BackendMinimumVersion(9, 1))
269 {
270 sql += wxT(",\n(SELECT array_agg(label) FROM pg_seclabels sl1 WHERE sl1.objoid=d.oid) AS labels");
271 sql += wxT(",\n(SELECT array_agg(provider) FROM pg_seclabels sl2 WHERE sl2.objoid=d.oid) AS providers");
272 }
273 sql += wxT("\n FROM pg_type d\n")
274 wxT(" JOIN pg_type b ON b.oid = d.typbasetype\n")
275 wxT(" JOIN pg_namespace bn ON bn.oid=b.typnamespace\n")
276 wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid=d.oid AND des.classoid='pg_type'::regclass)\n");
277 if (collection->GetDatabase()->BackendMinimumVersion(9, 1))
278 sql += wxT(" LEFT OUTER JOIN pg_collation c ON d.typcollation=c.oid\n")
279 wxT(" LEFT OUTER JOIN pg_namespace cn ON c.collnamespace=cn.oid\n");
280 sql += wxT(" WHERE d.typtype = 'd' AND d.typnamespace = ") + NumToStr(collection->GetSchema()->GetOid()) + wxT("::oid\n")
281 + restriction +
282 wxT(" ORDER BY d.typname");
283 pgSet *domains = db->ExecuteSet(sql);
284
285 if (domains)
286 {
287 while (!domains->Eof())
288 {
289 domain = new pgDomain(collection->GetSchema(), domains->GetVal(wxT("domname")));
290
291 domain->iSetOid(domains->GetOid(wxT("oid")));
292 domain->iSetOwner(domains->GetVal(wxT("domainowner")));
293 domain->iSetBasetype(domains->GetVal(wxT("basetype")));
294 domain->iSetBasetypeOid(domains->GetOid(wxT("typbasetype")));
295 domain->iSetComment(domains->GetVal(wxT("description")));
296 long typmod = domains->GetLong(wxT("typtypmod"));
297
298 pgDatatype dt(domains->GetVal(wxT("basensp")), domains->GetVal(wxT("basetype")),
299 domains->GetBool(wxT("baseisdup")), domains->GetLong(wxT("typndims")), typmod);
300
301 domain->iSetTyplen(domains->GetLong(wxT("typlen")));
302 domain->iSetTypmod(typmod);
303 domain->iSetLength(dt.Length());
304 domain->iSetPrecision(dt.Precision());
305 domain->iSetBasetype(dt.GetSchemaPrefix(db) + dt.FullName());
306 domain->iSetQuotedBasetype(dt.GetQuotedSchemaPrefix(db) + dt.QuotedFullName());
307 domain->iSetDefault(domains->GetVal(wxT("typdefault")));
308 domain->iSetNotNull(domains->GetBool(wxT("typnotnull")));
309 domain->iSetDimensions(domains->GetLong(wxT("typndims")));
310 domain->iSetDelimiter(domains->GetVal(wxT("typdelim")));
311 domain->iSetIsDup(domains->GetBool(wxT("domisdup")));
312 if (collection->GetDatabase()->BackendMinimumVersion(9, 1))
313 {
314 domain->iSetCollation(domains->GetVal(wxT("collname")));
315 domain->iSetQuotedCollation(qtIdent(domains->GetVal(wxT("collnspname"))) + wxT(".") + qtIdent(domains->GetVal(wxT("collname"))));
316 domain->iSetCollationOid(domains->GetOid(wxT("colloid")));
317 }
318 else
319 domain->iSetCollationOid(0);
320
321 if (collection->GetDatabase()->BackendMinimumVersion(9, 1))
322 {
323 domain->iSetProviders(domains->GetVal(wxT("providers")));
324 domain->iSetLabels(domains->GetVal(wxT("labels")));
325 }
326
327 // we suppose the constraint valid now
328 // this is checked in ShowTreeDetail for each domain
329 domain->iSetValid(true);
330
331 if (browser)
332 {
333 browser->AppendObject(collection, domain);
334 domains->MoveNext();
335 }
336 else
337 break;
338 }
339
340 delete domains;
341 }
342 return domain;
343 }
344
345 /////////////////////////////
346
pgDomainCollection(pgaFactory * factory,pgSchema * sch)347 pgDomainCollection::pgDomainCollection(pgaFactory *factory, pgSchema *sch)
348 : pgSchemaObjCollection(factory, sch)
349 {
350 }
351
352
GetTranslatedMessage(int kindOfMessage) const353 wxString pgDomainCollection::GetTranslatedMessage(int kindOfMessage) const
354 {
355 wxString message = wxEmptyString;
356
357 switch (kindOfMessage)
358 {
359 case RETRIEVINGDETAILS:
360 message = _("Retrieving details on domains");
361 break;
362 case REFRESHINGDETAILS:
363 message = _("Refreshing domains");
364 break;
365 case OBJECTSLISTREPORT:
366 message = _("Domains list report");
367 break;
368 }
369
370 return message;
371 }
372
373 /////////////////////////////
374
375 #include "images/domain.pngc"
376 #include "images/domain-sm.pngc"
377 #include "images/domains.pngc"
378
pgDomainFactory()379 pgDomainFactory::pgDomainFactory()
380 : pgSchemaObjFactory(__("Domain"), __("New Domain..."), __("Create a new Domain."), domain_png_img, domain_sm_png_img)
381 {
382 metaType = PGM_DOMAIN;
383 }
384
385
CreateCollection(pgObject * obj)386 pgCollection *pgDomainFactory::CreateCollection(pgObject *obj)
387 {
388 return new pgDomainCollection(GetCollectionFactory(), (pgSchema *)obj);
389 }
390
391 pgDomainFactory domainFactory;
392 static pgaCollectionFactory cf(&domainFactory, __("Domains"), domains_png_img);
393
validateDomainCheckFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)394 validateDomainCheckFactory::validateDomainCheckFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
395 {
396 mnu->Append(id, _("Validate domain check constraint"), _("Validate the selected domain check constraint."));
397 }
398
399
StartDialog(frmMain * form,pgObject * obj)400 wxWindow *validateDomainCheckFactory::StartDialog(frmMain *form, pgObject *obj)
401 {
402 ((pgDomain *)obj)->Validate(form);
403 ((pgDomain *)obj)->SetDirty();
404
405 wxTreeItemId item = form->GetBrowser()->GetSelection();
406 if (obj == form->GetBrowser()->GetObject(item))
407 {
408 obj->ShowTreeDetail(form->GetBrowser(), 0, form->GetProperties());
409 form->GetSqlPane()->SetReadOnly(false);
410 form->GetSqlPane()->SetText(((pgDomain *)obj)->GetSql(form->GetBrowser()));
411 form->GetSqlPane()->SetReadOnly(true);
412 }
413 form->GetMenuFactories()->CheckMenu(obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar());
414
415 return 0;
416 }
417
418
CheckEnable(pgObject * obj)419 bool validateDomainCheckFactory::CheckEnable(pgObject *obj)
420 {
421 return obj && obj->IsCreatedBy(domainFactory) && obj->CanEdit()
422 && ((pgDomain *)obj)->GetConnection()->BackendMinimumVersion(9, 2)
423 && !((pgDomain *)obj)->GetValid();
424 }
425
426