Add support for column level privileges on PostgreSQL 8.4 and above [Ashesh Vashi].
authordpage <dpage@a7884b65-44f6-0310-8a51-81a127f17b15>
Tue, 3 Feb 2009 17:25:21 +0000 (17:25 +0000)
committerdpage <dpage@a7884b65-44f6-0310-8a51-81a127f17b15>
Tue, 3 Feb 2009 17:25:21 +0000 (17:25 +0000)
git-svn-id: svn://svn.pgadmin.org/trunk/pgadmin3@7577 a7884b65-44f6-0310-8a51-81a127f17b15

CHANGELOG
pgadmin/ctl/ctlSecurityPanel.cpp
pgadmin/dlg/dlgColumn.cpp
pgadmin/dlg/dlgProperty.cpp
pgadmin/include/ctl/ctlSecurityPanel.h
pgadmin/include/dlg/dlgColumn.h
pgadmin/include/schema/pgColumn.h
pgadmin/include/schema/pgObject.h
pgadmin/schema/pgColumn.cpp
pgadmin/schema/pgObject.cpp
pgadmin/schema/pgTable.cpp

index c95ff1958e1a454bd1d81efa2d31b67f552c30ec..edf84ef80b73471e9d9cac085dda716e34148225 100644 (file)
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -36,6 +36,8 @@ Changes
 \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
index c9a52a977060f2d24da78b85fdd2e90772bcd012..1bcc0bf5fda87749ebe85b01f8828c365f0e1aa6 100644 (file)
@@ -13,6 +13,7 @@
 // wxWindows headers
 #include <wx/wx.h>
 #include <wx/settings.h>
+#include <wx/imaglist.h>
 
 // App headers
 #include "pgAdmin3.h"
@@ -75,7 +76,9 @@ ctlSecurityPanel::ctlSecurityPanel(wxNotebook *nb, const wxString &privList, con
         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);
 
@@ -157,7 +160,7 @@ void ctlSecurityPanel::SetConnection(pgConn *conn)
 }
 
 
-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)
@@ -197,8 +200,8 @@ wxString ctlSecurityPanel::GetGrant(const wxString &allPattern, const wxString &
         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);
         }
     }
 
@@ -210,7 +213,7 @@ wxString ctlSecurityPanel::GetGrant(const wxString &allPattern, const wxString &
             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;
 }
index 742ab5adc42d9689b319a0e55cb33f264fbd2d82..ccb7e38f28caccac0d943887362aab0fbade953e 100644 (file)
@@ -22,6 +22,9 @@
 #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
@@ -37,6 +40,11 @@ BEGIN_EVENT_TABLE(dlgColumn, dlgTypeProperty)
     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();
 
 
@@ -54,9 +62,111 @@ dlgColumn::dlgColumn(pgaFactory *f, frmMain *frame, pgColumn *node, pgTable *par
     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;
@@ -65,6 +175,27 @@ pgObject *dlgColumn::GetObject()
 
 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
@@ -273,6 +404,10 @@ wxString dlgColumn::GetSql()
 
         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(), &currentAcl, qtIdent(name));
     }
     return sql;
 }
@@ -351,7 +486,8 @@ void dlgColumn::CheckChange()
                     || (isVarLen && varlen != column->GetLength())
                     || (isVarPrec && varprec != column->GetPrecision())
                     || txtAttstattarget->GetValue() != NumToStr(column->GetAttstattarget());
-        EnableOK(enable);
+
+        EnableOK(enable | securityChanged);
     }
     else
     {
@@ -374,4 +510,16 @@ void dlgColumn::CheckChange()
 }
 
 
+void dlgColumn::OnAddPriv(wxCommandEvent &ev)
+{
+    securityChanged=true;
+    CheckChange();
+}
+
+
+void dlgColumn::OnDelPriv(wxCommandEvent &ev)
+{
+    securityChanged=true;
+    CheckChange();
+}
 
