From fb1227af67eae5e97795f7e3563673c6e67d2844 Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Mon, 4 Jan 2016 01:03:53 -0500 Subject: [PATCH] Fix regrole and regnamespace types to honor quoting like other reg* types. Aside from any consistency arguments, this is logically necessary because the I/O functions for these types also handle numeric OID values. Without a quoting rule it is impossible to distinguish numeric OIDs from role or namespace names that happen to contain only digits. Also change the to_regrole and to_regnamespace functions to dequote their arguments. While not logically essential, this seems like a good idea since the other to_reg* functions do it. Anyone who really wants raw lookup of an uninterpreted name can fall back on the time-honored solution of (SELECT oid FROM pg_namespace WHERE nspname = whatever). Report and patch by Jim Nasby, reviewed by Michael Paquier --- src/backend/utils/adt/regproc.c | 48 ++++++-- src/test/regress/expected/regproc.out | 169 +++++++++++++++++++------- src/test/regress/sql/regproc.sql | 44 +++++-- 3 files changed, 201 insertions(+), 60 deletions(-) diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 59e5dc8ddd..fc939e641f 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -855,8 +855,7 @@ format_operator_internal(Oid operator_oid, bool force_qualify) /* * Would this oper be found (given the right args) by regoperatorin? - * If not, or if caller explicitly requests it, we need to qualify - * it. + * If not, or if caller explicitly requests it, we need to qualify it. */ if (force_qualify || !OperatorIsVisible(operator_oid)) { @@ -1570,6 +1569,7 @@ regrolein(PG_FUNCTION_ARGS) { char *role_name_or_oid = PG_GETARG_CSTRING(0); Oid result; + List *names; /* '-' ? */ if (strcmp(role_name_or_oid, "-") == 0) @@ -1586,7 +1586,14 @@ regrolein(PG_FUNCTION_ARGS) } /* Normal case: see if the name matches any pg_authid entry. */ - result = get_role_oid(role_name_or_oid, false); + names = stringToQualifiedNameList(role_name_or_oid); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_role_oid(strVal(linitial(names)), false); PG_RETURN_OID(result); } @@ -1601,8 +1608,16 @@ to_regrole(PG_FUNCTION_ARGS) { char *role_name = PG_GETARG_CSTRING(0); Oid result; + List *names; - result = get_role_oid(role_name, true); + names = stringToQualifiedNameList(role_name); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_role_oid(strVal(linitial(names)), true); if (OidIsValid(result)) PG_RETURN_OID(result); @@ -1619,7 +1634,6 @@ regroleout(PG_FUNCTION_ARGS) Oid roleoid = PG_GETARG_OID(0); char *result; - if (roleoid == InvalidOid) { result = pstrdup("-"); @@ -1627,6 +1641,7 @@ regroleout(PG_FUNCTION_ARGS) } result = GetUserNameFromId(roleoid, true); + if (!result) { /* If OID doesn't match any role, return it numerically */ @@ -1668,7 +1683,8 @@ Datum regnamespacein(PG_FUNCTION_ARGS) { char *nsp_name_or_oid = PG_GETARG_CSTRING(0); - Oid result = InvalidOid; + Oid result; + List *names; /* '-' ? */ if (strcmp(nsp_name_or_oid, "-") == 0) @@ -1685,7 +1701,14 @@ regnamespacein(PG_FUNCTION_ARGS) } /* Normal case: see if the name matches any pg_namespace entry. */ - result = get_namespace_oid(nsp_name_or_oid, false); + names = stringToQualifiedNameList(nsp_name_or_oid); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_namespace_oid(strVal(linitial(names)), false); PG_RETURN_OID(result); } @@ -1700,8 +1723,16 @@ to_regnamespace(PG_FUNCTION_ARGS) { char *nsp_name = PG_GETARG_CSTRING(0); Oid result; + List *names; - result = get_namespace_oid(nsp_name, true); + names = stringToQualifiedNameList(nsp_name); + + if (list_length(names) != 1) + ereport(ERROR, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_namespace_oid(strVal(linitial(names)), true); if (OidIsValid(result)) PG_RETURN_OID(result); @@ -1725,6 +1756,7 @@ regnamespaceout(PG_FUNCTION_ARGS) } result = get_namespace_name(nspid); + if (!result) { /* If OID doesn't match any namespace, return it numerically */ diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out index 8c734f413c..91ea94e20f 100644 --- a/src/test/regress/expected/regproc.out +++ b/src/test/regress/expected/regproc.out @@ -40,18 +40,6 @@ SELECT regtype('int4'); integer (1 row) -SELECT regrole('regtestrole'); - regrole -------------- - regtestrole -(1 row) - -SELECT regnamespace('pg_catalog'); - regnamespace --------------- - pg_catalog -(1 row) - SELECT to_regoper('||/'); to_regoper ------------ @@ -88,18 +76,6 @@ SELECT to_regtype('int4'); integer (1 row) -SELECT to_regrole('regtestrole'); - to_regrole -------------- - regtestrole -(1 row) - -SELECT to_regnamespace('pg_catalog'); - to_regnamespace ------------------ - pg_catalog -(1 row) - -- with schemaname SELECT regoper('pg_catalog.||/'); regoper @@ -167,6 +143,55 @@ SELECT to_regtype('pg_catalog.int4'); integer (1 row) +-- schemaname not applicable +SELECT regrole('regtestrole'); + regrole +------------- + regtestrole +(1 row) + +SELECT regrole('"regtestrole"'); + regrole +------------- + regtestrole +(1 row) + +SELECT regnamespace('pg_catalog'); + regnamespace +-------------- + pg_catalog +(1 row) + +SELECT regnamespace('"pg_catalog"'); + regnamespace +-------------- + pg_catalog +(1 row) + +SELECT to_regrole('regtestrole'); + to_regrole +------------- + regtestrole +(1 row) + +SELECT to_regrole('"regtestrole"'); + to_regrole +------------- + regtestrole +(1 row) + +SELECT to_regnamespace('pg_catalog'); + to_regnamespace +----------------- + pg_catalog +(1 row) + +SELECT to_regnamespace('"pg_catalog"'); + to_regnamespace +----------------- + pg_catalog +(1 row) + /* If objects don't exist, raise errors. */ DROP ROLE regtestrole; -- without schemaname @@ -194,14 +219,6 @@ 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'); - ^ -SELECT regnamespace('nonexistent'); -ERROR: schema "nonexistent" does not exist -LINE 1: SELECT regnamespace('nonexistent'); - ^ -- with schemaname SELECT regoper('ng_catalog.||/'); ERROR: schema "ng_catalog" does not exist @@ -227,6 +244,39 @@ SELECT regtype('ng_catalog.int4'); ERROR: schema "ng_catalog" does not exist LINE 1: SELECT regtype('ng_catalog.int4'); ^ +-- schemaname not applicable +SELECT regrole('regtestrole'); +ERROR: role "regtestrole" does not exist +LINE 1: SELECT regrole('regtestrole'); + ^ +SELECT regrole('"regtestrole"'); +ERROR: role "regtestrole" does not exist +LINE 1: SELECT regrole('"regtestrole"'); + ^ +SELECT regrole('Nonexistent'); +ERROR: role "nonexistent" does not exist +LINE 1: SELECT regrole('Nonexistent'); + ^ +SELECT regrole('"Nonexistent"'); +ERROR: role "Nonexistent" does not exist +LINE 1: SELECT regrole('"Nonexistent"'); + ^ +SELECT regrole('foo.bar'); +ERROR: invalid name syntax +LINE 1: SELECT regrole('foo.bar'); + ^ +SELECT regnamespace('Nonexistent'); +ERROR: schema "nonexistent" does not exist +LINE 1: SELECT regnamespace('Nonexistent'); + ^ +SELECT regnamespace('"Nonexistent"'); +ERROR: schema "Nonexistent" does not exist +LINE 1: SELECT regnamespace('"Nonexistent"'); + ^ +SELECT regnamespace('foo.bar'); +ERROR: invalid name syntax +LINE 1: SELECT regnamespace('foo.bar'); + ^ /* If objects don't exist, return NULL with no error. */ -- without schemaname SELECT to_regoper('||//'); @@ -265,18 +315,6 @@ SELECT to_regtype('int3'); (1 row) -SELECT to_regrole('regtestrole'); - to_regrole ------------- - -(1 row) - -SELECT to_regnamespace('nonexistent'); - to_regnamespace ------------------ - -(1 row) - -- with schemaname SELECT to_regoper('ng_catalog.||/'); to_regoper @@ -314,3 +352,46 @@ SELECT to_regtype('ng_catalog.int4'); (1 row) +-- schemaname not applicable +SELECT to_regrole('regtestrole'); + to_regrole +------------ + +(1 row) + +SELECT to_regrole('"regtestrole"'); + to_regrole +------------ + +(1 row) + +SELECT to_regrole('foo.bar'); +ERROR: invalid name syntax +SELECT to_regrole('Nonexistent'); + to_regrole +------------ + +(1 row) + +SELECT to_regrole('"Nonexistent"'); + to_regrole +------------ + +(1 row) + +SELECT to_regrole('foo.bar'); +ERROR: invalid name syntax +SELECT to_regnamespace('Nonexistent'); + to_regnamespace +----------------- + +(1 row) + +SELECT to_regnamespace('"Nonexistent"'); + to_regnamespace +----------------- + +(1 row) + +SELECT to_regnamespace('foo.bar'); +ERROR: invalid name syntax diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql index 8edaf15f75..aa8521475c 100644 --- a/src/test/regress/sql/regproc.sql +++ b/src/test/regress/sql/regproc.sql @@ -5,6 +5,7 @@ /* If objects exist, return oids */ CREATE ROLE regtestrole; + -- without schemaname SELECT regoper('||/'); @@ -13,8 +14,6 @@ SELECT regproc('now'); SELECT regprocedure('abs(numeric)'); SELECT regclass('pg_class'); SELECT regtype('int4'); -SELECT regrole('regtestrole'); -SELECT regnamespace('pg_catalog'); SELECT to_regoper('||/'); SELECT to_regoperator('+(int4,int4)'); @@ -22,8 +21,6 @@ SELECT to_regproc('now'); SELECT to_regprocedure('abs(numeric)'); SELECT to_regclass('pg_class'); SELECT to_regtype('int4'); -SELECT to_regrole('regtestrole'); -SELECT to_regnamespace('pg_catalog'); -- with schemaname @@ -40,6 +37,18 @@ SELECT to_regprocedure('pg_catalog.abs(numeric)'); SELECT to_regclass('pg_catalog.pg_class'); SELECT to_regtype('pg_catalog.int4'); +-- schemaname not applicable + +SELECT regrole('regtestrole'); +SELECT regrole('"regtestrole"'); +SELECT regnamespace('pg_catalog'); +SELECT regnamespace('"pg_catalog"'); + +SELECT to_regrole('regtestrole'); +SELECT to_regrole('"regtestrole"'); +SELECT to_regnamespace('pg_catalog'); +SELECT to_regnamespace('"pg_catalog"'); + /* If objects don't exist, raise errors. */ DROP ROLE regtestrole; @@ -52,8 +61,6 @@ SELECT regproc('know'); SELECT regprocedure('absinthe(numeric)'); SELECT regclass('pg_classes'); SELECT regtype('int3'); -SELECT regrole('regtestrole'); -SELECT regnamespace('nonexistent'); -- with schemaname @@ -64,6 +71,17 @@ SELECT regprocedure('ng_catalog.abs(numeric)'); SELECT regclass('ng_catalog.pg_class'); SELECT regtype('ng_catalog.int4'); +-- schemaname not applicable + +SELECT regrole('regtestrole'); +SELECT regrole('"regtestrole"'); +SELECT regrole('Nonexistent'); +SELECT regrole('"Nonexistent"'); +SELECT regrole('foo.bar'); +SELECT regnamespace('Nonexistent'); +SELECT regnamespace('"Nonexistent"'); +SELECT regnamespace('foo.bar'); + /* If objects don't exist, return NULL with no error. */ -- without schemaname @@ -74,8 +92,6 @@ SELECT to_regproc('know'); SELECT to_regprocedure('absinthe(numeric)'); SELECT to_regclass('pg_classes'); SELECT to_regtype('int3'); -SELECT to_regrole('regtestrole'); -SELECT to_regnamespace('nonexistent'); -- with schemaname @@ -85,3 +101,15 @@ SELECT to_regproc('ng_catalog.now'); SELECT to_regprocedure('ng_catalog.abs(numeric)'); SELECT to_regclass('ng_catalog.pg_class'); SELECT to_regtype('ng_catalog.int4'); + +-- schemaname not applicable + +SELECT to_regrole('regtestrole'); +SELECT to_regrole('"regtestrole"'); +SELECT to_regrole('foo.bar'); +SELECT to_regrole('Nonexistent'); +SELECT to_regrole('"Nonexistent"'); +SELECT to_regrole('foo.bar'); +SELECT to_regnamespace('Nonexistent'); +SELECT to_regnamespace('"Nonexistent"'); +SELECT to_regnamespace('foo.bar');