Hi all,
Good day! I am a newbee to PostgreSQL and recently came across an idea about type-casting tablespace OID. The motibation is that when I have to upgrade a PostgreSQL database, we need to join other tables to track tablespace name. I have just created a simple patch to resolve this. Hope you can take a look with this. My Execution Sample: # After Patch: ------------------------------------------------------------------------ postgres=# SELECT oid,oid::regtablespace,spcname from pg_tablespace ; oid | oid | spcname ------+------------+------------ 1663 | pg_default | pg_default 1664 | pg_global | pg_global (2 rows) ------------------------------------------------------------------------ # Before Patch ------------------------------------------------------------------------ postgres-# SELECT oid,oid::regtablespace,spcname from pg_tablespace ; ERROR: syntax error at or near "oid" LINE 1: oid | oid | spcname ^ ------------------------------------------------------------------------ I added the "::regtablespace" part to source. Note: While developing, I also had to add several rows to pgcatalog tables. Please point out if any OID newly assigned is not appropriate. Kind Regards, Yuki Tei
diff --git a/src/backend/utils/adt/regproc.c b/src/backend/utils/adt/regproc.c index 296930eb3b..3ab0f75c84 100644 --- a/src/backend/utils/adt/regproc.c +++ b/src/backend/utils/adt/regproc.c @@ -30,6 +30,7 @@ #include "catalog/pg_ts_config.h" #include "catalog/pg_ts_dict.h" #include "catalog/pg_type.h" +#include "commands/tablespace.h" #include "lib/stringinfo.h" #include "mb/pg_wchar.h" #include "miscadmin.h" @@ -869,6 +870,122 @@ regoperatorsend(PG_FUNCTION_ARGS) return oidsend(fcinfo); } +/* + * regtablespacein - converts "tablespacename" to tablespace 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_tablespace entry. + */ +Datum +regtablespacein(PG_FUNCTION_ARGS) +{ + char *tablespace_name_or_oid = PG_GETARG_CSTRING(0); + Node *escontext = fcinfo->context; + Oid result; + List *names; + + /* Handle "-" or numeric OID */ + if (parseDashOrOid(tablespace_name_or_oid, &result, escontext)) + PG_RETURN_OID(result); + + /* The rest of this wouldn't work in bootstrap mode */ + if (IsBootstrapProcessingMode()) + elog(ERROR, "regtablespace values must be OIDs in bootstrap mode"); + + /* Normal case: see if the name matches any pg_tablespace entry. */ + names = stringToQualifiedNameList(tablespace_name_or_oid, escontext); + if (names == NIL) + PG_RETURN_NULL(); + + if (list_length(names) != 1) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_INVALID_NAME), + errmsg("invalid name syntax"))); + + result = get_tablespace_oid(strVal(linitial(names)), true); + + if (!OidIsValid(result)) + ereturn(escontext, (Datum) 0, + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("tablespace \"%s\" does not exist", + strVal(linitial(names))))); + + PG_RETURN_OID(result); +} + +/* + * to_regtablespace - converts "tablespacename" to tablespace OID + * + * If the name is not found, we return NULL. + */ +Datum +to_regtablespace(PG_FUNCTION_ARGS) +{ + char *tablespace_name = text_to_cstring(PG_GETARG_TEXT_PP(0)); + Datum result; + ErrorSaveContext escontext = {T_ErrorSaveContext}; + + if (!DirectInputFunctionCallSafe(regtablespacein, tablespace_name, + InvalidOid, -1, + (Node *) &escontext, + &result)) + PG_RETURN_NULL(); + PG_RETURN_DATUM(result); +} + +/* + * regtablespaceout - converts tablespace OID to "tablespace_name" + */ +Datum +regtablespaceout(PG_FUNCTION_ARGS) +{ + Oid spcid = PG_GETARG_OID(0); + char *result; + + if (spcid == InvalidOid) + { + result = pstrdup("-"); + PG_RETURN_CSTRING(result); + } + + result = get_tablespace_name(spcid); + + if (result) + { + /* pstrdup is not really necessary, but it avoids a compiler warning */ + result = pstrdup(quote_identifier(result)); + } + else + { + /* If OID doesn't match any tablespace, return it numerically */ + result = (char *) palloc(NAMEDATALEN); + snprintf(result, NAMEDATALEN, "%u", spcid); + } + + PG_RETURN_CSTRING(result); +} + +/* + * regtablespacerecv - converts external binary format to regtablespace + */ +Datum +regtablespacerecv(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidrecv, so share code */ + return oidrecv(fcinfo); +} + +/* + * regtablespacesend - converts regtablespace to binary format + */ +Datum +regtablespacesend(PG_FUNCTION_ARGS) +{ + /* Exactly the same as oidsend, so share code */ + return oidsend(fcinfo); +} /* * regclassin - converts "classname" to class OID diff --git a/src/include/catalog/pg_cast.dat b/src/include/catalog/pg_cast.dat index fb3a7b3f3b..f7f78e3a0d 100644 --- a/src/include/catalog/pg_cast.dat +++ b/src/include/catalog/pg_cast.dat @@ -281,6 +281,20 @@ castcontext => 'a', castmethod => 'f' }, { castsource => 'regnamespace', casttarget => 'int4', castfunc => '0', castcontext => 'a', castmethod => 'b' }, +{ castsource => 'oid', casttarget => 'regtablespace', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regtablespace', casttarget => 'oid', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'int8', casttarget => 'regtablespace', castfunc => 'oid', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int2', casttarget => 'regtablespace', castfunc => 'int4(int2)', + castcontext => 'i', castmethod => 'f' }, +{ castsource => 'int4', casttarget => 'regtablespace', castfunc => '0', + castcontext => 'i', castmethod => 'b' }, +{ castsource => 'regtablespace', casttarget => 'int8', castfunc => 'int8(oid)', + castcontext => 'a', castmethod => 'f' }, +{ castsource => 'regtablespace', casttarget => 'int4', castfunc => '0', + castcontext => 'a', castmethod => 'b' }, # String category { castsource => 'text', casttarget => 'bpchar', castfunc => '0', diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 9805bc6118..c0f7f41848 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -7154,6 +7154,17 @@ prorettype => 'regnamespace', proargtypes => 'text', prosrc => 'to_regnamespace' }, +{ oid => '6403', descr => 'I/O', + proname => 'regtablespacein', provolatile => 's', prorettype => 'regtablespace', + proargtypes => 'cstring', prosrc => 'regtablespacein' }, +{ oid => '6404', descr => 'I/O', + proname => 'regtablespaceout', provolatile => 's', prorettype => 'cstring', + proargtypes => 'regtablespace', prosrc => 'regtablespaceout' }, +{ oid => '6405', descr => 'convert tablespacespace name to regtablespace', + proname => 'to_regtablespace', provolatile => 's', + prorettype => 'regtablespace', proargtypes => 'text', + prosrc => 'to_regtablespace' }, + { oid => '6210', descr => 'test whether string is valid input for data type', proname => 'pg_input_is_valid', provolatile => 's', prorettype => 'bool', proargtypes => 'text text', prosrc => 'pg_input_is_valid' }, @@ -8000,6 +8011,12 @@ { oid => '4088', descr => 'I/O', proname => 'regnamespacesend', prorettype => 'bytea', proargtypes => 'regnamespace', prosrc => 'regnamespacesend' }, +{ oid => '6406', descr => 'I/O', + proname => 'regtablespacerecv', prorettype => 'regtablespace', + proargtypes => 'internal', prosrc => 'regtablespacerecv' }, +{ oid => '6407', descr => 'I/O', + proname => 'regtablespacesend', prorettype => 'bytea', + proargtypes => 'regtablespace', prosrc => 'regtablespacesend' }, { oid => '2456', descr => 'I/O', proname => 'bit_recv', prorettype => 'bit', proargtypes => 'internal oid int4', prosrc => 'bit_recv' }, diff --git a/src/include/catalog/pg_type.dat b/src/include/catalog/pg_type.dat index 92bcaf2c73..887a44dadc 100644 --- a/src/include/catalog/pg_type.dat +++ b/src/include/catalog/pg_type.dat @@ -398,6 +398,11 @@ typinput => 'regnamespacein', typoutput => 'regnamespaceout', typreceive => 'regnamespacerecv', typsend => 'regnamespacesend', typalign => 'i' }, +{ oid => '6401', array_type_oid => '6402', descr => 'registered tablespace', + typname => 'regtablespace', typlen => '4', typbyval => 't', typcategory => 'N', + typinput => 'regtablespacein', typoutput => 'regtablespaceout', + typreceive => 'regtablespacerecv', typsend => 'regtablespacesend', + typalign => 'i' }, # uuid { oid => '2950', array_type_oid => '2951', descr => 'UUID datatype',