Add new OID alias type regrole

The new type has the scope of whole the database cluster so it doesn't
behave the same as the existing OID alias types which have database
scope,
concerning object dependency. To avoid confusion constants of the new
type are prohibited from appearing where dependencies are made involving
it.

Also, add a note to the docs about possible MVCC violation and
optimization issues, which are general over the all reg* types.

Kyotaro Horiguchi
This commit is contained in:
Andrew Dunstan 2015-05-09 13:06:49 -04:00
parent 0cf56f14dd
commit 0c90f6769d
20 changed files with 235 additions and 31 deletions

View File

@ -79,7 +79,7 @@ insert_username(PG_FUNCTION_ARGS)
args[0], relname)));
/* create fields containing name */
newval = CStringGetTextDatum(GetUserNameFromId(GetUserId()));
newval = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false));
/* construct new tuple */
rettuple = SPI_modifytuple(rel, rettuple, 1, &attnum, &newval, NULL);

View File

@ -174,7 +174,7 @@ timetravel(PG_FUNCTION_ARGS)
}
/* create fields containing name */
newuser = CStringGetTextDatum(GetUserNameFromId(GetUserId()));
newuser = CStringGetTextDatum(GetUserNameFromId(GetUserId(), false));
nulltext = (Datum) NULL;

View File

@ -4321,8 +4321,9 @@ SET xmloption TO { DOCUMENT | CONTENT };
an object identifier. There are also several alias types for
<type>oid</>: <type>regproc</>, <type>regprocedure</>,
<type>regoper</>, <type>regoperator</>, <type>regclass</>,
<type>regtype</>, <type>regconfig</>, and <type>regdictionary</>.
<xref linkend="datatype-oid-table"> shows an overview.
<type>regtype</>, <type>regrole</>, <type>regconfig</>, and
<type>regdictionary</>. <xref linkend="datatype-oid-table"> shows
an overview.
</para>
<para>
@ -4430,6 +4431,13 @@ SELECT * FROM pg_attribute
<entry><literal>integer</></entry>
</row>
<row>
<entry><type>regrole</></entry>
<entry><structname>pg_authid</></entry>
<entry>role name</entry>
<entry><literal>smithee</></entry>
</row>
<row>
<entry><type>regconfig</></entry>
<entry><structname>pg_ts_config</></entry>
@ -4448,7 +4456,8 @@ SELECT * FROM pg_attribute
</table>
<para>
All of the OID alias types accept schema-qualified names, and will
All of the OID alias types for objects grouped by namespace accept
schema-qualified names, and will
display schema-qualified names on output if the object would not
be found in the current search path without being qualified.
The <type>regproc</> and <type>regoper</> alias types will only
@ -4460,7 +4469,7 @@ SELECT * FROM pg_attribute
</para>
<para>
An additional property of the OID alias types is the creation of
An additional property of most of the OID alias types is the creation of
dependencies. If a
constant of one of these types appears in a stored expression
(such as a column default expression or view), it creates a dependency
@ -4470,8 +4479,18 @@ SELECT * FROM pg_attribute
understands that the default expression depends on the sequence
<literal>my_seq</>; the system will not let the sequence be dropped
without first removing the default expression.
<type>regrole</> is the only exception for the property. Constants of this
type are not allowed in such expressions.
</para>
<note>
<para>
The OID alias types do not completely follow transaction isolation
rules. The planner also treats them as simple constants, which may
result in sub-optimal planning.
</para>
</note>
<para>
Another identifier type used by the system is <type>xid</>, or transaction
(abbreviated <abbrev>xact</>) identifier. This is the data type of the system columns

View File

@ -113,6 +113,8 @@ static const struct typinfo TypInfo[] = {
F_REGPROCIN, F_REGPROCOUT},
{"regtype", REGTYPEOID, 0, 4, true, 'i', 'p', InvalidOid,
F_REGTYPEIN, F_REGTYPEOUT},
{"regrole", REGROLEOID, 0, 4, true, 'i', 'p', InvalidOid,
F_REGROLEIN, F_REGROLEOUT},
{"text", TEXTOID, 0, -1, false, 'i', 'x', DEFAULT_COLLATION_OID,
F_TEXTIN, F_TEXTOUT},
{"oid", OIDOID, 0, 4, true, 'i', 'p', InvalidOid,

View File

@ -1602,6 +1602,16 @@ find_expr_references_walker(Node *node,
add_object_address(OCLASS_TSDICT, objoid, 0,
context->addrs);
break;
/*
* Dependencies for regrole should be shared among all
* databases, so explicitly inhibit to have dependencies.
*/
case REGROLEOID:
ereport(ERROR,
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("constant of the type \'regrole\' cannot be used here")));
break;
}
}
return false;

