diff --git a/pglab/CrudModel.cpp b/pglab/CrudModel.cpp index 7fb3343..6089774 100644 --- a/pglab/CrudModel.cpp +++ b/pglab/CrudModel.cpp @@ -511,7 +511,7 @@ void CrudModel::appendNewRow() std::tuple CrudModel::removeRows(const std::set> &row_ranges) { if (row_ranges.empty()) return { true, "" }; - if (row_ranges.rbegin()->end() > m_rowMapping.size()) return { false, "Range error" }; + if (row_ranges.rbegin()->end() > static_cast(m_rowMapping.size())) return { false, "Range error" }; // When removing rows there is no direct mapping anymore between the rows in the grid // and the rows in m_roData diff --git a/pglablib/catalog/PgAcl.cpp b/pglablib/catalog/PgAcl.cpp new file mode 100644 index 0000000..d7d2938 --- /dev/null +++ b/pglablib/catalog/PgAcl.cpp @@ -0,0 +1,190 @@ +#include "PgAcl.h" +#include + +namespace { + + QString privilegeLetterToKeyword(char c) + { + switch (c) { + case 'r': return "SELECT"; + case 'w': return "UPDATE"; + case 'a': return "INSERT"; + case 'd': return "DELETE"; + case 'D': return "TRUNCATE"; + case 'x': return "REFERENCES"; + case 't': return "TRIGGER"; + case 'X': return "EXECUTE"; + case 'U': return "USAGE"; + case 'C': return "CREATE"; + case 'c': return "CONNECT"; + case 'T': return "TEMPORARY"; + } + throw std::runtime_error("Unexpected value for c in privilegeLetterToKeyword"); + } + +} + +char privilegeToChar(Privilege p) +{ + switch (p) { + case Privilege::Select: return 'r'; + case Privilege::Update: return 'w'; + case Privilege::Insert: return 'a'; + case Privilege::Delete: return 'd'; + case Privilege::Truncate: return 'D'; + case Privilege::References: return 'x'; + case Privilege::Trigger: return 't'; + case Privilege::Execute: return 'X'; + case Privilege::Usage: return 'U'; + case Privilege::Create: return 'C'; + case Privilege::Connect: return 'c'; + case Privilege::Temporary: return 'T'; + } + throw std::runtime_error("Unexpected value for privilege in privilegeToChar"); +} + +PgAcl::PgAcl(const QString &acl) +{ + setFromString(acl); +} + +void PgAcl::setFromString(const QString &acl) +{ + m_grantee = acl.section('=', 0, 0); + auto t = acl.section('=', 1); + m_privileges = t.section('/', 0, 0); + m_grantor = t.section('/', 1); +} + +PrivValue PgAcl::privilege(Privilege priv) const +{ + char c = privilegeToChar(priv); + return privilege(c); +} + +PrivValue PgAcl::privilege(char c) const +{ + int pos = m_privileges.indexOf(c); + if (pos >= 0) { + if ( (pos+1) < m_privileges.length() && m_privileges[pos+1] == '*') + return PrivValue::YesWithGrant; + return PrivValue::Yes; + } + return PrivValue::No; +} + +QString PgAcl::singleString() const +{ + return m_grantee % "=" % m_privileges % "/" % m_grantor; +} + +//void operator<<(AclList &s, const Pgsql::Value &v) +void operator<<(PgAcl &acl, const Pgsql::Value &v) +{ + acl.setFromString(v); +// const char *c = v.c_str(); +// Pgsql::ArrayParser parser(c); + +// while (true) { +// auto elem = parser.GetNextElem(); +// if (!elem.ok) +// break; +// auto&& v = elem.value.value_or(""); +// s.emplace_back(QString(v.data())); +// } +} + +namespace Pgsql { + template <> + PgAcl StringToArrayElem(std::string_view sv) + { + return PgAcl(QString::fromUtf8(sv.data(), static_cast(sv.length()))); + } +} + +namespace { + + void appendColumn(QString &rights, const QString &column) + { + if (!column.isEmpty()) { + rights += "(" % column % ")"; + } + } + + QString privilegeGrant(const QString &all_pattern, const QString &acl, const QString &grantOnObject, QString user, const QString &column) + { + QString rights; + + if (user.isEmpty()) + user = "PUBLIC"; + + if (all_pattern.length() > 1 && acl == all_pattern) { + rights = "ALL"; + appendColumn(rights, column); + } + else { + for (auto c : acl) { + if (!rights.isEmpty()) + rights += ", "; + rights += privilegeLetterToKeyword(c.toLatin1()); + appendColumn(rights, column); + } + } + QString grant; + if (rights.isEmpty()) { + grant += "REVOKE ALL"; + appendColumn(grant, column); + } + else + grant += "GRANT " + rights; + + grant += " ON " + grantOnObject; + + if (rights.isEmpty()) + grant += " FROM "; + else + grant += " TO "; + + grant += user; + + return grant; + } + +} + + +QString PgAcl::sql(const QString &all_pattern, const QString &grant_on_object, const QString &column) const +{ + QString acl, acl_with_grant; + // Doorloop acl en scheid de rechten met GRANT optie van die zonder + for (auto c : all_pattern) { + switch(privilege(c.toLatin1())) { + case PrivValue::No: + break; + case PrivValue::Yes: + acl += c; + break; + case PrivValue::YesWithGrant: + acl_with_grant += c; + break; + } + } + + QString sql; + // Call when acl is not empty or both are empty + // needs to be calledwhen both are empty to generate REVOKE + if (!acl.isEmpty() || acl_with_grant.isEmpty()) { + sql += privilegeGrant(all_pattern, acl, grant_on_object, m_grantee, column) + + ";\n"; + } + if (!acl_with_grant.isEmpty()) { + sql += privilegeGrant(all_pattern, acl_with_grant, grant_on_object, m_grantee, column) + + " WITH GRANT OPTION;\n"; + } + return sql; +} + +bool PgAcl::empty() const +{ + return m_privileges.isEmpty(); +} diff --git a/pglablib/catalog/PgAcl.h b/pglablib/catalog/PgAcl.h new file mode 100644 index 0000000..da81112 --- /dev/null +++ b/pglablib/catalog/PgAcl.h @@ -0,0 +1,61 @@ +#ifndef PGACL_H +#define PGACL_H + +#include "Pgsql_Value.h" +#include +#include + +enum class Privilege { + Select, + Update, + Insert, + Delete, + Truncate, + References, + Trigger, + Execute, + Usage, + Create, + Connect, + Temporary +}; + +char privilegeToChar(Privilege p); + +enum class PrivValue { + No, Yes, YesWithGrant +}; + +class PgAcl { +public: + PgAcl() = default; + explicit PgAcl(const QString &acl); + void setFromString(const QString &acl); + + PrivValue privilege(Privilege priv) const; + PrivValue privilege(char c) const; + const QString& grantee() const { return m_grantee; } + const QString& grantor() const { return m_grantor; } + QString singleString() const; + + QString sql(const QString &all_pattern, const QString &grant_on_object, const QString &column) const; + // Returns true when the list of privileges is empty + bool empty() const; +private: + QString m_grantee; + QString m_grantor; + QString m_privileges; + +}; + +using AclList = std::vector; + +void operator<<(PgAcl &acl, const Pgsql::Value &v); + +namespace Pgsql { + template <> + PgAcl StringToArrayElem(std::string_view sv); +} + + +#endif // PGACL_H diff --git a/pglablib/catalog/PgClass.h b/pglablib/catalog/PgClass.h index 28d4680..b57a047 100644 --- a/pglablib/catalog/PgClass.h +++ b/pglablib/catalog/PgClass.h @@ -3,7 +3,6 @@ #include "Pgsql_Value.h" #include "PgNamespaceObject.h" -#include "PgOwnedObject.h" #include #include @@ -29,7 +28,7 @@ enum class RelKind { void operator<<(RelKind &s, const Pgsql::Value &v); -class PgClass: public PgNamespaceObject, public PgOwnedObject { +class PgClass: public PgNamespaceObject { public: // Oid oid = InvalidOid; diff --git a/pglablib/catalog/PgClassContainer.cpp b/pglablib/catalog/PgClassContainer.cpp index b0cc48b..d705b61 100644 --- a/pglablib/catalog/PgClassContainer.cpp +++ b/pglablib/catalog/PgClassContainer.cpp @@ -29,7 +29,7 @@ PgClass PgClassContainer::loadElem(const Pgsql::Row &row) >> v.tuples_est >> v.toastrelid >> v.isshared >> v.persistence >> v.kind >> v.hasoids >> v.ispopulated >> v.frozenxid >> v.minmxid >> v.acl >> v.options; - v.setOwnerOid(m_catalog, owner); + v.setOwnerOid(owner); // auto&& ns = m_catalog.namespaces()->getByKey(v.relnamespace); // if (ns) { // v.relnamespace_name = ns->objectName(); diff --git a/pglablib/catalog/PgCollation.h b/pglablib/catalog/PgCollation.h index 6e806a8..7ec0601 100644 --- a/pglablib/catalog/PgCollation.h +++ b/pglablib/catalog/PgCollation.h @@ -2,13 +2,12 @@ #define PGCOLLATION_H #include "PgNamespaceObject.h" -#include "PgOwnedObject.h" #include #include #include "Pgsql_Value.h" //#include -class PgCollation: public PgNamespaceObject, public PgOwnedObject { +class PgCollation: public PgNamespaceObject { public: using PgNamespaceObject::PgNamespaceObject; diff --git a/pglablib/catalog/PgCollationContainer.cpp b/pglablib/catalog/PgCollationContainer.cpp index d93ce67..5efeaf9 100644 --- a/pglablib/catalog/PgCollationContainer.cpp +++ b/pglablib/catalog/PgCollationContainer.cpp @@ -22,7 +22,7 @@ PgCollation PgCollationContainer::loadElem(const Pgsql::Row &row) Oid owner ; col >> owner >> v.collencoding >> v.collcollate >> v.collctype; - v.setOwnerOid(m_catalog, owner); + v.setOwnerOid(owner); return v; } diff --git a/pglablib/catalog/PgContainer.h b/pglablib/catalog/PgContainer.h index fb148a7..466127c 100644 --- a/pglablib/catalog/PgContainer.h +++ b/pglablib/catalog/PgContainer.h @@ -123,7 +123,7 @@ public: using t_Elem = std::shared_ptr; using t_Container = std::vector; ///< Do not assume it will stay a vector only expect bidirectional access - explicit PgSPtrContainer(std::weak_ptr cat) + explicit PgSPtrContainer(PgDatabaseCatalog& cat) : IPgContainer(cat) {} @@ -145,7 +145,7 @@ public: int count() const { - return (int)m_container.size(); + return static_cast(m_container.size()); } const t_Elem getByKey(const K &key) const diff --git a/pglablib/catalog/PgLanguage.h b/pglablib/catalog/PgLanguage.h index 1360a6d..db8d53c 100644 --- a/pglablib/catalog/PgLanguage.h +++ b/pglablib/catalog/PgLanguage.h @@ -2,12 +2,11 @@ #define PGLANGUAGE_H #include "PgDatabaseObject.h" -#include "PgOwnedObject.h" #include #include //#include "Pgsql_Value.h" -class PgLanguage: public PgDatabaseObject, public PgOwnedObject { +class PgLanguage: public PgDatabaseObject { public: // Oid oid; diff --git a/pglablib/catalog/PgLanguageContainer.cpp b/pglablib/catalog/PgLanguageContainer.cpp index bb6aa0c..bb4dfbd 100644 --- a/pglablib/catalog/PgLanguageContainer.cpp +++ b/pglablib/catalog/PgLanguageContainer.cpp @@ -17,6 +17,6 @@ PgLanguage PgLanguageContainer::loadElem(const Pgsql::Row &row) Oid owner = col.nextValue(); PgLanguage v(m_catalog, lan_oid, name); col >> v.ispl >> v.pltrusted >> v.plcallfoid >> v.inline_ >> v.validator >> v.acl; - v.setOwnerOid(m_catalog, owner); + v.setOwnerOid(owner); return v; } diff --git a/pglablib/catalog/PgNamespaceObject.h b/pglablib/catalog/PgNamespaceObject.h index af156d5..ae2c4cd 100644 --- a/pglablib/catalog/PgNamespaceObject.h +++ b/pglablib/catalog/PgNamespaceObject.h @@ -18,7 +18,7 @@ public: QString nsName() const; QString quotedNsName() const; /// Returns the schema name and object name with proper quotes - QString fullyQualifiedQuotedObjectName() const; + QString fullyQualifiedQuotedObjectName() const override; const PgNamespace& ns() const; private: diff --git a/pglablib/catalog/PgObject.cpp b/pglablib/catalog/PgObject.cpp index 4c6dab4..04b384c 100644 --- a/pglablib/catalog/PgObject.cpp +++ b/pglablib/catalog/PgObject.cpp @@ -25,6 +25,11 @@ QString PgObject::quotedObjectName() const return quoteIdent(objectName()); } +QString PgObject::fullyQualifiedQuotedObjectName() const +{ + return quotedObjectName(); +} + const PgDatabaseCatalog& PgObject::catalog() const { return *m_catalog; diff --git a/pglablib/catalog/PgObject.h b/pglablib/catalog/PgObject.h index e30635c..57080ff 100644 --- a/pglablib/catalog/PgObject.h +++ b/pglablib/catalog/PgObject.h @@ -15,6 +15,9 @@ public: const QString& objectName() const; /// Default implementation uses objectName and add quotes when needed. virtual QString quotedObjectName() const; + /// By default same as quotedObjectName however for objects that reside in namespaces + /// the namespace name is added to the name. + virtual QString fullyQualifiedQuotedObjectName() const; virtual QString typeName() const = 0; bool operator==(Oid _oid) const { return m_oid == _oid; } diff --git a/pglablib/catalog/PgOwnedObject.cpp b/pglablib/catalog/PgOwnedObject.cpp deleted file mode 100644 index 7a28980..0000000 --- a/pglablib/catalog/PgOwnedObject.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "PgOwnedObject.h" -#include "PgAuthId.h" -#include "PgAuthIdContainer.h" -#include "PgDatabaseCatalog.h" -#include "SqlFormattingUtils.h" - -void PgOwnedObject::setOwnerOid(PgDatabaseCatalog& cat, Oid oid) -{ - m_ownerOid = oid; - m_owner = cat.authIds()->getByKey(oid); -} - -Oid PgOwnedObject::ownerOid() const -{ - return m_ownerOid; -} - -QString PgOwnedObject::ownerName() const -{ - return m_owner->name; -} - -const PgAuthId* PgOwnedObject::owner() const -{ - return m_owner; -} - - -QString PgOwnedObject::alterOwnerSql(const QString& ident) const -{ - return QString("\nALTER %1 OWNER TO %2;").arg(ident, quoteIdent(ownerName())); -} diff --git a/pglablib/catalog/PgOwnedObject.h b/pglablib/catalog/PgOwnedObject.h deleted file mode 100644 index 62761dc..0000000 --- a/pglablib/catalog/PgOwnedObject.h +++ /dev/null @@ -1,24 +0,0 @@ -#ifndef PGOWNEDOBJECT_H -#define PGOWNEDOBJECT_H - -#include -#include -#include - -class PgDatabaseCatalog; -class PgAuthId; -class PgOwnedObject { -public: - void setOwnerOid(PgDatabaseCatalog& cat, Oid oid); - - Oid ownerOid() const; - QString ownerName() const; - const PgAuthId* owner() const; - - QString alterOwnerSql(const QString& ident) const; -private: - Oid m_ownerOid = InvalidOid; - const PgAuthId * m_owner; -}; - -#endif // PGOWNEDOBJECT_H diff --git a/pglablib/catalog/PgProc.cpp b/pglablib/catalog/PgProc.cpp index bf67e10..bf161aa 100644 --- a/pglablib/catalog/PgProc.cpp +++ b/pglablib/catalog/PgProc.cpp @@ -344,6 +344,7 @@ const QString& PgProc::createSql() const // + GetGrant(wxT("X"), wxT("FUNCTION ") + qtSig); sql += alterOwnerSql("FUNCTION " + quoted_sig); + sql += grantSql(); // if (!GetComment().IsNull()) // { @@ -384,3 +385,9 @@ QString PgProc::typeName() const } throw std::runtime_error("Unexpected kind in PgProc::typeName()"); } + +QString PgProc::aclAllPattern() const +{ + // X = execute + return "X"; +} diff --git a/pglablib/catalog/PgProc.h b/pglablib/catalog/PgProc.h index 5d3a9da..8123e4f 100644 --- a/pglablib/catalog/PgProc.h +++ b/pglablib/catalog/PgProc.h @@ -2,7 +2,6 @@ #define PGPROC_H #include "PgNamespaceObject.h" -#include "PgOwnedObject.h" #include #include #include "Pgsql_Value.h" @@ -52,7 +51,7 @@ void operator<<(ParallelMode &s, const Pgsql::Value &v); QString parallelModeToSql(ParallelMode pm, bool explicit_unsafe = false); -class PgProc: public PgNamespaceObject, public PgOwnedObject { +class PgProc: public PgNamespaceObject { public: using PgNamespaceObject::PgNamespaceObject; @@ -98,6 +97,7 @@ public: bool isWindow() const { return kind == ProcKind::Window; } QString typeName() const override; + QString aclAllPattern() const override; // bool isTrigger() const // { // return typname == wxT("\"trigger\"") || typname == wxT("trigger") || typname == wxT("event_trigger") || typname == wxT("\"event_trigger\"")) diff --git a/pglablib/catalog/PgProcContainer.cpp b/pglablib/catalog/PgProcContainer.cpp index e328774..5f3531e 100644 --- a/pglablib/catalog/PgProcContainer.cpp +++ b/pglablib/catalog/PgProcContainer.cpp @@ -36,7 +36,7 @@ PgProc PgProcContainer::loadElem(const Pgsql::Row &row) //ProcKind PgProc v(m_catalog, oid, name, namespace_oid); - v.setOwnerOid(m_catalog, owner_oid); + v.setOwnerOid(owner_oid); col >> v.lang >> v.cost >> v.rows >> v.variadic >> v.transform >> v.secdef >> v.leakproof >> v.isstrict >> v.retset >> v.provolatile >> v.nargs >> v.nargdefaults diff --git a/pglablib/catalog/PgServerObject.cpp b/pglablib/catalog/PgServerObject.cpp index daa159c..0691dc6 100644 --- a/pglablib/catalog/PgServerObject.cpp +++ b/pglablib/catalog/PgServerObject.cpp @@ -1,110 +1,40 @@ #include "PgServerObject.h" #include "ArrayParser.h" +#include "PgAuthIdContainer.h" +#include "PgDatabaseCatalog.h" +#include "SqlFormattingUtils.h" #include -namespace { - QString privilegeLetterToKeyword(char c) - { - switch (c) { - case 'r': return "SELECT"; - case 'w': return "UPDATE"; - case 'a': return "INSERT"; - case 'd': return "DELETE"; - case 'D': return "TRUNCATE"; - case 'x': return "REFERENCES"; - case 't': return "TRIGGER"; - case 'X': return "EXECUTE"; - case 'U': return "USAGE"; - case 'C': return "CREATE"; - case 'c': return "CONNECT"; - case 'T': return "TEMPORARY"; - } - throw std::runtime_error("Unexpected value for c in privilegeLetterToKeyword"); - } - -} - -char privilegeToChar(Privilege p) +void PgServerObject::setOwnerOid(Oid oid) { - switch (p) { - case Privilege::Select: return 'r'; - case Privilege::Update: return 'w'; - case Privilege::Insert: return 'a'; - case Privilege::Delete: return 'd'; - case Privilege::Truncate: return 'D'; - case Privilege::References: return 'x'; - case Privilege::Trigger: return 't'; - case Privilege::Execute: return 'X'; - case Privilege::Usage: return 'U'; - case Privilege::Create: return 'C'; - case Privilege::Connect: return 'c'; - case Privilege::Temporary: return 'T'; - } - throw std::runtime_error("Unexpected value for privilege in privilegeToChar"); + m_ownerOid = oid; + m_owner = catalog().authIds()->getByKey(oid); } -PgAcl::PgAcl(const QString &acl) +Oid PgServerObject::ownerOid() const { - setFromString(acl); + return m_ownerOid; } -void PgAcl::setFromString(const QString &acl) +QString PgServerObject::ownerName() const { - m_grantee = acl.section('=', 0, 0); - auto t = acl.section('=', 1); - m_privileges = t.section('/', 0, 0); - m_grantor = t.section('/', 1); + return m_owner->name; } -PrivValue PgAcl::privilege(Privilege priv) const +const PgAuthId* PgServerObject::owner() const { - char c = privilegeToChar(priv); - return privilege(c); + return m_owner; } -PrivValue PgAcl::privilege(char c) const + +QString PgServerObject::alterOwnerSql(const QString& ident) const { - int pos = m_privileges.indexOf(c); - if (pos >= 0) { - if ( (pos+1) < m_privileges.length() && m_privileges[pos+1] == '*') - return PrivValue::YesWithGrant; - return PrivValue::Yes; - } - return PrivValue::No; -} - -QString PgAcl::singleString() const -{ - return m_grantee % "=" % m_privileges % "/" % m_grantor; -} - -//void operator<<(AclList &s, const Pgsql::Value &v) -void operator<<(PgAcl &acl, const Pgsql::Value &v) -{ - acl.setFromString(v); -// const char *c = v.c_str(); -// Pgsql::ArrayParser parser(c); - -// while (true) { -// auto elem = parser.GetNextElem(); -// if (!elem.ok) -// break; -// auto&& v = elem.value.value_or(""); -// s.emplace_back(QString(v.data())); -// } -} - -namespace Pgsql { - template <> - PgAcl StringToArrayElem(std::string_view sv) - { - return PgAcl(QString::fromUtf8(sv.data(), static_cast(sv.length()))); - } + return QString("\nALTER %1 OWNER TO %2;").arg(ident, quoteIdent(ownerName())); } -void PgServerObject::setAcls(AclList acls) +void PgServerObject::setAcls(boost::optional acls) { m_acls = std::move(acls); } @@ -112,100 +42,46 @@ void PgServerObject::setAcls(AclList acls) QString PgServerObject::aclString() const { QString result; - for (auto&& acl : m_acls) { - if (result.isEmpty()) result += "{"; - else result += ","; - result += acl.singleString(); + if (m_acls) { + for (auto&& acl : *m_acls) { + if (result.isEmpty()) result += "{"; + else result += ","; + result += acl.singleString(); + } + if (!result.isEmpty()) + result += "}"; } - if (!result.isEmpty()) - result += "}"; return result; } -QString PgServerObject::grantSql(const QString &all_pattern, const QString &grantee, const QString &column) const +QString PgServerObject::grantSql() const { + // object_type_and_name => TABLE X + // GRANT ??? ON object_type_and_name TO ... + + const QString column; ///< \todo should be set when called on a column object + + QString all_pattern = aclAllPattern(); + if (all_pattern.isEmpty()) + return {}; + QString grant; -// wxString grant, str, user, grantFor, tmpUser; - -// if (_grantFor.IsNull()) -// { -// grantFor = GetTypeName(); -// grantFor.MakeUpper(); -// grantFor += wxT(" ") + GetQuotedFullIdentifier(); -// } -// else -// grantFor = _grantFor; - -// if (!acl.IsNull()) -// { -// if (acl == wxT("{}")) -// { -// grant += GetPrivileges(allPattern, str, grantFor, wxT("public"), qtIdent(_column)); -// grant += GetPrivileges(allPattern, str, grantFor, qtIdent(owner), qtIdent(_column)); -// } -// else -// { -// // checks if certain privilege is granted to public -// bool grantedToPublic = false; -// // checks if certain privilege is granted to owner -// bool grantedToOwner = false; - -// queryTokenizer acls(acl.Mid(1, acl.Length() - 2), ','); -// while (acls.HasMoreTokens()) -// { -// str = acls.GetNextToken(); - -// if (str.Left(1) == '"') -// str = str.Mid(1, str.Length() - 2); -// user = str.BeforeFirst('='); -// str = str.AfterFirst('=').BeforeFirst('/'); -// if (user == wxT("")) -// { -// user = wxT("public"); -// grantedToPublic = true; -// } -// else -// { -// if (user.Left(6) == wxT("group ")) -// { -// tmpUser = user.Mid(6); -// if (user.Mid(6).StartsWith(wxT("\\\"")) && user.Mid(6).EndsWith(wxT("\\\""))) -// user = wxT("GROUP ") + qtIdent(user.Mid(8, user.Length() - 10)); -// else -// user = wxT("GROUP ") + qtIdent(user.Mid(6)); -// } -// else -// { -// tmpUser = user; -// if (user.StartsWith(wxT("\\\"")) && user.EndsWith(wxT("\\\""))) -// user = qtIdent(user.Mid(2, user.Length() - 4)); -// else -// user = qtIdent(user); -// } - -// if (tmpUser.Contains(owner)) -// grantedToOwner = true; -// } - -// grant += GetPrivileges(allPattern, str, grantFor, user, qtIdent(_column)); -// } - -// str = wxEmptyString; -// int metaType = GetMetaType(); - -// // We check here that whether the user has revoked prvileges granted to databases, functions -// // and languages. If so then this must be part of reverse engineered sql statement -// if (!grantedToPublic && (metaType == PGM_LANGUAGE || metaType == PGM_FUNCTION || metaType == PGM_DATABASE)) -// grant += GetPrivileges(allPattern, str, grantFor, wxT("public"), qtIdent(_column)); -// // We check here that whether the owner has revoked prvileges on himself to this postgres -// // object. If so then this must be part of reverse engineered sql statement -// if (!grantedToOwner) -// grant += GetPrivileges(allPattern, str, grantFor, qtIdent(owner), qtIdent(_column)); -// } -// } + auto grant_on_object = QString("%1 %2").arg(typeName(), fullyQualifiedQuotedObjectName()); + if (m_acls) { + for (auto&& acl : *m_acls) { + grant += acl.sql(all_pattern, grant_on_object, column); + } + } + else { + // PUBLIC, no priviliges + grant += PgAcl("=").sql(all_pattern, grant_on_object, column); + // owner no privileges + grant += PgAcl(ownerName() + "=").sql(all_pattern, grant_on_object, column); + } return grant; } - - - +QString PgServerObject::aclAllPattern() const +{ + return {}; +} diff --git a/pglablib/catalog/PgServerObject.h b/pglablib/catalog/PgServerObject.h index 3bc23f8..654a722 100644 --- a/pglablib/catalog/PgServerObject.h +++ b/pglablib/catalog/PgServerObject.h @@ -3,56 +3,10 @@ #include #include "PgObject.h" -#include "Pgsql_Value.h" -#include +#include "PgAcl.h" +#include - -enum class Privilege { - Select, - Update, - Insert, - Delete, - Truncate, - References, - Trigger, - Execute, - Usage, - Create, - Connect, - Temporary -}; - -char privilegeToChar(Privilege p); - -enum class PrivValue { - No, Yes, YesWithGrant -}; - -class PgAcl { -public: - PgAcl() = default; - explicit PgAcl(const QString &acl); - void setFromString(const QString &acl); - - PrivValue privilege(Privilege priv) const; - PrivValue privilege(char c) const; - const QString& grantee() const { return m_grantee; } - const QString& grantor() const { return m_grantor; } - QString singleString() const; -private: - QString m_grantee; - QString m_grantor; - QString m_privileges; -}; - -using AclList = std::vector; - -void operator<<(PgAcl &acl, const Pgsql::Value &v); - -namespace Pgsql { - template <> - PgAcl StringToArrayElem(std::string_view sv); -} +class PgAuthId; /// Base object for objects that belong to a server class PgServerObject: public PgObject { @@ -60,26 +14,36 @@ public: using PgObject::PgObject; + void setOwnerOid(Oid oid); + Oid ownerOid() const; + QString ownerName() const; + const PgAuthId* owner() const; + QString alterOwnerSql(const QString& ident) const; /** - * @brief setAcls Takes the acl array as stored by postgres as a single string - * and decodes it directly into an AclList. - * @param acls - * + * @brief setAcls + * @param acls Important: pass empty optional when acl IS NULL, pass empty list for empty array */ - void setAcls(AclList acls); + void setAcls(boost::optional acls); QString aclString() const; /** * @brief grantSql - * @param all_pattern Used to recognize when a GRANT ALL can be generated but also to not consider irrelevant letters. - * @param grantee - * @param column * @return */ - QString grantSql(const QString &all_pattern, const QString &grantee, const QString &column) const; + QString grantSql() const; + /** + * @brief Returns a string containing all the possible privileges for this type of object. + * + * The default implementation returns an empty string. + * + * @return A string containing all posible privileges for this type of object. + */ + virtual QString aclAllPattern() const; private: - AclList m_acls; + Oid m_ownerOid = InvalidOid; + const PgAuthId * m_owner; + boost::optional m_acls; }; #endif // PGSERVEROBJECT_H diff --git a/pglablib/catalog/PgType.h b/pglablib/catalog/PgType.h index c64a762..ae125d5 100644 --- a/pglablib/catalog/PgType.h +++ b/pglablib/catalog/PgType.h @@ -2,7 +2,6 @@ #define PGTYPE_H #include "PgNamespaceObject.h" -#include "PgOwnedObject.h" #include #include #include "Pgsql_Value.h" @@ -28,7 +27,7 @@ enum class TypCategory { void operator<<(TypCategory &s, const Pgsql::Value &v); -class PgType: public PgNamespaceObject, public PgOwnedObject { +class PgType: public PgNamespaceObject { public: // Oid oid = InvalidOid; // QString name; // formatted name as per database, arrays diff --git a/pglablib/catalog/PgTypeContainer.cpp b/pglablib/catalog/PgTypeContainer.cpp index 68a52f8..025c4ee 100644 --- a/pglablib/catalog/PgTypeContainer.cpp +++ b/pglablib/catalog/PgTypeContainer.cpp @@ -26,6 +26,6 @@ PgType PgTypeContainer::loadElem(const Pgsql::Row &row) >> v.ispreferred >> v.isdefined >> v.delim >> v.relid >> v.elem >> v.array >> v.input >> v.output >> v.receive >> v.send >> v.modin >> v.modout >> v.analyze >> v.align >> v.storage >> v.notnull >> v.basetype >> v.typmod >> v.ndims >> v.collation >> v.defaultbin >> v.typdefault >> v.acl; - v.setOwnerOid(m_catalog, owner); + v.setOwnerOid(owner); return v; } diff --git a/pglablib/pglablib.pro b/pglablib/pglablib.pro index 1b13b78..c87d6a8 100644 --- a/pglablib/pglablib.pro +++ b/pglablib/pglablib.pro @@ -68,7 +68,6 @@ SOURCES += \ catalog/PgProcContainer.cpp \ catalog/PgDatabaseObject.cpp \ catalog/PgServerObject.cpp \ - catalog/PgOwnedObject.cpp \ catalog/PgNamespaceObject.cpp \ catalog/PgCollation.cpp \ catalog/PgCollationContainer.cpp \ @@ -82,7 +81,8 @@ SOURCES += \ model/CollationModel.cpp \ model/CollationModelFactory.cpp \ catalog/PgLanguageContainer.cpp \ - catalog/PgLanguage.cpp + catalog/PgLanguage.cpp \ + catalog/PgAcl.cpp HEADERS += \ Pglablib.h \ @@ -133,7 +133,6 @@ HEADERS += \ catalog/PgProcContainer.h \ catalog/PgDatabaseObject.h \ catalog/PgServerObject.h \ - catalog/PgOwnedObject.h \ catalog/PgNamespaceObject.h \ catalog/PgCollation.h \ catalog/PgCollationContainer.h \ @@ -149,7 +148,8 @@ HEADERS += \ model/CollationModel.h \ model/CollationModelFactory.h \ catalog/PgLanguageContainer.h \ - catalog/PgLanguage.h + catalog/PgLanguage.h \ + catalog/PgAcl.h unix { target.path = /usr/lib