Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 4eada20

Browse files
committed
Add has_largeobject_privilege function.
This function checks whether a user has specific privileges on a large object, identified by OID. The user can be provided by name, OID, or default to the current user. If the specified large object doesn't exist, the function returns NULL. It raises an error for a non-existent user name. This behavior is basically consistent with other privilege inquiry functions like has_table_privilege. Bump catalog version. Author: Yugo Nagata Reviewed-by: Fujii Masao Discussion: https://postgr.es/m/20240702163444.ab586f6075e502eb84f11b1a@sranhm.sraoss.co.jp
1 parent 412229d commit 4eada20

File tree

6 files changed

+376
-1
lines changed

6 files changed

+376
-1
lines changed

doc/src/sgml/func.sgml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25117,6 +25117,24 @@ SELECT has_function_privilege('joeuser', 'myfunc(int, text)', 'execute');
2511725117
</para></entry>
2511825118
</row>
2511925119

25120+
<row>
25121+
<entry role="func_table_entry"><para role="func_signature">
25122+
<indexterm>
25123+
<primary>has_largeobject_privilege</primary>
25124+
</indexterm>
25125+
<function>has_largeobject_privilege</function> (
25126+
<optional> <parameter>user</parameter> <type>name</type> or <type>oid</type>, </optional>
25127+
<parameter>largeobject</parameter> <type>oid</type>,
25128+
<parameter>privilege</parameter> <type>text</type> )
25129+
<returnvalue>boolean</returnvalue>
25130+
</para>
25131+
<para>
25132+
Does user have privilege for large object?
25133+
Allowable privilege types are
25134+
<literal>SELECT</literal> and <literal>UPDATE</literal>.
25135+
</para></entry>
25136+
</row>
25137+
2512025138
<row>
2512125139
<entry role="func_table_entry"><para role="func_signature">
2512225140
<indexterm>

src/backend/utils/adt/acl.c

Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "catalog/pg_foreign_data_wrapper.h"
2727
#include "catalog/pg_foreign_server.h"
2828
#include "catalog/pg_language.h"
29+
#include "catalog/pg_largeobject.h"
2930
#include "catalog/pg_namespace.h"
3031
#include "catalog/pg_proc.h"
3132
#include "catalog/pg_tablespace.h"
@@ -39,13 +40,15 @@
3940
#include "lib/bloomfilter.h"
4041
#include "lib/qunique.h"
4142
#include "miscadmin.h"
43+
#include "storage/large_object.h"
4244
#include "utils/acl.h"
4345
#include "utils/array.h"
4446
#include "utils/builtins.h"
4547
#include "utils/catcache.h"
4648
#include "utils/inval.h"
4749
#include "utils/lsyscache.h"
4850
#include "utils/memutils.h"
51+
#include "utils/snapmgr.h"
4952
#include "utils/syscache.h"
5053
#include "utils/varlena.h"
5154

@@ -124,6 +127,7 @@ static AclMode convert_tablespace_priv_string(text *priv_type_text);
124127
static Oid convert_type_name(text *typename);
125128
static AclMode convert_type_priv_string(text *priv_type_text);
126129
static AclMode convert_parameter_priv_string(text *priv_text);
130+
static AclMode convert_largeobject_priv_string(text *priv_text);
127131
static AclMode convert_role_priv_string(text *priv_type_text);
128132
static AclResult pg_role_aclcheck(Oid role_oid, Oid roleid, AclMode mode);
129133

@@ -4663,6 +4667,142 @@ convert_parameter_priv_string(text *priv_text)
46634667
return convert_any_priv_string(priv_text, parameter_priv_map);
46644668
}
46654669

