From 3f80a72bdffc50329f5699bc31f59be38fc8baac Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 5 Dec 2019 18:59:28 +0100 Subject: [PATCH v16 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 | 23 +++- doc/src/sgml/func.sgml | 38 ++++--- doc/src/sgml/ref/pgupgrade.sgml | 4 +- src/backend/utils/adt/regproc.c | 152 ++++++++++++++++++++++++++ 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 | 24 ++++ src/test/regress/sql/regproc.sql | 4 + 9 files changed, 256 insertions(+), 22 deletions(-) diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 410eaedcb7..86d16e7b13 100644 --- a/doc/src/sgml/datatype.sgml +++ b/doc/src/sgml/datatype.sgml @@ -4496,6 +4496,10 @@ INSERT INTO mytable VALUES(-1); -- fails regtype + + regcollation + + regconfig @@ -4522,12 +4526,12 @@ INSERT INTO mytable VALUES(-1); -- fails system tables. Type oid represents an object identifier. There are also - several alias types for oid: regproc, - regprocedure, regoper, regoperator, - regclass, regtype, regrole, - regnamespace, regconfig, and - regdictionary. shows an - overview. + several alias types for oid: regcollation, + regproc, regprocedure, regoper, + regoperator, regclass, regtype, + regrole, regnamespace, regconfig, + and regdictionary. shows + an overview. @@ -4591,6 +4595,13 @@ SELECT * FROM pg_attribute 564182 + + regcollation + pg_collation + collation name + "POSIX" + + regproc pg_proc diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index b2d991ac7f..02779ab713 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_regproc @@ -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_regproc(func_name) regproc @@ -18720,20 +18729,21 @@ SELECT collation for ('foo' COLLATE "de_DE"); - The to_regclass, to_regproc, - to_regprocedure, to_regoper, - to_regoperator, to_regtype, - to_regnamespace, and to_regrole - functions translate relation, function, operator, type, schema, and role - names (given as text) to objects of - type regclass, regproc, regprocedure, + The to_regclass, to_regcollation, + to_regproc, to_regprocedure, + to_regoper, to_regoperator, + to_regtype, to_regnamespace, and + to_regrole functions translate relation, collation, + function, operator, type, schema, and role names (given as + text) to objects of type regclass, + regcollation, regproc, regprocedure, regoper, regoperator, regtype, - regnamespace, and regrole - respectively. 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). + regnamespace, and regrole respectively. 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). @@ -21095,7 +21105,7 @@ postgres=# SELECT * FROM pg_walfile_name_offset(pg_stop_backup()); pg_collation_actual_version - pg_collation_actual_version(oid) + pg_collation_actual_version(regcollation) text Return actual version of collation from operating system diff --git a/doc/src/sgml/ref/pgupgrade.sgml b/doc/src/sgml/ref/pgupgrade.sgml index 6629d736b8..8e229135c2 100644 --- a/doc/src/sgml/ref/pgupgrade.sgml +++ b/doc/src/sgml/ref/pgupgrade.sgml @@ -773,8 +773,8 @@ psql --username=postgres --file=script.sql postgres pg_upgrade does not support upgrading of databases containing table columns using these reg* OID-referencing system data types: - regproc, regprocedure, regoper, - regoperator, regconfig, and + regcollation, regproc, regprocedure, + regoper, regoperator, regconfig, and regdictionary. (regtype can be upgraded.) diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index f0fa52bc27..da8cc0cf6b 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,157 @@ 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..16994e0909 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 diff --git a/src/test/regress/sql/regproc.sql b/src/test/regress/sql/regproc.sql index a60bc28901..5c8032800a 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 -- 2.20.1