View File

@ -2818,7 +2818,7 @@ getObjectDescription(const ObjectAddress *object)
case OCLASS_ROLE:
{
appendStringInfo(&buffer, _("role %s"),
GetUserNameFromId(object->objectId));
GetUserNameFromId(object->objectId, false));
break;
}
@ -2884,7 +2884,7 @@ getObjectDescription(const ObjectAddress *object)
ReleaseSysCache(tup);
if (OidIsValid(useid))
usename = GetUserNameFromId(useid);
usename = GetUserNameFromId(useid, false);
else
usename = "public";
@ -2924,28 +2924,28 @@ getObjectDescription(const ObjectAddress *object)
case DEFACLOBJ_RELATION:
appendStringInfo(&buffer,
_("default privileges on new relations belonging to role %s"),
GetUserNameFromId(defacl->defaclrole));
GetUserNameFromId(defacl->defaclrole, false));
break;
case DEFACLOBJ_SEQUENCE:
appendStringInfo(&buffer,
_("default privileges on new sequences belonging to role %s"),
GetUserNameFromId(defacl->defaclrole));
GetUserNameFromId(defacl->defaclrole, false));
break;
case DEFACLOBJ_FUNCTION:
appendStringInfo(&buffer,
_("default privileges on new functions belonging to role %s"),
GetUserNameFromId(defacl->defaclrole));
GetUserNameFromId(defacl->defaclrole, false));
break;
case DEFACLOBJ_TYPE:
appendStringInfo(&buffer,
_("default privileges on new types belonging to role %s"),
GetUserNameFromId(defacl->defaclrole));
GetUserNameFromId(defacl->defaclrole, false));
break;
default:
/* shouldn't get here */
appendStringInfo(&buffer,
_("default privileges belonging to role %s"),
GetUserNameFromId(defacl->defaclrole));
GetUserNameFromId(defacl->defaclrole, false));
break;
}
@ -4214,7 +4214,7 @@ getObjectIdentityParts(const ObjectAddress *object,
{
char *username;
username = GetUserNameFromId(object->objectId);
username = GetUserNameFromId(object->objectId, false);
if (objname)
*objname = list_make1(username);
appendStringInfoString(&buffer,
@ -4295,7 +4295,7 @@ getObjectIdentityParts(const ObjectAddress *object,
ReleaseSysCache(tup);
if (OidIsValid(useid))
usename = GetUserNameFromId(useid);
usename = GetUserNameFromId(useid, false);
else
usename = "public";
@ -4339,7 +4339,7 @@ getObjectIdentityParts(const ObjectAddress *object,
defacl = (Form_pg_default_acl) GETSTRUCT(tup);
username = GetUserNameFromId(defacl->defaclrole);
username = GetUserNameFromId(defacl->defaclrole, false);
appendStringInfo(&buffer,
"for role %s",
quote_identifier(username));

View File

@ -4878,7 +4878,7 @@ check_is_member_of_role(Oid member, Oid role)
ereport(ERROR,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be member of role \"%s\"",
GetUserNameFromId(role))));
GetUserNameFromId(role, false))));
}
/*

View File

@ -263,13 +263,13 @@ namestrcmp(Name name, const char *str)
Datum
current_user(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId()))));
PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetUserId(), false))));
}
Datum
session_user(PG_FUNCTION_ARGS)
{
PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId()))));
PG_RETURN_DATUM(DirectFunctionCall1(namein, CStringGetDatum(GetUserNameFromId(GetSessionUserId(), false))));
}

View File

@ -40,6 +40,7 @@
#include "utils/lsyscache.h"
#include "utils/syscache.h"
#include "utils/tqual.h"
#include "utils/acl.h"
static char *format_operator_internal(Oid operator_oid, bool force_qualify);
static char *format_procedure_internal(Oid procedure_oid, bool force_qualify);
@ -1553,6 +1554,109 @@ regdictionarysend(PG_FUNCTION_ARGS)
return oidsend(fcinfo);
}
/*
* regrolein - converts "rolename" to role OID
*
* We also accept a numeric OID, for symmetry with the output routine.
*
* '-' signifies unknown (OID 0). In all other cases, the input must
* match an existing pg_authid entry.
*
* This function is not needed in bootstrap mode, so we don't worry about
* making it work then.
*/
Datum
regrolein(PG_FUNCTION_ARGS)
{
char *role_name_or_oid = PG_GETARG_CSTRING(0);
Oid result;
/* '-' ? */
if (strcmp(role_name_or_oid, "-") == 0)
PG_RETURN_OID(InvalidOid);
/* Numeric OID? */
if (role_name_or_oid[0] >= '0' &&
role_name_or_oid[0] <= '9' &&
strspn(role_name_or_oid, "0123456789") == strlen(role_name_or_oid))
{
result = DatumGetObjectId(DirectFunctionCall1(oidin,
CStringGetDatum(role_name_or_oid)));
PG_RETURN_OID(result);
}
/* Normal case: see if the name matches any pg_authid entry. */
result = get_role_oid(role_name_or_oid, false);
PG_RETURN_OID(result);
}
/*
* to_regrole - converts "rolename" to role OID
*
* If the name is not found, we return NULL.
*/
Datum
to_regrole(PG_FUNCTION_ARGS)
{
char *role_name = PG_GETARG_CSTRING(0);
Oid result;
result = get_role_oid(role_name, true);
if (OidIsValid(result))
PG_RETURN_OID(result);
else
PG_RETURN_NULL();
}
/*
* regroleout - converts role OID to "role_name"
*/
Datum
regroleout(PG_FUNCTION_ARGS)
{
Oid roleoid = PG_GETARG_OID(0);
char *result;
if (roleoid == InvalidOid)
{
result = pstrdup("-");
PG_RETURN_CSTRING(result);
}
result = GetUserNameFromId(roleoid, true);
if (!result)
{
/* If OID doesn't match any role, return it numerically */
result = (char *) palloc(NAMEDATALEN);
snprintf(result, NAMEDATALEN, "%u", roleoid);
}
PG_RETURN_CSTRING(result);
}
/*
* regrolerecv - converts external binary format to regrole
*/
Datum
regrolerecv(PG_FUNCTION_ARGS)
{
/* Exactly the same as oidrecv, so share code */
return oidrecv(fcinfo);
}
/*
* regrolesend - converts regrole to binary format
*/
Datum
regrolesend(PG_FUNCTION_ARGS)
{
/* Exactly the same as oidsend, so share code */
return oidsend(fcinfo);
}
/*
* text_regclass: convert text to regclass

View File

@ -3619,6 +3619,7 @@ convert_to_scalar(Datum value, Oid valuetypid, double *scaledvalue,
case REGTYPEOID:
case REGCONFIGOID:
case REGDICTIONARYOID:
case REGROLEOID:
*scaledvalue = convert_numeric_to_scalar(value, valuetypid);
*scaledlobound = convert_numeric_to_scalar(lobound, boundstypid);
*scaledhibound = convert_numeric_to_scalar(hibound, boundstypid);
@ -3724,6 +3725,7 @@ convert_numeric_to_scalar(Datum value, Oid typid)
case REGTYPEOID:
case REGCONFIGOID:
case REGDICTIONARYOID:
case REGROLEOID:
/* we can treat OIDs as integers... */
return (double) DatumGetObjectId(value);
}

