Compare commits

...

4 Commits

Author SHA1 Message Date
Noah Misch
5f27b5f848 Dissociate btequalimage() from interval_ops, ending its deduplication.
Under interval_ops, some equal values are distinguishable.  One such
pair is '24:00:00' and '1 day'.  With that being so, btequalimage()
breaches the documented contract for the "equalimage" btree support
function.  This can cause incorrect results from index-only scans.
Users should REINDEX any btree indexes having interval-type columns.
After updating, pg_amcheck will report an error for almost all such
indexes.  This fix makes interval_ops simply omit the support function,
like numeric_ops does.  Back-pack to v13, where btequalimage() first
appeared.  In back branches, for the benefit of old catalog content,
btequalimage() code will return false for type "interval".  Going
forward, back-branch initdb will include the catalog change.

Reviewed by Peter Geoghegan.

Discussion: https://postgr.es/m/20231011013317.22.nmisch@google.com
2023-10-14 16:33:51 -07:00
Noah Misch
90ebcc32d9 Don't spuriously report FD_SETSIZE exhaustion on Windows.
Starting on 2023-08-03, this intermittently terminated a "pgbench -C"
test in CI.  It could affect a high-client-count "pgbench" without "-C".
While parallel reindexdb and vacuumdb reach the same problematic check,
sufficient client count and/or connection turnover is less plausible for
them.  Given the lack of examples from the buildfarm or from manual
builds, reproducing this must entail rare operating system
configurations.  Also correct the associated error message, which was
wrong for non-Windows.  Back-patch to v12, where the pgbench check first
appeared.  While v11 vacuumdb has the problematic check, reaching it
with typical vacuumdb usage is implausible.

Reviewed by Thomas Munro.

Discussion: https://postgr.es/m/CA+hUKG+JwvTNdcyJTriy9BbtzF1veSRQ=9M_ZKFn9_LqE7Kp7Q@mail.gmail.com
2023-10-14 15:54:46 -07:00
Tom Lane
fcdd6689d0 Harden xxx_is_visible() functions against concurrent object drops.
For the same reasons given in commit 403ac226d, adjust these
functions to not assume that checking SearchSysCacheExists can
guarantee success of a later fetch.

This follows the same internal API choices made in the earlier commit:
add a function XXXExt(oid, is_missing) and use that to eliminate
the need for a separate existence check.  The changes are very
straightforward, though tedious.  For the moment I just made the new
functions static in namespace.c, but we could export them if a need
emerges.

Per bug #18014 from Alexander Lakhin.  Given the lack of hard evidence
that there's a bug in non-debug builds, I'm content to fix this only
in HEAD.

Discussion: https://postgr.es/m/18014-28c81cb79d44295d@postgresql.org
2023-10-14 16:13:11 -04:00
Tom Lane
403ac226dd Harden has_xxx_privilege() functions against concurrent object drops.
The versions of these functions that accept object OIDs are supposed
to return NULL, rather than failing, if the target object has been
dropped.  This makes it safe(r) to use them in queries that scan
catalogs, since the functions will be applied to objects that are
visible in the query's snapshot but might now be gone according to
the catalog snapshot.  In most cases we implemented this by doing
a SearchSysCacheExists test and assuming that if that succeeds, we
can safely invoke the appropriate aclchk.c function, which will
immediately re-fetch the same syscache entry.  It was argued that
if the existence test succeeds then the followup fetch must succeed
as well, for lack of any intervening AcceptInvalidationMessages call.

Alexander Lakhin demonstrated that this is not so when
CATCACHE_FORCE_RELEASE is enabled: the syscache entry will be forcibly
dropped at the end of SearchSysCacheExists, and then it is possible
for the catalog snapshot to get advanced while re-fetching the entry.
Alexander's test case requires the operation to happen inside a
parallel worker, but that seems incidental to the fundamental problem.
What remains obscure is whether there is a way for this to happen in a
non-debug build.  Nonetheless, CATCACHE_FORCE_RELEASE is a very useful
test methodology, so we'd better make the code safe for it.

After some discussion we concluded that the most future-proof fix
is to give up the assumption that checking SearchSysCacheExists can
guarantee success of a later fetch.  At best that assumption leads
to fragile code --- for example, has_type_privilege appears broken
for array types even if you believe the assumption holds.  And it's
not even particularly efficient.

There had already been some work towards extending the aclchk.c
APIs to include "is_missing" output flags, so this patch extends
that work to cover all the aclchk.c functions that are used by the
has_xxx_privilege() functions.  (This allows getting rid of some
ad-hoc decisions about not throwing errors in certain places in
aclchk.c.)

In passing, this fixes the has_sequence_privilege() functions to
provide the same guarantees as their cousins: for some reason the
SearchSysCacheExists tests never got added to those.

There is more work to do to remove the unsafe coding pattern with
SearchSysCacheExists in other places, but this is a pretty
self-contained patch so I'll commit it separately.

