From 0d6c5f4757ef35a61eccf94987c0afee9a16d73c Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 5 Dec 2019 18:59:28 +0100 Subject: [PATCH v17 3/7] Implement type regcollation. This will be helpful for a following commit. Author: Julien Rouhaud Reviewed-by: Thomas Munro and Michael Paquier Discussion: https://postgr.es/m/CAEepm%3D0uEQCpfq_%2BLYFBdArCe4Ot98t1aR4eYiYTe%3DyavQygiQ%40mail.gmail.com --- doc/src/sgml/datatype.sgml | 14 +++ doc/src/sgml/func.sgml | 32 ++++-- doc/src/sgml/ref/pgupgrade.sgml | 1 + src/backend/utils/adt/regproc.c | 153 ++++++++++++++++++++++++++ src/include/catalog/pg_cast.dat | 14 +++ src/include/catalog/pg_proc.dat | 15 +++ src/include/catalog/pg_type.dat | 4 + src/test/regress/expected/regproc.out | 40 +++++++ src/test/regress/sql/regproc.sql | 7 ++ 9 files changed, 269 insertions(+), 11 deletions(-) diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 157fe4e727..ffe497a63a 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4476,6 +4476,10 @@ INSERT INTO mytable VALUES(-1); -- fails regclass + + regcollation + + regconfig @@ -4496,6 +4500,10 @@ INSERT INTO mytable VALUES(-1); -- fails regoperator + + regtype + + regproc @@ -4602,6 +4610,12 @@ SELECT * FROM pg_attribute pg_type + + regcollation + pg_collation + collation name + "POSIX" + regconfig diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 710b51ff7c..b84502295e 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -18177,6 +18177,10 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); to_regclass + + to_regcollation + + to_regnamespace @@ -18389,6 +18393,11 @@ SELECT pg_type_is_visible('myschema.widget'::regtype); regclass get the OID of the named relation + + to_regcollation(coll_name) + regcollation + get the OID of the named collation + to_regnamespace(schema_name) regnamespace @@ -18721,17 +18730,18 @@ SELECT collation for ('foo' COLLATE "de_DE"); The functions to_regclass, - to_regnamespace, to_regoper, - to_regoperator, to_regrole, - to_regproc, to_regprocedure, and - to_regtype, functions translate relation, schema, - operator, role, function, and type names (given as text) to - objects of the corresponding reg* type (see about the types). These functions differ from a - cast from text in that they don't accept a numeric OID, and that they - return null rather than throwing an error if the name is not found (or, for - to_regproc and to_regoper, if the - given name matches multiple objects). + to_regcollation, to_regnamespace, + to_regoper, to_regoperator, + to_regrole, to_regproc, + to_regprocedure, and to_regtype, + functions translate relation, collation, schema, operator, role, function, + and type names (given as text) to objects of the corresponding + reg* type (see about the types). + These functions differ from a cast from text in that they don't accept a + numeric OID, and that they return null rather than throwing an error if the + name is not found (or, for to_regproc and + to_regoper, if the given name matches multiple + objects). diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml index 9e4b2d69a4..5e396f41fb 100644 --- a/doc/src/sgml/ref/pgupgrade.sgml +++ b/doc/src/sgml/ref/pgupgrade.sgml @@ -775,6 +775,7 @@ psql --username=postgres --file=script.sql postgres containing table columns using these reg* OID-referencing system data types: regconfig + regcollation regdictionary regnamespace regoper diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index f0fa52bc27..c800d797ac 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -24,6 +24,7 @@ #include "access/htup_details.h" #include "catalog/namespace.h" #include "catalog/pg_class.h" +#include "catalog/pg_collation.h" #include "catalog/pg_operator.h" #include "catalog/pg_proc.h" #include "catalog/pg_ts_config.h" @@ -1043,6 +1044,158 @@ regclasssend(PG_FUNCTION_ARGS) } +/* + * regcollationin - converts "collationname" to collation 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_collation entry. + */ +Datum +regcollationin(PG_FUNCTION_ARGS) +{ + char *collation_name_or_oid = PG_GETARG_CSTRING(0); + Oid result = InvalidOid; + List *names; + + /* '-' ? */ + if (strcmp(collation_name_or_oid, "-") == 0) + PG_RETURN_OID(InvalidOid); + + /* Numeric OID? */ + if (collation_name_or_oid[0] >= '0' && + collation_name_or_oid[0] <= '9' && + strspn(collation_name_or_oid, "0123456789") == strlen(collation_name_or_oid)) + { + result = DatumGetObjectId(DirectFunctionCall1(oidin, + CStringGetDatum(collation_name_or_oid))); + PG_RETURN_OID(result); + } + + /* Else it's a name, possibly schema-qualified */ + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regcollation values must be OIDs in bootstrap mode"); + + /* + * Normal case: parse the name into components and see if it matches any + * pg_collation entries in the current search path. + */ + names = stringToQualifiedNameList(collation_name_or_oid); + + result = get_collation_oid(names, false); + + PG_RETURN_OID(result); +} + +/* + * to_regcollation - converts "collationname" to collation OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regcollation(PG_FUNCTION_ARGS) +{ + char *collation_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Oid result; + List *names; + + /* + * Parse the name into components and see if it matches any pg_collation + * entries in the current search path. + */ + names = stringToQualifiedNameList(collation_name); + + /* We might not even have permissions on this relation; don't lock it. */ + result = get_collation_oid(names, true); + + if (OidIsValid(result)) + PG_RETURN_OID(result); + else + PG_RETURN_NULL(); +} + +/* + * regcollationout - converts collation OID to "collation_name" + */ +Datum +regcollationout(PG_FUNCTION_ARGS) +{ + Oid collationid = PG_GETARG_OID(0); + char *result; + HeapTuple collationtup; + + if (collationid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + collationtup = SearchSysCache1(COLLOID, ObjectIdGetDatum(collationid)); + + if (HeapTupleIsValid(collationtup)) + { + Form_pg_collation collationform = (Form_pg_collation) GETSTRUCT(collationtup); + char *collationname = NameStr(collationform->collname); + + /* + * In bootstrap mode, skip the fancy namespace stuff and just return + * the collation name. (This path is only needed for debugging output + * anyway.) + */ + if (IsBootstrapProcessingMode()) + result = pstrdup(collationname); + else + { + char *nspname; + + /* + * Would this collation be found by regcollationin? If not, + * qualify it. + */ + if (CollationIsVisible(collationid)) + nspname = NULL; + else + nspname = get_namespace_name(collationform->collnamespace); + + result = quote_qualified_identifier(nspname, collationname); + } + + ReleaseSysCache(collationtup); + } + else + { + /* If OID doesn't match any pg_collation entry, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", collationid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regcollationrecv - converts external binary format to regcollation + */ +Datum +regcollationrecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regcollationsend - converts regcollation to binary format + */ +Datum +regcollationsend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} + + /* * regtypein - converts "typename" to type OID * diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat index 6ef8b8a4e7..01c5328ddd 100644 --- a/src/include/catalog/pg_cast.dat +++ b/src/include/catalog/pg_cast.dat @@ -189,6 +189,20 @@ castcontext => 'a', castmethod => 'f' }, { castsource => 'regclass', casttarget => 'int4', castfunc => '0', castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regcollation', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regcollation', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regcollation', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regcollation', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regcollation', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regcollation', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regcollation', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, { castsource => 'oid', casttarget => 'regtype', castfunc => '0', castcontext => 'i', castmethod => 'b' }, { castsource => 'regtype', casttarget => 'oid', castfunc => '0', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 7fb574f9dc..c7c25e1eae 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -6666,6 +6666,15 @@ { oid => '3495', descr => 'convert classname to regclass', proname => 'to_regclass', provolatile => 's', prorettype => 'regclass', proargtypes => 'text', prosrc => 'to_regclass' }, +{ oid => '9508', descr => 'I/O', + proname => 'regcollationin', provolatile => 's', prorettype => 'regcollation', + proargtypes => 'cstring', prosrc => 'regcollationin' }, +{ oid => '9509', descr => 'I/O', + proname => 'regcollationout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regcollation', prosrc => 'regcollationout' }, +{ oid => '9510', descr => 'convert classname to regcollation', + proname => 'to_regcollation', provolatile => 's', prorettype => 'regcollation', + proargtypes => 'text', prosrc => 'to_regcollation' }, { oid => '2220', descr => 'I/O', proname => 'regtypein', provolatile => 's', prorettype => 'regtype', proargtypes => 'cstring', prosrc => 'regtypein' }, @@ -7446,6 +7455,12 @@ { oid => '2453', descr => 'I/O', proname => 'regclasssend', prorettype => 'bytea', proargtypes => 'regclass', prosrc => 'regclasssend' }, +{ oid => '9511', descr => 'I/O', + proname => 'regcollationrecv', prorettype => 'regcollation', + proargtypes => 'internal', prosrc => 'regcollationrecv' }, +{ oid => '9512', descr => 'I/O', + proname => 'regcollationsend', prorettype => 'bytea', proargtypes => 'regcollation', + prosrc => 'regcollationsend' }, { oid => '2454', descr => 'I/O', proname => 'regtyperecv', prorettype => 'regtype', proargtypes => 'internal', prosrc => 'regtyperecv' }, diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index b00597d6ff..ad777e37c6 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -379,6 +379,10 @@ typname => 'regclass', typlen => '4', typbyval => 't', typcategory => 'N', typinput => 'regclassin', typoutput => 'regclassout', typreceive => 'regclassrecv', typsend => 'regclasssend', typalign => 'i' }, +{ oid => '9506', array_type_oid => '9507', descr => 'registered collation', + typname => 'regcollation', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regcollationin', typoutput => 'regcollationout', + typreceive => 'regcollationrecv', typsend => 'regcollationsend', typalign => 'i' }, { oid => '2206', array_type_oid => '2211', descr => 'registered type', typname => 'regtype', typlen => '4', typbyval => 't', typcategory => 'N', typinput => 'regtypein', typoutput => 'regtypeout', diff --git a/src/test/regress/expected/regproc.out b/src/test/regress/expected/regproc.out index ee4fcda866..e45ff5483f 100644 --- a/src/test/regress/expected/regproc.out +++ b/src/test/regress/expected/regproc.out @@ -40,6 +40,12 @@ SELECT regtype('int4'); integer (1 row) +SELECT regcollation('"POSIX"'); + regcollation +-------------- + "POSIX" +(1 row) + SELECT to_regoper('||/'); to_regoper ------------ @@ -76,6 +82,12 @@ SELECT to_regtype('int4'); integer (1 row) +SELECT to_regcollation('"POSIX"'); + to_regcollation +----------------- + "POSIX" +(1 row) + -- with schemaname SELECT regoper('pg_catalog.||/'); regoper @@ -113,6 +125,12 @@ SELECT regtype('pg_catalog.int4'); integer (1 row) +SELECT regcollation('pg_catalog."POSIX"'); + regcollation +-------------- + "POSIX" +(1 row) + SELECT to_regoper('pg_catalog.||/'); to_regoper ------------ @@ -143,6 +161,12 @@ SELECT to_regtype('pg_catalog.int4'); integer (1 row) +SELECT to_regcollation('pg_catalog."POSIX"'); + to_regcollation +----------------- + "POSIX" +(1 row) + -- schemaname not applicable SELECT regrole('regress_regrole_test'); regrole @@ -244,6 +268,10 @@ SELECT regtype('ng_catalog.int4'); ERROR: schema "ng_catalog" does not exist LINE 1: SELECT regtype('ng_catalog.int4'); ^ +SELECT regcollation('ng_catalog."POSIX"'); +ERROR: schema "ng_catalog" does not exist +LINE 1: SELECT regcollation('ng_catalog."POSIX"'); + ^ -- schemaname not applicable SELECT regrole('regress_regrole_test'); ERROR: role "regress_regrole_test" does not exist @@ -315,6 +343,12 @@ SELECT to_regtype('int3'); (1 row) +SELECT to_regcollation('notacollation'); + to_regcollation +----------------- + +(1 row) + -- with schemaname SELECT to_regoper('ng_catalog.||/'); to_regoper @@ -352,6 +386,12 @@ SELECT to_regtype('ng_catalog.int4'); (1 row) +SELECT to_regcollation('ng_catalog."POSIX"'); + to_regcollation +----------------- + +(1 row) + -- schemaname not applicable SELECT to_regrole('regress_regrole_test'); to_regrole diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql index a60bc28901..faab0c15ce 100644 --- a/src/test/regress/sql/regproc.sql +++ b/src/test/regress/sql/regproc.sql @@ -14,6 +14,7 @@ SELECT regproc('now'); SELECT regprocedure('abs(numeric)'); SELECT regclass('pg_class'); SELECT regtype('int4'); +SELECT regcollation('"POSIX"'); SELECT to_regoper('||/'); SELECT to_regoperator('+(int4,int4)'); @@ -21,6 +22,7 @@ SELECT to_regproc('now'); SELECT to_regprocedure('abs(numeric)'); SELECT to_regclass('pg_class'); SELECT to_regtype('int4'); +SELECT to_regcollation('"POSIX"'); -- with schemaname @@ -30,12 +32,14 @@ SELECT regproc('pg_catalog.now'); SELECT regprocedure('pg_catalog.abs(numeric)'); SELECT regclass('pg_catalog.pg_class'); SELECT regtype('pg_catalog.int4'); +SELECT regcollation('pg_catalog."POSIX"'); SELECT to_regoper('pg_catalog.||/'); SELECT to_regproc('pg_catalog.now'); SELECT to_regprocedure('pg_catalog.abs(numeric)'); SELECT to_regclass('pg_catalog.pg_class'); SELECT to_regtype('pg_catalog.int4'); +SELECT to_regcollation('pg_catalog."POSIX"'); -- schemaname not applicable @@ -70,6 +74,7 @@ SELECT regproc('ng_catalog.now'); SELECT regprocedure('ng_catalog.abs(numeric)'); SELECT regclass('ng_catalog.pg_class'); SELECT regtype('ng_catalog.int4'); +SELECT regcollation('ng_catalog."POSIX"'); -- schemaname not applicable @@ -92,6 +97,7 @@ SELECT to_regproc('know'); SELECT to_regprocedure('absinthe(numeric)'); SELECT to_regclass('pg_classes'); SELECT to_regtype('int3'); +SELECT to_regcollation('notacollation'); -- with schemaname @@ -101,6 +107,7 @@ 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'); +SELECT to_regcollation('ng_catalog."POSIX"'); -- schemaname not applicable -- 2.20.1