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 // pgRule.cpp - Rule 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/pgRule.h"
20 
21 
pgRule(pgSchema * newSchema,const wxString & newName)22 pgRule::pgRule(pgSchema *newSchema, const wxString &newName)
23 	: pgRuleObject(newSchema, ruleFactory, newName)
24 {
25 }
26 
~pgRule()27 pgRule::~pgRule()
28 {
29 }
30 
GetTranslatedMessage(int kindOfMessage) const31 wxString pgRule::GetTranslatedMessage(int kindOfMessage) const
32 {
33 	wxString message = wxEmptyString;
34 
35 	switch (kindOfMessage)
36 	{
37 		case RETRIEVINGDETAILS:
38 			message = _("Retrieving details on rule");
39 			message += wxT(" ") + GetName();
40 			break;
41 		case REFRESHINGDETAILS:
42 			message = _("Refreshing rule");
43 			message += wxT(" ") + GetName();
44 			break;
45 		case GRANTWIZARDTITLE:
46 			message = _("Privileges for rule");
47 			message += wxT(" ") + GetName();
48 			break;
49 		case DROPINCLUDINGDEPS:
50 			message = wxString::Format(_("Are you sure you wish to drop rule \"%s\" including all objects that depend on it?"),
51 			                           GetFullIdentifier().c_str());
52 			break;
53 		case DROPEXCLUDINGDEPS:
54 			message = wxString::Format(_("Are you sure you wish to drop rule \"%s\"?"),
55 			                           GetFullIdentifier().c_str());
56 			break;
57 		case DROPCASCADETITLE:
58 			message = _("Drop rule cascaded?");
59 			break;
60 		case DROPTITLE:
61 			message = _("Drop rule?");
62 			break;
63 		case PROPERTIESREPORT:
64 			message = _("Rule properties report");
65 			message += wxT(" - ") + GetName();
66 			break;
67 		case PROPERTIES:
68 			message = _("Rule properties");
69 			break;
70 		case DDLREPORT:
71 			message = _("Rule DDL report");
72 			message += wxT(" - ") + GetName();
73 			break;
74 		case DDL:
75 			message = _("Rule DDL");
76 			break;
77 		case DEPENDENCIESREPORT:
78 			message = _("Rule dependencies report");
79 			message += wxT(" - ") + GetName();
80 			break;
81 		case DEPENDENCIES:
82 			message = _("Rule dependencies");
83 			break;
84 		case DEPENDENTSREPORT:
85 			message = _("Rule dependents report");
86 			message += wxT(" - ") + GetName();
87 			break;
88 		case DEPENDENTS:
89 			message = _("Rule dependents");
90 			break;
91 	}
92 
93 	return message;
94 }
95 
96 
GetIconId()97 int pgRule::GetIconId()
98 {
99 	if (GetEnabled())
100 		return ruleFactory.GetIconId();
101 	else
102 		return ruleFactory.GetClosedIconId();
103 }
104 
105 
DropObject(wxFrame * frame,ctlTree * browser,bool cascaded)106 bool pgRule::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded)
107 {
108 	wxString sql = wxT("DROP RULE ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable();
109 	if (cascaded)
110 		sql += wxT(" CASCADE");
111 	return GetDatabase()->ExecuteVoid(sql);
112 }
113 
114 
SetEnabled(ctlTree * browser,const bool b)115 void pgRule::SetEnabled(ctlTree *browser, const bool b)
116 {
117 	if (GetQuotedFullTable().Len() > 0 && ((enabled && !b) || (!enabled && b)))
118 	{
119 		wxString sql = wxT("ALTER TABLE ") + GetQuotedFullTable() + wxT(" ");
120 		if (enabled && !b)
121 			sql += wxT("DISABLE");
122 		else if (!enabled && b)
123 			sql += wxT("ENABLE");
124 		sql += wxT(" RULE ") + GetQuotedIdentifier();
125 		GetDatabase()->ExecuteVoid(sql);
126 	}
127 
128 	enabled = b;
129 	UpdateIcon(browser);
130 }
131 
132 
GetSql(ctlTree * browser)133 wxString pgRule::GetSql(ctlTree *browser)
134 {
135 	if (sql.IsNull())
136 	{
137 		sql = wxT("-- Rule: ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable() + wxT("\n\n")
138 		      + wxT("-- DROP RULE ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable() + wxT(";\n\n")
139 		      + wxT("CREATE OR REPLACE") + GetFormattedDefinition().Mid(6) // the backend pg_get_ruledef gives CREATE only
140 		      + wxT("\n");
141 
142 		if (!GetEnabled())
143 		{
144 			sql += wxT("ALTER TABLE ") + GetQuotedFullTable() + wxT(" ")
145 			       +  wxT("DISABLE RULE ") + GetQuotedIdentifier() + wxT(";\n");
146 		}
147 
148 		if (!GetComment().IsEmpty())
149 			sql += wxT("COMMENT ON RULE ") + GetQuotedIdentifier() + wxT(" ON ") + GetQuotedFullTable()
150 			       +  wxT(" IS ") + qtDbString(GetComment()) + wxT(";\n");
151 	}
152 	return sql;
153 }
154 
155 
ShowTreeDetail(ctlTree * browser,frmMain * form,ctlListView * properties,ctlSQLBox * sqlPane)156 void pgRule::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane)
157 {
158 	if (properties)
159 	{
160 		CreateListColumns(properties);
161 		wxString def = GetFormattedDefinition();
162 		if (!def.IsEmpty())
163 		{
164 			int doPos = def.Find(wxT(" DO INSTEAD "));
165 			if (doPos > 0)
166 				def = def.Mid(doPos + 12).Strip(wxString::both);
167 			else
168 			{
169 				doPos = def.Find(wxT(" DO "));
170 				if (doPos > 0)
171 					def = def.Mid(doPos + 4).Strip(wxString::both);
172 			}
173 		}
174 
175 		properties->AppendItem(_("Name"), GetName());
176 		properties->AppendItem(_("OID"), GetOid());
177 		properties->AppendItem(_("Event"), GetEvent());
178 		properties->AppendItem(_("Condition"), GetCondition());
179 		properties->AppendYesNoItem(_("Do instead?"), GetDoInstead());
180 		properties->AppendItem(_("Definition"), firstLineOnly(def));
181 		if (this->GetDatabase()->connection()->BackendMinimumVersion(8, 3))
182 			properties->AppendYesNoItem(_("Enabled?"), GetEnabled());
183 		properties->AppendYesNoItem(_("System rule?"), GetSystemObject());
184 		properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
185 	}
186 }
187 
188 
189 
Refresh(ctlTree * browser,const wxTreeItemId item)190 pgObject *pgRule::Refresh(ctlTree *browser, const wxTreeItemId item)
191 {
192 	pgObject *rule = 0;
193 	pgCollection *coll = browser->GetParentCollection(item);
194 	if (coll)
195 		rule = ruleFactory.CreateObjects(coll, 0, wxT("\n   AND rw.oid=") + GetOidStr());
196 
197 	return rule;
198 }
199 
200 
CreateObjects(pgCollection * collection,ctlTree * browser,const wxString & restriction)201 pgObject *pgRuleFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction)
202 {
203 	pgRule *rule = 0;
204 
205 	pgSet *rules = collection->GetDatabase()->ExecuteSet(
206 	                   wxT("SELECT rw.oid, rw.*, relname, CASE WHEN relkind = 'r' THEN TRUE ELSE FALSE END AS parentistable, nspname, description,\n")
207 	                   wxT("       pg_get_ruledef(rw.oid") + collection->GetDatabase()->GetPrettyOption() + wxT(") AS definition\n")
208 	                   wxT("  FROM pg_rewrite rw\n")
209 	                   wxT("  JOIN pg_class cl ON cl.oid=rw.ev_class\n")
210 	                   wxT("  JOIN pg_namespace nsp ON nsp.oid=cl.relnamespace\n")
211 	                   wxT("  LEFT OUTER JOIN pg_description des ON (des.objoid=rw.oid AND des.classoid='pg_rewrite'::regclass)\n")
212 	                   wxT(" WHERE ev_class = ") + NumToStr(collection->GetOid())
213 	                   + restriction + wxT("\n")
214 	                   wxT(" ORDER BY rw.rulename"));
215 
216 	if (rules)
217 	{
218 		while (!rules->Eof())
219 		{
220 			// Be careful that the schema of a rule (and a trigger) is the schema of the schema
221 			rule = new pgRule(collection->GetSchema()->GetSchema(), rules->GetVal(wxT("rulename")));
222 
223 			rule->iSetOid(rules->GetOid(wxT("oid")));
224 			rule->iSetComment(rules->GetVal(wxT("description")));
225 
226 			if (collection->GetDatabase()->connection()->BackendMinimumVersion(8, 3))
227 			{
228 				if (rules->GetVal(wxT("ev_enabled")) != wxT("D"))
229 					rule->iSetEnabled(true);
230 				else
231 					rule->iSetEnabled(false);
232 			}
233 
234 			rule->iSetParentIsTable(rules->GetBool(wxT("parentistable")));
235 			rule->iSetDoInstead(rules->GetBool(wxT("is_instead")));
236 			rule->iSetAction(rules->GetVal(wxT("ev_action")));
237 			wxString definition = rules->GetVal(wxT("definition"));
238 			int doPos = definition.Find(wxT(" DO "));
239 			int wherePos = definition.Find(wxT(" WHERE "));
240 			if (wherePos > 0 && wherePos < doPos)
241 				rule->iSetCondition(definition.Mid(wherePos + 7, doPos - wherePos - 7));
242 
243 			rule->iSetDefinition(definition);
244 			rule->iSetQuotedFullTable(collection->GetDatabase()->GetQuotedSchemaPrefix(rules->GetVal(wxT("nspname")))
245 			                          + qtIdent(rules->GetVal(wxT("relname"))));
246 			const wxChar *evts[] = {0, wxT("SELECT"), wxT("UPDATE"), wxT("INSERT"), wxT("DELETE")};
247 			int evno = StrToLong(rules->GetVal(wxT("ev_type")));
248 			if (evno > 0 && evno < 5)
249 				rule->iSetEvent(evts[evno]);
250 			else
251 				rule->iSetEvent(wxT("Unknown"));
252 
253 			if (browser)
254 			{
255 				browser->AppendObject(collection, rule);
256 				rules->MoveNext();
257 			}
258 			else
259 				break;
260 		}
261 
262 		delete rules;
263 	}
264 	return rule;
265 }
266 
267 
268 /////////////////////////////
269 
270 
pgRuleCollection(pgaFactory * factory,pgSchema * sch)271 pgRuleCollection::pgRuleCollection(pgaFactory *factory, pgSchema *sch)
272 	: pgSchemaObjCollection(factory, sch)
273 {
274 }
275 
276 
GetTranslatedMessage(int kindOfMessage) const277 wxString pgRuleCollection::GetTranslatedMessage(int kindOfMessage) const
278 {
279 	wxString message = wxEmptyString;
280 
281 	switch (kindOfMessage)
282 	{
283 		case RETRIEVINGDETAILS:
284 			message = _("Retrieving details on rules");
285 			break;
286 		case REFRESHINGDETAILS:
287 			message = _("Refreshing rules");
288 			break;
289 		case OBJECTSLISTREPORT:
290 			message = _("Rules list report");
291 			break;
292 	}
293 
294 	return message;
295 }
296 
297 
298 /////////////////////////////
299 
300 #include "images/rule.pngc"
301 #include "images/rulebad.pngc"
302 #include "images/rules.pngc"
303 
pgRuleFactory()304 pgRuleFactory::pgRuleFactory()
305 	: pgSchemaObjFactory(__("Rule"), __("New Rule..."), __("Create a new Rule."), rule_png_img)
306 {
307 	metaType = PGM_RULE;
308 	closedId = addIcon(rulebad_png_img);
309 }
310 
311 
CreateCollection(pgObject * obj)312 pgCollection *pgRuleFactory::CreateCollection(pgObject *obj)
313 {
314 	return new pgRuleCollection(GetCollectionFactory(), (pgSchema *)obj);
315 }
316 
317 pgRuleFactory ruleFactory;
318 static pgaCollectionFactory cf(&ruleFactory, __("Rules"), rules_png_img);
319 
320 
enabledisableRuleFactory(menuFactoryList * list,wxMenu * mnu,ctlMenuToolbar * toolbar)321 enabledisableRuleFactory::enabledisableRuleFactory(menuFactoryList *list, wxMenu *mnu, ctlMenuToolbar *toolbar) : contextActionFactory(list)
322 {
323 	mnu->Append(id, _("Rule enabled?"), _("Enable or disable selected rule."), wxITEM_CHECK);
324 }
325 
326 
StartDialog(frmMain * form,pgObject * obj)327 wxWindow *enabledisableRuleFactory::StartDialog(frmMain *form, pgObject *obj)
328 {
329 	((pgRule *)obj)->SetEnabled(form->GetBrowser(), !((pgRule *)obj)->GetEnabled());
330 	((pgRule *)obj)->SetDirty();
331 
332 	wxTreeItemId item = form->GetBrowser()->GetSelection();
333 	if (obj == form->GetBrowser()->GetObject(item))
334 	{
335 		obj->ShowTreeDetail(form->GetBrowser(), 0, form->GetProperties());
336 		form->GetSqlPane()->SetReadOnly(false);
337 		form->GetSqlPane()->SetText(((pgRule *)obj)->GetSql(form->GetBrowser()));
338 		form->GetSqlPane()->SetReadOnly(true);
339 	}
340 	form->GetMenuFactories()->CheckMenu(obj, form->GetMenuBar(), (ctlMenuToolbar *)form->GetToolBar());
341 
342 	return 0;
343 }
344 
345 
CheckEnable(pgObject * obj)346 bool enabledisableRuleFactory::CheckEnable(pgObject *obj)
347 {
348 	return obj && obj->IsCreatedBy(ruleFactory)
349 	       && ((pgRule *)obj)->GetConnection()->BackendMinimumVersion(8, 3)
350 	       && ((pgRule *)obj)->GetParentIsTable();
351 }
352 
CheckChecked(pgObject * obj)353 bool enabledisableRuleFactory::CheckChecked(pgObject *obj)
354 {
355 	return obj && obj->IsCreatedBy(ruleFactory) && ((pgRule *)obj)->GetEnabled();
356 }
357