From ffeb0292591816c77949efe267c2db4f8c210ea7 Mon Sep 17 00:00:00 2001 From: Julien Rouhaud Date: Thu, 5 Dec 2019 18:59:28 +0100 Subject: [PATCH v14 3/7] Implement type regcollation. This will be helpful for a following commit. Author: Julien Rouhaud Reviewed-by: Thomas Munro Discussion: https://postgr.es/m/CAEepm%3D0uEQCpfq_%2BLYFBdArCe4Ot98t1aR4eYiYTe%3DyavQygiQ%40mail.gmail.com --- doc/src/sgml/datatype.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 + 5 files changed, 189 insertions(+) diff --git a/doc/src/sgml/datatype.sgml b/doc/src/sgml/datatype.sgml index 410eaedcb7..9a86d645a0 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 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', -- 2.20.1