View File

@ -150,6 +150,7 @@ GetCCHashEqFuncs(Oid keytype, PGFunction *hashfunc, RegProcedure *eqfunc)
case REGTYPEOID:
case REGCONFIGOID:
case REGDICTIONARYOID:
case REGROLEOID:
*hashfunc = hashoid;
*eqfunc = F_OIDEQ;

View File

@ -648,23 +648,29 @@ SetCurrentRoleId(Oid roleid, bool is_superuser)
/*
* Get user name from user oid
* Get user name from user oid, returns NULL for nonexistent roleid if noerr
* is true.
*/
char *
GetUserNameFromId(Oid roleid)
GetUserNameFromId(Oid roleid, bool noerr)
{
HeapTuple tuple;
char *result;
tuple = SearchSysCache1(AUTHOID, ObjectIdGetDatum(roleid));
if (!HeapTupleIsValid(tuple))
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid role OID: %u", roleid)));
result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
ReleaseSysCache(tuple);
{
if (!noerr)
ereport(ERROR,
(errcode(ERRCODE_UNDEFINED_OBJECT),
errmsg("invalid role OID: %u", roleid)));
result = NULL;
}
else
{
result = pstrdup(NameStr(((Form_pg_authid) GETSTRUCT(tuple))->rolname));
ReleaseSysCache(tuple);
}
return result;
}

View File

