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