\r
Date Dev Ver Change details\r
---------- --- ----- --------------\r
+2009-02-03 DP 1.9.0 Add support for column level privileges on PostgreSQL\r
+ 8.4 and above [Ashesh Vashi].\r
2009-01-13 DP 1.9.0 Warn the user if connecting to a newer version of the\r
server than is supported.\r
2009-01-12 DP 1.9.0 Add support for Window functions [Ashesh Vashi]\r
// wxWindows headers
#include <wx/wx.h>
#include <wx/settings.h>
+#include <wx/imaglist.h>
// App headers
#include "pgAdmin3.h"
itemSizer1->AddGrowableCol(0);
itemSizer1->AddGrowableRow(0);
lbPrivileges = new ctlListView(this, CTL_LBPRIV, wxDefaultPosition, wxDefaultSize, wxSUNKEN_BORDER|wxLC_REPORT);
- lbPrivileges->CreateColumns(imgList, _("User/Group"), _("Privileges"), -1);
+ lbPrivileges->SetImageList(imgList, wxIMAGE_LIST_SMALL);
+ lbPrivileges->AddColumn(_("User/Group"), 70, wxLIST_FORMAT_LEFT);
+ lbPrivileges->AddColumn(_("Privileges"), 70, wxLIST_FORMAT_LEFT);
itemSizer1->Add(lbPrivileges, 0, wxEXPAND|wxALIGN_CENTRE_VERTICAL|wxTOP|wxLEFT|wxRIGHT, 4);
item0->Add(itemSizer1, 0, wxEXPAND|wxALL, 5);
}
-wxString ctlSecurityPanel::GetGrant(const wxString &allPattern, const wxString &grantObject, wxArrayString *currentAcl)
+wxString ctlSecurityPanel::GetGrant(const wxString &allPattern, const wxString &grantObject, wxArrayString *currentAcl, wxString column)
{
wxArrayString tmpAcl;
if (currentAcl)
if (!privWasAssigned)
{
if (privPartiallyAssigned)
- sql += pgObject::GetPrivileges(allPattern, wxT(""), grantObject, name);
- sql += pgObject::GetPrivileges(allPattern, value, grantObject, name);
+ sql += pgObject::GetPrivileges(allPattern, wxT(""), grantObject, name, column);
+ sql += pgObject::GetPrivileges(allPattern, value, grantObject, name, column);
}
}
name = wxT("GROUP ") + qtIdent(name.Mid(6));
else
name=qtIdent(name);
- sql += pgObject::GetPrivileges(allPattern, wxT(""), grantObject, name);
+ sql += pgObject::GetPrivileges(allPattern, wxT(""), grantObject, name, column);
}
return sql;
}
#include "schema/pgColumn.h"
#include "schema/pgTable.h"
#include "schema/pgDatatype.h"
+#include "frm/frmMain.h"
+#include "schema/pgUser.h"
+#include "schema/pgGroup.h"
// pointer to controls
EVT_TEXT(XRCID("txtAttstattarget"), dlgProperty::OnChange)
EVT_TEXT(XRCID("cbDatatype"), dlgColumn::OnSelChangeTyp)
EVT_COMBOBOX(XRCID("cbDatatype"), dlgColumn::OnSelChangeTyp)
+ EVT_BUTTON(CTL_ADDPRIV, dlgColumn::OnAddPriv)
+ EVT_BUTTON(CTL_DELPRIV, dlgColumn::OnDelPriv)
+#ifdef __WXMAC__
+ EVT_SIZE( dlgColumn::OnChangeSize)
+#endif
END_EVENT_TABLE();
wxASSERT(!table || (table->GetMetaType() == PGM_TABLE || table->GetMetaType() == PGM_VIEW));
txtAttstattarget->SetValidator(numericValidator);
+
+ /* Column Level Privileges */
+ securityChanged=false;
+ if (node)
+ connection = node->GetConnection();
+ securityPage = new ctlSecurityPanel(nbNotebook, wxT("INSERT,SELECT,UPDATE,REFERENCES"), "arwx", frame->GetImageList());
+ if (connection && connection->BackendMinimumVersion(8, 4) && (!node || node->CanCreate()))
+ {
+ // Fetch Groups Information
+ pgSet *setGrp = connection->ExecuteSet(wxT("SELECT groname FROM pg_group ORDER BY groname"));
+
+ if (setGrp)
+ {
+ while (!setGrp->Eof())
+ {
+ groups.Add(setGrp->GetVal(0));
+ setGrp->MoveNext();
+ }
+ delete setGrp;
+ }
+
+ if (node)
+ {
+ wxString strAcl = node->GetAcl();
+ if (!strAcl.IsEmpty())
+ {
+ wxArrayString aclArray;
+ strAcl = strAcl.Mid(1, strAcl.Length()-2);
+ getArrayFromCommaSeparatedList(strAcl, aclArray);
+ wxString roleName;
+ for (unsigned int index = 0; index < aclArray.Count(); index++)
+ {
+ wxString strCurrAcl = aclArray[index];
+
+ /*
+ * In rare case, we can have ',' (comma) in the user name.
+ * But, we need to handle them also
+ */
+ if (strCurrAcl.Find(wxChar('=')) == wxNOT_FOUND)
+ {
+ // Check it is start of the ACL
+ if (strCurrAcl[0U] == (wxChar)'"')
+ roleName = strCurrAcl + wxT(",");
+ continue;
+ }
+ else
+ strCurrAcl = roleName + strCurrAcl;
+
+ if (strCurrAcl[0U] == (wxChar)'"')
+ strCurrAcl = strCurrAcl.Mid(1, strCurrAcl.Length()-1);
+ roleName = strCurrAcl.BeforeLast('=');
+
+ wxString value=strCurrAcl.Mid(roleName.Length()+1).BeforeLast('/');
+
+ int icon = userFactory.GetIconId();
+
+ if (roleName.Left(6).IsSameAs(wxT("group ")), false)
+ {
+ icon = groupFactory.GetIconId();
+ roleName = wxT("group ") + qtStrip(roleName.Mid(6));
+ }
+ else if (roleName.IsEmpty())
+ {
+ icon = PGICON_PUBLIC;
+ roleName = wxT("public");
+ }
+ else
+ {
+ roleName = qtStrip(roleName);
+ for (unsigned int index=0; index < groups.Count(); index++)
+ if (roleName == groups[index])
+ {
+ roleName = wxT("group ") + roleName;
+ icon = groupFactory.GetIconId();
+ break;
+ }
+ }
+
+ securityPage->lbPrivileges->AppendItem(icon, roleName, value);
+ currentAcl.Add(roleName + wxT("=") + value);
+
+ // Reset roleName
+ roleName.Empty();
+ }
+ }
+ }
+ }
+ else
+ securityPage->Disable();
+
}
+#ifdef __WXMAC__
+void dlgColumn::OnChangeSize(wxSizeEvent &ev)
+{
+ securityPage->lbPrivileges->SetSize(wxDefaultCoord, wxDefaultCoord,
+ ev.GetSize().GetWidth(), ev.GetSize().GetHeight() - 550);
+ if (GetAutoLayout())
+ {
+ Layout();
+ }
+}
+#endif
+
pgObject *dlgColumn::GetObject()
{
return column;
int dlgColumn::Go(bool modal)
{
+ if (connection->BackendMinimumVersion(8, 4))
+ {
+ securityPage->SetConnection(connection);
+
+ if (securityPage->cbGroups)
+ {
+ // Fetch Groups Information
+ for ( unsigned int index=0; index < groups.Count();)
+ securityPage->cbGroups->Append(wxT("group ") + groups[index++]);
+
+ // Fetch Users Information
+ if (settings->GetShowUsersForPrivileges())
+ {
+ securityPage->stGroup->SetLabel(_("Group/User"));
+ dlgProperty::AddUsers(securityPage->cbGroups);
+ }
+ }
+ securityPage->lbPrivileges->GetParent()->Layout();
+ }
+
+
if (column)
{
// edit mode
AppendComment(sql, wxT("COLUMN ") + table->GetQuotedFullIdentifier()
+ wxT(".") + qtIdent(name), column);
+
+ // securityPage will exists only for PG 8.4 and later
+ if (connection->BackendMinimumVersion(8, 4))
+ sql += securityPage->GetGrant(wxT("arwx"), table->GetQuotedFullIdentifier(), ¤tAcl, qtIdent(name));
}
return sql;
}
|| (isVarLen && varlen != column->GetLength())
|| (isVarPrec && varprec != column->GetPrecision())
|| txtAttstattarget->GetValue() != NumToStr(column->GetAttstattarget());
- EnableOK(enable);
+
+ EnableOK(enable | securityChanged);
}
else
{
}
+void dlgColumn::OnAddPriv(wxCommandEvent &ev)
+{
+ securityChanged=true;
+ CheckChange();
+}
+
+
+void dlgColumn::OnDelPriv(wxCommandEvent &ev)
+{
+ securityChanged=true;
+ CheckChange();
+}
if (obj)
{
+
+ wxArrayString groups;
+ // Fetch Groups Information
+ pgSet *setGrp = obj->GetConnection()->ExecuteSet(wxT("SELECT groname FROM pg_group ORDER BY groname"));
+
+ if (setGrp)
+ {
+ while (!setGrp->Eof())
+ {
+ groups.Add(setGrp->GetVal(0));
+ setGrp->MoveNext();
+ }
+ delete setGrp;
+ }
+
wxString str=obj->GetAcl();
if (!str.IsEmpty())
{
name=wxT("public");
}
else
+ {
name = qtStrip(name);
+ for (unsigned int index=0; index < groups.Count(); index++)
+ if (name == groups[index])
+ {
+ name = wxT("group ") + name;
+ icon = groupFactory.GetIconId();
+ break;
+ }
+ }
securityPage->lbPrivileges->AppendItem(icon, name, value);
currentAcl.Add(name + wxT("=") + value);
ctlComboBox *cbGroups;
wxStaticText *stGroup;
void SetConnection(pgConn *conn);
- wxString GetGrant(const wxString &allPattern, const wxString &grantObject, wxArrayString *currentAcl=0);
+
+ /*
+ * Except column level privileges, column will be always an empty string in any case
+ */
+ wxString GetGrant(const wxString &allPattern, const wxString &grantObject, wxArrayString *currentAcl=0, wxString column = wxEmptyString);
bool DisablePrivilege(const wxString &priv);
protected:
wxNotebook *nbNotebook;
wxString GetHelpPage(bool forCreate) const { return wxT("pg/sql-createtable"); }
+protected:
+ /*
+ * Column Level Privileges:
+ * - Did not inherit dlgTypeProperty & dlgSecurityProperty as, it will
+ * lead to a lot of problem later
+ **/
+
+ ctlSecurityPanel *securityPage;
+ wxArrayString currentAcl;
+ wxArrayString groups;
+ bool securityChanged;
+
+ wxString GetGrant(const wxString &allPattern, const wxString &grantObject);
+
+ void OnAddPriv(wxCommandEvent& ev);
+ void OnDelPriv(wxCommandEvent& ev);
+
+#ifdef __WXMAC__
+ void OnChangeSize(wxSizeEvent &ev);
+#endif
+
private:
pgColumn *column;
pgTable *table;
bool GetSystemObject() const { return colNumber < 0; }
wxString GetSql(ctlTree *browser);
wxString GetCommentSql();
+ wxString GetPrivileges();
wxString GetHelpPage(bool forCreate) const { return wxT("pg/sql-altertable"); }
virtual bool CanDrop() { return inheritedCount == 0 && pgSchemaObject::CanDrop() && GetSchema()->GetMetaType() != PGM_CATALOG && GetTable()->GetMetaType() != PGM_VIEW; }
pgObject(pgaFactory &factory, const wxString& newName=wxEmptyString);
public:
-
- static wxString GetPrivileges(const wxString& allPattern, const wxString& acl, const wxString& grantObject, const wxString& user);
+ /*
+ * Except column level privileges, column will be always an empty
+ * string in any case
+ */
+ static wxString GetPrivileges(const wxString& allPattern,
+ const wxString& acl, const wxString& grantObject,
+ const wxString& user, const wxString& column=wxT(""));
static int GetTypeId(const wxString &typname);
pgaFactory *GetFactory() { return factory; }
virtual wxMenu *GetNewMenu();
virtual wxString GetSql(ctlTree *browser) { return wxT(""); }
- wxString GetGrant(const wxString& allPattern, const wxString& grantFor=wxT(""));
+ /*
+ * Except column level privileges, column will be always an empty
+ * string in any case
+ */
+ wxString GetGrant(const wxString& allPattern, const wxString& grantFor=wxT(""), const wxString& column=wxT(""));
wxString GetCommentSql();
wxString GetOwnerSql(int major, int minor, wxString objname=wxEmptyString);
pgConn *GetConnection() const;
pgaFactory *factory;
private:
- static void AppendRight(wxString &rights, const wxString& acl, wxChar c, const wxChar *rightName);
- static wxString GetPrivilegeGrant(const wxString& allPattern, const wxString& acl, const wxString& grantObject, const wxString& user);
+ /*
+ * Except column level privileges, column will be always an empty
+ * string in any case
+ */
+ static void AppendRight(wxString &rights, const wxString& acl, wxChar c, const wxChar *rightName, const wxString& column=wxEmptyString);
+ static wxString GetPrivilegeGrant(const wxString& allPattern, const wxString& acl, const wxString& grantObject, const wxString& user, const wxString& column);
void ShowDependency(pgDatabase *db, ctlListView *list, const wxString &query, const wxString &clsOrder);
wxString name, owner, comment, acl;
int type;
+ wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
+ wxT(" SET STATISTICS ") + NumToStr(GetAttstattarget()) + wxT(";\n");
- sql += GetCommentSql();
+ sql += GetCommentSql();
+
+ if (GetDatabase()->BackendMinimumVersion(8, 4))
+ sql += GetPrivileges();
}
}
}
return commentSql;
}
+wxString pgColumn::GetPrivileges()
+{
+ wxString privileges;
+ wxString strAcl = GetAcl();
+ if (!strAcl.IsEmpty())
+ {
+ wxArrayString aclArray;
+ strAcl = strAcl.Mid(1, strAcl.Length()-2);
+ getArrayFromCommaSeparatedList(strAcl, aclArray);
+ wxString role;
+ for (unsigned int index = 0; index < aclArray.Count(); index++)
+ {
+ wxString strCurrAcl = aclArray[index];
+ /*
+ * In rare case, we can have ',' (comma) in the user name.
+ * But, we need to handle them also
+ */
+ if (strCurrAcl.Find(wxChar('=')) == wxNOT_FOUND)
+ {
+ // Check it is start of the ACL
+ if (strCurrAcl[0U] == (wxChar)'"')
+ role = strCurrAcl + wxT(",");
+ continue;
+ }
+ else
+ strCurrAcl = role + strCurrAcl;
+
+ if (strCurrAcl[0U] == (wxChar)'"')
+ strCurrAcl = strCurrAcl.Mid(1, strCurrAcl.Length()-1);
+ role = strCurrAcl.BeforeLast('=');
+ wxString value=strCurrAcl.Mid(role.Length()+1).BeforeLast('/');
+
+ if (role.Left(6).IsSameAs(wxT("group ")), false)
+ {
+ role = wxT("group ") + qtIdent(qtStrip(role.Mid(6)));
+ }
+ else if (role.IsEmpty())
+ {
+ role = wxT("public");
+ }
+ else
+ role = qtIdent(qtStrip(role));
+
+ privileges += pgObject::GetPrivileges(wxT("awrx"), value, GetQuotedFullTable(), role, GetQuotedIdentifier());
+ role.Clear();
+ }
+ }
+ return privileges;
+}
wxString pgColumn::GetDefinition()
{
wxString sql = GetQuotedTypename();
properties->AppendItem(_("System column?"), GetSystemObject());
}
}
+ if (GetDatabase()->BackendMinimumVersion(8, 4))
+ {
+ properties->AppendItem(_("ACL"), GetAcl());
+ }
properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
}
column->iSetInheritedTableName(columns->GetVal(wxT("inhrelname")));
column->iSetIsLocal(columns->GetBool(wxT("attislocal")));
column->iSetAttstattarget(columns->GetLong(wxT("attstattarget")));
+ if (database->BackendMinimumVersion(8, 4))
+ column->iSetAcl(columns->GetVal(wxT("attacl")));
if (browser)
{
}
-void pgObject::AppendRight(wxString &rights, const wxString& acl, wxChar c, const wxChar *rightName)
+void pgObject::AppendRight(wxString &rights, const wxString& acl, wxChar c, const wxChar *rightName, const wxString& column)
{
if (acl.Find(c) >= 0)
{
if (!rights.IsNull())
rights.Append(wxT(", "));
rights.Append(rightName);
+
+ if (!column.IsEmpty())
+ rights.Append(wxT("(") + column + wxT(")"));
}
}
-wxString pgObject::GetPrivilegeGrant(const wxString& allPattern, const wxString& acl, const wxString& grantOnObject, const wxString& user)
+wxString pgObject::GetPrivilegeGrant(const wxString& allPattern, const wxString& acl, const wxString& grantOnObject, const wxString& user, const wxString& column)
{
wxString rights;
if (allPattern.Length() > 1 && acl == allPattern)
+ {
rights = wxT("ALL");
+ if (!column.IsEmpty())
+ rights += wxT("(") + column + wxT(")");
+ }
else
{
- AppendRight(rights, acl, 'r', wxT("SELECT"));
- AppendRight(rights, acl, 'w', wxT("UPDATE"));
- AppendRight(rights, acl, 'a', wxT("INSERT"));
- AppendRight(rights, acl, 'c', wxT("CONNECT"));
- AppendRight(rights, acl, 'd', wxT("DELETE"));
- AppendRight(rights, acl, 'R', wxT("RULE"));
- AppendRight(rights, acl, 'x', wxT("REFERENCES"));
- AppendRight(rights, acl, 't', wxT("TRIGGER"));
- AppendRight(rights, acl, 'X', wxT("EXECUTE"));
- AppendRight(rights, acl, 'U', wxT("USAGE"));
- AppendRight(rights, acl, 'C', wxT("CREATE"));
- AppendRight(rights, acl, 'T', wxT("TEMPORARY"));
+ AppendRight(rights, acl, 'r', wxT("SELECT"), column);
+ AppendRight(rights, acl, 'w', wxT("UPDATE"), column);
+ AppendRight(rights, acl, 'a', wxT("INSERT"), column);
+ AppendRight(rights, acl, 'c', wxT("CONNECT"), column);
+ AppendRight(rights, acl, 'd', wxT("DELETE"), column);
+ AppendRight(rights, acl, 'R', wxT("RULE"), column);
+ AppendRight(rights, acl, 'x', wxT("REFERENCES"), column);
+ AppendRight(rights, acl, 't', wxT("TRIGGER"), column);
+ AppendRight(rights, acl, 'X', wxT("EXECUTE"), column);
+ AppendRight(rights, acl, 'U', wxT("USAGE"), column);
+ AppendRight(rights, acl, 'C', wxT("CREATE"), column);
+ AppendRight(rights, acl, 'T', wxT("TEMPORARY"), column);
}
wxString grant;
- if (rights.IsNull()) grant += wxT("REVOKE ALL");
- else grant += wxT("GRANT ") + rights;
+ if (rights.IsNull())
+ {
+ grant += wxT("REVOKE ALL");
+ if (!column.IsEmpty())
+ grant += wxT("(") + column + wxT(")");
+ }
+ else
+ grant += wxT("GRANT ") + rights;
grant += wxT(" ON ") + grantOnObject;
}
-wxString pgObject::GetPrivileges(const wxString& allPattern, const wxString& str, const wxString& grantOnObject, const wxString& user)
+wxString pgObject::GetPrivileges(const wxString& allPattern, const wxString& str, const wxString& grantOnObject, const wxString& user, const wxString& column)
{
wxString aclWithGrant, aclWithoutGrant;
wxString grant;
if (!aclWithoutGrant.IsEmpty() || aclWithGrant.IsEmpty())
- grant += GetPrivilegeGrant(allPattern, aclWithoutGrant, grantOnObject, user) + wxT(";\n");
+ grant += GetPrivilegeGrant(allPattern, aclWithoutGrant, grantOnObject, user, column) + wxT(";\n");
if (!aclWithGrant.IsEmpty())
- grant += GetPrivilegeGrant(allPattern, aclWithGrant, grantOnObject, user) + wxT(" WITH GRANT OPTION;\n");
+ grant += GetPrivilegeGrant(allPattern, aclWithGrant, grantOnObject, user, column) + wxT(" WITH GRANT OPTION;\n");
return grant;
}
-wxString pgObject::GetGrant(const wxString& allPattern, const wxString& _grantFor)
+wxString pgObject::GetGrant(const wxString& allPattern, const wxString& _grantFor, const wxString& _column)
{
wxString grant, str, user, grantFor;
if (_grantFor.IsNull())
}
}
- grant += GetPrivileges(allPattern, str, grantFor, user);
+ grant += GetPrivileges(allPattern, str, grantFor, user, qtIdent(_column));
}
}
return grant;
wxString colDetails, conDetails;
wxString prevComment;
+ wxString columnPrivileges;
+
if (sql.IsNull())
{
// make sure all kids are appended
// Perhaps we should also get storage types here?
colDetails += column->GetCommentSql();
if (colDetails.Length() > 0)
- if (colDetails.Last() != '\n') colDetails += wxT("\n");
+ if (colDetails.Last() != '\n')
+ colDetails += wxT("\n");
colCount++;
+ columnPrivileges += column->GetPrivileges();
}
}
}
if (!conDetails.IsEmpty())
sql += conDetails + wxT("\n");
+ if (!columnPrivileges.IsEmpty())
+ {
+ sql += columnPrivileges + wxT("\n");
+ }
+
AppendStuff(sql, browser, indexFactory);
AppendStuff(sql, browser, ruleFactory);
AppendStuff(sql, browser, triggerFactory);