@ -210,6 +210,13 @@ DATA(insert ( 3769 20 1288 a f ));
DATA(insert ( 3769 23 0 a b ));
DATA(insert ( 25 2205 1079 i f ));
DATA(insert ( 1043 2205 1079 i f ));
DATA(insert ( 26 4096 0 i b ));
DATA(insert ( 4096 26 0 i b ));
DATA(insert ( 20 4096 1287 i f ));
DATA(insert ( 21 4096 313 i f ));
DATA(insert ( 23 4096 0 i b ));
DATA(insert ( 4096 20 1288 a f ));
DATA(insert ( 4096 23 0 a b ));
/*
* String category

View File

@ -3481,6 +3481,13 @@ DESCR("convert type name to regtype");
DATA(insert OID = 1079 ( regclass PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2205 "25" _null_ _null_ _null_ _null_ _null_ text_regclass _null_ _null_ _null_ ));
DESCR("convert text to regclass");
DATA(insert OID = 4098 ( regrolein PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 4096 "2275" _null_ _null_ _null_ _null_ _null_ regrolein _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 4092 ( regroleout PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2275 "4096" _null_ _null_ _null_ _null_ _null_ regroleout _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 4093 ( to_regrole PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 4096 "2275" _null_ _null_ _null_ _null_ _null_ to_regrole _null_ _null_ _null_ ));
DESCR("convert role name to regrole");
DATA(insert OID = 2246 ( fmgr_internal_validator PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ fmgr_internal_validator _null_ _null_ _null_ ));
DESCR("(internal)");
DATA(insert OID = 2247 ( fmgr_c_validator PGNSP PGUID 12 1 0 0 0 f f f f t f s 1 0 2278 "26" _null_ _null_ _null_ _null_ _null_ fmgr_c_validator _null_ _null_ _null_ ));
@ -3876,6 +3883,11 @@ DATA(insert OID = 2454 ( regtyperecv PGNSP PGUID 12 1 0 0 0 f f f f t f i 1
DESCR("I/O");
DATA(insert OID = 2455 ( regtypesend PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "2206" _null_ _null_ _null_ _null_ _null_ regtypesend _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 4094 ( regrolerecv PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 4096 "2281" _null_ _null_ _null_ _null_ _null_ regrolerecv _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 4095 ( regrolesend PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "4096" _null_ _null_ _null_ _null_ _null_ regrolesend _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 2456 ( bit_recv PGNSP PGUID 12 1 0 0 0 f f f f t f i 3 0 1560 "2281 26 23" _null_ _null_ _null_ _null_ _null_ bit_recv _null_ _null_ _null_ ));
DESCR("I/O");
DATA(insert OID = 2457 ( bit_send PGNSP PGUID 12 1 0 0 0 f f f f t f i 1 0 17 "1560" _null_ _null_ _null_ _null_ _null_ bit_send _null_ _null_ _null_ ));

View File

@ -564,12 +564,17 @@ DATA(insert OID = 2206 ( regtype PGNSP PGUID 4 t b N f t \054 0 0 2211 regty
DESCR("registered type");
#define REGTYPEOID 2206
DATA(insert OID = 4096 ( regrole PGNSP PGUID 4 t b N f t \054 0 0 4097 regrolein regroleout regrolerecv regrolesend - - - i p f 0 -1 0 0 _null_ _null_ _null_ ));
DESCR("registered role");
#define REGROLEOID 4096
DATA(insert OID = 2207 ( _regprocedure PGNSP PGUID -1 f b A f t \054 0 2202 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
DATA(insert OID = 2208 ( _regoper PGNSP PGUID -1 f b A f t \054 0 2203 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
DATA(insert OID = 2209 ( _regoperator PGNSP PGUID -1 f b A f t \054 0 2204 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
DATA(insert OID = 2210 ( _regclass PGNSP PGUID -1 f b A f t \054 0 2205 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
DATA(insert OID = 2211 ( _regtype PGNSP PGUID -1 f b A f t \054 0 2206 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
#define REGTYPEARRAYOID 2211
DATA(insert OID = 4097 ( _regrole PGNSP PGUID -1 f b A f t \054 0 4096 0 array_in array_out array_recv array_send - - array_typanalyze i x f 0 -1 0 0 _null_ _null_ _null_ ));
/* uuid */
DATA(insert OID = 2950 ( uuid PGNSP PGUID 16 f b U f t \054 0 0 2951 uuid_in uuid_out uuid_recv uuid_send - - - c p f 0 -1 0 0 _null_ _null_ _null_ ));

View File

