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 // pgCheck.cpp - Check 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/pgCheck.h"
20 
21 
pgCheck(pgSchema * newSchema,const wxString & newName)22 pgCheck::pgCheck(pgSchema *newSchema, const wxString &newName)
23 	: pgSchemaObject(newSchema, checkFactory, newName)
24 {
25 }
26 
~pgCheck()27 pgCheck::~pgCheck()
28 {
29 }
30 
31 
GetTranslatedMessage(int kindOfMessage) const32 wxString pgCheck::GetTranslatedMessage(int kindOfMessage) const
33 {
34 	wxString message = wxEmptyString;
35 
36 	switch (kindOfMessage)
37 	{
38 		case RETRIEVINGDETAILS:
39 			message = _("Retrieving details on check constraint");
40 			message += wxT(" ") + GetName();
41 			break;
42 		case REFRESHINGDETAILS:
43 			message = _("Refreshing check constraint");
44 			message += wxT(" ") + GetName();
45 			break;
46 		case GRANTWIZARDTITLE:
47 			message = _("Privileges for check constraint");
48 			message += wxT(" ") + GetName();
49 			break;
50 		case DROPINCLUDINGDEPS:
51 			message = wxString::Format(_("Are you sure you wish to drop check constraint \"%s\" including all objects that depend on it?"),
52 			                           GetFullIdentifier().c_str());
53 			break;
54 		case DROPEXCLUDINGDEPS:
55 			message = wxString::Format(_("Are you sure you wish to drop check constraint \"%s\"?"),
56 			                           GetFullIdentifier().c_str());
57 			break;
58 		case DROPCASCADETITLE:
59 			message = _("Drop check constraint cascaded?");
60 			break;
61 		case DROPTITLE:
62 			message = _("Drop check constraint?");
63 			break;
64 		case PROPERTIESREPORT:
65 			message = _("Check constraint properties report");
66 			message += wxT(" - ") + GetName();
67 			break;
68 		case PROPERTIES:
69 			message = _("Check constraint properties");
70 			break;
71 		case DDLREPORT:
72 			message = _("Check constraint DDL report");
73 			message += wxT(" - ") + GetName();
74 			break;
75 		case DDL:
76 			message = _("Check constraint DDL");
77 			break;
78 		case DEPENDENCIESREPORT:
79 			message = _("Check constraint dependencies report");
80 			message += wxT(" - ") + GetName();
81 			break;
82 		case DEPENDENCIES:
83 			message = _("Check constraint dependencies");
84 			break;
85 		case DEPENDENTSREPORT:
86 			message = _("Check constraint dependents report");
87 			message += wxT(" - ") + GetName();
88 			break;
89 		case DEPENDENTS:
90 			message = _("Check constraint dependents");
91 			break;
92 	}
93 
94 	return message;
95 }
96 
97 
GetIconId()98 int pgCheck::GetIconId()
99 {
100 	if (!GetDatabase()->BackendMinimumVersion(9, 2) || GetValid())
101 		return checkFactory.GetIconId();
102 	else
103 		return checkFactory.GetClosedIconId();
104 }
105 
106 
DropObject(wxFrame * frame,ctlTree * browser,bool cascaded)107 bool pgCheck::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
108 {
109 	wxString sql = wxT("ALTER ") + objectKind + wxT(" ") + qtIdent(objectSchema) + wxT(".") + qtIdent(objectName)
110 	               + wxT(" DROP CONSTRAINT ") + GetQuotedIdentifier();
111 	if (cascaded)
112 		sql += wxT(" CASCADE");
113 	return GetDatabase()->ExecuteVoid(sql);
114 }
115 
116 
GetConstraint()117 wxString pgCheck::GetConstraint()
118 {
119 	sql = GetQuotedIdentifier() +  wxT(" CHECK ");
120 
121 	sql += wxT("(") + GetDefinition() + wxT(")");
122 
123 	if (GetDatabase()->BackendMinimumVersion(9, 2) && GetNoInherit())
124 		sql += wxT(" NO INHERIT");
125 
126 	if (GetDatabase()->BackendMinimumVersion(9, 2) && !GetValid())
127 		sql += wxT(" NOT VALID");
128 
129 	return sql;
130 }
131 
132 
GetSql(ctlTree * browser)133 wxString pgCheck::GetSql(ctlTree *browser)
134 {
135 	if (sql.IsNull())
136 	{
137 		sql = wxT("-- Check: ") + GetQuotedFullIdentifier() + wxT("\n\n")
138 		      + wxT("-- ALTER ") + objectKind + wxT(" ") + GetQuotedSchemaPrefix(objectSchema) + qtIdent(objectName)
139 		      + wxT(" DROP CONSTRAINT ") + GetQuotedIdentifier()
140 		      + wxT(";\n\nALTER ") + objectKind + wxT(" ") + GetQuotedSchemaPrefix(objectSchema) + qtIdent(objectName)
141 		      + wxT("\n  ADD CONSTRAINT ") + GetConstraint()
142 		      + wxT(";\n");
143 
144 		if (!GetComment().IsNull())
145 		{
146 			sql += wxT("COMMENT ON CONSTRAINT ") + GetQuotedIdentifier()
147 			       + wxT(" ON ") + GetQuotedSchemaPrefix(objectSchema) + qtIdent(objectName)
148 			       + wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
149 		}
150 	}
151 
152 	return sql;
153 }
154 
155 
ShowTreeDetail(ctlTree * browser,frmMain * form,ctlListView * properties,ctlSQLBox * sqlPane)156 void pgCheck::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
157 {
158 	if (properties)
159 	{
160 		CreateListColumns(properties);
161 
162 		properties->AppendItem(_("Name"), GetName());
163 		properties->AppendItem(_("OID"), GetOid());
164 		properties->AppendItem(_("Definition"), GetDefinition());
165 		if (GetDatabase()->BackendMinimumVersion(9, 2))
166 		{
167 			properties->AppendItem(_("No Inherit?"), BoolToYesNo(GetNoInherit()));
168 			properties->AppendItem(_("Valid?"), BoolToYesNo(GetValid()));
169 		}
170 		// Check constraints on a domain don't have comments
171 		if (objectKind.Upper() == wxT("TABLE"))
172 			properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
173 	}
174 }
175 
176 
Refresh(ctlTree * browser,const wxTreeItemId item)177 pgObject *pgCheck::Refresh(ctlTree *browser, const wxTreeItemId item)
178 {
179 	pgObject *check = 0;
180 
181 	pgCollection *coll = browser->GetParentCollection(item);
182 	if (coll)
183 		check = checkFactory.CreateObjects(coll, 0, wxT("\n   AND c.oid=") + GetOidStr());
184 
185 	return check;
186 }
187 
188 
Validate(frmMain * form)189 void pgCheck::Validate(frmMain *form)
190 {
191 	wxString sql = wxT("ALTER ") + objectKind + wxT(" ")
192 	               + GetQuotedSchemaPrefix(objectSchema) + qtIdent(objectName)
193 	               + wxT("\n  VALIDATE CONSTRAINT ") + GetQuotedIdentifier();
194 	GetDatabase()->ExecuteVoid(sql);
195 
196 	iSetValid(true);
197 	UpdateIcon(form->GetBrowser());
198 }
199 
200 
CreateObjects(pgCollection * coll,ctlTree * browser,const wxString & restriction)201 pgObject *pgCheckFactory::CreateObjects(pgCollection *coll, ctlTree *browser, const wxString &restriction)
202 {
203 	pgSchemaObjCollection *collection = (pgSchemaObjCollection *)coll;
204 	pgCheck *check = 0;
205 
206 	wxString connoinherit = collection->GetDatabase()->BackendMinimumVersion(9, 2) ? wxT(", connoinherit") : wxEmptyString;
207 	wxString convalidated = collection->GetDatabase()->BackendMinimumVersion(9, 2) ? wxT(", convalidated") : wxEmptyString;
208 
209 	wxString sql =
210 	    wxT("SELECT 'TABLE' AS objectkind, c.oid, conname, relname, nspname, description,\n")
211 	    wxT("       pg_get_expr(conbin, conrelid") + collection->GetDatabase()->GetPrettyOption() + wxT(") as consrc\n")
212 	    + connoinherit + convalidated +
213 	    wxT("  FROM pg_constraint c\n")
214 	    wxT("  JOIN pg_class cl ON cl.oid=conrelid\n")
215 	    wxT("  JOIN pg_namespace nl ON nl.oid=relnamespace\n")
216 	    wxT("  LEFT OUTER JOIN pg_description des ON (des.objoid=c.oid AND des.classoid='pg_constraint'::regclass)\n")
217 	    wxT(" WHERE contype = 'c' AND conrelid =  ") + NumToStr(collection->GetOid())
218 	    + restriction + wxT("::oid\n")
219 	    wxT("UNION\n")
220 	    wxT("SELECT 'DOMAIN' AS objectkind, c.oid, conname, typname as relname, nspname, description,\n")
221 	    wxT("       regexp_replace(pg_get_constraintdef(c.oid, true), E'CHECK \\\\((.*)\\\\).*', E'\\\\1') as consrc\n")
222 	    + connoinherit + convalidated +
223 	    wxT("  FROM pg_constraint c\n")
224 	    wxT("  JOIN pg_type t ON t.oid=contypid\n")
225 	    wxT("  JOIN pg_namespace nl ON nl.oid=typnamespace\n")
226 	    wxT("  LEFT OUTER JOIN pg_description des ON (des.objoid=t.oid AND des.classoid='pg_constraint'::regclass)\n")
227 	    wxT(" WHERE contype = 'c' AND contypid =  ") + NumToStr(collection->GetOid())
228 	    + restriction + wxT("::oid\n")
229 	    wxT(" ORDER BY conname");
230 
231 	pgSet *checks = collection->GetDatabase()->ExecuteSet(sql);
232 
233 	if (checks)
234 	{
235 		while (!checks->Eof())
236 		{
237 			check = new pgCheck(collection->GetSchema()->GetSchema(), checks->GetVal(wxT("conname")));
238 
239 			check->iSetOid(checks->GetOid(wxT("oid")));
240 			check->iSetDefinition(checks->GetVal(wxT("consrc")));
241 			check->iSetObjectKind(checks->GetVal(wxT("objectkind")));
242 			check->iSetObjectName(checks->GetVal(wxT("relname")));
243 			check->iSetObjectSchema(checks->GetVal(wxT("nspname")));
244 			if (collection->GetDatabase()->BackendMinimumVersion(9, 2))
245 			{
246 				check->iSetNoInherit(checks->GetBool(wxT("connoinherit")));
247 				check->iSetValid(checks->GetBool(wxT("convalidated")));
248 			}
249 			check->iSetComment(checks->GetVal(wxT("description")));
250 
251 			if (browser)
252 			{
253 				browser->AppendObject(collection, check);
254 				checks->MoveNext();
255 			}
256 			else
257 				break;
258 		}
259 
260 		delete checks;
261 	}
262 	return check;
263 }
264 
265 /////////////////////////////
266 
GetTranslatedMessage(int kindOfMessage) const267 wxString pgCheckCollection::GetTranslatedMessage(int kindOfMessage) const
268 {
269 	wxString message = wxEmptyString;
270 
271 	switch (kindOfMessage)
272 	{
273 		case RETRIEVINGDETAILS:
274 			message = _("Retrieving details on check constraints");
275 			break;
276 		case REFRESHINGDETAILS:
277 			message = _("Refreshing check constraints");
278 			break;
279 		case OBJECTSLISTREPORT:
280 			message = _("Check constraints list report");
281 			break;
282 	}
283 
284 	return message;
285 }
286 
287 /////////////////////////////
288 
289 #include "images/check.pngc"
290 #include "images/checkbad.pngc"
291 
pgCheckFactory()292 pgCheckFactory::pgCheckFactory()
293 	: pgSchemaObjFactory(__("Check"), __("New Check..."), __("Create a new Check constraint."), check_png_img)
294 {
295 	metaType = PGM_CHECK;
296 	collectionFactory = &constraintCollectionFactory;
297 	closedId = addIcon(checkbad_png_img);
298 }
299 
300 
301 pgCheckFactory checkFactory;
302 
validateCheckFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)303 validateCheckFactory::validateCheckFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
304 {
305 	mnu->Append(id, _("Validate check constraint"), _("Validate the selected check constraint."));
306 }
307 
308 
StartDialog(frmMain * form,pgObject * obj)309 wxWindow *validateCheckFactory::StartDialog(frmMain *form, pgObject *obj)
310 {
311 	((pgCheck *)obj)->Validate(form);
312 	((pgCheck *)obj)->SetDirty();
313 
314 	wxTreeItemId item = form->GetBrowser()->GetSelection();
315 	if (obj == form->GetBrowser()->GetObject(item))
316 	{
317 		obj->ShowTreeDetail(form->GetBrowser(), 0, form->GetProperties());
318 		form->GetSqlPane()->SetReadOnly(false);
319 		form->GetSqlPane()->SetText(((pgCheck *)obj)->GetSql(form->GetBrowser()));
320 		form->GetSqlPane()->SetReadOnly(true);
321 	}
322 	form->GetMenuFactories()->CheckMenu(obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar());
323 
324 	return 0;
325 }
326 
327 
CheckEnable(pgObject * obj)328 bool validateCheckFactory::CheckEnable(pgObject *obj)
329 {
330 	return obj && obj->IsCreatedBy(checkFactory) && obj->CanEdit()
331 	       && ((pgCheck *)obj)->GetConnection()->BackendMinimumVersion(9, 2)
332 	       && !((pgCheck *)obj)->GetValid();
333 }
334