Per bug #18014 from Alexander Lakhin.  Given the lack of hard evidence
that there's a bug in non-debug builds, I'm content to fix this only
in HEAD.  (Perhaps we should clean up the has_sequence_privilege()
oversight in the back branches, but in the absence of field complaints
I'm not too excited about that either.)

Discussion: https://postgr.es/m/18014-28c81cb79d44295d@postgresql.org
2023-10-14 14:49:50 -04:00
12 changed files with 810 additions and 219 deletions

View File

@ -31,6 +31,7 @@
#include "access/xact.h"
#include "catalog/index.h"
#include "catalog/pg_am.h"
#include "catalog/pg_opfamily_d.h"
#include "commands/tablecmds.h"
#include "common/pg_prng.h"
#include "lib/bloomfilter.h"
@ -338,10 +339,20 @@ bt_index_check_internal(Oid indrelid, bool parentcheck, bool heapallindexed,
errmsg("index \"%s\" metapage has equalimage field set on unsupported nbtree version",
RelationGetRelationName(indrel))));
if (allequalimage && !_bt_allequalimage(indrel, false))
{
bool has_interval_ops = false;
for (int i = 0; i < IndexRelationGetNumberOfKeyAttributes(indrel); i++)
if (indrel->rd_opfamily[i] == INTERVAL_BTREE_FAM_OID)
has_interval_ops = true;
ereport(ERROR,
(errcode(ERRCODE_INDEX_CORRUPTED),
errmsg("index \"%s\" metapage incorrectly indicates that deduplication is safe",
RelationGetRelationName(indrel))));
RelationGetRelationName(indrel)),
has_interval_ops
? errhint("This is known of \"interval\" indexes last built on a version predating 2023-11.")
: 0));
}
/* Check index, possibly against table it is an index on */
bt_check_every_level(indrel, heaprel, heapkeyspace, parentcheck,

View File

@ -13,6 +13,27 @@
* NOTES
* See acl.h.
*
* The xxx_aclmask() functions in this file are wrappers around
* acl.c's aclmask() function; see that for basic usage information.
* The wrapper functions add object-type-specific lookup capability.
* Generally, they will throw error if the object doesn't exist.
*
* The xxx_aclmask_ext() functions add the ability to not throw
* error if the object doesn't exist. If their "is_missing" argument
* isn't NULL, then when the object isn't found they will set
* *is_missing = true and return zero (no privileges) instead of
* throwing an error. Caller must initialize *is_missing = false.
*
* The xxx_aclcheck() functions are simplified wrappers around the
* corresponding xxx_aclmask() functions, simply returning ACLCHECK_OK
* if any of the privileges specified in "mode" are held, and otherwise
* a suitable error code (in practice, always ACLCHECK_NO_PRIV).
* Again, they will throw error if the object doesn't exist.
*
* The xxx_aclcheck_ext() functions add the ability to not throw
* error if the object doesn't exist. Their "is_missing" argument
* works similarly to the xxx_aclmask_ext() functions.
*
*-------------------------------------------------------------------------
*/
#include "postgres.h"
@ -139,6 +160,9 @@ static AclMode pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum,
Oid roleid, AclMode mask, AclMaskHow how);
static AclMode object_aclmask(Oid classid, Oid objectid, Oid roleid,
AclMode mask, AclMaskHow how);
static AclMode object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
AclMode mask, AclMaskHow how,
bool *is_missing);
static AclMode pg_attribute_aclmask(Oid table_oid, AttrNumber attnum,
Oid roleid, AclMode mask, AclMaskHow how);
static AclMode pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum,
@ -151,10 +175,12 @@ static AclMode pg_parameter_acl_aclmask(Oid acl_oid, Oid roleid,
AclMode mask, AclMaskHow how);
static AclMode pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
AclMode mask, AclMaskHow how, Snapshot snapshot);
static AclMode pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
AclMode mask, AclMaskHow how);
static AclMode pg_type_aclmask(Oid type_oid, Oid roleid,
AclMode mask, AclMaskHow how);
static AclMode pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
AclMode mask, AclMaskHow how,
bool *is_missing);
static AclMode pg_type_aclmask_ext(Oid type_oid, Oid roleid,
AclMode mask, AclMaskHow how,
bool *is_missing);
static void recordExtensionInitPriv(Oid objoid, Oid classoid, int objsubid,
Acl *new_acl);
static void recordExtensionInitPrivWorker(Oid objoid, Oid classoid, int objsubid,
@ -3064,6 +3090,18 @@ pg_aclmask(ObjectType objtype, Oid object_oid, AttrNumber attnum, Oid roleid,
static AclMode
object_aclmask(Oid classid, Oid objectid, Oid roleid,
AclMode mask, AclMaskHow how)
{
return object_aclmask_ext(classid, objectid, roleid, mask, how, NULL);
}
/*
* Generic routine for examining a user's privileges for an object,
* with is_missing
*/
static AclMode
object_aclmask_ext(Oid classid, Oid objectid, Oid roleid,
AclMode mask, AclMaskHow how,
bool *is_missing)
{
int cacheid;
AclMode result;
@ -3077,9 +3115,11 @@ object_aclmask(Oid classid, Oid objectid, Oid roleid,
switch (classid)
{
case NamespaceRelationId:
return pg_namespace_aclmask(objectid, roleid, mask, how);
return pg_namespace_aclmask_ext(objectid, roleid, mask, how,
is_missing);
case TypeRelationId:
return pg_type_aclmask(objectid, roleid, mask, how);
return pg_type_aclmask_ext(objectid, roleid, mask, how,
is_missing);
}
/* Even more special cases */
@ -3092,16 +3132,26 @@ object_aclmask(Oid classid, Oid objectid, Oid roleid,
return mask;
/*
* Get the objects's ACL from its catalog
* Get the object's ACL from its catalog
*/
cacheid = get_object_catcache_oid(classid);
tuple = SearchSysCache1(cacheid, ObjectIdGetDatum(objectid));
if (!HeapTupleIsValid(tuple))
{
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return 0;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_DATABASE),
errmsg("%s with OID %u does not exist", get_object_class_descr(classid), objectid)));
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("%s with OID %u does not exist",
get_object_class_descr(classid), objectid)));
}
ownerId = DatumGetObjectId(SysCacheGetAttrNotNull(cacheid,
tuple,
@ -3149,10 +3199,7 @@ pg_attribute_aclmask(Oid table_oid, AttrNumber attnum, Oid roleid,
}
/*
* Routine for examining a user's privileges for a column
*
* Does the bulk of the work for pg_attribute_aclmask(), and allows other
* callers to avoid the missing attribute ERROR when is_missing is non-NULL.
* Routine for examining a user's privileges for a column, with is_missing
*/
static AclMode
pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
@ -3226,16 +3273,25 @@ pg_attribute_aclmask_ext(Oid table_oid, AttrNumber attnum, Oid roleid,
* Must get the relation's ownerId from pg_class. Since we already found
* a pg_attribute entry, the only likely reason for this to fail is that a
* concurrent DROP of the relation committed since then (which could only
* happen if we don't have lock on the relation). We prefer to report "no
* privileges" rather than failing in such a case, so as to avoid unwanted
* failures in has_column_privilege() tests.
* happen if we don't have lock on the relation). Treat that similarly to
* not finding the attribute entry.
*/
classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
if (!HeapTupleIsValid(classTuple))
{
ReleaseSysCache(attTuple);
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return 0;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist",
table_oid)));
}
classForm = (Form_pg_class) GETSTRUCT(classTuple);
ownerId = classForm->relowner;
@ -3267,10 +3323,7 @@ pg_class_aclmask(Oid table_oid, Oid roleid,
}
/*
* Routine for examining a user's privileges for a table
*
* Does the bulk of the work for pg_class_aclmask(), and allows other
* callers to avoid the missing relation ERROR when is_missing is non-NULL.
* Routine for examining a user's privileges for a table, with is_missing
*/
static AclMode
pg_class_aclmask_ext(Oid table_oid, Oid roleid, AclMode mask,
@ -3585,11 +3638,12 @@ pg_largeobject_aclmask_snapshot(Oid lobj_oid, Oid roleid,
}
/*
* Routine for examining a user's privileges for a namespace
* Routine for examining a user's privileges for a namespace, with is_missing
*/
static AclMode
pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
AclMode mask, AclMaskHow how)
pg_namespace_aclmask_ext(Oid nsp_oid, Oid roleid,
AclMode mask, AclMaskHow how,
bool *is_missing)
{
AclMode result;
HeapTuple tuple;
@ -3623,8 +3677,8 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
*/
if (isTempNamespace(nsp_oid))
{
if (object_aclcheck(DatabaseRelationId, MyDatabaseId, roleid,
ACL_CREATE_TEMP) == ACLCHECK_OK)
if (object_aclcheck_ext(DatabaseRelationId, MyDatabaseId, roleid,
ACL_CREATE_TEMP, is_missing) == ACLCHECK_OK)
return mask & ACL_ALL_RIGHTS_SCHEMA;
else
return mask & ACL_USAGE;
@ -3635,9 +3689,18 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
*/
tuple = SearchSysCache1(NAMESPACEOID, ObjectIdGetDatum(nsp_oid));
if (!HeapTupleIsValid(tuple))
{
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return 0;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_SCHEMA),
errmsg("schema with OID %u does not exist", nsp_oid)));
}
ownerId = ((Form_pg_namespace) GETSTRUCT(tuple))->nspowner;
@ -3677,20 +3740,20 @@ pg_namespace_aclmask(Oid nsp_oid, Oid roleid,
}
/*
* Routine for examining a user's privileges for a type.
* Routine for examining a user's privileges for a type, with is_missing
*/
static AclMode
pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
pg_type_aclmask_ext(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how,
bool *is_missing)
{
AclMode result;
HeapTuple tuple;
Form_pg_type typeForm;
Datum aclDatum;
bool isNull;
Acl *acl;
Oid ownerId;
Form_pg_type typeForm;
/* Bypass permission checks for superusers */
if (superuser_arg(roleid))
return mask;
@ -3700,10 +3763,19 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
*/
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(type_oid));
if (!HeapTupleIsValid(tuple))
{
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return 0;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type with OID %u does not exist",
type_oid)));
}
typeForm = (Form_pg_type) GETSTRUCT(tuple);
/*
@ -3717,9 +3789,20 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
ReleaseSysCache(tuple);
tuple = SearchSysCache1(TYPEOID, ObjectIdGetDatum(elttype_oid));
/* this case is not a user-facing error, so elog not ereport */
if (!HeapTupleIsValid(tuple))
elog(ERROR, "cache lookup failed for type %u", elttype_oid);
{
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return 0;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("type with OID %u does not exist",
elttype_oid)));
}
typeForm = (Form_pg_type) GETSTRUCT(tuple);
}
@ -3759,7 +3842,20 @@ pg_type_aclmask(Oid type_oid, Oid roleid, AclMode mask, AclMaskHow how)
AclResult
object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode)
{
if (object_aclmask(classid, objectid, roleid, mode, ACLMASK_ANY) != 0)
return object_aclcheck_ext(classid, objectid, roleid, mode, NULL);
}
/*
* Exported generic routine for checking a user's access privileges to an
* object, with is_missing
*/
AclResult
object_aclcheck_ext(Oid classid, Oid objectid,
Oid roleid, AclMode mode,
bool *is_missing)
{
if (object_aclmask_ext(classid, objectid, roleid, mode, ACLMASK_ANY,
is_missing) != 0)
return ACLCHECK_OK;
else
return ACLCHECK_NO_PRIV;
@ -3784,10 +3880,8 @@ pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
/*
* Exported routine for checking a user's access privileges to a column
*
* Does the bulk of the work for pg_attribute_aclcheck(), and allows other
* callers to avoid the missing attribute ERROR when is_missing is non-NULL.
* Exported routine for checking a user's access privileges to a column,
* with is_missing
*/
AclResult
pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
@ -3822,23 +3916,47 @@ pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
AclResult
pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
AclMaskHow how)
{
return pg_attribute_aclcheck_all_ext(table_oid, roleid, mode, how, NULL);
}
/*
* Exported routine for checking a user's access privileges to any/all columns,
* with is_missing
*/
AclResult
pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
AclMode mode, AclMaskHow how,
bool *is_missing)
{
AclResult result;
HeapTuple classTuple;
Form_pg_class classForm;
Oid ownerId;
AttrNumber nattrs;
AttrNumber curr_att;
/*
* Must fetch pg_class row to check number of attributes. As in
* pg_attribute_aclmask, we prefer to return "no privileges" instead of
* throwing an error if we get any unexpected lookup errors.
* Must fetch pg_class row to get owner ID and number of attributes.
*/
classTuple = SearchSysCache1(RELOID, ObjectIdGetDatum(table_oid));
if (!HeapTupleIsValid(classTuple))
{
if (is_missing != NULL)
{
/* return "no privileges" instead of throwing an error */
*is_missing = true;
return ACLCHECK_NO_PRIV;
}
else
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_TABLE),
errmsg("relation with OID %u does not exist",
table_oid)));
}
classForm = (Form_pg_class) GETSTRUCT(classTuple);
ownerId = classForm->relowner;
nattrs = classForm->relnatts;
ReleaseSysCache(classTuple);
@ -3852,11 +3970,20 @@ pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
for (curr_att = 1; curr_att <= nattrs; curr_att++)
{
HeapTuple attTuple;
Datum aclDatum;
bool isNull;
Acl *acl;
AclMode attmask;
attTuple = SearchSysCache2(ATTNUM,
ObjectIdGetDatum(table_oid),
Int16GetDatum(curr_att));
/*
* Lookup failure probably indicates that the table was just dropped,
* but we'll treat it the same as a dropped column rather than
* throwing error.
*/
if (!HeapTupleIsValid(attTuple))
continue;
@ -3867,16 +3994,27 @@ pg_attribute_aclcheck_all(Oid table_oid, Oid roleid, AclMode mode,
continue;
}
aclDatum = SysCacheGetAttr(ATTNUM, attTuple, Anum_pg_attribute_attacl,
&isNull);
/*
* Here we hard-wire knowledge that the default ACL for a column
* grants no privileges, so that we can fall out quickly in the very
* common case where attacl is null.
*/
if (heap_attisnull(attTuple, Anum_pg_attribute_attacl, NULL))
if (isNull)
attmask = 0;
else
attmask = pg_attribute_aclmask(table_oid, curr_att, roleid,
mode, ACLMASK_ANY);
{
/* detoast column's ACL if necessary */
acl = DatumGetAclP(aclDatum);
attmask = aclmask(acl, roleid, ownerId, mode, ACLMASK_ANY);
/* if we have a detoasted copy, free it */
if ((Pointer) acl != DatumGetPointer(aclDatum))
pfree(acl);
}
ReleaseSysCache(attTuple);
@ -3911,10 +4049,8 @@ pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode)
}
/*
* Exported routine for checking a user's access privileges to a table
*
* Does the bulk of the work for pg_class_aclcheck(), and allows other
* callers to avoid the missing relation ERROR when is_missing is non-NULL.
* Exported routine for checking a user's access privileges to a table,
* with is_missing
*/
AclResult
pg_class_aclcheck_ext(Oid table_oid, Oid roleid,

View File

@ -183,6 +183,19 @@ char *namespace_search_path = NULL;
/* Local functions */
static bool RelationIsVisibleExt(Oid relid, bool *is_missing);
static bool TypeIsVisibleExt(Oid typid, bool *is_missing);
static bool FunctionIsVisibleExt(Oid funcid, bool *is_missing);
static bool OperatorIsVisibleExt(Oid oprid, bool *is_missing);
static bool OpclassIsVisibleExt(Oid opcid, bool *is_missing);
static bool OpfamilyIsVisibleExt(Oid opfid, bool *is_missing);
static bool CollationIsVisibleExt(Oid collid, bool *is_missing);
static bool ConversionIsVisibleExt(Oid conid, bool *is_missing);
static bool StatisticsObjIsVisibleExt(Oid stxid, bool *is_missing);
static bool TSParserIsVisibleExt(Oid prsId, bool *is_missing);
static bool TSDictionaryIsVisibleExt(Oid dictId, bool *is_missing);
static bool TSTemplateIsVisibleExt(Oid tmplId, bool *is_missing);
static bool TSConfigIsVisibleExt(Oid cfgid, bool *is_missing);
static void recomputeNamespacePath(void);
static void AccessTempTableNamespace(bool force);
static void InitTempTableNamespace(void);
@ -691,6 +704,18 @@ RelnameGetRelid(const char *relname)
*/
bool
RelationIsVisible(Oid relid)
{
return RelationIsVisibleExt(relid, NULL);
}
/*
* RelationIsVisibleExt
* As above, but if the relation isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
RelationIsVisibleExt(Oid relid, bool *is_missing)
{
HeapTuple reltup;
Form_pg_class relform;
@ -699,7 +724,14 @@ RelationIsVisible(Oid relid)
reltup = SearchSysCache1(RELOID, ObjectIdGetDatum(relid));
if (!HeapTupleIsValid(reltup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for relation %u", relid);
}
relform = (Form_pg_class) GETSTRUCT(reltup);
recomputeNamespacePath();
@ -799,6 +831,18 @@ TypenameGetTypidExtended(const char *typname, bool temp_ok)
*/
bool
TypeIsVisible(Oid typid)
{
return TypeIsVisibleExt(typid, NULL);
}
/*
* TypeIsVisibleExt
* As above, but if the type isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
TypeIsVisibleExt(Oid typid, bool *is_missing)
{
HeapTuple typtup;
Form_pg_type typform;
@ -807,7 +851,14 @@ TypeIsVisible(Oid typid)
typtup = SearchSysCache1(TYPEOID, ObjectIdGetDatum(typid));
if (!HeapTupleIsValid(typtup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for type %u", typid);
}
typform = (Form_pg_type) GETSTRUCT(typtup);
recomputeNamespacePath();
@ -1436,6 +1487,18 @@ MatchNamedCall(HeapTuple proctup, int nargs, List *argnames,
*/
bool
FunctionIsVisible(Oid funcid)
{
return FunctionIsVisibleExt(funcid, NULL);
}
/*
* FunctionIsVisibleExt
* As above, but if the function isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
FunctionIsVisibleExt(Oid funcid, bool *is_missing)
{
HeapTuple proctup;
Form_pg_proc procform;
@ -1444,7 +1507,14 @@ FunctionIsVisible(Oid funcid)
proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid));
if (!HeapTupleIsValid(proctup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for function %u", funcid);
}
procform = (Form_pg_proc) GETSTRUCT(proctup);
recomputeNamespacePath();
@ -1770,6 +1840,18 @@ OpernameGetCandidates(List *names, char oprkind, bool missing_schema_ok)
*/
bool
OperatorIsVisible(Oid oprid)
{
return OperatorIsVisibleExt(oprid, NULL);
}
/*
* OperatorIsVisibleExt
* As above, but if the operator isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
OperatorIsVisibleExt(Oid oprid, bool *is_missing)
{
HeapTuple oprtup;
Form_pg_operator oprform;
@ -1778,7 +1860,14 @@ OperatorIsVisible(Oid oprid)
oprtup = SearchSysCache1(OPEROID, ObjectIdGetDatum(oprid));
if (!HeapTupleIsValid(oprtup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for operator %u", oprid);
}
oprform = (Form_pg_operator) GETSTRUCT(oprtup);
recomputeNamespacePath();
@ -1856,6 +1945,18 @@ OpclassnameGetOpcid(Oid amid, const char *opcname)
*/
bool
OpclassIsVisible(Oid opcid)
{
return OpclassIsVisibleExt(opcid, NULL);
}
/*
* OpclassIsVisibleExt
* As above, but if the opclass isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
OpclassIsVisibleExt(Oid opcid, bool *is_missing)
{
HeapTuple opctup;
Form_pg_opclass opcform;
@ -1864,7 +1965,14 @@ OpclassIsVisible(Oid opcid)
opctup = SearchSysCache1(CLAOID, ObjectIdGetDatum(opcid));
if (!HeapTupleIsValid(opctup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for opclass %u", opcid);
}
opcform = (Form_pg_opclass) GETSTRUCT(opctup);
recomputeNamespacePath();
@ -1939,6 +2047,18 @@ OpfamilynameGetOpfid(Oid amid, const char *opfname)
*/
bool
OpfamilyIsVisible(Oid opfid)
{
return OpfamilyIsVisibleExt(opfid, NULL);
}
/*
* OpfamilyIsVisibleExt
* As above, but if the opfamily isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
OpfamilyIsVisibleExt(Oid opfid, bool *is_missing)
{
HeapTuple opftup;
Form_pg_opfamily opfform;
@ -1947,7 +2067,14 @@ OpfamilyIsVisible(Oid opfid)
opftup = SearchSysCache1(OPFAMILYOID, ObjectIdGetDatum(opfid));
if (!HeapTupleIsValid(opftup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for opfamily %u", opfid);
}
opfform = (Form_pg_opfamily) GETSTRUCT(opftup);
recomputeNamespacePath();
@ -2071,6 +2198,18 @@ CollationGetCollid(const char *collname)
*/
bool
CollationIsVisible(Oid collid)
{
return CollationIsVisibleExt(collid, NULL);
}
/*
* CollationIsVisibleExt
* As above, but if the collation isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
CollationIsVisibleExt(Oid collid, bool *is_missing)
{
HeapTuple colltup;
Form_pg_collation collform;
@ -2079,7 +2218,14 @@ CollationIsVisible(Oid collid)
colltup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collid));
if (!HeapTupleIsValid(colltup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for collation %u", collid);
}
collform = (Form_pg_collation) GETSTRUCT(colltup);
recomputeNamespacePath();
@ -2154,6 +2300,18 @@ ConversionGetConid(const char *conname)
*/
bool
ConversionIsVisible(Oid conid)
{
return ConversionIsVisibleExt(conid, NULL);
}
/*
* ConversionIsVisibleExt
* As above, but if the conversion isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
ConversionIsVisibleExt(Oid conid, bool *is_missing)
{
HeapTuple contup;
Form_pg_conversion conform;
@ -2162,7 +2320,14 @@ ConversionIsVisible(Oid conid)
contup = SearchSysCache1(CONVOID, ObjectIdGetDatum(conid));
if (!HeapTupleIsValid(contup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for conversion %u", conid);
}
conform = (Form_pg_conversion) GETSTRUCT(contup);
recomputeNamespacePath();
@ -2257,16 +2422,35 @@ get_statistics_object_oid(List *names, bool missing_ok)
* for the unqualified statistics object name".
*/
bool
StatisticsObjIsVisible(Oid relid)
StatisticsObjIsVisible(Oid stxid)
{
return StatisticsObjIsVisibleExt(stxid, NULL);
}
/*
* StatisticsObjIsVisibleExt
* As above, but if the statistics object isn't found and is_missing is
* not NULL, then set *is_missing = true and return false instead of
* throwing an error. (Caller must initialize *is_missing = false.)
*/
static bool
StatisticsObjIsVisibleExt(Oid stxid, bool *is_missing)
{
HeapTuple stxtup;
Form_pg_statistic_ext stxform;
Oid stxnamespace;
bool visible;
stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(relid));
stxtup = SearchSysCache1(STATEXTOID, ObjectIdGetDatum(stxid));
if (!HeapTupleIsValid(stxtup))
elog(ERROR, "cache lookup failed for statistics object %u", relid);
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for statistics object %u", stxid);
}
stxform = (Form_pg_statistic_ext) GETSTRUCT(stxtup);
recomputeNamespacePath();
@ -2381,6 +2565,18 @@ get_ts_parser_oid(List *names, bool missing_ok)
*/
bool
TSParserIsVisible(Oid prsId)
{
return TSParserIsVisibleExt(prsId, NULL);
}
/*
* TSParserIsVisibleExt
* As above, but if the parser isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
TSParserIsVisibleExt(Oid prsId, bool *is_missing)
{
HeapTuple tup;
Form_pg_ts_parser form;
@ -2389,7 +2585,14 @@ TSParserIsVisible(Oid prsId)
tup = SearchSysCache1(TSPARSEROID, ObjectIdGetDatum(prsId));
if (!HeapTupleIsValid(tup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for text search parser %u", prsId);
}
form = (Form_pg_ts_parser) GETSTRUCT(tup);
recomputeNamespacePath();
@ -2507,6 +2710,18 @@ get_ts_dict_oid(List *names, bool missing_ok)
*/
bool
TSDictionaryIsVisible(Oid dictId)
{
return TSDictionaryIsVisibleExt(dictId, NULL);
}
/*
* TSDictionaryIsVisibleExt
* As above, but if the dictionary isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
TSDictionaryIsVisibleExt(Oid dictId, bool *is_missing)
{
HeapTuple tup;
Form_pg_ts_dict form;
@ -2515,8 +2730,15 @@ TSDictionaryIsVisible(Oid dictId)
tup = SearchSysCache1(TSDICTOID, ObjectIdGetDatum(dictId));
if (!HeapTupleIsValid(tup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for text search dictionary %u",
dictId);
}
form = (Form_pg_ts_dict) GETSTRUCT(tup);
recomputeNamespacePath();
@ -2634,6 +2856,18 @@ get_ts_template_oid(List *names, bool missing_ok)
*/
bool
TSTemplateIsVisible(Oid tmplId)
{
return TSTemplateIsVisibleExt(tmplId, NULL);
}
/*
* TSTemplateIsVisibleExt
* As above, but if the template isn't found and is_missing is not NULL,
* then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
TSTemplateIsVisibleExt(Oid tmplId, bool *is_missing)
{
HeapTuple tup;
Form_pg_ts_template form;
@ -2642,7 +2876,14 @@ TSTemplateIsVisible(Oid tmplId)
tup = SearchSysCache1(TSTEMPLATEOID, ObjectIdGetDatum(tmplId));
if (!HeapTupleIsValid(tup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for text search template %u", tmplId);
}
form = (Form_pg_ts_template) GETSTRUCT(tup);
recomputeNamespacePath();
@ -2760,6 +3001,18 @@ get_ts_config_oid(List *names, bool missing_ok)
*/
bool
TSConfigIsVisible(Oid cfgid)
{
return TSConfigIsVisibleExt(cfgid, NULL);
}
/*
* TSConfigIsVisibleExt
* As above, but if the configuration isn't found and is_missing is not
* NULL, then set *is_missing = true and return false instead of throwing
* an error. (Caller must initialize *is_missing = false.)
*/
static bool
TSConfigIsVisibleExt(Oid cfgid, bool *is_missing)
{
HeapTuple tup;
Form_pg_ts_config form;
@ -2768,8 +3021,15 @@ TSConfigIsVisible(Oid cfgid)
tup = SearchSysCache1(TSCONFIGOID, ObjectIdGetDatum(cfgid));
if (!HeapTupleIsValid(tup))
{
if (is_missing != NULL)
{
*is_missing = true;
return false;
}
elog(ERROR, "cache lookup failed for text search configuration %u",
cfgid);
}
form = (Form_pg_ts_config) GETSTRUCT(tup);
recomputeNamespacePath();
@ -4283,152 +4543,189 @@ fetch_search_path_array(Oid *sarray, int sarray_len)
* condition errors when a query that's scanning a catalog using an MVCC
* snapshot uses one of these functions. The underlying IsVisible functions
* always use an up-to-date snapshot and so might see the object as already
* gone when it's still visible to the transaction snapshot. (There is no race
* condition in the current coding because we don't accept sinval messages
* between the SearchSysCacheExists test and the subsequent lookup.)
* gone when it's still visible to the transaction snapshot.
*/
Datum
pg_table_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(oid)))
result = RelationIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(RelationIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_type_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(oid)))
result = TypeIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(TypeIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_function_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(oid)))
result = FunctionIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(FunctionIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_operator_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(OPEROID, ObjectIdGetDatum(oid)))
result = OperatorIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(OperatorIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_opclass_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(CLAOID, ObjectIdGetDatum(oid)))
result = OpclassIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(OpclassIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_opfamily_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(OPFAMILYOID, ObjectIdGetDatum(oid)))
result = OpfamilyIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(OpfamilyIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_collation_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(COLLOID, ObjectIdGetDatum(oid)))
result = CollationIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(CollationIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_conversion_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(CONVOID, ObjectIdGetDatum(oid)))
result = ConversionIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(ConversionIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_statistics_obj_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(STATEXTOID, ObjectIdGetDatum(oid)))
result = StatisticsObjIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(StatisticsObjIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_ts_parser_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(TSPARSEROID, ObjectIdGetDatum(oid)))
result = TSParserIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(TSParserIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_ts_dict_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(TSDICTOID, ObjectIdGetDatum(oid)))
result = TSDictionaryIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(TSDictionaryIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_ts_template_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(TSTEMPLATEOID, ObjectIdGetDatum(oid)))
result = TSTemplateIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(TSTemplateIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum
pg_ts_config_is_visible(PG_FUNCTION_ARGS)
{
Oid oid = PG_GETARG_OID(0);
bool result;
bool is_missing = false;
if (!SearchSysCacheExists1(TSCONFIGOID, ObjectIdGetDatum(oid)))
result = TSConfigIsVisibleExt(oid, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(TSConfigIsVisible(oid));
PG_RETURN_BOOL(result);
}
Datum

View File

@ -1915,14 +1915,15 @@ has_table_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_table_priv_string(priv_type_text);
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
PG_RETURN_NULL();
aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -1941,14 +1942,15 @@ has_table_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_table_priv_string(priv_type_text);
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
PG_RETURN_NULL();
aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -1989,13 +1991,14 @@ has_table_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_table_priv_string(priv_type_text);
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
PG_RETURN_NULL();
aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2134,6 +2137,7 @@ has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
AclMode mode;
AclResult aclresult;
char relkind;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_sequence_priv_string(priv_type_text);
@ -2146,7 +2150,10 @@ has_sequence_privilege_name_id(PG_FUNCTION_ARGS)
errmsg("\"%s\" is not a sequence",
get_rel_name(sequenceoid))));
aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2166,6 +2173,7 @@ has_sequence_privilege_id(PG_FUNCTION_ARGS)
AclMode mode;
AclResult aclresult;
char relkind;
bool is_missing = false;
roleid = GetUserId();
mode = convert_sequence_priv_string(priv_type_text);
@ -2178,7 +2186,10 @@ has_sequence_privilege_id(PG_FUNCTION_ARGS)
errmsg("\"%s\" is not a sequence",
get_rel_name(sequenceoid))));
aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2225,6 +2236,7 @@ has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
AclMode mode;
AclResult aclresult;
char relkind;
bool is_missing = false;
mode = convert_sequence_priv_string(priv_type_text);
relkind = get_rel_relkind(sequenceoid);
@ -2236,7 +2248,10 @@ has_sequence_privilege_id_id(PG_FUNCTION_ARGS)
errmsg("\"%s\" is not a sequence",
get_rel_name(sequenceoid))));
aclresult = pg_class_aclcheck(sequenceoid, roleid, mode);
aclresult = pg_class_aclcheck_ext(sequenceoid, roleid, mode, &is_missing);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2345,18 +2360,22 @@ has_any_column_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_column_priv_string(priv_type_text);
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
PG_RETURN_NULL();
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
{
if (is_missing)
PG_RETURN_NULL();
aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
ACLMASK_ANY, &is_missing);
if (is_missing)
PG_RETURN_NULL();
}
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2375,18 +2394,22 @@ has_any_column_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_column_priv_string(priv_type_text);
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
PG_RETURN_NULL();
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
{
if (is_missing)
PG_RETURN_NULL();
aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
ACLMASK_ANY, &is_missing);
if (is_missing)
PG_RETURN_NULL();
}
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2431,17 +2454,21 @@ has_any_column_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_column_priv_string(priv_type_text);
if (!SearchSysCacheExists1(RELOID, ObjectIdGetDatum(tableoid)))
PG_RETURN_NULL();
/* First check at table level, then examine each column if needed */
aclresult = pg_class_aclcheck(tableoid, roleid, mode);
aclresult = pg_class_aclcheck_ext(tableoid, roleid, mode, &is_missing);
if (aclresult != ACLCHECK_OK)
aclresult = pg_attribute_aclcheck_all(tableoid, roleid, mode,
ACLMASK_ANY);
{
if (is_missing)
PG_RETURN_NULL();
aclresult = pg_attribute_aclcheck_all_ext(tableoid, roleid, mode,
ACLMASK_ANY, &is_missing);
if (is_missing)
PG_RETURN_NULL();
}
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -2981,14 +3008,17 @@ has_database_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_database_priv_string(priv_type_text);
if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3007,14 +3037,17 @@ has_database_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_database_priv_string(priv_type_text);
if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3055,13 +3088,16 @@ has_database_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_database_priv_string(priv_type_text);
if (!SearchSysCacheExists1(DATABASEOID, ObjectIdGetDatum(databaseoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(DatabaseRelationId, databaseoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(DatabaseRelationId, databaseoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3178,14 +3214,17 @@ has_foreign_data_wrapper_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3204,14 +3243,17 @@ has_foreign_data_wrapper_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3252,13 +3294,16 @@ has_foreign_data_wrapper_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_foreign_data_wrapper_priv_string(priv_type_text);
if (!SearchSysCacheExists1(FOREIGNDATAWRAPPEROID, ObjectIdGetDatum(fdwid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ForeignDataWrapperRelationId, fdwid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ForeignDataWrapperRelationId, fdwid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3369,14 +3414,17 @@ has_function_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_function_priv_string(priv_type_text);
if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3395,14 +3443,17 @@ has_function_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_function_priv_string(priv_type_text);
if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3443,13 +3494,16 @@ has_function_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_function_priv_string(priv_type_text);
if (!SearchSysCacheExists1(PROCOID, ObjectIdGetDatum(functionoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ProcedureRelationId, functionoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ProcedureRelationId, functionoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3569,14 +3623,17 @@ has_language_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_language_priv_string(priv_type_text);
if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3595,14 +3652,17 @@ has_language_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_language_priv_string(priv_type_text);
if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3643,13 +3703,16 @@ has_language_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_language_priv_string(priv_type_text);
if (!SearchSysCacheExists1(LANGOID, ObjectIdGetDatum(languageoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(LanguageRelationId, languageoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(LanguageRelationId, languageoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3760,14 +3823,17 @@ has_schema_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_schema_priv_string(priv_type_text);
if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3786,14 +3852,17 @@ has_schema_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_schema_priv_string(priv_type_text);
if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3834,13 +3903,16 @@ has_schema_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_schema_priv_string(priv_type_text);
if (!SearchSysCacheExists1(NAMESPACEOID, ObjectIdGetDatum(schemaoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(NamespaceRelationId, schemaoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(NamespaceRelationId, schemaoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3953,14 +4025,17 @@ has_server_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_server_priv_string(priv_type_text);
if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -3979,14 +4054,17 @@ has_server_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_server_priv_string(priv_type_text);
if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4027,13 +4105,16 @@ has_server_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_server_priv_string(priv_type_text);
if (!SearchSysCacheExists1(FOREIGNSERVEROID, ObjectIdGetDatum(serverid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(ForeignServerRelationId, serverid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(ForeignServerRelationId, serverid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4144,14 +4225,17 @@ has_tablespace_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_tablespace_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4170,14 +4254,17 @@ has_tablespace_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_tablespace_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4218,13 +4305,16 @@ has_tablespace_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_tablespace_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TABLESPACEOID, ObjectIdGetDatum(tablespaceoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(TableSpaceRelationId, tablespaceoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(TableSpaceRelationId, tablespaceoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4334,14 +4424,17 @@ has_type_privilege_name_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = get_role_oid_or_public(NameStr(*username));
mode = convert_type_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4360,14 +4453,17 @@ has_type_privilege_id(PG_FUNCTION_ARGS)
Oid roleid;
AclMode mode;
AclResult aclresult;
bool is_missing = false;
roleid = GetUserId();
mode = convert_type_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}
@ -4408,13 +4504,16 @@ has_type_privilege_id_id(PG_FUNCTION_ARGS)
text *priv_type_text = PG_GETARG_TEXT_PP(2);
AclMode mode;
AclResult aclresult;
bool is_missing = false;
mode = convert_type_priv_string(priv_type_text);
if (!SearchSysCacheExists1(TYPEOID, ObjectIdGetDatum(typeoid)))
PG_RETURN_NULL();
aclresult = object_aclcheck_ext(TypeRelationId, typeoid,
roleid, mode,
&is_missing);
aclresult = object_aclcheck(TypeRelationId, typeoid, roleid, mode);
if (is_missing)
PG_RETURN_NULL();
PG_RETURN_BOOL(aclresult == ACLCHECK_OK);
}

View File

@ -7837,14 +7837,23 @@ clear_socket_set(socket_set *sa)
static void
add_socket_to_set(socket_set *sa, int fd, int idx)
{
/* See connect_slot() for background on this code. */
#ifdef WIN32
if (sa->fds.fd_count + 1 >= FD_SETSIZE)
{
pg_log_error("too many concurrent database clients for this platform: %d",
sa->fds.fd_count + 1);
exit(1);
}
#else
if (fd < 0 || fd >= FD_SETSIZE)
{
/*
* Doing a hard exit here is a bit grotty, but it doesn't seem worth
* complicating the API to make it less grotty.
*/
pg_fatal("too many client connections for select()");
pg_log_error("socket file descriptor out of range for select(): %d",
fd);
pg_log_error_hint("Try fewer concurrent database clients.");
exit(1);
}
#endif
FD_SET(fd, &sa->fds);
if (fd > sa->maxfd)
sa->maxfd = fd;

View File

@ -295,8 +295,41 @@ connect_slot(ParallelSlotArray *sa, int slotno, const char *dbname)
slot->connection = connectDatabase(sa->cparams, sa->progname, sa->echo, false, true);
sa->cparams->override_dbname = old_override;
if (PQsocket(slot->connection) >= FD_SETSIZE)
pg_fatal("too many jobs for this platform");
/*
* POSIX defines FD_SETSIZE as the highest file descriptor acceptable to
* FD_SET() and allied macros. Windows defines it as a ceiling on the
* count of file descriptors in the set, not a ceiling on the value of
* each file descriptor; see
* https://learn.microsoft.com/en-us/windows/win32/api/winsock2/nf-winsock2-select
* and
* https://learn.microsoft.com/en-us/windows/win32/api/winsock/ns-winsock-fd_set.
* We can't ignore that, because Windows starts file descriptors at a
* higher value, delays reuse, and skips values. With less than ten
* concurrent file descriptors, opened and closed rapidly, one can reach
* file descriptor 1024.
*
* Doing a hard exit here is a bit grotty, but it doesn't seem worth
* complicating the API to make it less grotty.
*/
#ifdef WIN32
if (slotno >= FD_SETSIZE)
{
pg_log_error("too many jobs for this platform: %d", slotno);
exit(1);
}
#else
{
int fd = PQsocket(slot->connection);
if (fd >= FD_SETSIZE)
{
pg_log_error("socket file descriptor out of range for select(): %d",
fd);
pg_log_error_hint("Try fewer jobs.");
exit(1);
}
}
#endif
/* Setup the connection using the supplied command, if any. */
if (sa->initcmd)

View File

@ -57,6 +57,6 @@
*/
/* yyyymmddN */
#define CATALOG_VERSION_NO 202310131
#define CATALOG_VERSION_NO 202310141
#endif

View File

@ -122,7 +122,7 @@ extern Oid ConversionGetConid(const char *conname);
extern bool ConversionIsVisible(Oid conid);
extern Oid get_statistics_object_oid(List *names, bool missing_ok);
extern bool StatisticsObjIsVisible(Oid relid);
extern bool StatisticsObjIsVisible(Oid stxid);
extern Oid get_ts_parser_oid(List *names, bool missing_ok);
extern bool TSParserIsVisible(Oid prsId);

View File

@ -172,8 +172,6 @@
{ amprocfamily => 'btree/interval_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '3',
amproc => 'in_range(interval,interval,interval,bool,bool)' },
{ amprocfamily => 'btree/interval_ops', amproclefttype => 'interval',
amprocrighttype => 'interval', amprocnum => '4', amproc => 'btequalimage' },
{ amprocfamily => 'btree/macaddr_ops', amproclefttype => 'macaddr',
amprocrighttype => 'macaddr', amprocnum => '1', amproc => 'macaddr_cmp' },
{ amprocfamily => 'btree/macaddr_ops', amproclefttype => 'macaddr',

View File

@ -50,7 +50,7 @@
opfmethod => 'btree', opfname => 'integer_ops' },
{ oid => '1977',
opfmethod => 'hash', opfname => 'integer_ops' },
{ oid => '1982',
{ oid => '1982', oid_symbol => 'INTERVAL_BTREE_FAM_OID',
opfmethod => 'btree', opfname => 'interval_ops' },
{ oid => '1983',
opfmethod => 'hash', opfname => 'interval_ops' },

View File

@ -239,8 +239,12 @@ extern void RemoveRoleFromObjectACL(Oid roleid, Oid classid, Oid objid);
extern AclMode pg_class_aclmask(Oid table_oid, Oid roleid,
AclMode mask, AclMaskHow how);
/* generic function */
extern AclResult object_aclcheck(Oid classid, Oid objectid, Oid roleid, AclMode mode);
/* generic functions */
extern AclResult object_aclcheck(Oid classid, Oid objectid,
Oid roleid, AclMode mode);
extern AclResult object_aclcheck_ext(Oid classid, Oid objectid,
Oid roleid, AclMode mode,
bool *is_missing);
/* special cases */
extern AclResult pg_attribute_aclcheck(Oid table_oid, AttrNumber attnum,
@ -250,6 +254,9 @@ extern AclResult pg_attribute_aclcheck_ext(Oid table_oid, AttrNumber attnum,
bool *is_missing);
extern AclResult pg_attribute_aclcheck_all(Oid table_oid, Oid roleid,
AclMode mode, AclMaskHow how);
extern AclResult pg_attribute_aclcheck_all_ext(Oid table_oid, Oid roleid,
AclMode mode, AclMaskHow how,
bool *is_missing);
extern AclResult pg_class_aclcheck(Oid table_oid, Oid roleid, AclMode mode);
extern AclResult pg_class_aclcheck_ext(Oid table_oid, Oid roleid,
AclMode mode, bool *is_missing);

View File

@ -2208,6 +2208,7 @@ ORDER BY 1, 2, 3;
| array_ops | array_ops | anyarray
| float_ops | float4_ops | real
| float_ops | float8_ops | double precision
| interval_ops | interval_ops | interval
| jsonb_ops | jsonb_ops | jsonb
| multirange_ops | multirange_ops | anymultirange
| numeric_ops | numeric_ops | numeric
@ -2216,7 +2217,7 @@ ORDER BY 1, 2, 3;
| record_ops | record_ops | record
| tsquery_ops | tsquery_ops | tsquery
| tsvector_ops | tsvector_ops | tsvector
(15 rows)
(16 rows)
-- **************** pg_index ****************
-- Look for illegal values in pg_index fields.