@ -18,7 +18,7 @@
/* Helper for obtaining username for user mapping */
#define MappingUserName(userid) \
(OidIsValid(userid) ? GetUserNameFromId(userid) : "public")
(OidIsValid(userid) ? GetUserNameFromId(userid, false) : "public")
/*

View File

@ -296,7 +296,7 @@ extern void InitStandaloneProcess(const char *argv0);
extern void SetDatabasePath(const char *path);
extern char *GetUserNameFromId(Oid roleid);
extern char *GetUserNameFromId(Oid roleid, bool noerr);
extern Oid GetUserId(void);
extern Oid GetOuterUserId(void);
extern Oid GetSessionUserId(void);

View File

@ -630,6 +630,11 @@ extern Datum regtypeout(PG_FUNCTION_ARGS);
extern Datum regtyperecv(PG_FUNCTION_ARGS);
extern Datum regtypesend(PG_FUNCTION_ARGS);
extern Datum to_regtype(PG_FUNCTION_ARGS);
extern Datum regrolein(PG_FUNCTION_ARGS);
extern Datum regroleout(PG_FUNCTION_ARGS);
extern Datum regrolerecv(PG_FUNCTION_ARGS);
extern Datum regrolesend(PG_FUNCTION_ARGS);
extern Datum to_regrole(PG_FUNCTION_ARGS);
extern Datum regconfigin(PG_FUNCTION_ARGS);
extern Datum regconfigout(PG_FUNCTION_ARGS);
extern Datum regconfigrecv(PG_FUNCTION_ARGS);

View File

@ -2,6 +2,7 @@
-- regproc
--
/* If objects exist, return oids */
CREATE ROLE regtestrole;
-- without schemaname
SELECT regoper('||/');
regoper
@ -39,6 +40,12 @@ SELECT regtype('int4');
integer
(1 row)
SELECT regrole('regtestrole');
regrole
-------------
regtestrole
(1 row)
SELECT to_regoper('||/');
to_regoper
------------
@ -75,6 +82,12 @@ SELECT to_regtype('int4');
integer
(1 row)
SELECT to_regrole('regtestrole');
to_regrole
-------------
regtestrole
(1 row)
-- with schemaname
SELECT regoper('pg_catalog.||/');
regoper
@ -143,10 +156,11 @@ SELECT to_regtype('pg_catalog.int4');
(1 row)
/* If objects don't exist, raise errors. */
DROP ROLE regtestrole;
-- without schemaname
SELECT regoper('||//');
ERROR: operator does not exist: ||//
LINE 3: SELECT regoper('||//');
LINE 1: SELECT regoper('||//');
^
SELECT regoperator('++(int4,int4)');
ERROR: operator does not exist: ++(int4,int4)
@ -168,6 +182,10 @@ SELECT regtype('int3');
ERROR: type "int3" does not exist
LINE 1: SELECT regtype('int3');
^
SELECT regrole('regtestrole');
ERROR: role "regtestrole" does not exist
LINE 1: SELECT regrole('regtestrole');
^
-- with schemaname
SELECT regoper('ng_catalog.||/');
ERROR: schema "ng_catalog" does not exist
@ -231,6 +249,12 @@ SELECT to_regtype('int3');
(1 row)
SELECT to_regrole('regtestrole');
to_regrole
------------
(1 row)
-- with schemaname
SELECT to_regoper('ng_catalog.||/');
to_regoper

View File

@ -4,6 +4,7 @@
/* If objects exist, return oids */
CREATE ROLE regtestrole;
-- without schemaname
SELECT regoper('||/');
@ -12,6 +13,7 @@ SELECT regproc('now');
SELECT regprocedure('abs(numeric)');
SELECT regclass('pg_class');
SELECT regtype('int4');
SELECT regrole('regtestrole');
SELECT to_regoper('||/');
SELECT to_regoperator('+(int4,int4)');
@ -19,6 +21,7 @@ SELECT to_regproc('now');
SELECT to_regprocedure('abs(numeric)');
SELECT to_regclass('pg_class');
SELECT to_regtype('int4');
SELECT to_regrole('regtestrole');
-- with schemaname
@ -37,6 +40,8 @@ SELECT to_regtype('pg_catalog.int4');
/* If objects don't exist, raise errors. */
DROP ROLE regtestrole;
-- without schemaname
SELECT regoper('||//');
@ -45,6 +50,7 @@ SELECT regproc('know');
SELECT regprocedure('absinthe(numeric)');
SELECT regclass('pg_classes');
SELECT regtype('int3');
SELECT regrole('regtestrole');
-- with schemaname
@ -65,6 +71,7 @@ SELECT to_regproc('know');
SELECT to_regprocedure('absinthe(numeric)');
SELECT to_regclass('pg_classes');
SELECT to_regtype('int3');
SELECT to_regrole('regtestrole');
-- with schemaname