All,
Attached is a patch with minor updates/corrections.
-Adam
--
Adam Brightwell - [email protected]
Database Engineer - www.crunchydatasolutions.com
diff --git a/src/backend/catalog/Makefile b/src/backend/catalog/Makefile
new file mode 100644
index b257b02..8cdc5cb
*** a/src/backend/catalog/Makefile
--- b/src/backend/catalog/Makefile
*************** POSTGRES_BKI_SRCS = $(addprefix $(top_sr
*** 41,47 ****
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h pg_rowsecurity.h \
pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \
! toasting.h indexing.h \
)
# location of Catalog.pm
--- 41,47 ----
pg_foreign_data_wrapper.h pg_foreign_server.h pg_user_mapping.h \
pg_foreign_table.h pg_rowsecurity.h \
pg_default_acl.h pg_seclabel.h pg_shseclabel.h pg_collation.h pg_range.h \
! pg_diralias.h toasting.h indexing.h \
)
# location of Catalog.pm
diff --git a/src/backend/catalog/aclchk.c b/src/backend/catalog/aclchk.c
new file mode 100644
index d30612c..3717bf5
*** a/src/backend/catalog/aclchk.c
--- b/src/backend/catalog/aclchk.c
***************
*** 30,35 ****
--- 30,36 ----
#include "catalog/pg_collation.h"
#include "catalog/pg_conversion.h"
#include "catalog/pg_database.h"
+ #include "catalog/pg_diralias.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
***************
*** 48,53 ****
--- 49,55 ----
#include "catalog/pg_ts_config.h"
#include "catalog/pg_ts_dict.h"
#include "commands/dbcommands.h"
+ #include "commands/diralias.h"
#include "commands/proclang.h"
#include "commands/tablespace.h"
#include "foreign/foreign.h"
*************** ExecGrant_Type(InternalGrant *istmt)
*** 3183,3188 ****
--- 3185,3374 ----
heap_close(relation, RowExclusiveLock);
}
+ /*
+ * ExecuteGrantDirAliasStmt
+ * handles the execution of the GRANT/REVOKE ON DIRALIAS command.
+ *
+ * stmt - the GrantDirAliasStmt that describes the directory aliases and
+ * permissions to be granted/revoked.
+ */
+ void
+ ExecuteGrantDirAliasStmt(GrantDirAliasStmt *stmt)
+ {
+ Relation pg_diralias_rel;
+ Oid grantor;
+ List *grantee_ids = NIL;
+ AclMode permissions;
+ ListCell *item;
+
+ /* Must be superuser to grant directory alias permissions */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to grant directory alias permissions")));
+
+ /*
+ * Grantor is optional. If it is not provided then set it to the current
+ * user.
+ */
+ if (stmt->grantor)
+ grantor = get_role_oid(stmt->grantor, false);
+ else
+ grantor = GetUserId();
+
+ /* Convert grantee names to oids */
+ foreach(item, stmt->grantees)
+ {
+ PrivGrantee *grantee = (PrivGrantee *) lfirst(item);
+
+ if (grantee->rolname == NULL)
+ grantee_ids = lappend_oid(grantee_ids, ACL_ID_PUBLIC);
+ else
+ {
+ Oid roleid = get_role_oid(grantee->rolname, false);
+ grantee_ids = lappend_oid(grantee_ids, roleid);
+ }
+ }
+
+ permissions = ACL_NO_RIGHTS;
+
+ /* If ALL was provided then set permissions to ACL_ALL_RIGHTS_DIRALIAS */
+ if (stmt->permissions == NIL)
+ permissions = ACL_ALL_RIGHTS_DIRALIAS;
+ else
+ {
+ /* Condense all permissions */
+ foreach(item, stmt->permissions)
+ {
+ AccessPriv *priv = (AccessPriv *) lfirst(item);
+ permissions |= string_to_privilege(priv->priv_name);
+ }
+ }
+
+
+ /*
+ * Though it shouldn't be possible to provide permissions other than READ
+ * and WRITE, check to make sure no others have been set. If they have,
+ * then warn the user and correct the permissions.
+ */
+ if (permissions & !((AclMode) ACL_ALL_RIGHTS_DIRALIAS))
+ {
+ ereport(WARNING,
+ (errcode(ERRCODE_INVALID_GRANT_OPERATION),
+ errmsg("directory aliases only support READ and WRITE permissions")));
+
+ permissions &= ACL_ALL_RIGHTS_DIRALIAS;
+ }
+
+ pg_diralias_rel = heap_open(DirAliasRelationId, RowExclusiveLock);
+
+ /* Grant/Revoke permissions on directory aliases */
+ foreach(item, stmt->directories)
+ {
+ Datum values[Natts_pg_diralias];
+ bool replaces[Natts_pg_diralias];
+ bool nulls[Natts_pg_diralias];
+ ScanKeyData skey[1];
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+ HeapTuple new_tuple;
+ Datum datum;
+ Oid owner_id;
+ Acl *dir_acl;
+ Acl *new_acl;
+ bool is_null;
+ int num_old_members;
+ int num_new_members;
+ Oid *old_members;
+ Oid *new_members;
+ Oid diralias_id;
+ char *name;
+
+ name = strVal(lfirst(item));
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_diralias_dirname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ CStringGetDatum(name));
+
+ scandesc = heap_beginscan_catalog(pg_diralias_rel, 1, skey);
+
+ tuple = heap_getnext(scandesc, ForwardScanDirection);
+
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for directory alias \"%s\"", name);
+
+ /*
+ * Get directory alias owner id. Since all superusers are considered
+ * to be owners of a directory alias, it is safe to assume that the
+ * current user is an owner, given the superuser check above.
+ */
+ owner_id = GetUserId();
+
+ /* Get directory alias ACL */
+ datum = heap_getattr(tuple, Anum_pg_diralias_diracl,
+ RelationGetDescr(pg_diralias_rel), &is_null);
+
+ /* Get the directory alias oid */
+ diralias_id = HeapTupleGetOid(tuple);
+
+ /*
+ * If there are currently no permissions granted on the directory alias,
+ * then add default permissions, which should include the permssions
+ * granted to the owner of the table. Directory aliases are owned by
+ * all superusers.
+ */
+ if (is_null)
+ {
+ dir_acl = acldefault(ACL_OBJECT_DIRALIAS, owner_id);
+ num_old_members = 0;
+ old_members = NULL;
+ }
+ else
+ {
+ dir_acl = DatumGetAclPCopy(datum);
+
+ /* Get the roles in the current ACL */
+ num_old_members = aclmembers(dir_acl, &old_members);
+ }
+
+ /* Merge new ACL with current ACL */
+ new_acl = merge_acl_with_grant(dir_acl, stmt->is_grant, false,
+ DROP_CASCADE, grantee_ids, permissions,
+ grantor, owner_id);
+
+ num_new_members = aclmembers(new_acl, &new_members);
+
+ /* Insert new ACL value */
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
+ memset(replaces, 0, sizeof(replaces));
+
+ values[Anum_pg_diralias_diracl - 1] = PointerGetDatum(new_acl);
+ replaces[Anum_pg_diralias_diracl - 1] = true;
+
+ new_tuple = heap_modify_tuple(tuple, RelationGetDescr(pg_diralias_rel),
+ values, nulls, replaces);
+
+ simple_heap_update(pg_diralias_rel, &new_tuple->t_self, new_tuple);
+
+ /* Update Indexes */
+ CatalogUpdateIndexes(pg_diralias_rel, new_tuple);
+
+ /* Update shared dependency ACL information */
+ updateAclDependencies(DirAliasRelationId, diralias_id, 0,
+ owner_id,
+ num_old_members, old_members,
+ num_new_members, new_members);
+
+ /* Clean Up */
+ pfree(new_acl);
+ heap_endscan(scandesc);
+ }
+
+ heap_close(pg_diralias_rel, RowExclusiveLock);
+ }
+
static AclMode
string_to_privilege(const char *privname)
*************** static const char *const no_priv_msg[MAX
*** 3307,3312 ****
--- 3493,3500 ----
gettext_noop("permission denied for event trigger %s"),
/* ACL_KIND_EXTENSION */
gettext_noop("permission denied for extension %s"),
+ /* ACL_KIND_DIRALIAS */
+ gettext_noop("permission denied for directory alias %s"),
};
static const char *const not_owner_msg[MAX_ACL_KIND] =
*************** static const char *const not_owner_msg[M
*** 3353,3358 ****
--- 3541,3548 ----
gettext_noop("must be owner of event trigger %s"),
/* ACL_KIND_EXTENSION */
gettext_noop("must be owner of extension %s"),
+ /* ACL_KIND_DIRALIAS */
+ gettext_noop("must be owner of directory alias %s"),
};
*************** pg_foreign_server_aclmask(Oid srv_oid, O
*** 4194,4199 ****
--- 4384,4445 ----
}
/*
+ * Exported routine for examining a user's permissions for a directory alias.
+ */
+ AclMode
+ pg_diralias_aclmask(Oid dir_oid, Oid roleid, AclMode mask, AclMaskHow how)
+ {
+ AclMode result;
+ HeapTuple tuple;
+ Datum aclDatum;
+ bool isNull;
+ Acl *acl;
+
+ /* Bypass permission checks for superusers */
+ if (superuser_arg(roleid))
+ return mask;
+
+ /* Must get the directory alias's tuple from pg_diralias */
+ tuple = SearchSysCache1(DIRALIASOID, ObjectIdGetDatum(dir_oid));
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("directory alias with OID %u does not exist", dir_oid)));
+
+ aclDatum = SysCacheGetAttr(DIRALIASOID, tuple,
+ Anum_pg_diralias_diracl, &isNull);
+ if (isNull)
+ {
+ /* No ACL, so build default ACL */
+ acl = acldefault(ACL_OBJECT_DIRALIAS, roleid);
+ aclDatum = (Datum) 0;
+ }
+ else
+ {
+ /* detoast rel's ACL if necessary */
+ acl = DatumGetAclP(aclDatum);
+ }
+
+ /*
+ * We use InvalidOid as the ownerid for determining the aclmask. This is
+ * because directory aliases belong to all superusers. aclmask() uses the
+ * ownerid to determine grant options by implying that owners always have
+ * all grant options. If roleid, is not a superuser and therefore an owner
+ * (which it couldn't be at this point), then this check in aclmask() must
+ * be false. Therefore, by using InvalidOid we are guaranteed this behavior.
+ */
+ result = aclmask(acl, roleid, InvalidOid, mask, how);
+
+ /* if we have a detoasted copy, free it */
+ if (acl && (Pointer) acl != DatumGetPointer(aclDatum))
+ pfree(acl);
+
+ ReleaseSysCache(tuple);
+
+ return result;
+ }
+
+ /*
* Exported routine for examining a user's privileges for a type.
*/
AclMode
*************** pg_type_aclcheck(Oid type_oid, Oid rolei
*** 4510,4515 ****
--- 4756,4773 ----
return ACLCHECK_OK;
else
return ACLCHECK_NO_PRIV;
+ }
+
+ /*
+ * Exported routine for checking a user's access permissions to a directory alias
+ */
+ AclResult
+ pg_diralias_aclcheck(Oid dir_oid, Oid roleid, AclMode mode)
+ {
+ if (pg_diralias_aclmask(dir_oid, roleid, mode, ACLMASK_ANY) != 0)
+ return ACLCHECK_OK;
+ else
+ return ACLCHECK_NO_PRIV;
}
/*
diff --git a/src/backend/catalog/dependency.c b/src/backend/catalog/dependency.c
new file mode 100644
index 256486c..b056559
*** a/src/backend/catalog/dependency.c
--- b/src/backend/catalog/dependency.c
***************
*** 33,38 ****
--- 33,39 ----
#include "catalog/pg_database.h"
#include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.h"
+ #include "catalog/pg_diralias.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_extension.h"
#include "catalog/pg_foreign_data_wrapper.h"
***************
*** 56,61 ****
--- 57,63 ----
#include "catalog/pg_user_mapping.h"
#include "commands/comment.h"
#include "commands/defrem.h"
+ #include "commands/diralias.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/policy.h"
*************** doDeletion(const ObjectAddress *object,
*** 1255,1260 ****
--- 1257,1266 ----
RemovePolicyById(object->objectId);
break;
+ case OCLASS_DIRALIAS:
+ RemoveDirAliasById(object->objectId);
+ break;
+
default:
elog(ERROR, "unrecognized object class: %u",
object->classId);
*************** getObjectClass(const ObjectAddress *obje
*** 2325,2330 ****
--- 2331,2339 ----
case RowSecurityRelationId:
return OCLASS_ROWSECURITY;
+
+ case DirAliasRelationId:
+ return OCLASS_DIRALIAS;
}
/* shouldn't get here */
diff --git a/src/backend/catalog/objectaddress.c b/src/backend/catalog/objectaddress.c
new file mode 100644
index b69b75b..872d233
*** a/src/backend/catalog/objectaddress.c
--- b/src/backend/catalog/objectaddress.c
***************
*** 26,31 ****
--- 26,32 ----
#include "catalog/pg_authid.h"
#include "catalog/pg_cast.h"
#include "catalog/pg_default_acl.h"
+ #include "catalog/pg_diralias.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_collation.h"
#include "catalog/pg_constraint.h"
***************
*** 54,59 ****
--- 55,61 ----
#include "catalog/pg_user_mapping.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
+ #include "commands/diralias.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/policy.h"
*************** static const ObjectPropertyType ObjectPr
*** 358,363 ****
--- 360,377 ----
false
},
{
+ DirAliasRelationId,
+ DirAliasOidIndexId,
+ DIRALIASOID,
+ -1,
+ Anum_pg_diralias_dirname,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
+ InvalidAttrNumber,
+ -1,
+ false
+ },
+ {
EventTriggerRelationId,
EventTriggerOidIndexId,
EVENTTRIGGEROID,
*************** get_object_address(ObjectType objtype, L
*** 536,541 ****
--- 550,556 ----
&relation, missing_ok);
break;
case OBJECT_DATABASE:
+ case OBJECT_DIRALIAS:
case OBJECT_EXTENSION:
case OBJECT_TABLESPACE:
case OBJECT_ROLE:
*************** get_object_address_unqualified(ObjectTyp
*** 746,751 ****
--- 761,769 ----
case OBJECT_DATABASE:
msg = gettext_noop("database name cannot be qualified");
break;
+ case OBJECT_DIRALIAS:
+ msg = gettext_noop("directory alias cannot be qualified");
+ break;
case OBJECT_EXTENSION:
msg = gettext_noop("extension name cannot be qualified");
break;
*************** get_object_address_unqualified(ObjectTyp
*** 790,795 ****
--- 808,818 ----
address.objectId = get_database_oid(name, missing_ok);
address.objectSubId = 0;
break;
+ case OBJECT_DIRALIAS:
+ address.classId = DirAliasRelationId;
+ address.objectId = get_diralias_oid(name, missing_ok);
+ address.objectSubId = 0;
+ break;
case OBJECT_EXTENSION:
address.classId = ExtensionRelationId;
address.objectId = get_extension_oid(name, missing_ok);
*************** check_object_ownership(Oid roleid, Objec
*** 1318,1323 ****
--- 1341,1347 ----
break;
case OBJECT_TSPARSER:
case OBJECT_TSTEMPLATE:
+ case OBJECT_DIRALIAS:
/* We treat these object types as being owned by superusers */
if (!superuser_arg(roleid))
ereport(ERROR,
*************** getObjectDescription(const ObjectAddress
*** 2224,2229 ****
--- 2248,2265 ----
break;
}
+ case OCLASS_DIRALIAS:
+ {
+ char *diralias_name;
+
+ diralias_name = get_diralias_name(object->objectId);
+ if (!diralias_name)
+ elog(ERROR, "cache lookup failed for directory alias %u",
+ object->objectId);
+ appendStringInfo(&buffer, _("directory alias %s"), diralias_name);
+ break;
+ }
+
default:
appendStringInfo(&buffer, "unrecognized object %u %u %d",
object->classId,
diff --git a/src/backend/commands/Makefile b/src/backend/commands/Makefile
new file mode 100644
index b1ac704..36a897c
*** a/src/backend/commands/Makefile
--- b/src/backend/commands/Makefile
*************** include $(top_builddir)/src/Makefile.glo
*** 14,20 ****
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
collationcmds.o constraint.o conversioncmds.o copy.o createas.o \
! dbcommands.o define.o discard.o dropcmds.o \
event_trigger.o explain.o extension.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o matview.o operatorcmds.o opclasscmds.o \
policy.o portalcmds.o prepare.o proclang.o \
--- 14,20 ----
OBJS = aggregatecmds.o alter.o analyze.o async.o cluster.o comment.o \
collationcmds.o constraint.o conversioncmds.o copy.o createas.o \
! dbcommands.o define.o diralias.o discard.o dropcmds.o \
event_trigger.o explain.o extension.o foreigncmds.o functioncmds.o \
indexcmds.o lockcmds.o matview.o operatorcmds.o opclasscmds.o \
policy.o portalcmds.o prepare.o proclang.o \
diff --git a/src/backend/commands/alter.c b/src/backend/commands/alter.c
new file mode 100644
index c9a9baf..47f8d49
*** a/src/backend/commands/alter.c
--- b/src/backend/commands/alter.c
***************
*** 41,46 ****
--- 41,47 ----
#include "commands/conversioncmds.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
+ #include "commands/diralias.h"
#include "commands/event_trigger.h"
#include "commands/extension.h"
#include "commands/policy.h"
*************** ExecRenameStmt(RenameStmt *stmt)
*** 349,354 ****
--- 350,356 ----
case OBJECT_AGGREGATE:
case OBJECT_COLLATION:
case OBJECT_CONVERSION:
+ case OBJECT_DIRALIAS:
case OBJECT_EVENT_TRIGGER:
case OBJECT_FDW:
case OBJECT_FOREIGN_SERVER:
diff --git a/src/backend/commands/copy.c b/src/backend/commands/copy.c
new file mode 100644
index 6b83576..3a9562b
*** a/src/backend/commands/copy.c
--- b/src/backend/commands/copy.c
***************
*** 28,33 ****
--- 28,34 ----
#include "catalog/pg_type.h"
#include "commands/copy.h"
#include "commands/defrem.h"
+ #include "commands/diralias.h"
#include "commands/trigger.h"
#include "executor/executor.h"
#include "libpq/libpq.h"
*************** DoCopy(const CopyStmt *stmt, const char
*** 788,796 ****
Oid relid;
Node *query = NULL;
- /* Disallow COPY to/from file or program except to superusers. */
if (!pipe && !superuser())
{
if (stmt->is_program)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
--- 789,801 ----
Oid relid;
Node *query = NULL;
if (!pipe && !superuser())
{
+ /*
+ * Disallow COPY to/from program except to superusers. If COPY is to/from
+ * a file then diallow unless the current user is either superuser or has
+ * been granted the appropriate permissions on the target parent directory.
+ */
if (stmt->is_program)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
*************** DoCopy(const CopyStmt *stmt, const char
*** 798,808 ****
errhint("Anyone can COPY to stdout or from stdin. "
"psql's \\copy command also works for anyone.")));
else
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser to COPY to or from a file"),
! errhint("Anyone can COPY to stdout or from stdin. "
! "psql's \\copy command also works for anyone.")));
}
if (stmt->relation)
--- 803,845 ----
errhint("Anyone can COPY to stdout or from stdin. "
"psql's \\copy command also works for anyone.")));
else
! {
! char *path;
! Oid diralias_id;
! AclResult aclresult;
!
! /* Get the parent directory */
! path = pstrdup(stmt->filename);
! canonicalize_path(path);
! get_parent_directory(path);
!
! /* Search for directory in pg_diralias */
! diralias_id = get_diralias_oid_by_path(path);
!
! /*
! * If an entry does not exist for the path in pg_diralias then raise
! * an error.
! */
! if (!OidIsValid(diralias_id))
! ereport(ERROR,
! (errcode(ERRCODE_UNDEFINED_OBJECT),
! errmsg("a directory alias entry for \"%s\" does not exist.",
! path)));
!
! /* Check directory alias entry permissions */
! if (stmt->is_from)
! aclresult = pg_diralias_aclcheck(diralias_id, GetUserId(), ACL_SELECT);
! else
! aclresult = pg_diralias_aclcheck(diralias_id, GetUserId(), ACL_UPDATE);
!
! /* If the current user has insufficient privileges then raise an error. */
! if (aclresult != ACLCHECK_OK)
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must have permissions to COPY to or from \"%s\"", path),
! errhint("Anyone can COPY to stdout or from stdin. "
! "psql's \\copy command also works for anyone.")));
! }
}
if (stmt->relation)
diff --git a/src/backend/commands/diralias.c b/src/backend/commands/diralias.c
new file mode 100644
index ...9ccd77e
*** a/src/backend/commands/diralias.c
--- b/src/backend/commands/diralias.c
***************
*** 0 ****
--- 1,375 ----
+ /*-------------------------------------------------------------------------
+ *
+ * diralias.c
+ * Commands for manipulating directory aliases.
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/backend/commands/diralias.c
+ *
+ *-------------------------------------------------------------------------
+ */
+ #include "postgres.h"
+
+ #include "access/htup_details.h"
+ #include "access/sysattr.h"
+ #include "catalog/dependency.h"
+ #include "catalog/indexing.h"
+ #include "catalog/objectaccess.h"
+ #include "catalog/pg_authid.h"
+ #include "catalog/pg_diralias.h"
+ #include "commands/diralias.h"
+ #include "commands/user.h"
+ #include "miscadmin.h"
+ #include "utils/acl.h"
+ #include "utils/builtins.h"
+ #include "utils/guc.h"
+ #include "utils/fmgroids.h"
+ #include "utils/rel.h"
+ #include "utils/syscache.h"
+
+ /*
+ * RemoveDirAliasById
+ * remove a directory alias by its OID. If a directory does not exist with
+ * the provided oid, then an error is raised.
+ *
+ * diralias_id - the oid of the directory alias.
+ */
+ void
+ RemoveDirAliasById(Oid diralias_id)
+ {
+ Relation pg_diralias_rel;
+ HeapTuple tuple;
+
+ pg_diralias_rel = heap_open(DirAliasRelationId, RowExclusiveLock);
+
+ /*
+ * Find the directory alias to delete.
+ */
+ tuple = SearchSysCache1(DIRALIASOID, ObjectIdGetDatum(diralias_id));
+
+ /* If the directory alias exists, then remove it, otherwise raise an error. */
+ if (!HeapTupleIsValid(tuple))
+ elog(ERROR, "could not find tuple for directory alias %u", diralias_id);
+
+ simple_heap_delete(pg_diralias_rel, &tuple->t_self);
+
+ ReleaseSysCache(tuple);
+ heap_close(pg_diralias_rel, RowExclusiveLock);
+ }
+
+ /*
+ * CreateDirAlias
+ * handles the execution of the CREATE DIRALIAS command.
+ *
+ * stmt - the CreateDirAliasStmt that describes the directory alias entry to
+ * create.
+ */
+ void
+ CreateDirAlias(CreateDirAliasStmt *stmt)
+ {
+ Relation pg_diralias_rel;
+ Datum values[Natts_pg_diralias];
+ bool nulls[Natts_pg_diralias];
+ ScanKeyData skey[1];
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+ Oid diralias_id;
+ char *path;
+
+ /* Must be superuser to create a directory alias entry. */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to create directory alias")));
+
+ /* Unix-ify the path, and strip any trailing slashes */
+ path = pstrdup(stmt->path);
+ canonicalize_path(path);
+
+ /* Disallow quotes */
+ if (strchr(path, '\''))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("directory path cannot contain single quotes")));
+
+ /*
+ * Allowing relative paths seems risky and really a bad idea. Therefore,
+ * if a relative path is provided then an error is raised.
+ *
+ * This also helps us ensure that directory path is not empty or whitespace.
+ */
+ if (!is_absolute_path(path))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
+ errmsg("directory path must be an absolute path")));
+
+ /* Open pg_diralias catalog */
+ pg_diralias_rel = heap_open(DirAliasRelationId, RowExclusiveLock);
+
+ /*
+ * Make sure a duplicate does not already exist. Need to check both the name
+ * and the path. If either exists, then raise an error.
+ */
+
+ /* Check alias name does not already exist */
+ ScanKeyInit(&skey[0],
+ Anum_pg_diralias_dirname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ CStringGetDatum(stmt->name));
+
+ /*
+ * We use a heapscan here even though there is an index on alias and path.
+ * We do this on the theory that pg_diralias will usually have a
+ * relatively small number of entries and therefore it is safe to assume
+ * an index scan would be wasted effort.
+ */
+ scandesc = heap_beginscan_catalog(pg_diralias_rel, 1, skey);
+
+ if (HeapTupleIsValid(heap_getnext(scandesc, ForwardScanDirection)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("directory alias \"%s\" already exists", stmt->name)));
+
+ heap_endscan(scandesc);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_diralias_dirpath,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ CStringGetTextDatum(path));
+
+ scandesc = heap_beginscan_catalog(pg_diralias_rel, 1, skey);
+
+ /* Check that path does not already exist. */
+ if (HeapTupleIsValid(heap_getnext(scandesc, ForwardScanDirection)))
+ ereport(ERROR,
+ (errcode(ERRCODE_DUPLICATE_OBJECT),
+ errmsg("directory alias with path \"%s\" already exists", path)));
+
+ heap_endscan(scandesc);
+
+ /*
+ * All is well and safe to insert.
+ */
+
+ /* zero-clear */
+ memset(values, 0, sizeof(values));
+ memset(nulls, 0, sizeof(nulls));
+
+ values[Anum_pg_diralias_dirname - 1] = CStringGetDatum(stmt->name);
+ values[Anum_pg_diralias_dirpath - 1] = CStringGetTextDatum(path);
+
+ /* No ACL items are set on the directory by default */
+ nulls[Anum_pg_diralias_diracl - 1] = true;
+
+ tuple = heap_form_tuple(RelationGetDescr(pg_diralias_rel), values, nulls);
+
+ diralias_id = simple_heap_insert(pg_diralias_rel, tuple);
+
+ /* Update Indexes */
+ CatalogUpdateIndexes(pg_diralias_rel, tuple);
+
+ /* Post creation hook for new directory alias */
+ InvokeObjectPostCreateHook(DirAliasRelationId, diralias_id, 0);
+
+ /* Clean up */
+ heap_close(pg_diralias_rel, RowExclusiveLock);
+ }
+
+ /*
+ * AlterDirAlias
+ * handles the execution of the ALTER DIRALIAS command.
+ *
+ * stmt - the AlterDirAliasStmt that describes the directory alias entry to alter.
+ */
+ void
+ AlterDirAlias(AlterDirAliasStmt *stmt)
+ {
+ Relation pg_diralias_rel;
+ ScanKeyData skey[1];
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+ Datum values[Natts_pg_diralias];
+ bool nulls[Natts_pg_diralias];
+ bool replaces[Natts_pg_diralias];
+ HeapTuple new_tuple;
+ char *path;
+
+ /* Must be superuser to alter directory alias */
+ if (!superuser())
+ ereport(ERROR,
+ (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
+ errmsg("must be superuser to alter directory alias")));
+
+ /* Unix-ify the new path, and strip any trailing slashes */
+ path = pstrdup(stmt->path);
+ canonicalize_path(path);
+
+ /* Disallow quotes */
+ if (strchr(path, '\''))
+ ereport(ERROR,
+ (errcode(ERRCODE_INVALID_NAME),
+ errmsg("directory path cannot contain single quotes")));
+
+ /* Open pg_diralias catalog */
+ pg_diralias_rel = heap_open(DirAliasRelationId, RowExclusiveLock);
+
+ /* Search for directory alias by name */
+ ScanKeyInit(&skey[0],
+ Anum_pg_diralias_dirname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ CStringGetDatum(stmt->name));
+
+ /*
+ * We use a heapscan here even though there is an index on alias and path.
+ * We do this on the theory that pg_diralias will usually have a
+ * relatively small number of entries and therefore it is safe to assume
+ * an index scan would be wasted effort.
+ */
+ scandesc = heap_beginscan_catalog(pg_diralias_rel, 1, skey);
+
+ tuple = heap_getnext(scandesc, ForwardScanDirection);
+
+ /* If directory alias does not exist then raise an error */
+ if (!HeapTupleIsValid(tuple))
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("directory alias \"%s\" does not exist", stmt->name)));
+
+ /* Build new tuple and update pg_diralias */
+ memset(nulls, 0, sizeof(nulls));
+ memset(replaces, 0, sizeof(replaces));
+ memset(values, 0, sizeof(values));
+
+ values[Anum_pg_diralias_dirpath - 1] = CStringGetTextDatum(path);
+ replaces[Anum_pg_diralias_dirpath - 1] = true;
+
+ new_tuple = heap_modify_tuple(tuple, RelationGetDescr(pg_diralias_rel),
+ values, nulls, replaces);
+
+ simple_heap_update(pg_diralias_rel, &new_tuple->t_self, new_tuple);
+
+ /* Update Indexes */
+ CatalogUpdateIndexes(pg_diralias_rel, new_tuple);
+
+ /* Post alter hook for directory alias */
+ InvokeObjectPostAlterHook(DirAliasRelationId, HeapTupleGetOid(tuple), 0);
+
+ /* Clean Up */
+ heap_freetuple(new_tuple);
+ heap_endscan(scandesc);
+ heap_close(pg_diralias_rel, RowExclusiveLock);
+ }
+
+ /*
+ * get_diralias_name
+ * given a directory alias OID, look up the name. If the directory does not
+ * exist then NULL is returned.
+ *
+ * diralias_id - the OID of the directory alias entry in pg_diralias.
+ */
+ char *
+ get_diralias_name(Oid diralias_id)
+ {
+ char *name = NULL;
+ HeapTuple tuple;
+
+ tuple = SearchSysCache1(DIRALIASOID, ObjectIdGetDatum(diralias_id));
+ if (HeapTupleIsValid(tuple))
+ {
+ name = pstrdup(NameStr(((Form_pg_diralias) GETSTRUCT(tuple))->dirname));
+ ReleaseSysCache(tuple);
+ }
+
+ return name;
+ }
+
+ /*
+ * get_directory_oid_by_path
+ * given a directory path, look up the OID. If the directory does not exist
+ * this InvalidOid is returned.
+ *
+ * path - the path of the directory
+ */
+ Oid
+ get_diralias_oid_by_path(const char *path)
+ {
+ Oid dir_id = InvalidOid;
+ Relation pg_diralias_rel;
+ HeapScanDesc scandesc;
+ HeapTuple tuple;
+ ScanKeyData skey[1];
+
+ /*
+ * Search pg_diralias. We use a heapscan here even though there is an index
+ * on alias. We do this on the theory that pg_diralias will usually have a
+ * relatively small number of entries and therefore it is safe to assume
+ * an index scan would be wasted effort.
+ */
+ pg_diralias_rel = heap_open(DirAliasRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_diralias_dirpath,
+ BTEqualStrategyNumber, F_TEXTEQ,
+ CStringGetTextDatum(path));
+
+ scandesc = heap_beginscan_catalog(pg_diralias_rel, 1, skey);
+ tuple = heap_getnext(scandesc, ForwardScanDirection);
+
+ if (HeapTupleIsValid(tuple))
+ dir_id = HeapTupleGetOid(tuple);
+
+ heap_endscan(scandesc);
+ heap_close(pg_diralias_rel, AccessShareLock);
+
+ return dir_id;
+ }
+
+ /*
+ * get_directory_oid
+ * given a directory alias name, look up the OID. If a directory alias does
+ * not exist for the given name then raise an error. However, if missing_ok
+ * is true, then return InvalidOid.
+ *
+ * name - the name of the directory alias
+ * missing_ok - false if an error should be raised if the directory alias does
+ * not exist.
+ */
+ Oid
+ get_diralias_oid(const char *name, bool missing_ok)
+ {
+ Oid dir_id;
+ Relation pg_diralias_rel;
+ ScanKeyData skey[1];
+ SysScanDesc sscan;
+ HeapTuple tuple;
+
+ /* Search pg_diralias for a directory alias entry with provided name */
+ pg_diralias_rel = heap_open(DirAliasRelationId, AccessShareLock);
+
+ ScanKeyInit(&skey[0],
+ Anum_pg_diralias_dirname,
+ BTEqualStrategyNumber, F_NAMEEQ,
+ CStringGetDatum(name));
+
+ sscan = systable_beginscan(pg_diralias_rel, DirAliasNameIndexId,
+ true, NULL, 1, skey);
+
+ tuple = systable_getnext(sscan);
+
+ if (HeapTupleIsValid(tuple))
+ dir_id = HeapTupleGetOid(tuple);
+ else
+ dir_id = InvalidOid;
+
+ systable_endscan(sscan);
+ heap_close(pg_diralias_rel, AccessShareLock);
+
+ if (!OidIsValid(dir_id) && !missing_ok)
+ ereport(ERROR,
+ (errcode(ERRCODE_UNDEFINED_OBJECT),
+ errmsg("directory alias \"%s\" does not exist", name)));
+
+ return dir_id;
+ }
diff --git a/src/backend/commands/dropcmds.c b/src/backend/commands/dropcmds.c
new file mode 100644
index 8583581..8cae12e
*** a/src/backend/commands/dropcmds.c
--- b/src/backend/commands/dropcmds.c
*************** does_not_exist_skipping(ObjectType objty
*** 380,385 ****
--- 380,389 ----
list_length(objname) - 1));
}
break;
+ case OBJECT_DIRALIAS:
+ msg = gettext_noop("directory alias \"%s\" does not exist, skipping");
+ name = NameListToString(objname);
+ break;
case OBJECT_EVENT_TRIGGER:
msg = gettext_noop("event trigger \"%s\" does not exist, skipping");
name = NameListToString(objname);
diff --git a/src/backend/commands/event_trigger.c b/src/backend/commands/event_trigger.c
new file mode 100644
index 1b8c94b..b70c322
*** a/src/backend/commands/event_trigger.c
--- b/src/backend/commands/event_trigger.c
*************** static event_trigger_support_data event_
*** 73,78 ****
--- 73,79 ----
{"COLLATION", true},
{"CONVERSION", true},
{"DATABASE", false},
+ {"DIRALIAS", true},
{"DOMAIN", true},
{"EXTENSION", true},
{"EVENT TRIGGER", false},
*************** EventTriggerSupportsObjectType(ObjectTyp
*** 924,929 ****
--- 925,931 ----
case OBJECT_CONSTRAINT:
case OBJECT_COLLATION:
case OBJECT_CONVERSION:
+ case OBJECT_DIRALIAS:
case OBJECT_DOMAIN:
case OBJECT_EXTENSION:
case OBJECT_FDW:
*************** EventTriggerSupportsObjectClass(ObjectCl
*** 998,1003 ****
--- 1000,1006 ----
case OCLASS_DEFACL:
case OCLASS_EXTENSION:
case OCLASS_ROWSECURITY:
+ case OCLASS_DIRALIAS:
return true;
case MAX_OCLASS:
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
new file mode 100644
index 21b070a..8941fa2
*** a/src/backend/nodes/copyfuncs.c
--- b/src/backend/nodes/copyfuncs.c
*************** _copyGrantRoleStmt(const GrantRoleStmt *
*** 2702,2707 ****
--- 2702,2721 ----
return newnode;
}
+ static GrantDirAliasStmt *
+ _copyGrantDirAliasStmt(const GrantDirAliasStmt *from)
+ {
+ GrantDirAliasStmt *newnode = makeNode(GrantDirAliasStmt);
+
+ COPY_NODE_FIELD(directories);
+ COPY_NODE_FIELD(permissions);
+ COPY_NODE_FIELD(grantees);
+ COPY_SCALAR_FIELD(is_grant);
+ COPY_STRING_FIELD(grantor);
+
+ return newnode;
+ }
+
static AlterDefaultPrivilegesStmt *
_copyAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *from)
{
*************** _copyAlterPolicyStmt(const AlterPolicySt
*** 3879,3884 ****
--- 3893,3920 ----
return newnode;
}
+ static CreateDirAliasStmt *
+ _copyCreateDirAliasStmt(const CreateDirAliasStmt *from)
+ {
+ CreateDirAliasStmt *newnode = makeNode(CreateDirAliasStmt);
+
+ COPY_STRING_FIELD(name);
+ COPY_STRING_FIELD(path);
+
+ return newnode;
+ }
+
+ static AlterDirAliasStmt *
+ _copyAlterDirAliasStmt(const AlterDirAliasStmt *from)
+ {
+ AlterDirAliasStmt *newnode = makeNode(AlterDirAliasStmt);
+
+ COPY_STRING_FIELD(name);
+ COPY_STRING_FIELD(path);
+
+ return newnode;
+ }
+
/* ****************************************************************
* pg_list.h copy functions
* ****************************************************************
*************** copyObject(const void *from)
*** 4318,4323 ****
--- 4354,4362 ----
case T_GrantStmt:
retval = _copyGrantStmt(from);
break;
+ case T_GrantDirAliasStmt:
+ retval = _copyGrantDirAliasStmt(from);
+ break;
case T_GrantRoleStmt:
retval = _copyGrantRoleStmt(from);
break;
*************** copyObject(const void *from)
*** 4597,4602 ****
--- 4636,4647 ----
case T_AlterPolicyStmt:
retval = _copyAlterPolicyStmt(from);
break;
+ case T_CreateDirAliasStmt:
+ retval = _copyCreateDirAliasStmt(from);
+ break;
+ case T_AlterDirAliasStmt:
+ retval = _copyAlterDirAliasStmt(from);
+ break;
case T_A_Expr:
retval = _copyAExpr(from);
break;
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
new file mode 100644
index 358395f..e266ad8
*** a/src/backend/nodes/equalfuncs.c
--- b/src/backend/nodes/equalfuncs.c
*************** _equalGrantRoleStmt(const GrantRoleStmt
*** 1046,1051 ****
--- 1046,1063 ----
}
static bool
+ _equalGrantDirAliasStmt(const GrantDirAliasStmt *a, const GrantDirAliasStmt *b)
+ {
+ COMPARE_NODE_FIELD(directories);
+ COMPARE_NODE_FIELD(permissions);
+ COMPARE_NODE_FIELD(grantees);
+ COMPARE_SCALAR_FIELD(is_grant);
+ COMPARE_STRING_FIELD(grantor);
+
+ return true;
+ }
+
+ static bool
_equalAlterDefaultPrivilegesStmt(const AlterDefaultPrivilegesStmt *a, const AlterDefaultPrivilegesStmt *b)
{
COMPARE_NODE_FIELD(options);
*************** _equalAlterPolicyStmt(const AlterPolicyS
*** 2034,2039 ****
--- 2046,2069 ----
}
static bool
+ _equalCreateDirAliasStmt(const CreateDirAliasStmt *a, const CreateDirAliasStmt *b)
+ {
+ COMPARE_STRING_FIELD(name);
+ COMPARE_STRING_FIELD(path);
+
+ return true;
+ }
+
+ static bool
+ _equalAlterDirAliasStmt(const AlterDirAliasStmt *a, const AlterDirAliasStmt *b)
+ {
+ COMPARE_STRING_FIELD(name);
+ COMPARE_STRING_FIELD(path);
+
+ return true;
+ }
+
+ static bool
_equalAExpr(const A_Expr *a, const A_Expr *b)
{
COMPARE_SCALAR_FIELD(kind);
*************** equal(const void *a, const void *b)
*** 2778,2783 ****
--- 2808,2816 ----
case T_GrantStmt:
retval = _equalGrantStmt(a, b);
break;
+ case T_GrantDirAliasStmt:
+ retval = _equalGrantDirAliasStmt(a, b);
+ break;
case T_GrantRoleStmt:
retval = _equalGrantRoleStmt(a, b);
break;
*************** equal(const void *a, const void *b)
*** 3057,3062 ****
--- 3090,3101 ----
case T_AlterPolicyStmt:
retval = _equalAlterPolicyStmt(a, b);
break;
+ case T_CreateDirAliasStmt:
+ retval = _equalCreateDirAliasStmt(a, b);
+ break;
+ case T_AlterDirAliasStmt:
+ retval = _equalAlterDirAliasStmt(a, b);
+ break;
case T_A_Expr:
retval = _equalAExpr(a, b);
break;
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
new file mode 100644
index 0de9584..24d5eb5
*** a/src/backend/parser/gram.y
--- b/src/backend/parser/gram.y
*************** static Node *makeRecursiveViewSelect(cha
*** 258,264 ****
DeallocateStmt PrepareStmt ExecuteStmt
DropOwnedStmt ReassignOwnedStmt
AlterTSConfigurationStmt AlterTSDictionaryStmt
! CreateMatViewStmt RefreshMatViewStmt
%type <node> select_no_parens select_with_parens select_clause
simple_select values_clause
--- 258,265 ----
DeallocateStmt PrepareStmt ExecuteStmt
DropOwnedStmt ReassignOwnedStmt
AlterTSConfigurationStmt AlterTSDictionaryStmt
! CreateMatViewStmt RefreshMatViewStmt GrantDirStmt RevokeDirStmt
! CreateDirAliasStmt AlterDirAliasStmt
%type <node> select_no_parens select_with_parens select_clause
simple_select values_clause
*************** static Node *makeRecursiveViewSelect(cha
*** 324,329 ****
--- 325,333 ----
%type <node> RowSecurityOptionalWithCheck RowSecurityOptionalExpr
%type <list> RowSecurityDefaultToRole RowSecurityOptionalToRole
+ %type <node> dir_perm_opts
+ %type <list> dir_permissions dir_perm_list
+
%type <str> iso_level opt_encoding
%type <node> grantee
%type <list> grantee_list
*************** static Node *makeRecursiveViewSelect(cha
*** 559,565 ****
DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
! DICTIONARY DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P DOUBLE_P DROP
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT
EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN
--- 563,570 ----
DATA_P DATABASE DAY_P DEALLOCATE DEC DECIMAL_P DECLARE DEFAULT DEFAULTS
DEFERRABLE DEFERRED DEFINER DELETE_P DELIMITER DELIMITERS DESC
! DICTIONARY DIRALIAS DISABLE_P DISCARD DISTINCT DO DOCUMENT_P DOMAIN_P
! DOUBLE_P DROP
EACH ELSE ENABLE_P ENCODING ENCRYPTED END_P ENUM_P ESCAPE EVENT EXCEPT
EXCLUDE EXCLUDING EXCLUSIVE EXECUTE EXISTS EXPLAIN
*************** stmt :
*** 734,739 ****
--- 739,745 ----
| AlterDatabaseStmt
| AlterDatabaseSetStmt
| AlterDefaultPrivilegesStmt
+ | AlterDirAliasStmt
| AlterDomainStmt
| AlterEnumStmt
| AlterExtensionStmt
*************** stmt :
*** 769,774 ****
--- 775,781 ----
| CreateAssertStmt
| CreateCastStmt
| CreateConversionStmt
+ | CreateDirAliasStmt
| CreateDomainStmt
| CreateExtensionStmt
| CreateFdwStmt
*************** stmt :
*** 820,825 ****
--- 827,833 ----
| ExplainStmt
| FetchStmt
| GrantStmt
+ | GrantDirStmt
| GrantRoleStmt
| ImportForeignSchemaStmt
| IndexStmt
*************** stmt :
*** 837,842 ****
--- 845,851 ----
| RemoveOperStmt
| RenameStmt
| RevokeStmt
+ | RevokeDirStmt
| RevokeRoleStmt
| RuleStmt
| SecLabelStmt
*************** row_security_cmd:
*** 4606,4611 ****
--- 4615,4648 ----
/*****************************************************************************
*
+ * QUERIES:
+ * CREATE DIRALIAS <name> AS <path>
+ * ALTER DIRALIAS <name> AS <path>
+ *
+ *****************************************************************************/
+
+ CreateDirAliasStmt:
+ CREATE DIRALIAS name AS Sconst
+ {
+ CreateDirAliasStmt *n = makeNode(CreateDirAliasStmt);
+ n->name = $3;
+ n->path = $5;
+ $$ = (Node *) n;
+ }
+ ;
+
+ AlterDirAliasStmt:
+ ALTER DIRALIAS name AS Sconst
+ {
+ AlterDirAliasStmt *n = makeNode(AlterDirAliasStmt);
+ n->name = $3;
+ n->path = $5;
+ $$ = (Node *) n;
+ }
+ ;
+
+ /*****************************************************************************
+ *
* QUERIES :
* CREATE TRIGGER ...
* DROP TRIGGER ...
*************** drop_type: TABLE { $$ = OBJECT_T
*** 5481,5486 ****
--- 5518,5524 ----
| CONVERSION_P { $$ = OBJECT_CONVERSION; }
| SCHEMA { $$ = OBJECT_SCHEMA; }
| EXTENSION { $$ = OBJECT_EXTENSION; }
+ | DIRALIAS { $$ = OBJECT_DIRALIAS; }
| TEXT_P SEARCH PARSER { $$ = OBJECT_TSPARSER; }
| TEXT_P SEARCH DICTIONARY { $$ = OBJECT_TSDICTIONARY; }
| TEXT_P SEARCH TEMPLATE { $$ = OBJECT_TSTEMPLATE; }
*************** opt_granted_by: GRANTED BY RoleId {
*** 6314,6319 ****
--- 6352,6418 ----
/*****************************************************************************
*
+ * QUERIES:
+ * GRANT ON DIRALIAS <alias> <permissions> TO <roles>
+ * REVOKE ON DIRALIAS <alias> <permsissions> FROM <roles>
+ *
+ *****************************************************************************/
+ GrantDirStmt:
+ GRANT ON DIRALIAS name_list dir_permissions TO grantee_list
+ opt_granted_by
+ {
+ GrantDirAliasStmt *n = makeNode(GrantDirAliasStmt);
+ n->is_grant = true;
+ n->directories = $4;
+ n->permissions = $5;
+ n->grantees = $7;
+ n->grantor = $8;
+ $$ = (Node*)n;
+ }
+ ;
+
+ RevokeDirStmt:
+ REVOKE ON DIRALIAS name_list dir_permissions FROM grantee_list
+ {
+ GrantDirAliasStmt *n = makeNode(GrantDirAliasStmt);
+ n->is_grant = false;
+ n->directories = $4;
+ n->permissions = $5;
+ n->grantees = $7;
+ $$ = (Node*)n;
+ }
+ ;
+
+ /* either ALL or a list of individual permissions */
+ dir_permissions: dir_perm_list
+ { $$ = $1; }
+ | ALL { $$ = NIL; }
+ ;
+
+
+ dir_perm_list: dir_perm_opts { $$ = list_make1($1); }
+ | dir_perm_list ',' dir_perm_opts { $$ = lappend($1, $3); }
+ ;
+
+ dir_perm_opts:
+ READ
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = pstrdup("select");
+ n->cols = NIL;
+ $$ = (Node*)n;
+ }
+ | WRITE
+ {
+ AccessPriv *n = makeNode(AccessPriv);
+ n->priv_name = pstrdup("update");
+ n->cols = NIL;
+ $$ = (Node*)n;
+ }
+ ;
+
+ /*****************************************************************************
+ *
* ALTER DEFAULT PRIVILEGES statement
*
*****************************************************************************/
*************** RenameStmt: ALTER AGGREGATE func_name ag
*** 7273,7278 ****
--- 7372,7386 ----
n->missing_ok = false;
$$ = (Node *)n;
}
+ | ALTER DIRALIAS name RENAME TO name
+ {
+ RenameStmt *n = makeNode(RenameStmt);
+ n->renameType = OBJECT_DIRALIAS;
+ n->object = list_make1(makeString($3));
+ n->newname = $6;
+ n->missing_ok = false;
+ $$ = (Node *)n;
+ }
| ALTER DOMAIN_P any_name RENAME TO name
{
RenameStmt *n = makeNode(RenameStmt);
*************** unreserved_keyword:
*** 13051,13056 ****
--- 13159,13165 ----
| DELIMITER
| DELIMITERS
| DICTIONARY
+ | DIRALIAS
| DISABLE_P
| DISCARD
| DOCUMENT_P
diff --git a/src/backend/tcop/utility.c b/src/backend/tcop/utility.c
new file mode 100644
index 4a2a339..4980016
*** a/src/backend/tcop/utility.c
--- b/src/backend/tcop/utility.c
***************
*** 33,38 ****
--- 33,39 ----
#include "commands/createas.h"
#include "commands/dbcommands.h"
#include "commands/defrem.h"
+ #include "commands/diralias.h"
#include "commands/discard.h"
#include "commands/event_trigger.h"
#include "commands/explain.h"
*************** check_xact_readonly(Node *parsetree)
*** 185,190 ****
--- 186,192 ----
case T_DropRoleStmt:
case T_GrantStmt:
case T_GrantRoleStmt:
+ case T_GrantDirAliasStmt:
case T_AlterDefaultPrivilegesStmt:
case T_TruncateStmt:
case T_DropOwnedStmt:
*************** standard_ProcessUtility(Node *parsetree,
*** 557,562 ****
--- 559,568 ----
GrantRole((GrantRoleStmt *) parsetree);
break;
+ case T_GrantDirAliasStmt:
+ ExecuteGrantDirAliasStmt((GrantDirAliasStmt *) parsetree);
+ break;
+
case T_CreatedbStmt:
/* no event triggers for global objects */
PreventTransactionChain(isTopLevel, "CREATE DATABASE");
*************** ProcessUtilitySlow(Node *parsetree,
*** 1329,1334 ****
--- 1335,1348 ----
AlterPolicy((AlterPolicyStmt *) parsetree);
break;
+ case T_CreateDirAliasStmt: /* CREATE DIRALIAS */
+ CreateDirAlias((CreateDirAliasStmt *) parsetree);
+ break;
+
+ case T_AlterDirAliasStmt: /* ALTER DIRALIAS */
+ AlterDirAlias((AlterDirAliasStmt *) parsetree);
+ break;
+
default:
elog(ERROR, "unrecognized node type: %d",
(int) nodeTag(parsetree));
*************** AlterObjectTypeCommandTag(ObjectType obj
*** 1596,1601 ****
--- 1610,1618 ----
case OBJECT_DATABASE:
tag = "ALTER DATABASE";
break;
+ case OBJECT_DIRALIAS:
+ tag = "ALTER DIRALIAS";
+ break;
case OBJECT_DOMAIN:
tag = "ALTER DOMAIN";
break;
*************** CreateCommandTag(Node *parsetree)
*** 1959,1964 ****
--- 1976,1984 ----
case OBJECT_POLICY:
tag = "DROP POLICY";
break;
+ case OBJECT_DIRALIAS:
+ tag = "DROP DIRALIAS";
+ break;
default:
tag = "???";
}
*************** CreateCommandTag(Node *parsetree)
*** 2016,2021 ****
--- 2036,2049 ----
}
break;
+ case T_GrantDirAliasStmt:
+ {
+ GrantDirAliasStmt *stmt = (GrantDirAliasStmt *) parsetree;
+
+ tag = (stmt->is_grant ? "GRANT ON DIRALIAS" : "REVOKE ON DIRALIAS");
+ }
+ break;
+
case T_GrantRoleStmt:
{
GrantRoleStmt *stmt = (GrantRoleStmt *) parsetree;
*************** CreateCommandTag(Node *parsetree)
*** 2310,2315 ****
--- 2338,2351 ----
tag = "ALTER POLICY";
break;
+ case T_CreateDirAliasStmt:
+ tag = "CREATE DIRALIAS";
+ break;
+
+ case T_AlterDirAliasStmt:
+ tag = "ALTER DIRALIAS";
+ break;
+
case T_PrepareStmt:
tag = "PREPARE";
break;
*************** GetCommandLogLevel(Node *parsetree)
*** 2862,2867 ****
--- 2898,2911 ----
lev = LOGSTMT_DDL;
break;
+ case T_CreateDirAliasStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
+ case T_AlterDirAliasStmt:
+ lev = LOGSTMT_DDL;
+ break;
+
case T_AlterTSDictionaryStmt:
lev = LOGSTMT_DDL;
break;
diff --git a/src/backend/utils/adt/acl.c b/src/backend/utils/adt/acl.c
new file mode 100644
index dc6eb2c..7cc00ef
*** a/src/backend/utils/adt/acl.c
--- b/src/backend/utils/adt/acl.c
*************** acldefault(GrantObjectType objtype, Oid
*** 790,795 ****
--- 790,799 ----
world_default = ACL_USAGE;
owner_default = ACL_ALL_RIGHTS_TYPE;
break;
+ case ACL_OBJECT_DIRALIAS:
+ world_default = ACL_NO_RIGHTS;
+ owner_default = ACL_ALL_RIGHTS_DIRALIAS;
+ break;
default:
elog(ERROR, "unrecognized objtype: %d", (int) objtype);
world_default = ACL_NO_RIGHTS; /* keep compiler quiet */
diff --git a/src/backend/utils/adt/genfile.c b/src/backend/utils/adt/genfile.c
new file mode 100644
index 3a0957f..58dd1dc
*** a/src/backend/utils/adt/genfile.c
--- b/src/backend/utils/adt/genfile.c
***************
*** 22,32 ****
--- 22,34 ----
#include "access/htup_details.h"
#include "catalog/pg_type.h"
+ #include "commands/diralias.h"
#include "funcapi.h"
#include "mb/pg_wchar.h"
#include "miscadmin.h"
#include "postmaster/syslogger.h"
#include "storage/fd.h"
+ #include "utils/acl.h"
#include "utils/builtins.h"
#include "utils/memutils.h"
#include "utils/timestamp.h"
*************** typedef struct
*** 37,82 ****
DIR *dirdesc;
} directory_fctx;
-
/*
! * Convert a "text" filename argument to C string, and check it's allowable.
*
! * Filename may be absolute or relative to the DataDir, but we only allow
! * absolute paths that match DataDir or Log_directory.
*/
! static char *
! convert_and_check_filename(text *arg)
{
! char *filename;
! filename = text_to_cstring(arg);
! canonicalize_path(filename); /* filename can change length here */
! if (is_absolute_path(filename))
! {
! /* Disallow '/a/b/data/..' */
! if (path_contains_parent_reference(filename))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("reference to parent directory (\"..\") not allowed"))));
! /*
! * Allow absolute paths if within DataDir or Log_directory, even
! * though Log_directory might be outside DataDir.
! */
! if (!path_is_prefix_of_path(DataDir, filename) &&
! (!is_absolute_path(Log_directory) ||
! !path_is_prefix_of_path(Log_directory, filename)))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("absolute path not allowed"))));
! }
! else if (!path_is_relative_and_below_cwd(filename))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("path must be in or below the current directory"))));
! return filename;
}
--- 39,82 ----
DIR *dirdesc;
} directory_fctx;
/*
! * Check the directory permissions for the provided filename/path.
*
! * The filename must be an absolute path to the file.
*/
! static void
! check_directory_permissions(char *directory)
{
! Oid diralias_id;
! AclResult aclresult;
! /* Do not allow relative paths */
! if (!is_absolute_path(directory))
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("relative path not allowed")));
! /* Search for directory in pg_diralias */
! diralias_id = get_diralias_oid_by_path(directory);
! /*
! * If an entry does not exist for the path in pg_diralias then raise
! * an error.
! */
! if (!OidIsValid(diralias_id))
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("directory alias entry for \"%s\" does not exist",
! directory)));
! /* Check directory alias entry permissions */
! aclresult = pg_diralias_aclcheck(diralias_id, GetUserId(), ACL_SELECT);
!
! /* If the current user has insufficient privileges then raise an error */
! if (aclresult != ACLCHECK_OK)
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must have read permissions on directory")));
}
*************** pg_read_file(PG_FUNCTION_ARGS)
*** 173,185 ****
int64 seek_offset = PG_GETARG_INT64(1);
int64 bytes_to_read = PG_GETARG_INT64(2);
char *filename;
! if (!superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to read files"))));
! filename = convert_and_check_filename(filename_t);
if (bytes_to_read < 0)
ereport(ERROR,
--- 173,191 ----
int64 seek_offset = PG_GETARG_INT64(1);
int64 bytes_to_read = PG_GETARG_INT64(2);
char *filename;
+ char *directory;
! /* Convert and cleanup the filename */
! filename = text_to_cstring(filename_t);
! canonicalize_path(filename);
! /* Superuser is always allowed to bypass directory permissions */
! if (!superuser())
! {
! directory = pstrdup(filename);
! get_parent_directory(directory);
! check_directory_permissions(directory);
! }
if (bytes_to_read < 0)
ereport(ERROR,
*************** pg_read_file_all(PG_FUNCTION_ARGS)
*** 197,209 ****
{
text *filename_t = PG_GETARG_TEXT_P(0);
char *filename;
! if (!superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to read files"))));
! filename = convert_and_check_filename(filename_t);
PG_RETURN_TEXT_P(read_text_file(filename, 0, -1));
}
--- 203,221 ----
{
text *filename_t = PG_GETARG_TEXT_P(0);
char *filename;
+ char *directory;
! /* Convert and cleanup the filename */
! filename = text_to_cstring(filename_t);
! canonicalize_path(filename);
! /* Superuser is always allowed to bypass directory permissions */
! if (!superuser())
! {
! directory = pstrdup(filename);
! get_parent_directory(directory);
! check_directory_permissions(directory);
! }
PG_RETURN_TEXT_P(read_text_file(filename, 0, -1));
}
*************** pg_read_binary_file(PG_FUNCTION_ARGS)
*** 218,230 ****
int64 seek_offset = PG_GETARG_INT64(1);
int64 bytes_to_read = PG_GETARG_INT64(2);
char *filename;
! if (!superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to read files"))));
! filename = convert_and_check_filename(filename_t);
if (bytes_to_read < 0)
ereport(ERROR,
--- 230,248 ----
int64 seek_offset = PG_GETARG_INT64(1);
int64 bytes_to_read = PG_GETARG_INT64(2);
char *filename;
+ char *directory;
! /* Convert and cleanup the filename */
! filename = text_to_cstring(filename_t);
! canonicalize_path(filename);
! /* Superuser is always allowed to bypass directory permissions */
! if (!superuser())
! {
! directory = pstrdup(filename);
! get_parent_directory(directory);
! check_directory_permissions(directory);
! }
if (bytes_to_read < 0)
ereport(ERROR,
*************** pg_read_binary_file_all(PG_FUNCTION_ARGS
*** 242,254 ****
{
text *filename_t = PG_GETARG_TEXT_P(0);
char *filename;
! if (!superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to read files"))));
! filename = convert_and_check_filename(filename_t);
PG_RETURN_BYTEA_P(read_binary_file(filename, 0, -1));
}
--- 260,278 ----
{
text *filename_t = PG_GETARG_TEXT_P(0);
char *filename;
+ char *directory;
! /* Convert and cleanup the filename */
! filename = text_to_cstring(filename_t);
! canonicalize_path(filename);
! /* Superuser is always allowed to bypass directory permissions */
! if (!superuser())
! {
! directory = pstrdup(filename);
! get_parent_directory(directory);
! check_directory_permissions(directory);
! }
PG_RETURN_BYTEA_P(read_binary_file(filename, 0, -1));
}
*************** pg_stat_file(PG_FUNCTION_ARGS)
*** 261,278 ****
{
text *filename_t = PG_GETARG_TEXT_P(0);
char *filename;
struct stat fst;
Datum values[6];
bool isnull[6];
HeapTuple tuple;
TupleDesc tupdesc;
! if (!superuser())
! ereport(ERROR,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! (errmsg("must be superuser to get file information"))));
! filename = convert_and_check_filename(filename_t);
if (stat(filename, &fst) < 0)
ereport(ERROR,
--- 285,307 ----
{
text *filename_t = PG_GETARG_TEXT_P(0);
char *filename;
+ char *directory;
struct stat fst;
Datum values[6];
bool isnull[6];
HeapTuple tuple;
TupleDesc tupdesc;
! filename = text_to_cstring(filename_t);
! canonicalize_path(filename);
! /* Superuser is always allowed to bypass directory permissions */
! if (!superuser())
! {
! directory = pstrdup(filename);
! get_parent_directory(directory);
! check_directory_permissions(directory);
! }
if (stat(filename, &fst) < 0)
ereport(ERROR,
*************** pg_ls_dir(PG_FUNCTION_ARGS)
*** 331,341 ****
struct dirent *de;
directory_fctx *fctx;
- if (!superuser())
- ereport(ERROR,
- (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
- (errmsg("must be superuser to get directory listings"))));
-
if (SRF_IS_FIRSTCALL())
{
MemoryContext oldcontext;
--- 360,365 ----
*************** pg_ls_dir(PG_FUNCTION_ARGS)
*** 344,350 ****
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
fctx = palloc(sizeof(directory_fctx));
! fctx->location = convert_and_check_filename(PG_GETARG_TEXT_P(0));
fctx->dirdesc = AllocateDir(fctx->location);
--- 368,379 ----
oldcontext = MemoryContextSwitchTo(funcctx->multi_call_memory_ctx);
fctx = palloc(sizeof(directory_fctx));
! fctx->location = text_to_cstring(PG_GETARG_TEXT_P(0));
! canonicalize_path(fctx->location);
!
! /* Superuser is always allowed to bypass directory permissions */
! if (!superuser())
! check_directory_permissions(fctx->location);
fctx->dirdesc = AllocateDir(fctx->location);
diff --git a/src/backend/utils/cache/syscache.c b/src/backend/utils/cache/syscache.c
new file mode 100644
index 94d951c..383e1c9
*** a/src/backend/utils/cache/syscache.c
--- b/src/backend/utils/cache/syscache.c
***************
*** 37,42 ****
--- 37,43 ----
#include "catalog/pg_default_acl.h"
#include "catalog/pg_depend.h"
#include "catalog/pg_description.h"
+ #include "catalog/pg_diralias.h"
#include "catalog/pg_enum.h"
#include "catalog/pg_event_trigger.h"
#include "catalog/pg_foreign_data_wrapper.h"
*************** static const struct cachedesc cacheinfo[
*** 366,371 ****
--- 367,383 ----
0
},
8
+ },
+ {DirAliasRelationId, /* DIRALIASOID */
+ DirAliasOidIndexId,
+ 1,
+ {
+ ObjectIdAttributeNumber,
+ 0,
+ 0,
+ 0
+ },
+ 8
},
{EnumRelationId, /* ENUMOID */
EnumOidIndexId,
diff --git a/src/bin/pg_dump/common.c b/src/bin/pg_dump/common.c
new file mode 100644
index 8bfc604..da46c9f
*** a/src/bin/pg_dump/common.c
--- b/src/bin/pg_dump/common.c
*************** getSchemaData(Archive *fout, DumpOptions
*** 103,108 ****
--- 103,109 ----
int numForeignServers;
int numDefaultACLs;
int numEventTriggers;
+ int numDirectoryAliases;
if (g_verbose)
write_msg(NULL, "reading schemas\n");
*************** getSchemaData(Archive *fout, DumpOptions
*** 251,256 ****
--- 252,261 ----
write_msg(NULL, "reading row-security policies\n");
getRowSecurity(fout, tblinfo, numTables);
+ if (g_verbose)
+ write_msg(NULL, "reading directory aliases\n");
+ getDirectoryAliases(fout, &numDirectoryAliases);
+
*numTablesPtr = numTables;
return tblinfo;
}
diff --git a/src/bin/pg_dump/dumputils.c b/src/bin/pg_dump/dumputils.c
new file mode 100644
index 259c472..08761e3
*** a/src/bin/pg_dump/dumputils.c
--- b/src/bin/pg_dump/dumputils.c
***************
*** 19,24 ****
--- 19,25 ----
#include "dumputils.h"
#include "parser/keywords.h"
+ #include "pg_backup_utils.h"
/* Globals from keywords.c */
*************** buildACLCommands(const char *name, const
*** 545,554 ****
* wire-in knowledge about the default public privileges for different
* kinds of objects.
*/
! appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
! if (subname)
! appendPQExpBuffer(firstsql, "(%s)", subname);
! appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
/*
* We still need some hacking though to cover the case where new default
--- 546,561 ----
* wire-in knowledge about the default public privileges for different
* kinds of objects.
*/
! if (strcmp(type, "DIRALIAS") == 0)
! appendPQExpBuffer(firstsql, "REVOKE ON DIRALIAS %s ALL FROM PUBLIC;\n",
! name);
! else
! {
! appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
! if (subname)
! appendPQExpBuffer(firstsql, "(%s)", subname);
! appendPQExpBuffer(firstsql, " ON %s %s FROM PUBLIC;\n", type, name);
! }
/*
* We still need some hacking though to cover the case where new default
*************** buildACLCommands(const char *name, const
*** 593,608 ****
? strcmp(privswgo->data, "ALL") != 0
: strcmp(privs->data, "ALL") != 0)
{
! appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
! if (subname)
! appendPQExpBuffer(firstsql, "(%s)", subname);
! appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
! type, name, fmtId(grantee->data));
if (privs->len > 0)
! appendPQExpBuffer(firstsql,
! "%sGRANT %s ON %s %s TO %s;\n",
! prefix, privs->data, type, name,
! fmtId(grantee->data));
if (privswgo->len > 0)
appendPQExpBuffer(firstsql,
"%sGRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
--- 600,633 ----
? strcmp(privswgo->data, "ALL") != 0
: strcmp(privs->data, "ALL") != 0)
{
! /* Handle special GRANT syntax for DIRALIAS */
! if (strcmp(type, "DIRALIAS") == 0)
! appendPQExpBuffer(firstsql, "REVOKE ON DIRALIAS %s ALL FROM %s;\n",
! name, fmtId(grantee->data));
! else
! {
! appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
! if (subname)
! appendPQExpBuffer(firstsql, "(%s)", subname);
! appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
! type, name, fmtId(grantee->data));
! }
!
if (privs->len > 0)
! {
! /* Handle special GRANT syntax for DIRALIAS */
! if (strcmp(type, "DIRALIAS") == 0)
! appendPQExpBuffer(firstsql,
! "%sGRANT ON DIRALIAS %s %s TO %s;\n",
! prefix, name, privs->data,
! fmtId(grantee->data));
! else
! appendPQExpBuffer(firstsql,
! "%sGRANT %s ON %s %s TO %s;\n",
! prefix, privs->data, type, name,
! fmtId(grantee->data));
! }
!
if (privswgo->len > 0)
appendPQExpBuffer(firstsql,
"%sGRANT %s ON %s %s TO %s WITH GRANT OPTION;\n",
*************** buildACLCommands(const char *name, const
*** 622,629 ****
if (privs->len > 0)
{
! appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
! prefix, privs->data, type, name);
if (grantee->len == 0)
appendPQExpBufferStr(secondsql, "PUBLIC;\n");
else if (strncmp(grantee->data, "group ",
--- 647,660 ----
if (privs->len > 0)
{
! /* Handle special GRANT syntax for DIRALIAS */
! if (strcmp(type, "DIRALIAS") == 0)
! appendPQExpBuffer(secondsql, "%sGRANT ON DIRALIAS %s %s TO ",
! prefix, name, privs->data);
! else
! appendPQExpBuffer(secondsql, "%sGRANT %s ON %s %s TO ",
! prefix, privs->data, type, name);
!
if (grantee->len == 0)
appendPQExpBufferStr(secondsql, "PUBLIC;\n");
else if (strncmp(grantee->data, "group ",
*************** buildACLCommands(const char *name, const
*** 660,670 ****
*/
if (!found_owner_privs && owner)
{
! appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
! if (subname)
! appendPQExpBuffer(firstsql, "(%s)", subname);
! appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
! type, name, fmtId(owner));
}
destroyPQExpBuffer(grantee);
--- 691,708 ----
*/
if (!found_owner_privs && owner)
{
! /* Handle special GRANT syntax for DIRALIAS */
! if (strcmp(type, "DIRALIAS") == 0)
! appendPQExpBuffer(firstsql, "REVOKE ON DIRALIAS %s ALL FROM %s",
! name, fmtId(owner));
! else
! {
! appendPQExpBuffer(firstsql, "%sREVOKE ALL", prefix);
! if (subname)
! appendPQExpBuffer(firstsql, "(%s)", subname);
! appendPQExpBuffer(firstsql, " ON %s %s FROM %s;\n",
! type, name, fmtId(owner));
! }
}
destroyPQExpBuffer(grantee);
*************** do { \
*** 873,878 ****
--- 911,921 ----
CONVERT_PRIV('r', "SELECT");
CONVERT_PRIV('w', "UPDATE");
}
+ else if (strcmp(type, "DIRALIAS") == 0)
+ {
+ CONVERT_PRIV('r', "READ");
+ CONVERT_PRIV('w', "WRITE");
+ }
else
abort();
diff --git a/src/bin/pg_dump/pg_backup_archiver.c b/src/bin/pg_dump/pg_backup_archiver.c
new file mode 100644
index ed28d36..0449b87
*** a/src/bin/pg_dump/pg_backup_archiver.c
--- b/src/bin/pg_dump/pg_backup_archiver.c
*************** _getObjectDescription(PQExpBuffer buf, T
*** 3106,3112 ****
strcmp(type, "SCHEMA") == 0 ||
strcmp(type, "FOREIGN DATA WRAPPER") == 0 ||
strcmp(type, "SERVER") == 0 ||
! strcmp(type, "USER MAPPING") == 0)
{
/* We already know that search_path was set properly */
appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
--- 3106,3113 ----
strcmp(type, "SCHEMA") == 0 ||
strcmp(type, "FOREIGN DATA WRAPPER") == 0 ||
strcmp(type, "SERVER") == 0 ||
! strcmp(type, "USER MAPPING") == 0 ||
! strcmp(type, "DIRALIAS") == 0)
{
/* We already know that search_path was set properly */
appendPQExpBuffer(buf, "%s %s", type, fmtId(te->tag));
*************** _printTocEntry(ArchiveHandle *AH, TocEnt
*** 3307,3313 ****
strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 ||
strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 ||
strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 ||
! strcmp(te->desc, "SERVER") == 0)
{
PQExpBuffer temp = createPQExpBuffer();
--- 3308,3315 ----
strcmp(te->desc, "TEXT SEARCH DICTIONARY") == 0 ||
strcmp(te->desc, "TEXT SEARCH CONFIGURATION") == 0 ||
strcmp(te->desc, "FOREIGN DATA WRAPPER") == 0 ||
! strcmp(te->desc, "SERVER") == 0 ||
! strcmp(te->desc, "DIRALIAS") == 0)
{
PQExpBuffer temp = createPQExpBuffer();
diff --git a/src/bin/pg_dump/pg_dump.c b/src/bin/pg_dump/pg_dump.c
new file mode 100644
index 1e8f089..2c154c0
*** a/src/bin/pg_dump/pg_dump.c
--- b/src/bin/pg_dump/pg_dump.c
*************** static void dumpUserMappings(Archive *fo
*** 191,196 ****
--- 191,197 ----
const char *servername, const char *namespace,
const char *owner, CatalogId catalogId, DumpId dumpId);
static void dumpDefaultACL(Archive *fout, DumpOptions *dopt, DefaultACLInfo *daclinfo);
+ static void dumpDirectoryAlias(Archive *fout, DumpOptions *dopt, DirectoryAliasInfo *dirinfo);
static void dumpACL(Archive *fout, DumpOptions *dopt, CatalogId objCatId, DumpId objDumpId,
const char *type, const char *name, const char *subname,
*************** dumpRowSecurity(Archive *fout, DumpOptio
*** 2987,2992 ****
--- 2988,3086 ----
destroyPQExpBuffer(delqry);
}
+ void
+ getDirectoryAliases(Archive *fout, int *numDirectoryAliases)
+ {
+ PQExpBuffer query;
+ PGresult *res;
+ DirectoryAliasInfo *dirinfo;
+ int i_tableoid;
+ int i_oid;
+ int i_dirname;
+ int i_dirpath;
+ int i_rolname;
+ int i_diracl;
+ int i, ntups;
+
+ if (fout->remoteVersion < 90500)
+ return;
+
+ query = createPQExpBuffer();
+
+ /* Make sure we are in proper schema */
+ selectSourceSchema(fout, "pg_catalog");
+
+ appendPQExpBuffer(query, "SELECT tableoid, oid, dirname, dirpath, diracl, "
+ "(%s (SELECT relowner FROM pg_catalog.pg_class WHERE oid = tableoid)) AS rolname "
+ "FROM pg_catalog.pg_diralias",
+ username_subquery);
+
+ res = ExecuteSqlQuery(fout, query->data, PGRES_TUPLES_OK);
+
+ ntups = PQntuples(res);
+
+ dirinfo = (DirectoryAliasInfo *) pg_malloc(ntups * sizeof(DirectoryAliasInfo));
+
+ i_tableoid = PQfnumber(res, "tableoid");
+ i_oid = PQfnumber(res, "oid");
+ i_dirname = PQfnumber(res, "dirname");
+ i_dirpath = PQfnumber(res, "dirpath");
+ i_rolname = PQfnumber(res, "rolname");
+ i_diracl = PQfnumber(res, "diracl");
+
+ for (i = 0; i < ntups; i++)
+ {
+ dirinfo[i].dobj.objType = DO_DIRALIAS;
+ dirinfo[i].dobj.catId.tableoid = atooid(PQgetvalue(res, i, i_tableoid));
+ dirinfo[i].dobj.catId.oid = atooid(PQgetvalue(res, i, i_oid));
+ AssignDumpId(&dirinfo[i].dobj);
+ dirinfo[i].dobj.name = pg_strdup(PQgetvalue(res, i, i_dirname));
+ dirinfo[i].rolname = pg_strdup(PQgetvalue(res, i, i_rolname));
+ dirinfo[i].dirpath = pg_strdup(PQgetvalue(res, i, i_dirpath));
+ dirinfo[i].diracl = pg_strdup(PQgetvalue(res, i, i_diracl));
+ }
+ }
+
+ static void
+ dumpDirectoryAlias(Archive *fout, DumpOptions *dopt, DirectoryAliasInfo *dirinfo)
+ {
+ PQExpBuffer create_query;
+ PQExpBuffer delete_query;
+ char *dirname;
+
+ if (!dirinfo->dobj.dump || dopt->dataOnly)
+ return;
+
+ create_query = createPQExpBuffer();
+ delete_query = createPQExpBuffer();
+
+ dirname = pg_strdup(fmtId(dirinfo->dobj.name));
+
+ appendPQExpBuffer(delete_query, "DROP DIRALIAS %s;\n", dirname);
+
+ appendPQExpBuffer(create_query, "CREATE DIRALIAS %s AS \'%s\';\n",
+ dirname, dirinfo->dirpath);
+
+ ArchiveEntry(fout, dirinfo->dobj.catId, dirinfo->dobj.dumpId,
+ dirinfo->dobj.name,
+ NULL, NULL,
+ dirinfo->rolname, false,
+ "DIRALIAS", SECTION_POST_DATA,
+ create_query->data, delete_query->data, NULL,
+ NULL, 0,
+ NULL, NULL);
+
+ /* Dump ACL - because of the special GRANT syntax, we cannot use dumpACL */
+ if (dirinfo->diracl)
+ dumpACL(fout, dopt, dirinfo->dobj.catId, dirinfo->dobj.dumpId,
+ "DIRALIAS", dirname, NULL, dirinfo->dobj.name,
+ NULL, dirinfo->rolname,
+ dirinfo->diracl);
+
+ destroyPQExpBuffer(create_query);
+ destroyPQExpBuffer(delete_query);
+ }
+
static void
binary_upgrade_set_type_oids_by_type_oid(Archive *fout,
PQExpBuffer upgrade_buffer,
*************** dumpDumpableObject(Archive *fout, DumpOp
*** 8218,8223 ****
--- 8312,8320 ----
case DO_ROW_SECURITY:
dumpRowSecurity(fout, dopt, (RowSecurityInfo *) dobj);
break;
+ case DO_DIRALIAS:
+ dumpDirectoryAlias(fout, dopt, (DirectoryAliasInfo *) dobj);
+ break;
case DO_PRE_DATA_BOUNDARY:
case DO_POST_DATA_BOUNDARY:
/* never dumped, nothing to do */
*************** addBoundaryDependencies(DumpableObject *
*** 15615,15620 ****
--- 15712,15718 ----
case DO_EVENT_TRIGGER:
case DO_DEFAULT_ACL:
case DO_ROW_SECURITY:
+ case DO_DIRALIAS:
/* Post-data objects: must come after the post-data boundary */
addObjectDependency(dobj, postDataBound->dumpId);
break;
diff --git a/src/bin/pg_dump/pg_dump.h b/src/bin/pg_dump/pg_dump.h
new file mode 100644
index a7eb2fd..14a712c
*** a/src/bin/pg_dump/pg_dump.h
--- b/src/bin/pg_dump/pg_dump.h
*************** typedef enum
*** 76,82 ****
DO_POST_DATA_BOUNDARY,
DO_EVENT_TRIGGER,
DO_REFRESH_MATVIEW,
! DO_ROW_SECURITY
} DumpableObjectType;
typedef struct _dumpableObject
--- 76,83 ----
DO_POST_DATA_BOUNDARY,
DO_EVENT_TRIGGER,
DO_REFRESH_MATVIEW,
! DO_ROW_SECURITY,
! DO_DIRALIAS
} DumpableObjectType;
typedef struct _dumpableObject
*************** typedef struct _rowSecurityInfo
*** 469,474 ****
--- 470,484 ----
char *rsecwithcheck;
} RowSecurityInfo;
+ typedef struct _directoryAliasInfo
+ {
+ DumpableObject dobj;
+ char *diralias;
+ char *diracl;
+ char *dirpath;
+ char *rolname; /* name of owner */
+ } DirectoryAliasInfo;
+
/* global decls */
extern bool force_quotes; /* double-quotes for identifiers flag */
extern bool g_verbose; /* verbose flag */
*************** extern void getExtensionMembership(Archi
*** 550,554 ****
--- 560,565 ----
int numExtensions);
extern EventTriggerInfo *getEventTriggers(Archive *fout, int *numEventTriggers);
extern void getRowSecurity(Archive *fout, TableInfo tblinfo[], int numTables);
+ extern void getDirectoryAliases(Archive *fout, int *numDirectoryAliases);
#endif /* PG_DUMP_H */
diff --git a/src/bin/pg_dump/pg_dump_sort.c b/src/bin/pg_dump/pg_dump_sort.c
new file mode 100644
index 030bccc..5cece21
*** a/src/bin/pg_dump/pg_dump_sort.c
--- b/src/bin/pg_dump/pg_dump_sort.c
*************** static const int oldObjectTypePriority[]
*** 73,79 ****
13, /* DO_POST_DATA_BOUNDARY */
20, /* DO_EVENT_TRIGGER */
15, /* DO_REFRESH_MATVIEW */
! 21 /* DO_ROW_SECURITY */
};
/*
--- 73,80 ----
13, /* DO_POST_DATA_BOUNDARY */
20, /* DO_EVENT_TRIGGER */
15, /* DO_REFRESH_MATVIEW */
! 21, /* DO_ROW_SECURITY */
! 22, /* DO_DIRALIAS */
};
/*
*************** static const int newObjectTypePriority[]
*** 122,128 ****
25, /* DO_POST_DATA_BOUNDARY */
32, /* DO_EVENT_TRIGGER */
33, /* DO_REFRESH_MATVIEW */
! 34 /* DO_ROW_SECURITY */
};
static DumpId preDataBoundId;
--- 123,130 ----
25, /* DO_POST_DATA_BOUNDARY */
32, /* DO_EVENT_TRIGGER */
33, /* DO_REFRESH_MATVIEW */
! 34, /* DO_ROW_SECURITY */
! 35, /* DO_DIRALIAS */
};
static DumpId preDataBoundId;
*************** describeDumpableObject(DumpableObject *o
*** 1443,1448 ****
--- 1445,1455 ----
"ROW-SECURITY POLICY (ID %d OID %u)",
obj->dumpId, obj->catId.oid);
return;
+ case DO_DIRALIAS:
+ snprintf(buf, bufsize,
+ "DIRECTORY ALIAS (ID %d OID %u)",
+ obj->dumpId, obj->catId.oid);
+ return;
case DO_PRE_DATA_BOUNDARY:
snprintf(buf, bufsize,
"PRE-DATA BOUNDARY (ID %d)",
diff --git a/src/include/catalog/dependency.h b/src/include/catalog/dependency.h
new file mode 100644
index 6a4913a..1779bc0
*** a/src/include/catalog/dependency.h
--- b/src/include/catalog/dependency.h
*************** typedef enum ObjectClass
*** 148,153 ****
--- 148,154 ----
OCLASS_EXTENSION, /* pg_extension */
OCLASS_EVENT_TRIGGER, /* pg_event_trigger */
OCLASS_ROWSECURITY, /* pg_rowsecurity */
+ OCLASS_DIRALIAS, /* pg_diralias */
MAX_OCLASS /* MUST BE LAST */
} ObjectClass;
diff --git a/src/include/catalog/indexing.h b/src/include/catalog/indexing.h
new file mode 100644
index 870692c..ce7464a
*** a/src/include/catalog/indexing.h
--- b/src/include/catalog/indexing.h
*************** DECLARE_UNIQUE_INDEX(pg_extension_name_i
*** 299,304 ****
--- 299,310 ----
DECLARE_UNIQUE_INDEX(pg_range_rngtypid_index, 3542, on pg_range using btree(rngtypid oid_ops));
#define RangeTypidIndexId 3542
+ DECLARE_UNIQUE_INDEX(pg_diralias_oid_index, 6101, on pg_diralias using btree(oid oid_ops));
+ #define DirAliasOidIndexId 6101
+
+ DECLARE_UNIQUE_INDEX(pg_diralias_name_index, 6102, on pg_diralias using btree(dirname name_ops));
+ #define DirAliasNameIndexId 6102
+
DECLARE_UNIQUE_INDEX(pg_rowsecurity_oid_index, 3257, on pg_rowsecurity using btree(oid oid_ops));
#define RowSecurityOidIndexId 3257
diff --git a/src/include/catalog/pg_diralias.h b/src/include/catalog/pg_diralias.h
new file mode 100644
index ...e58f047
*** a/src/include/catalog/pg_diralias.h
--- b/src/include/catalog/pg_diralias.h
***************
*** 0 ****
--- 1,46 ----
+ /*
+ * pg_diralias.h
+ * definition of the system catalog for directory permissions (pg_diralias)
+ *
+ * Portions Copyright (c) 1996-2012, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ */
+ #ifndef PG_DIRALIAS_H
+ #define PG_DIRALIAS_H
+
+ #include "catalog/genbki.h"
+
+ /* ----------------
+ * pg_diralias definition. cpp turns this into
+ * typedef struct FormData_pg_diralias
+ * ----------------
+ */
+ #define DirAliasRelationId 6100
+
+ CATALOG(pg_diralias,6100)
+ {
+ NameData dirname; /* directory alias name */
+ text dirpath; /* directory path */
+ #ifdef CATALOG_VARLEN
+ aclitem diracl[1]; /* directory permissions */
+ #endif
+ } FormData_pg_diralias;
+
+ /* ----------------
+ * Form_pg_diralias corresponds to a pointer to a row with
+ * the format of pg_diralias relation.
+ * ----------------
+ */
+ typedef FormData_pg_diralias *Form_pg_diralias;
+
+ /* ----------------
+ * compiler constants for pg_diralias
+ * ----------------
+ */
+ #define Natts_pg_diralias 3
+ #define Anum_pg_diralias_dirname 1
+ #define Anum_pg_diralias_dirpath 2
+ #define Anum_pg_diralias_diracl 3
+
+ #endif /* PG_DIRALIAS_H */
\ No newline at end of file
diff --git a/src/include/commands/diralias.h b/src/include/commands/diralias.h
new file mode 100644
index ...fc2cf23
*** a/src/include/commands/diralias.h
--- b/src/include/commands/diralias.h
***************
*** 0 ****
--- 1,29 ----
+ /*-------------------------------------------------------------------------
+ *
+ * diralias.h
+ * prototypes for diralias.c.
+ *
+ *
+ * Portions Copyright (c) 1996-2014, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1994, Regents of the University of California
+ *
+ * src/include/commands/diralias.h
+ *
+ *-------------------------------------------------------------------------
+ */
+
+ #ifndef DIRECTORY_H
+ #define DIRECTORY_H
+
+ #include "nodes/parsenodes.h"
+
+ extern void RemoveDirAliasById(Oid dir_id);
+ extern void CreateDirAlias(CreateDirAliasStmt *stmt);
+ extern void AlterDirAlias(AlterDirAliasStmt *stmt);
+
+ extern char *get_diralias_name(Oid dir_id);
+ extern Oid get_diralias_oid(const char *name, bool missing_ok);
+ extern Oid get_diralias_owner(Oid dir_id);
+ extern Oid get_diralias_oid_by_path(const char *path);
+
+ #endif /* DIRECTORY_H */
\ No newline at end of file
diff --git a/src/include/nodes/nodes.h b/src/include/nodes/nodes.h
new file mode 100644
index 154d943..6b293aa
*** a/src/include/nodes/nodes.h
--- b/src/include/nodes/nodes.h
*************** typedef enum NodeTag
*** 278,283 ****
--- 278,284 ----
T_AlterDomainStmt,
T_SetOperationStmt,
T_GrantStmt,
+ T_GrantDirAliasStmt,
T_GrantRoleStmt,
T_AlterDefaultPrivilegesStmt,
T_ClosePortalStmt,
*************** typedef enum NodeTag
*** 368,373 ****
--- 369,376 ----
T_AlterSystemStmt,
T_CreatePolicyStmt,
T_AlterPolicyStmt,
+ T_CreateDirAliasStmt,
+ T_AlterDirAliasStmt,
/*
* TAGS FOR PARSE TREE NODES (parsenodes.h)
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
new file mode 100644
index cef9544..4b7197c
*** a/src/include/nodes/parsenodes.h
--- b/src/include/nodes/parsenodes.h
*************** typedef enum ObjectType
*** 1212,1217 ****
--- 1212,1218 ----
OBJECT_COLLATION,
OBJECT_CONVERSION,
OBJECT_DATABASE,
+ OBJECT_DIRALIAS,
OBJECT_DOMAIN,
OBJECT_EVENT_TRIGGER,
OBJECT_EXTENSION,
*************** typedef enum GrantObjectType
*** 1412,1417 ****
--- 1413,1419 ----
ACL_OBJECT_LARGEOBJECT, /* largeobject */
ACL_OBJECT_NAMESPACE, /* namespace */
ACL_OBJECT_TABLESPACE, /* tablespace */
+ ACL_OBJECT_DIRALIAS, /* directory alias */
ACL_OBJECT_TYPE /* type */
} GrantObjectType;
*************** typedef struct GrantRoleStmt
*** 1483,1488 ****
--- 1485,1504 ----
} GrantRoleStmt;
/* ----------------------
+ * Grant/Revoke Directory Permission Statement
+ * ----------------------
+ */
+ typedef struct GrantDirAliasStmt
+ {
+ NodeTag type;
+ List *directories; /* the directory alias/name */
+ List *permissions; /* list of permission to be granted/revoked */
+ List *grantees; /* list of roles to be granted/revoked permission */
+ bool is_grant; /* true = GRANT, false = REVOKE */
+ char *grantor; /* set grantor to other than current role */
+ } GrantDirAliasStmt;
+
+ /* ----------------------
* Alter Default Privileges Statement
* ----------------------
*/
*************** typedef struct AlterPolicyStmt
*** 1890,1895 ****
--- 1906,1933 ----
} AlterPolicyStmt;
/* ----------------------
+ * Create DIRALIAS Statement
+ * ----------------------
+ */
+ typedef struct CreateDirAliasStmt
+ {
+ NodeTag type;
+ char *name;
+ char *path;
+ } CreateDirAliasStmt;
+
+ /* ----------------------
+ * Alter DIRALIAS Statement
+ * ----------------------
+ */
+ typedef struct AlterDirAliasStmt
+ {
+ NodeTag type;
+ char *name;
+ char *path;
+ } AlterDirAliasStmt;
+
+ /* ----------------------
* Create TRIGGER Statement
* ----------------------
*/
diff --git a/src/include/parser/kwlist.h b/src/include/parser/kwlist.h
new file mode 100644
index e14dc9a..eb31cf7
*** a/src/include/parser/kwlist.h
--- b/src/include/parser/kwlist.h
*************** PG_KEYWORD("delimiter", DELIMITER, UNRES
*** 125,130 ****
--- 125,131 ----
PG_KEYWORD("delimiters", DELIMITERS, UNRESERVED_KEYWORD)
PG_KEYWORD("desc", DESC, RESERVED_KEYWORD)
PG_KEYWORD("dictionary", DICTIONARY, UNRESERVED_KEYWORD)
+ PG_KEYWORD("diralias", DIRALIAS, UNRESERVED_KEYWORD)
PG_KEYWORD("disable", DISABLE_P, UNRESERVED_KEYWORD)
PG_KEYWORD("discard", DISCARD, UNRESERVED_KEYWORD)
PG_KEYWORD("distinct", DISTINCT, RESERVED_KEYWORD)
diff --git a/src/include/utils/acl.h b/src/include/utils/acl.h
new file mode 100644
index a8e3164..cb75b1a
*** a/src/include/utils/acl.h
--- b/src/include/utils/acl.h
*************** typedef ArrayType Acl;
*** 156,161 ****
--- 156,162 ----
#define ACL_ALL_RIGHTS_NAMESPACE (ACL_USAGE|ACL_CREATE)
#define ACL_ALL_RIGHTS_TABLESPACE (ACL_CREATE)
#define ACL_ALL_RIGHTS_TYPE (ACL_USAGE)
+ #define ACL_ALL_RIGHTS_DIRALIAS (ACL_SELECT|ACL_UPDATE)
/* operation codes for pg_*_aclmask */
typedef enum
*************** typedef enum AclObjectKind
*** 197,202 ****
--- 198,204 ----
ACL_KIND_FOREIGN_SERVER, /* pg_foreign_server */
ACL_KIND_EVENT_TRIGGER, /* pg_event_trigger */
ACL_KIND_EXTENSION, /* pg_extension */
+ ACL_KIND_DIRALIAS, /* pg_diralias */
MAX_ACL_KIND /* MUST BE LAST */
} AclObjectKind;
*************** extern Datum aclexplode(PG_FUNCTION_ARGS
*** 255,260 ****
--- 257,263 ----
*/
extern void ExecuteGrantStmt(GrantStmt *stmt);
extern void ExecAlterDefaultPrivilegesStmt(AlterDefaultPrivilegesStmt *stmt);
+ extern void ExecuteGrantDirAliasStmt(GrantDirAliasStmt *stmt);
extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid);
extern void RemoveDefaultACLById(Oid defaclOid);
*************** extern AclMode pg_foreign_server_aclmask
*** 281,286 ****
--- 284,291 ----
AclMode mask, AclMaskHow how);
extern AclMode pg_type_aclmask(Oid type_oid, Oid roleid,
AclMode mask, AclMaskHow how);
+ extern AclMode pg_diralias_aclmask(Oid dir_oid, Oid roleid, AclMode mask,
+ AclMaskHow how);
extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
Oid roleid, AclMode mode);
*************** extern AclResult pg_tablespace_aclcheck(
*** 297,302 ****
--- 302,308 ----
extern AclResult pg_foreign_data_wrapper_aclcheck(Oid fdw_oid, Oid roleid, AclMode mode);
extern AclResult pg_foreign_server_aclcheck(Oid srv_oid, Oid roleid, AclMode mode);
extern AclResult pg_type_aclcheck(Oid type_oid, Oid roleid, AclMode mode);
+ extern AclResult pg_diralias_aclcheck(Oid diroid, Oid roleid, AclMode mode);
extern void aclcheck_error(AclResult aclerr, AclObjectKind objectkind,
const char *objectname);
diff --git a/src/include/utils/syscache.h b/src/include/utils/syscache.h
new file mode 100644
index f97229f..c4b822e
*** a/src/include/utils/syscache.h
--- b/src/include/utils/syscache.h
*************** enum SysCacheIdentifier
*** 54,59 ****
--- 54,60 ----
CONVOID,
DATABASEOID,
DEFACLROLENSPOBJ,
+ DIRALIASOID,
ENUMOID,
ENUMTYPOIDNAME,
EVENTTRIGGERNAME,
diff --git a/src/test/regress/expected/sanity_check.out b/src/test/regress/expected/sanity_check.out
new file mode 100644
index 2c8ec11..334f648
*** a/src/test/regress/expected/sanity_check.out
--- b/src/test/regress/expected/sanity_check.out
*************** pg_db_role_setting|t
*** 102,107 ****
--- 102,108 ----
pg_default_acl|t
pg_depend|t
pg_description|t
+ pg_diralias|t
pg_enum|t
pg_event_trigger|t
pg_extension|t
--
Sent via pgsql-hackers mailing list ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers