From 795125bf37e398a9299f88fa5679cc7ec7b09cae Mon Sep 17 00:00:00 2001 From: Alexander Polyakov Date: Thu, 14 Apr 2016 12:19:59 +0400 Subject: [PATCH] Row security policy support: object and dialog for policy, policy parameters in table object (Enable/Force RLS) --- pgadmin/dlg/dlgPolicy.cpp | 288 ++++++++++++++++++++++++++ pgadmin/dlg/dlgProperty.cpp | 1 + pgadmin/dlg/dlgTable.cpp | 56 +++++ pgadmin/dlg/module.mk | 1 + pgadmin/frm/events.cpp | 1 + pgadmin/include/dlg/dlgPolicy.h | 66 ++++++ pgadmin/include/dlg/dlgTable.h | 2 + pgadmin/include/dlg/module.mk | 1 + pgadmin/include/images/module.mk | 3 + pgadmin/include/images/policies.png | Bin 0 -> 439 bytes pgadmin/include/images/policy-sm.png | Bin 0 -> 394 bytes pgadmin/include/images/policy.png | Bin 0 -> 472 bytes pgadmin/include/schema/module.mk | 1 + pgadmin/include/schema/pgPolicy.h | 123 +++++++++++ pgadmin/include/schema/pgTable.h | 20 +- pgadmin/include/utils/misc.h | 1 + pgadmin/pgAdmin3.vcxproj | 10 +- pgadmin/pgAdmin3.vcxproj.filters | 24 +++ pgadmin/schema/module.mk | 1 + pgadmin/schema/pgPolicy.cpp | 391 +++++++++++++++++++++++++++++++++++ pgadmin/schema/pgTable.cpp | 46 +++++ pgadmin/ui/dlgPolicy.xrc | 278 +++++++++++++++++++++++++ pgadmin/ui/dlgTable.xrc | 30 +++ pgadmin/ui/module.mk | 1 + 24 files changed, 1343 insertions(+), 2 deletions(-) create mode 100644 pgadmin/dlg/dlgPolicy.cpp create mode 100644 pgadmin/include/dlg/dlgPolicy.h create mode 100644 pgadmin/include/images/policies.png create mode 100644 pgadmin/include/images/policy-sm.png create mode 100644 pgadmin/include/images/policy.png create mode 100644 pgadmin/include/schema/pgPolicy.h create mode 100644 pgadmin/schema/pgPolicy.cpp create mode 100644 pgadmin/ui/dlgPolicy.xrc diff --git a/pgadmin/dlg/dlgPolicy.cpp b/pgadmin/dlg/dlgPolicy.cpp new file mode 100644 index 0000000..49d83e1 --- /dev/null +++ b/pgadmin/dlg/dlgPolicy.cpp @@ -0,0 +1,288 @@ +////////////////////////////////////////////////////////////////////////// +// +// pgAdmin III - PostgreSQL Tools +// +// Copyright (C) 2002 - 2016, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +// dlgPolicy.cpp - Policy property dialog +// +////////////////////////////////////////////////////////////////////////// + +// wxWindows headers +#include + +// App headers +#include "pgAdmin3.h" +#include "utils/misc.h" +#include "utils/pgDefs.h" + +#include "ctl/ctlSQLBox.h" +#include "dlg/dlgPolicy.h" +#include "schema/pgPolicy.h" +#include "schema/pgTable.h" +#include "schema/pgCollection.h" + +#define rbxCommand CTRL_RADIOBOX("rbxCommand") +#define btnAddRole CTRL_BUTTON("btnAddRole") +#define btnDelRole CTRL_BUTTON("btnDelRole") +#define lbRolesSelected CTRL_LISTBOX("lbRolesSelected") +#define lbRolesAll CTRL_LISTBOX("lbRolesAll") +#define sqlBoxUsing CTRL_SQLBOX("sqlBoxUsing") +#define sqlBoxWithCheck CTRL_SQLBOX("sqlBoxWithCheck") + +BEGIN_EVENT_TABLE(dlgPolicy, dlgProperty) + EVT_RADIOBOX(XRCID("rbxCommand"), dlgProperty::OnChange) + EVT_BUTTON(XRCID("btnAddRole"), dlgPolicy::OnAddRole) + EVT_BUTTON(XRCID("btnDelRole"), dlgPolicy::OnDelRole) + EVT_STC_MODIFIED(XRCID("sqlBoxUsing"), dlgProperty::OnChangeStc) + EVT_STC_MODIFIED(XRCID("sqlBoxWithCheck"), dlgProperty::OnChangeStc) +END_EVENT_TABLE(); + +dlgPolicy::dlgPolicy(pgaFactory *f, frmMain *frame, pgPolicy *p, pgTable *tab) + : dlgProperty(f, frame, wxT("dlgPolicy")) +{ + table = tab; + policy = p; +} + +pgObject *dlgPolicy::GetObject() +{ + return policy; +} + +pgObject *dlgPolicy::CreateObject(pgCollection *collection) +{ + pgObject *obj = policyFactory.CreateObjects(collection, 0, + wxT("\n AND p.polname=") + qtDbString(GetName()) + + wxT("\n AND p.polrelid=") + table->GetOidStr()); + return obj; +} + +void dlgPolicy::SetPolicyCommand(char command) +{ + int index = 0; + switch (command) + { + case POLICY_ALL: index = 0; break; + case POLICY_SELECT: index = 1; break; + case POLICY_INSERT: index = 2; break; + case POLICY_UPDATE: index = 3; break; + case POLICY_DELETE: index = 4; break; + } + + rbxCommand->SetSelection(index); +} + +char dlgPolicy::GetPolicyCommand() const +{ + switch (rbxCommand->GetSelection()) + { + default: + case 0: return POLICY_ALL; + case 1: return POLICY_SELECT; + case 2: return POLICY_INSERT; + case 3: return POLICY_UPDATE; + case 4: return POLICY_DELETE; + } +} + +void dlgPolicy::SetPolicyRoles(const wxArrayString &roles) +{ + for (int i = 0; i < roles.size(); i++) + { + SelectRole(roles[i]); + } +} + +void dlgPolicy::SetPolicyUsingExpr(const wxString &expr) +{ + sqlBoxUsing->SetText(expr); +} + +wxString dlgPolicy::GetPolicyUsingExpr() const +{ + return sqlBoxUsing->GetText(); +} + +void dlgPolicy::SetPolicyWithCheckExpr(const wxString &expr) +{ + sqlBoxWithCheck->SetText(expr); +} + +wxString dlgPolicy::GetPolicyWithCheckExpr() const +{ + return sqlBoxWithCheck->GetText(); +} + +int dlgPolicy::Go(bool modal) +{ + PopulateAllRoles(); + + if (policy) + { + SetPolicyCommand(policy->GetPolicyCommand()); + rbxCommand->Disable(); + SetPolicyRoles(policy->GetPolicyRolesSorted()); + SetPolicyUsingExpr(policy->GetPolicyUsingExpression()); + SetPolicyWithCheckExpr(policy->GetPolicyWithCheckExpression()); + } + + return dlgProperty::Go(modal); +} + +// get sql command from pgPolicy object +wxString dlgPolicy::GetSql() +{ + wxString sql; + if(policy) + { + sql = policy->GetAlterPolicySql(qtIdent(GetName()), GetPolicyRolesSorted(), GetPolicyUsingExpr(), GetPolicyWithCheckExpr()); + } + else + { + sql = pgPolicy::GetCreatePolicySql(qtIdent(GetName()), table->GetQuotedFullIdentifier(), GetPolicyCommand(), GetPolicyRolesSorted(), + GetPolicyUsingExpr(), GetPolicyWithCheckExpr()); + } + + AppendComment(sql, wxT("POLICY ") + qtIdent(GetName()) + + wxT(" ON ") + table->GetQuotedFullIdentifier(), policy); + + return sql; +} + +void dlgPolicy::CheckChange() +{ + if (policy) + { + EnableOK(didChange()); + } + else + { + wxString name = GetName(); + bool enable = true; + CheckValid(enable, !name.IsEmpty(), _("Please specify name.")); + EnableOK(enable); + } +} + +// populate list box with roles from catalog +void dlgPolicy::PopulateAllRoles() +{ + lbRolesAll->Clear(); + // not sure if we really need these in pgAdmin + //lbRolesAll->Append(wxT("CURRENT_USER")); + //lbRolesAll->Append(wxT("SESSION_USER")); + + if (connection) + { + wxString sql = + wxT("SELECT rolname\n") + wxT(" FROM pg_roles r\n") + wxT(" ORDER BY rolname"); + + pgSet *roles = connection->ExecuteSet(sql); + if (roles) + { + while (!roles->Eof()) + { + lbRolesAll->Append(roles->GetVal(0)); + roles->MoveNext(); + } + + delete roles; + } + } +} + +// add role to list and reflect list box changes +// listIndex - index of entry in 'all roles' list box +void dlgPolicy::SelectRole(int listIndex) +{ + if (listIndex >= 0) + { + wxString role = lbRolesAll->GetString(listIndex); + lbRolesSelected->Append(role); + lbRolesAll->Delete(listIndex); + roleNames.Add(role); + } +} + +// add role to list of roles and and reflect list box changes +void dlgPolicy::SelectRole(const wxString &role) +{ + lbRolesSelected->Append(role); + lbRolesAll->Delete(lbRolesAll->FindString(role, true)); + roleNames.Add(role); +} + +// remove role from list and reflect list box changes +// listIndex - index of entry in 'selected roles' list box +void dlgPolicy::DeselectRole(int listIndex) +{ + if (listIndex >= 0) + { + wxString role = lbRolesSelected->GetString(listIndex); + lbRolesAll->Append(role); + lbRolesSelected->Delete(listIndex); + roleNames.Remove(role); + } +} + +// test for changes +bool dlgPolicy::didChange() +{ + if (GetName() != policy->GetName()) + return true; + if (GetPolicyRolesSorted() != policy->GetPolicyRolesSorted()) + return true; + if (GetPolicyUsingExpr() != policy->GetPolicyUsingExpression()) + return true; + if (GetPolicyWithCheckExpr() != policy->GetPolicyWithCheckExpression()) + return true; + if (txtComment->GetValue() != policy->GetComment()) + return true; + + return false; +} + +int IntArrayCmp(int *a, int *b) +{ + if (*a == *b) + return 0; + + if (*a > *b) + return 1; + else + return -1; +} + +// add role button +void dlgPolicy::OnAddRole(wxCommandEvent &ev) +{ + wxArrayInt selection; + lbRolesAll->GetSelections(selection); + selection.Sort(IntArrayCmp); + + for (int i = selection.size() - 1; i >= 0; i--) + { + SelectRole(selection[i]); + } + + OnChange(ev); +} + +// remove role button +void dlgPolicy::OnDelRole(wxCommandEvent &ev) +{ + wxArrayInt selection; + lbRolesSelected->GetSelections(selection); + selection.Sort(IntArrayCmp); + + for (int i = selection.size() - 1; i >= 0; i--) + { + DeselectRole(selection[i]); + } + + OnChange(ev); +} \ No newline at end of file diff --git a/pgadmin/dlg/dlgProperty.cpp b/pgadmin/dlg/dlgProperty.cpp index 7381729..578fa1b 100644 --- a/pgadmin/dlg/dlgProperty.cpp +++ b/pgadmin/dlg/dlgProperty.cpp @@ -1152,6 +1152,7 @@ void dlgProperty::InitDialog(frmMain *frame, pgObject *node) case PGM_PRIMARYKEY: case PGM_UNIQUE: case PGM_TRIGGER: + case PGM_POLICY: case PGM_RULE: // Rules are technically table objects! Yeuch case EDB_PACKAGEFUNCTION: case EDB_PACKAGEVARIABLE: diff --git a/pgadmin/dlg/dlgTable.cpp b/pgadmin/dlg/dlgTable.cpp index 8939a7c..32ad9c0 100644 --- a/pgadmin/dlg/dlgTable.cpp +++ b/pgadmin/dlg/dlgTable.cpp @@ -32,6 +32,7 @@ #include "schema/pgForeignKey.h" #include "schema/pgIndexConstraint.h" #include "schema/pgDatatype.h" +#include "schema/pgPolicy.h" #include "ctl/ctlSeclabelPanel.h" @@ -104,6 +105,10 @@ #define txtToastFreezeTableAge CTRL_TEXT("txtToastFreezeTableAge") #define stToastFreezeTableAgeCurr CTRL_STATIC("stToastFreezeTableAgeCurr") +/* Row level security options */ +#define chkPolicyEnable CTRL_CHECKBOX("chkPolicyEnable") +#define chkPolicyForce CTRL_CHECKBOX("chkPolicyForce") + BEGIN_EVENT_TABLE(dlgTable, dlgSecurityProperty) EVT_CHECKBOX(XRCID("chkUnlogged"), dlgProperty::OnChange) @@ -150,6 +155,9 @@ BEGIN_EVENT_TABLE(dlgTable, dlgSecurityProperty) EVT_TEXT(XRCID("txtToastFreezeMaxAge"), dlgTable::OnChangeVacuum) EVT_TEXT(XRCID("txtToastFreezeTableAge"), dlgTable::OnChangeVacuum) + EVT_CHECKBOX(XRCID("chkPolicyEnable"), dlgProperty::OnChange) + EVT_CHECKBOX(XRCID("chkPolicyForce"), dlgProperty::OnChange) + EVT_BUTTON(wxID_OK, dlgTable::OnOK) #ifdef __WXMAC__ @@ -236,6 +244,23 @@ int dlgTable::Go(bool modal) PrepareTablespace(cbTablespace); PopulateDatatypeCache(); + // Row level security options + if (connection->BackendMinimumVersion(9, 5)) + { + chkPolicyEnable->Enable(); + chkPolicyForce->Enable(); + if (table) + { + chkPolicyEnable->SetValue(table->GetRowLevelSecurityEnabled()); + chkPolicyForce->SetValue(table->GetForceRowLevelSecurity()); + } + } + else + { + chkPolicyEnable->Disable(); + chkPolicyForce->Disable(); + } + if (connection->BackendMinimumVersion(9, 1)) { seclabelPage->SetConnection(connection); @@ -1472,6 +1497,10 @@ wxString dlgTable::GetSql() } } + // Row level security options + if (connection->BackendMinimumVersion(9, 5)) + AppendPolicySql(sql, tabname); + // Comments for (pos = 0 ; pos < lstColumns->GetItemCount() ; pos++) { @@ -2112,3 +2141,30 @@ void dlgTable::OnChange(wxCommandEvent &event) { CheckChange(); } + +// append ALTER TABLE statement with row level security options +wxString& dlgTable::AppendPolicySql(wxString &sql, const wxString &tabname) +{ + int enableRls; + int forceRls; + + if (table) + { + if (table->GetRowLevelSecurityEnabled() != chkPolicyEnable->IsChecked()) + enableRls = chkPolicyEnable->IsChecked() ? ROW_SECURUTY_ENABLE : ROW_SECURUTY_DISABLE; + if (table->GetForceRowLevelSecurity() != chkPolicyForce->IsChecked()) + forceRls = chkPolicyForce->IsChecked() ? ROW_SECURUTY_FORCE : ROW_SECURUTY_NOFORCE; + } + else + { + // default values will be omitted + enableRls = chkPolicyEnable->IsChecked() ? ROW_SECURUTY_ENABLE : ROW_SECURUTY_SKIP; + forceRls = chkPolicyForce->IsChecked() ? ROW_SECURUTY_FORCE : ROW_SECURUTY_SKIP; + } + + wxString rlsSql = pgPolicy::GetAlterTablePolicyParamsSql(tabname, enableRls, forceRls); + if (!rlsSql.IsEmpty()) + sql += rlsSql + wxT("\n"); + + return sql; +} \ No newline at end of file diff --git a/pgadmin/dlg/module.mk b/pgadmin/dlg/module.mk index c1a4e33..3d53185 100644 --- a/pgadmin/dlg/module.mk +++ b/pgadmin/dlg/module.mk @@ -41,6 +41,7 @@ pgadmin3_SOURCES += \ dlg/dlgOperator.cpp \ dlg/dlgPackage.cpp \ dlg/dlgPgpassConfig.cpp \ + dlg/dlgPolicy.cpp \ dlg/dlgProperty.cpp \ dlg/dlgReassignDropOwned.cpp \ dlg/dlgRole.cpp \ diff --git a/pgadmin/frm/events.cpp b/pgadmin/frm/events.cpp index 4e05f84..0b6a959 100644 --- a/pgadmin/frm/events.cpp +++ b/pgadmin/frm/events.cpp @@ -789,6 +789,7 @@ void frmMain::ExecDrop(bool cascaded) case PGM_PRIMARYKEY: case PGM_UNIQUE: case PGM_TRIGGER: + case PGM_POLICY: case PGM_RULE: // Rules are technically table objects! Yeuch case EDB_PACKAGEFUNCTION: case EDB_PACKAGEVARIABLE: diff --git a/pgadmin/include/dlg/dlgPolicy.h b/pgadmin/include/dlg/dlgPolicy.h new file mode 100644 index 0000000..b340309 --- /dev/null +++ b/pgadmin/include/dlg/dlgPolicy.h @@ -0,0 +1,66 @@ +////////////////////////////////////////////////////////////////////////// +// +// pgAdmin III - PostgreSQL Tools +// +// Copyright (C) 2002 - 2016, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +// dlgPolicy.h - Policy property dialog +// +////////////////////////////////////////////////////////////////////////// + + +#ifndef DLG_POLICY_H +#define DLG_POLICY_H + +#include "dlg/dlgProperty.h" + +class pgTable; +class pgPolicy; + +class dlgPolicy : public dlgProperty +{ +public: + dlgPolicy(pgaFactory *factory, frmMain *frame, pgPolicy *p, pgTable *tab); + int Go(bool modal); + + void CheckChange(); + wxString GetSql(); + pgObject *CreateObject(pgCollection *collection); + pgObject *GetObject(); + + // ui control value getters and settes + void SetPolicyCommand(char command); + char GetPolicyCommand() const; + void SetPolicyRoles(const wxArrayString &roles); + const wxSortedArrayString& GetPolicyRolesSorted() const + { + return roleNames; + } + void SetPolicyUsingExpr(const wxString &expr); + wxString GetPolicyUsingExpr() const; + void SetPolicyWithCheckExpr(const wxString &expr); + wxString GetPolicyWithCheckExpr() const; + +private: + void PopulateAllRoles(); + void SelectRole(int listIndex); + void SelectRole(const wxString &role); + void DeselectRole(int listIndex); + + bool didChange(); + + void OnAddRole(wxCommandEvent &ev); + void OnDelRole(wxCommandEvent &ev); + +private: + pgTable *table; + pgPolicy *policy; + + // sorted, so we can easily test for changes + wxSortedArrayString roleNames; + + DECLARE_EVENT_TABLE() +}; + +#endif \ No newline at end of file diff --git a/pgadmin/include/dlg/dlgTable.h b/pgadmin/include/dlg/dlgTable.h index 1b82fe0..f28f05c 100644 --- a/pgadmin/include/dlg/dlgTable.h +++ b/pgadmin/include/dlg/dlgTable.h @@ -125,6 +125,8 @@ private: toastTableFreezeTableAge; wxString toastTableVacFactor; + wxString& AppendPolicySql(wxString &sql, const wxString &tabname); + DECLARE_EVENT_TABLE() }; diff --git a/pgadmin/include/dlg/module.mk b/pgadmin/include/dlg/module.mk index 8fed68d..f5e908f 100644 --- a/pgadmin/include/dlg/module.mk +++ b/pgadmin/include/dlg/module.mk @@ -41,6 +41,7 @@ pgadmin3_SOURCES += \ include/dlg/dlgOperator.h \ include/dlg/dlgPackage.h \ include/dlg/dlgPgpassConfig.h \ + include/dlg/dlgPolicy.h \ include/dlg/dlgProperty.h \ include/dlg/dlgReassignDropOwned.h \ include/dlg/dlgRole.h \ diff --git a/pgadmin/include/images/module.mk b/pgadmin/include/images/module.mk index 6d60abf..08ac833 100644 --- a/pgadmin/include/images/module.mk +++ b/pgadmin/include/images/module.mk @@ -218,6 +218,9 @@ pgadmin3_SOURCES += \ include/images/pgAdmin3.png \ include/images/pgAdmin3-16.png \ include/images/pgAdmin3-32.png \ + include/images/policies.png \ + include/images/policy.png \ + include/images/policy-sm.png \ include/images/primarykey.png \ include/images/procedures.png \ include/images/procedure.png \ diff --git a/pgadmin/include/images/policies.png b/pgadmin/include/images/policies.png new file mode 100644 index 0000000000000000000000000000000000000000..08a9c2d6df12bca22bd9fc5a363925749bc6cae7 GIT binary patch literal 439 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33 zJ=4@yqg0@w8lEnWAr}5~C!F>=93aqke)SI@w&*=uxW5PGXkF5BGQZos*CF09Cd1`I zE5BmN^a(mboSr3$DyK95Hx^rEDtWQl85vtXKka|z=ijbx%jW-gx+)rHv0A?Q_D5N>T^IJau%KsKix}U%1 zS{vD(lfFfi#qmJ14^v}lxeNPdVHe$tv&u6b#N@L6U7qOKptA4%W{bXLHu2Q;_NSO+ z-PL|>(D}77ms#&*TzwC#=cEq`lN}Tes@{}l#+S$0sh_nsspSF=x(eCf|3=f&3z zH(MtCdi+$=-kV88jKTBPXT7cBv37eZQxBYJ+AhV&<*nj*dCDf8#Wv@)MO+VF;R>)i e8LzSQiqui7d;|Wl=-0q-W$<+Mb6Mw<&;$VcjHGD* literal 0 HcmV?d00001 diff --git a/pgadmin/include/images/policy-sm.png b/pgadmin/include/images/policy-sm.png new file mode 100644 index 0000000000000000000000000000000000000000..cf335fa53c3d8f9470721893d475bdaa8349ea74 GIT binary patch literal 394 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`jKx9jP7LeL$-D$|SkfJR9T^xl z_H+M9WCij$3p^r=85sBugD~Uq{1qucL5ULAh?3y^w370~qEv>0#LT=By}Z;C1rt33 zJ=4@yqg0@p-<~dxAr}705;hAm&TjqR6+BypU-`mT5%zwV!(F5n_ z+5W!2PrhAI;ozRqrT?4NUH|Ie3;DV~CtH_|Z@$>~{VCq2iOf#RT>kUV7UK?TX*#_8 z_+S0ILCv=ts=vScTmRv~!T;_2^8f08eo~cSUK(&i!Ez4U9(|1;^_D76{y(22WWnaO zaD!tOhg3sPV~|G99=3)#?R||w1w6usGaWuY(<*QX%~}6He(!2dpnO5unKvm0y_XpR zL|lFP|H~UH%dL^n;5n{fccbBM1y9A_Utj;5=imEN|NGn9|M~a#B|dn6e}A)K7_$R| jiX%^(mb^$qBO`;Uam9K=ClPO8Ffe$!`njxgN@xNAUTB?z literal 0 HcmV?d00001 diff --git a/pgadmin/include/images/policy.png b/pgadmin/include/images/policy.png new file mode 100644 index 0000000000000000000000000000000000000000..2e04101d20605bb8e5d744ad3d3ed0ab3b119674 GIT binary patch literal 472 zcmV;}0Vn>6P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D02p*dSaefwW^{L9 za%BK;VQFr3E^cLXAT%y8E;VI^GGzb&0ZBfg zb-4Zvv1m=2jqd=1!GJRy4q=+6#AGtTbUMY=MhyF3yiIdk00gLdt{dS4U{XU;10exS&TSvK9 z$98W|z{&z@=7RSe!SdL??;{8T%w{u*`FxHzjyWj-4cb_TMcaQzq3{d$z%^$fS{q0J O0000 +#include "pgTable.h" + +class pgCollection; + +class pgPolicyFactory : public pgTableObjFactory +{ +public: + pgPolicyFactory(); + virtual dlgProperty *CreateDialog(frmMain *frame, pgObject *node, pgObject *parent); + virtual pgObject *CreateObjects(pgCollection *coll, ctlTree *browser, const wxString &restriction = wxEmptyString); + virtual pgCollection *CreateCollection(pgObject *obj); +}; +extern pgPolicyFactory policyFactory; + +// policy command values +enum +{ + POLICY_ALL = '*', + POLICY_SELECT = 'r', + POLICY_INSERT = 'a', + POLICY_UPDATE = 'w', + POLICY_DELETE = 'd' +}; + +// use with GetAlterTablePolicyParamsSql +enum +{ + ROW_SECURUTY_SKIP = 0, // do not generate statement + ROW_SECURUTY_ENABLE, // generate ENABLE ROW LEVEL SECURITY statement + ROW_SECURUTY_DISABLE, // generate DISABLE ROW LEVEL SECURITY statement + ROW_SECURUTY_FORCE, // generate FORCE ROW LEVEL SECURITY statement + ROW_SECURUTY_NOFORCE // generate NO FORCE ROW LEVEL SECURITY statement +}; + +// Row-Level Security policy object +class pgPolicy : public pgTableObject +{ +public: + pgPolicy(pgTable *newTable, const wxString &newName = wxT("")); + ~pgPolicy(); + + char GetPolicyCommand() const + { + return command; + } + void iSetPolicyCommand(char cmd) + { + command = cmd; + } + const wxSortedArrayString& GetPolicyRolesSorted() const + { + return roleNames; + } + void iSetPolicyRoles(const wxArrayString &names); + wxString GetPolicyUsingExpression() const + { + return exprUsing; + } + void iSetPolicyUsingExpression(const wxString &expr) + { + exprUsing = expr; + } + wxString GetPolicyWithCheckExpression() const + { + return exprWithCheck; + } + void iSetPolicyWithCheckExpression(const wxString &expr) + { + exprWithCheck = expr; + } + + bool DropObject(wxFrame *frame, ctlTree *browser, bool cascaded); + + + wxString GetSql(ctlTree *browser); + wxString GetTranslatedMessage(int kindOfMessage) const; + void ShowTreeDetail(ctlTree *browser, frmMain *form = 0, ctlListView *properties = 0, ctlSQLBox *sqlPane = 0); + + // generate ALTER statement for table RLS parameters (ENABLE/DISABLE/FORCE/NOFORCE) + static wxString GetAlterTablePolicyParamsSql(const wxString &table, int enableRls, int forceRls); + // generate ALTER POLICY statement + // arguments will be checked against current state of pgPolicy object and corresponding sql will be created + wxString GetAlterPolicySql(const wxString &name, const wxArrayString &sortedRoles, const wxString &exprUsing, const wxString &exprCheck) const; + // generate CREATE POLICY statement + // default statements will be omitted + static wxString GetCreatePolicySql(const wxString &name, const wxString &table, char command, const wxArrayString &roles, + const wxString &exprUsing, const wxString &checkExpr); + +private: + static wxString GetPolicyCommandString(char command); + static wxString& WrapParentheses(wxString &expr); + static wxString GetPolicyRolesString(const wxArrayString &roles); + +private: + char command; + wxSortedArrayString roleNames; // sorted for easy change checks. empty list means TO PUBLIC policy + wxString exprUsing, exprWithCheck; +}; + +class pgPolicyCollection : public pgTableObjCollection +{ +public: + pgPolicyCollection(pgaFactory *factory, pgTable *tbl); + wxString GetTranslatedMessage(int kindOfMessage) const; +}; + + +#endif \ No newline at end of file diff --git a/pgadmin/include/schema/pgTable.h b/pgadmin/include/schema/pgTable.h index 31eb25d..1add04c 100644 --- a/pgadmin/include/schema/pgTable.h +++ b/pgadmin/include/schema/pgTable.h @@ -517,6 +517,24 @@ public: } bool HasPgstattuple(); + /* row level security options */ + bool GetRowLevelSecurityEnabled() const + { + return rowSecurityEnabled; + } + void iSetRowLevelSecurityEnabled(bool enabled) + { + rowSecurityEnabled = enabled; + } + bool GetForceRowLevelSecurity() const + { + return forceRowSecurity; + } + void iSetForceRowLevelSecurity(bool force) + { + forceRowSecurity = force; + } + virtual wxMenu *GetNewMenu(); virtual wxString GetSql(ctlTree *browser); wxString GetSelectSql(ctlTree *browser); @@ -562,7 +580,7 @@ private: wxString checksum; wxString partitionDef; bool isPartitioned; - bool hasOids, unlogged, hasSubclass, rowsCounted, isReplicated, showExtendedStatistics, distributionIsRandom; + bool hasOids, unlogged, hasSubclass, rowsCounted, isReplicated, showExtendedStatistics, distributionIsRandom, rowSecurityEnabled, forceRowSecurity; wxString toast_fillFactor, toast_autovacuum_vacuum_threshold, toast_autovacuum_vacuum_scale_factor, toast_autovacuum_vacuum_cost_delay, diff --git a/pgadmin/include/utils/misc.h b/pgadmin/include/utils/misc.h index b4a30a0..3aabf8d 100644 --- a/pgadmin/include/utils/misc.h +++ b/pgadmin/include/utils/misc.h @@ -220,6 +220,7 @@ enum PGM_INDEX, PGM_OPCLASS, PGM_OPFAMILY, + PGM_POLICY, PGM_PRIMARYKEY, PGM_ROLE, PGM_RULE, diff --git a/pgadmin/pgAdmin3.vcxproj b/pgadmin/pgAdmin3.vcxproj index bc10166..5fffc24 100644 --- a/pgadmin/pgAdmin3.vcxproj +++ b/pgadmin/pgAdmin3.vcxproj @@ -857,6 +857,7 @@ + @@ -2217,6 +2218,7 @@ + @@ -2696,6 +2698,7 @@ + @@ -2787,6 +2790,7 @@ + @@ -2809,6 +2813,7 @@ + @@ -3458,6 +3463,9 @@ + + + @@ -3570,4 +3578,4 @@ - + \ No newline at end of file diff --git a/pgadmin/pgAdmin3.vcxproj.filters b/pgadmin/pgAdmin3.vcxproj.filters index f65b268..2758b3a 100644 --- a/pgadmin/pgAdmin3.vcxproj.filters +++ b/pgadmin/pgAdmin3.vcxproj.filters @@ -1686,6 +1686,12 @@ dlg + + schema + + + dlg + @@ -2211,6 +2217,9 @@ ui + + ui + @@ -3581,6 +3590,12 @@ include\db + + include\schema + + + include\dlg + @@ -4519,6 +4534,15 @@ include\images + + include\images + + + include\images + + + include\images + diff --git a/pgadmin/schema/module.mk b/pgadmin/schema/module.mk index 9ce59c5..1f832d4 100644 --- a/pgadmin/schema/module.mk +++ b/pgadmin/schema/module.mk @@ -42,6 +42,7 @@ pgadmin3_SOURCES += \ schema/pgOperator.cpp \ schema/pgOperatorClass.cpp \ schema/pgOperatorFamily.cpp \ + schema/pgPolicy.cpp \ schema/pgRole.cpp \ schema/pgRule.cpp \ schema/pgSchema.cpp \ diff --git a/pgadmin/schema/pgPolicy.cpp b/pgadmin/schema/pgPolicy.cpp new file mode 100644 index 0000000..6428295 --- /dev/null +++ b/pgadmin/schema/pgPolicy.cpp @@ -0,0 +1,391 @@ +////////////////////////////////////////////////////////////////////////// +// +// pgAdmin III - PostgreSQL Tools +// +// Copyright (C) 2002 - 2016, The pgAdmin Development Team +// This software is released under the PostgreSQL Licence +// +// pgPolicy.cpp PostgreSQL Row security policy +// +////////////////////////////////////////////////////////////////////////// + +// wxWindows headers +#include + +// App headers +#include "pgAdmin3.h" +#include "utils/misc.h" +#include "utils/pgDefs.h" +#include "schema/pgPolicy.h" +#include "dlg/dlgPolicy.h" + +#include + +pgPolicy::pgPolicy(pgTable *newTable, const wxString &newName) + : pgTableObject(newTable, policyFactory, newName) +{ + command = POLICY_ALL; +} + +pgPolicy::~pgPolicy() +{ +} + +void pgPolicy::iSetPolicyRoles(const wxArrayString &names) +{ + // can't use assignment operator because it rewrites m_autoSort flag of wxSortedArrayString + roleNames.Clear(); + for (int i = 0; i < names.size(); i++) + roleNames.Add(names[i]); +} + +bool pgPolicy::DropObject(wxFrame *frame, ctlTree *browser, bool cascaded) +{ + wxString sql = wxT("DROP POLICY ") + GetQuotedIdentifier() + wxT(" ON ") + GetTable()->GetQuotedFullIdentifier(); + + return GetDatabase()->ExecuteVoid(sql); +} + +wxString pgPolicy::GetAlterPolicySql(const wxString &name, const wxArrayString &sortedRoles, + const wxString &exprUsing, const wxString &exprCheck) const +{ + wxString sql; + wxString sqlRename; + wxString sqlChange; + + if (GetQuotedIdentifier() != name) + sqlRename = wxT("ALTER POLICY ") + GetQuotedIdentifier() + wxT(" ON ") + table->GetQuotedFullIdentifier() + wxT("\n") + + wxT(" RENAME TO ") + name + wxT(";\n\n"); + + if (sortedRoles != GetPolicyRolesSorted()) + { + wxString roles = GetPolicyRolesString(sortedRoles); + if (roles.IsEmpty()) + roles = wxT("PUBLIC"); + + sqlChange += wxT("\nTO ") + roles; + } + + if (exprUsing != GetPolicyUsingExpression()) + { + wxString expr = exprUsing; + if (expr.IsEmpty()) + expr = wxT("true"); + + sqlChange += wxT("\nUSING ") + WrapParentheses(expr); + } + + if (exprCheck != GetPolicyWithCheckExpression()) + { + wxString expr = exprCheck; + if (expr.IsEmpty()) + expr = wxT("true"); + + sqlChange += wxT("\nWITH CHECK ") + WrapParentheses(expr); + } + + if (!sqlRename.IsEmpty()) + sql += sqlRename; + + if (!sqlChange.IsEmpty()) + sql += wxT("ALTER POLICY ") + name + wxT(" ON ") + table->GetQuotedFullIdentifier() + wxT(" ") + sqlChange; + + return sql; +} + +wxString pgPolicy::GetCreatePolicySql(const wxString &name, const wxString &table, char command, const wxArrayString &roles, + const wxString &exprUsing, const wxString &checkExpr) +{ + wxString sql; + + sql += wxT("CREATE POLICY ") + name + wxT(" ON ") + table; + if (command != POLICY_ALL) + { + wxString cmd = pgPolicy::GetPolicyCommandString(command); + if (!cmd.IsEmpty()) + sql += wxT("\nFOR ") + cmd; + } + + if (!roles.IsEmpty()) + sql += wxT("\nTO ") + GetPolicyRolesString(roles); + + wxString expr = exprUsing; + if (!expr.IsEmpty()) + sql += wxT("\nUSING ") + WrapParentheses(expr); + + expr = checkExpr; + if (!expr.IsEmpty()) + sql += wxT("\nWITH CHECK ") + WrapParentheses(expr); + + sql += wxT(";\n"); + + return sql; +} + +wxString pgPolicy::GetSql(ctlTree *browser) +{ + wxString sql; + + sql = wxT("-- Policy: ") + GetQuotedIdentifier() + wxT("\n\n"); + sql += wxT("-- DROP POLICY ") + GetQuotedIdentifier() + wxT(" ON ") + GetTable()->GetQuotedFullIdentifier() + wxT("\n\n"); + sql += GetCreatePolicySql(GetQuotedIdentifier(), GetTable()->GetQuotedFullIdentifier(), GetPolicyCommand(), GetPolicyRolesSorted(), + GetPolicyUsingExpression(), GetPolicyWithCheckExpression()); + + if (!GetComment().IsEmpty()) + sql += wxT("\nCOMMENT ON POLICY ") + GetQuotedIdentifier() + wxT(" ON ") + GetTable()->GetQuotedFullIdentifier() + + wxT("\n IS ") + qtDbString(GetComment()) + wxT(";\n"); + + return sql; +} + +wxString pgPolicy::GetTranslatedMessage(int kindOfMessage) const +{ + wxString message = wxEmptyString; + + switch (kindOfMessage) + { + case RETRIEVINGDETAILS: + message = _("Retrieving details on policy"); + message += wxT(" ") + GetName(); + break; + case REFRESHINGDETAILS: + message = _("Refreshing policy"); + message += wxT(" ") + GetName(); + break; + case DROPEXCLUDINGDEPS: + message = wxString::Format(_("Are you sure you wish to drop policy \"%s\"?"), + GetFullIdentifier().c_str()); + break; + case DROPTITLE: + message = _("Drop policy?"); + break; + case PROPERTIESREPORT: + message = _("Policy properties report"); + message += wxT(" - ") + GetName(); + break; + case PROPERTIES: + message = _("Policy properties"); + break; + case DDLREPORT: + message = _("Policy DDL report"); + message += wxT(" - ") + GetName(); + break; + case DDL: + message = _("Policy DDL"); + break; + } + + return message; +} + +void pgPolicy::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *properties, ctlSQLBox *sqlPane) +{ + if (properties) + { + CreateListColumns(properties); + + properties->AppendItem(_("Name"), GetName()); + properties->AppendItem(_("Command"), pgPolicy::GetPolicyCommandString(GetPolicyCommand())); + properties->AppendItem(_("Roles"), GetPolicyRolesString(GetPolicyRolesSorted())); + properties->AppendItem(_("Using expression"), firstLineOnly(GetPolicyUsingExpression())); + properties->AppendItem(_("With Check expression"), firstLineOnly(GetPolicyWithCheckExpression())); + properties->AppendItem(_("Comment"), firstLineOnly(GetComment())); + } +} + +// char command value to sql text, e.g. '*' -> 'ALL', 'r' -> 'SELECT' +wxString pgPolicy::GetPolicyCommandString(char command) +{ + switch (command) + { + case POLICY_ALL: return wxT("ALL"); + case POLICY_SELECT: return wxT("SELECT"); + case POLICY_INSERT: return wxT("INSERT"); + case POLICY_UPDATE: return wxT("UPDATE"); + case POLICY_DELETE: return wxT("DELETE"); + default: return wxString(); + } +} + +wxString pgPolicy::GetAlterTablePolicyParamsSql(const wxString &table, int enableRls, int forceRls) +{ + wxString sql; + + wxString enableExpr; + if (enableRls == ROW_SECURUTY_ENABLE) + enableExpr = wxT("ENABLE ROW LEVEL SECURITY"); + else if (enableRls == ROW_SECURUTY_DISABLE) + enableExpr = wxT("DISABLE ROW LEVEL SECURITY"); + + wxString forceExpr; + if (forceRls == ROW_SECURUTY_FORCE) + forceExpr = wxT("FORCE ROW LEVEL SECURITY"); + else if (forceRls == ROW_SECURUTY_NOFORCE) + forceExpr = wxT("NO FORCE ROW LEVEL SECURITY"); + + if (!enableExpr.IsNull() || !forceExpr.IsNull()) + { + sql += wxT("ALTER TABLE ") + table + wxT(" "); + if (!enableExpr.IsNull()) + sql += enableExpr; + if (!forceExpr.IsNull()) + { + if (!enableExpr.IsNull()) + sql += wxT(", "); + sql += forceExpr; + } + sql += wxT(";"); + } + + return sql; +} + +// wrap expression in parantheses, if it is not already wrapped +wxString& pgPolicy::WrapParentheses(wxString &expr) +{ + if (expr.IsEmpty()) + return expr; + + if (expr.GetChar(0) != '(' || expr.GetChar(expr.size() - 1) != ')') + expr = wxT("(") + expr + wxT(")"); + + return expr; +} + +// array of roles to comma-separated string +wxString pgPolicy::GetPolicyRolesString(const wxArrayString &roles) +{ + wxString result; + int numRoles = roles.size(); + for (int i = 0; i < numRoles; i++) + { + result += roles[i] + wxT(", "); + } + result.RemoveLast(2); + + return result; +} + +///////////////////////////// + +pgPolicyCollection::pgPolicyCollection(pgaFactory *factory, pgTable *tbl) + : pgTableObjCollection(factory, tbl) +{ +} + + +wxString pgPolicyCollection::GetTranslatedMessage(int kindOfMessage) const +{ + wxString message = wxEmptyString; + + switch (kindOfMessage) + { + case RETRIEVINGDETAILS: + message = _("Retrieving details on policies"); + break; + case REFRESHINGDETAILS: + message = _("Refreshing policies"); + break; + case OBJECTSLISTREPORT: + message = _("Policies list report"); + break; + } + + return message; +} + +///////////////////////////// + +dlgProperty* pgPolicyFactory::CreateDialog(frmMain *frame, pgObject *node, pgObject *parent) +{ + return new dlgPolicy(this, frame, (pgPolicy*)node, (pgTable*)parent); +} + +pgObject* pgPolicyFactory::CreateObjects(pgCollection *collection, ctlTree *browser, const wxString &restriction) +{ + pgPolicy *policy = NULL; + pgSet *policies = NULL; + pgDatabase *db = collection->GetDatabase(); + wxString name, cmd, roleOids, roleOid, roleName; + wxStringTokenizer roleTokens; + + wxString query = + wxT("SELECT\n") + wxT(" p.oid, p.polname, p.polrelid, p.polcmd, p.polroles,\n") + wxT(" pg_get_expr(p.polqual, p.polrelid") + db->GetPrettyOption() + wxT(") AS exprusing,\n") + wxT(" pg_get_expr(p.polwithcheck, p.polrelid") + db->GetPrettyOption() + wxT(") AS exprwithcheck,\n") + wxT(" des.description\n") + wxT("FROM\n") + wxT(" pg_policy p\n") + wxT(" LEFT OUTER JOIN pg_description des ON (des.objoid = p.oid AND des.classoid = 'pg_policy'::regclass)\n") + wxT("WHERE\n") + wxT(" p.polrelid = ") + collection->GetOidStr() + wxT(" ") + restriction + wxT("\n") + wxT("ORDER BY p.polname\n"); + + policies = db->ExecuteSet(query); + if (policies) + { + while (!policies->Eof()) + { + name = policies->GetVal(wxT("polname")); + policy = new pgPolicy(collection->GetTable(), name); + + policy->iSetOid(policies->GetOid(wxT("oid"))); + policy->iSetComment(policies->GetVal(wxT("description"))); + cmd = policies->GetVal(wxT("polcmd")); + if (!cmd.IsEmpty()) + { + policy->iSetPolicyCommand(cmd[0]); + } + + policy->iSetPolicyUsingExpression(policies->GetVal(wxT("exprusing"))); + policy->iSetPolicyWithCheckExpression(policies->GetVal(wxT("exprwithcheck"))); + + wxArrayString roleNames; + roleOids = policies->GetVal(wxT("polroles")); + roleOids = roleOids.Mid(1, roleOids.size() - 2); + roleTokens.SetString(roleOids, wxT(",")); + while (roleTokens.HasMoreTokens()) + { + // get role names from catalog + roleOid = roleTokens.GetNextToken(); + if (roleOid != wxT("0")) // PUBLIC + { + roleName = db->ExecuteScalar(wxT("SELECT rolname FROM pg_roles WHERE oid =") + roleOid); + roleNames.Add(roleName); + } + } + policy->iSetPolicyRoles(roleNames); + + if (browser) + { + browser->AppendObject(collection, policy); + policies->MoveNext(); + } + else + break; + } + + delete policies; + } + + return policy; +} + +#include "images/policy.pngc" +#include "images/policy-sm.pngc" +#include "images/policies.pngc" + +pgPolicyFactory::pgPolicyFactory() + : pgTableObjFactory(__("Policy"), __("New Policy..."), __("Create a new Policy."), policy_png_img, policy_sm_png_img) +{ + metaType = PGM_POLICY; +} + +pgCollection* pgPolicyFactory::CreateCollection(pgObject *obj) +{ + return new pgPolicyCollection(GetCollectionFactory(), (pgTable *)obj); +} + +pgPolicyFactory policyFactory; +static pgaCollectionFactory cf(&policyFactory, __("Policies"), policies_png_img); \ No newline at end of file diff --git a/pgadmin/schema/pgTable.cpp b/pgadmin/schema/pgTable.cpp index fdfea40..792873d 100644 --- a/pgadmin/schema/pgTable.cpp +++ b/pgadmin/schema/pgTable.cpp @@ -27,6 +27,7 @@ #include "schema/pgTrigger.h" #include "schema/pgConstraints.h" #include "schema/gpPartition.h" +#include "schema/pgPolicy.h" // App headers @@ -65,6 +66,8 @@ void pgTable::Init() isReplicated = false; showExtendedStatistics = false; distributionIsRandom = false; + rowSecurityEnabled = false; + forceRowSecurity = false; inheritedTableCount = 0; triggerCount = 0; @@ -179,6 +182,8 @@ wxMenu *pgTable::GetNewMenu() indexFactory.AppendMenu(menu); ruleFactory.AppendMenu(menu); triggerFactory.AppendMenu(menu); + if (GetConnection() != 0 && GetConnection()->BackendMinimumVersion(9, 5)) + policyFactory.AppendMenu(menu); /* * TEMPORARY: Disable adding new partitions until that code is working right. @@ -682,6 +687,16 @@ wxString pgTable::GetSql(ctlTree *browser) sql += GetCommentSql(); + // row level security options + if (GetConnection()->BackendMinimumVersion(9, 5)) + { + int enableRls = GetRowLevelSecurityEnabled() ? ROW_SECURUTY_ENABLE : ROW_SECURUTY_SKIP; + int forceRls = GetForceRowLevelSecurity() ? ROW_SECURUTY_FORCE : ROW_SECURUTY_SKIP; + wxString rlsSql = pgPolicy::GetAlterTablePolicyParamsSql(GetQuotedFullIdentifier(), enableRls, forceRls); + if (!rlsSql.IsEmpty()) + sql += wxT("\n") + rlsSql + wxT("\n\n"); + } + if (GetConnection()->BackendMinimumVersion(9, 1)) sql += GetSeqLabelsSql(); @@ -701,6 +716,10 @@ wxString pgTable::GetSql(ctlTree *browser) AppendStuff(sql, browser, ruleFactory); AppendStuff(sql, browser, triggerFactory); + // row security policies for table + if (GetConnection()->BackendMinimumVersion(9, 5)) + AppendStuff(sql, browser, policyFactory); + /* * Disable adding partitions until that code works. * @@ -929,6 +948,9 @@ void pgTable::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *prope browser->AppendCollection(this, indexFactory); browser->AppendCollection(this, ruleFactory); browser->AppendCollection(this, triggerFactory); + // row level security policies + if (GetConnection() != 0 && GetConnection()->BackendMinimumVersion(9, 5)) + browser->AppendCollection(this, policyFactory); if (GetConnection() != 0 && GetConnection()->GetIsGreenplum() && GetIsPartitioned()) browser->AppendCollection(this, partitionFactory); @@ -1083,6 +1105,13 @@ void pgTable::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *prope if (!GetToastAutoVacuumFreezeTableAge().IsEmpty()) properties->AppendItem(_("Toast auto-vacuum FREEZE table age"), GetToastAutoVacuumFreezeTableAge()); } + + // row level security options + if (GetConnection()->BackendMinimumVersion(9, 5)) + { + properties->AppendItem(_("RLS enabled?"), GetRowLevelSecurityEnabled() ? _("Yes") : _("No")); + properties->AppendItem(_("RLS forced?"), GetForceRowLevelSecurity() ? _("Yes") : _("No")); + } properties->AppendItem(_("Comment"), firstLineOnly(GetComment())); if (!GetLabels().IsEmpty()) @@ -1450,6 +1479,12 @@ pgObject *pgTableFactory::CreateObjects(pgCollection *collection, ctlTree *brows wxT(" WHERE tgrelid=rel.oid AND tgisconstraint = FALSE) AS triggercount\n"); } + // row level security options + if (collection->GetDatabase()->BackendMinimumVersion(9, 5)) + { + query += wxT(", rel.relrowsecurity \n"); + query += wxT(", rel.relforcerowsecurity \n"); + } if (collection->GetConnection()->BackendMinimumVersion(9, 1)) query += wxT(", rel.relpersistence \n"); if (collection->GetConnection()->BackendMinimumVersion(8, 2)) @@ -1574,6 +1609,17 @@ pgObject *pgTableFactory::CreateObjects(pgCollection *collection, ctlTree *brows table->iSetOfType(wxT("")); } table->iSetComment(tables->GetVal(wxT("description"))); + // row level security options + if (collection->GetDatabase()->BackendMinimumVersion(9, 5)) + { + table->iSetRowLevelSecurityEnabled(StrToBool(tables->GetVal(wxT("relrowsecurity")))); + table->iSetForceRowLevelSecurity(StrToBool(tables->GetVal(wxT("relforcerowsecurity")))); + } + else + { + table->iSetRowLevelSecurityEnabled(false); + table->iSetForceRowLevelSecurity(false); + } if (collection->GetConnection()->BackendMinimumVersion(9, 1)) table->iSetUnlogged(tables->GetVal(wxT("relpersistence")) == wxT("u")); else diff --git a/pgadmin/ui/dlgPolicy.xrc b/pgadmin/ui/dlgPolicy.xrc new file mode 100644 index 0000000..64a613b --- /dev/null +++ b/pgadmin/ui/dlgPolicy.xrc @@ -0,0 +1,278 @@ + + + + + 300,265d + + + 1 + 0 + 0 + + + 296,240d + 0 + + + + + 2 + 5 + 5 + 2 + 1 + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxALL + 4 + + + + + + wxALIGN_CENTRE_VERTICAL|wxALL + 4 + + + + + + + wxEXPAND|wxALIGN_CENTRE_VERTICAL|wxALL + 4 + + + + + + + + + 2 + 5 + 5 + 1 + 1 + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + ALL + SELECT + INSERT + UPDATE + DELETE + + 1 + + + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxALIGN_TOP|wxTOP|wxLEFT|wxRIGHT + 4 + + + + 3 + 5 + 5 + 2 + 0,2 + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 0 + + + 0,0d + + + 0,0d + + + + + 86,123d + + + wxEXPAND|wxBOTTOM + 0 + + + + 1 + 5 + 5 + + + + Add role + 18,-1d + + wxEXPAND|wxALIGN_BOTTOM|wxALL + 4 + + + + + Remove role + 18,-1d + + wxEXPAND|wxALIGN_TOP|wxALL + 4 + + wxALIGN_CENTRE_VERTICAL|wxALL + 0 + + + + + + 86,123d + + + wxEXPAND|wxBOTTOM|wxRIGHT + 0 + + + wxEXPAND|wxALL + 4 + + + + + + + + + 2 + 5 + 5 + 0,1 + 1 + + + + + wxALIGN_TOP|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxEXPAND|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxALIGN_TOP|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxEXPAND|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxALL|wxGROW|wxALIGN_CENTRE + 3 + + + + 4 + 1 + + + + + wxEXPAND|wxALL + 3 + + + 0,0d + + + + + 1 + + wxEXPAND|wxALL + 3 + + + + + + wxEXPAND|wxALL + 3 + + + wxEXPAND|wxTOP|wxLEFT|wxRIGHT + + + + + + wxEXPAND|wxALIGN_CENTRE + 3 + + + + diff --git a/pgadmin/ui/dlgTable.xrc b/pgadmin/ui/dlgTable.xrc index 6ebaa32..bdb8512 100644 --- a/pgadmin/ui/dlgTable.xrc +++ b/pgadmin/ui/dlgTable.xrc @@ -187,6 +187,36 @@ wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT 4 + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + 0 + + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + + wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + + + + + 0 + + wxEXPAND|wxALIGN_CENTER_VERTICAL|wxTOP|wxLEFT|wxRIGHT + 4 + diff --git a/pgadmin/ui/module.mk b/pgadmin/ui/module.mk index b546e41..1b998b9 100644 --- a/pgadmin/ui/module.mk +++ b/pgadmin/ui/module.mk @@ -49,6 +49,7 @@ TMP_ui += \ ui/dlgOperator.xrc \ ui/dlgPackage.xrc \ ui/dlgPgpassConfig.xrc \ + ui/dlgPolicy.xrc \ ui/dlgReassignDropOwned.xrc \ ui/dlgRepCluster.xrc \ ui/dlgRepClusterUpgrade.xrc \ -- 2.7.2.windows.1