4670+
/*
4671+
* has_largeobject_privilege variants
4672+
* These are all named "has_largeobject_privilege" at the SQL level.
4673+
* They take various combinations of large object OID with
4674+
* user name, user OID, or implicit user = current_user.
4675+
*
4676+
* The result is a boolean value: true if user has the indicated
4677+
* privilege, false if not, or NULL if object doesn't exist.
4678+
*/
4679+
4680+
/*
4681+
* has_lo_priv_byid
4682+
*
4683+
* Helper function to check user privileges on a large object given the
4684+
* role by Oid, large object by Oid, and privileges as AclMode.
4685+
*/
4686+
static bool
4687+
has_lo_priv_byid(Oid roleid, Oid lobjId, AclMode priv, bool *is_missing)
4688+
{
4689+
Snapshot snapshot = NULL;
4690+
AclResult aclresult;
4691+
4692+
if (priv & ACL_UPDATE)
4693+
snapshot = NULL;
4694+
else
4695+
snapshot = GetActiveSnapshot();
4696+
4697+
if (!LargeObjectExistsWithSnapshot(lobjId, snapshot))
4698+
{
4699+
Assert(is_missing != NULL);
4700+
*is_missing = true;
4701+
return false;
4702+
}
4703+
4704+
if (lo_compat_privileges)
4705+
return true;
4706+
4707+
aclresult = pg_largeobject_aclcheck_snapshot(lobjId,
4708+
roleid,
4709+
priv,
4710+
snapshot);
4711+
return aclresult == ACLCHECK_OK;
4712+
}
4713+
4714+
/*
4715+
* has_largeobject_privilege_name_id
4716+
* Check user privileges on a large object given
4717+
* name username, large object oid, and text priv name.
4718+
*/
4719+
Datum
4720+
has_largeobject_privilege_name_id(PG_FUNCTION_ARGS)
4721+
{
4722+
Name username = PG_GETARG_NAME(0);
4723+
Oid roleid = get_role_oid_or_public(NameStr(*username));
4724+
Oid lobjId = PG_GETARG_OID(1);
4725+
text *priv_type_text = PG_GETARG_TEXT_PP(2);
4726+
AclMode mode;
4727+
bool is_missing = false;
4728+
bool result;
4729+
4730+
mode = convert_largeobject_priv_string(priv_type_text);
4731+
result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4732+
4733+
if (is_missing)
4734+
PG_RETURN_NULL();
4735+
4736+
PG_RETURN_BOOL(result);
4737+
}
4738+
4739+
/*
4740+
* has_largeobject_privilege_id
4741+
* Check user privileges on a large object given
4742+
* large object oid, and text priv name.
4743+
* current_user is assumed
4744+
*/
4745+
Datum
4746+
has_largeobject_privilege_id(PG_FUNCTION_ARGS)
4747+
{
4748+
Oid lobjId = PG_GETARG_OID(0);
4749+
Oid roleid = GetUserId();
4750+
text *priv_type_text = PG_GETARG_TEXT_PP(1);
4751+
AclMode mode;
4752+
bool is_missing = false;
4753+
bool result;
4754+
4755+
mode = convert_largeobject_priv_string(priv_type_text);
4756+
result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4757+
4758+
if (is_missing)
4759+
PG_RETURN_NULL();
4760+
4761+
PG_RETURN_BOOL(result);
4762+
}
4763+
4764+
/*
4765+
* has_largeobject_privilege_id_id
4766+
* Check user privileges on a large object given
4767+
* roleid, large object oid, and text priv name.
4768+
*/
4769+
Datum
4770+
has_largeobject_privilege_id_id(PG_FUNCTION_ARGS)
4771+
{
4772+
Oid roleid = PG_GETARG_OID(0);
4773+
Oid lobjId = PG_GETARG_OID(1);
4774+
text *priv_type_text = PG_GETARG_TEXT_PP(2);
4775+
AclMode mode;
4776+
bool is_missing = false;
4777+
bool result;
4778+
4779+
mode = convert_largeobject_priv_string(priv_type_text);
4780+
result = has_lo_priv_byid(roleid, lobjId, mode, &is_missing);
4781+
4782+
if (is_missing)
4783+
PG_RETURN_NULL();
4784+
4785+
PG_RETURN_BOOL(result);
4786+
}
4787+
4788+
/*
4789+
* convert_largeobject_priv_string
4790+
* Convert text string to AclMode value.
4791+
*/
4792+
static AclMode
4793+
convert_largeobject_priv_string(text *priv_type_text)
4794+
{
4795+
static const priv_map largeobject_priv_map[] = {
4796+
{"SELECT", ACL_SELECT},
4797+
{"SELECT WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_SELECT)},
4798+
{"UPDATE", ACL_UPDATE},
4799+
{"UPDATE WITH GRANT OPTION", ACL_GRANT_OPTION_FOR(ACL_UPDATE)},
4800+
{NULL, 0}
4801+
};
4802+
4803+
return convert_any_priv_string(priv_type_text, largeobject_priv_map);
4804+
}
4805+
46664806
/*
46674807
* pg_has_role variants
46684808
* These are all named "pg_has_role" at the SQL level.

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,6 @@
5757
*/
5858

5959
/* yyyymmddN */
60-
#define CATALOG_VERSION_NO 202409121
60+
#define CATALOG_VERSION_NO 202409122
6161

6262
#endif

src/include/catalog/pg_proc.dat

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5369,6 +5369,19 @@
53695369
prorettype => 'bool', proargtypes => 'oid text',
53705370
prosrc => 'has_any_column_privilege_id' },
53715371

5372+
{ oid => '4551', descr => 'user privilege on large objct by username, large object oid',
5373+
proname => 'has_largeobject_privilege', procost => '10', provolatile => 's',
5374+
prorettype => 'bool', proargtypes => 'name oid text',
5375+
prosrc => 'has_largeobject_privilege_name_id' },
5376+
{ oid => '4552', descr => 'current privilege on large objct by large object oid',
5377+
proname => 'has_largeobject_privilege', procost => '10', provolatile => 's',
5378+
prorettype => 'bool', proargtypes => 'oid text',
5379+
prosrc => 'has_largeobject_privilege_id' },
5380+
{ oid => '4553', descr => 'user privilege on large objct by user oid, large object oid',
5381+
proname => 'has_largeobject_privilege', procost => '10', provolatile => 's',
5382+
prorettype => 'bool', proargtypes => 'oid oid text',
5383+
prosrc => 'has_largeobject_privilege_id_id' },
5384+
53725385
{ oid => '3355', descr => 'I/O',
53735386
proname => 'pg_ndistinct_in', prorettype => 'pg_ndistinct',
53745387
proargtypes => 'cstring', prosrc => 'pg_ndistinct_in' },

0 commit comments

Comments
 (0)