index 3d04b9edd1f2b223a85aaf8a33f307ab65153f76..5589999585d6f523e4c7b236985104f392c2580f 100644 (file)
@@ -1462,6 +1462,21 @@ dlgSecurityProperty::dlgSecurityProperty(pgaFactory *f, frmMain *frame, pgObject
 
         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())
             {
@@ -1496,7 +1511,16 @@ dlgSecurityProperty::dlgSecurityProperty(pgaFactory *f, frmMain *frame, pgObject
                         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);
index c21e521198131548dc532123e7f58c7b405d965a..5ff89ba873af4582023b8499fec2c90cb418ea1d 100644 (file)
@@ -46,7 +46,11 @@ public:
     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;
index 03a4b91136ce8252d253bffa609bc182eafa355e..21a01133bddfdeebe228bbf8725ba4a1f0e29017 100644 (file)
@@ -36,6 +36,27 @@ public:
 
     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;
index 14c11c422dfef8feee5bf310997126f78995a1da..9ddf6023656fd06c5bfafdaf67a89fefb380269e 100644 (file)
@@ -94,6 +94,7 @@ public:
     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; }
index 8338ff7d18caca92d22511534515c4f0c1ee01b4..ec2c08ebe0ebb3e872415b9d475512a9c05206a5 100644 (file)
@@ -47,8 +47,13 @@ protected:
     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; }
@@ -97,7 +102,11 @@ public:
     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;
@@ -146,8 +155,12 @@ protected:
     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;
index d54a82af7788288e9cb35716924e42f1b6429220..c6c2d63c75d751c747508c4efa2234ca86bc8396 100644 (file)
@@ -121,7 +121,10 @@ wxString pgColumn::GetSql(ctlTree *browser)
                         + wxT(" ALTER COLUMN ") + GetQuotedIdentifier()
                         + wxT(" SET STATISTICS ") + NumToStr(GetAttstattarget()) + wxT(";\n");
 
-                           sql += GetCommentSql();
+                sql += GetCommentSql();
+
+                if (GetDatabase()->BackendMinimumVersion(8, 4))
+                    sql += GetPrivileges();
             }
         }
     }
@@ -140,6 +143,55 @@ wxString pgColumn::GetCommentSql()
        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();
@@ -267,6 +319,10 @@ void pgColumn::ShowTreeDetail(ctlTree *browser, frmMain *form, ctlListView *prop
                 properties->AppendItem(_("System column?"), GetSystemObject());
             }
         }
+        if (GetDatabase()->BackendMinimumVersion(8, 4))
+        {
+            properties->AppendItem(_("ACL"), GetAcl());
+        }
 
         properties->AppendItem(_("Comment"), firstLineOnly(GetComment()));
     }
@@ -393,6 +449,8 @@ pgObject *pgColumnFactory::CreateObjects(pgCollection *coll, ctlTree *browser, c
             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)
             {
index 2f90d274a4cd61f1f2c9d119e438c21f344ea518..7cb3027ea3e4cc3ebdd676f47d27ff7cb4c3fd0d 100644 (file)
@@ -521,41 +521,54 @@ wxString pgObject::GetOwnerSql(int major, int minor, wxString objname)
 }
 
 
-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;
 
@@ -568,7 +581,7 @@ wxString pgObject::GetPrivilegeGrant(const wxString& allPattern, const wxString&
 }
 
 
-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;
 
@@ -589,15 +602,15 @@ wxString pgObject::GetPrivileges(const wxString& allPattern, const wxString& str
 
     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())
@@ -640,7 +653,7 @@ wxString pgObject::GetGrant(const wxString& allPattern, const wxString& _grantFo
                                }
             }
 
-            grant += GetPrivileges(allPattern, str, grantFor, user);
+            grant += GetPrivileges(allPattern, str, grantFor, user, qtIdent(_column));
         }
     }
     return grant;
index 8173978e0eabe2b527886b116246ce85bb7c0d28..77d82d5c8dc47ed93e85a78df3100caf114c0e20 100644 (file)
@@ -172,6 +172,8 @@ wxString pgTable::GetSql(ctlTree *browser)
        wxString colDetails, conDetails;
     wxString prevComment;
 
+    wxString columnPrivileges;
+
     if (sql.IsNull())
     {
         // make sure all kids are appended
@@ -242,9 +244,11 @@ wxString pgTable::GetSql(ctlTree *browser)
                                        // 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();
                 }
             }
         }
@@ -339,6 +343,11 @@ wxString pgTable::GetSql(ctlTree *browser)
         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);