1
0
mirror of https://github.com/postgres/postgres.git synced 2025-11-19 13:42:17 +03:00

Avoid producing over-length specific_name outputs in information_schema.

information_schema output columns that are declared as being type
sql_identifier are supposed to conform to the implementation's rules
for valid identifiers, in particular the identifier length limit.
Several places potentially violated this limit by concatenating a
function's name and OID.  (The OID is added to ensure name uniqueness
within a schema, since the spec doesn't expect function name overloading.)

Simply truncating the concatenation result to fit in "name" won't do,
since losing part of the OID might wind up giving non-unique results.
Instead, let's truncate the function name as necessary.

The most practical way to do that is to do it in a C function; the
information_schema.sql script doesn't have easy access to the value
of NAMEDATALEN, nor does it have an easy way to truncate on the basis
of resulting byte-length rather than number of characters.

(There are still a couple of places that cast concatenation results to
sql_identifier, but as far as I can see they are guaranteed not to produce
over-length strings, at least with the normal value of NAMEDATALEN.)

Discussion: https://postgr.es/m/23817.1545283477@sss.pgh.pa.us
This commit is contained in:
Tom Lane
2018-12-20 15:58:58 -05:00
parent 7b14bcc06c
commit 5bbee34d9f
4 changed files with 51 additions and 10 deletions

View File

@@ -364,3 +364,38 @@ current_schemas(PG_FUNCTION_ARGS)
PG_RETURN_POINTER(array);
}
/*
* SQL-function nameconcatoid(name, oid) returns name
*
* This is used in the information_schema to produce specific_name columns,
* which are supposed to be unique per schema. We achieve that (in an ugly
* way) by appending the object's OID. The result is the same as
* ($1::text || '_' || $2::text)::name
* except that, if it would not fit in NAMEDATALEN, we make it do so by
* truncating the name input (not the oid).
*/
Datum
nameconcatoid(PG_FUNCTION_ARGS)
{
Name nam = PG_GETARG_NAME(0);
Oid oid = PG_GETARG_OID(1);
Name result;
char suffix[20];
int suflen;
int namlen;
suflen = snprintf(suffix, sizeof(suffix), "_%u", oid);
namlen = strlen(NameStr(*nam));
/* Truncate oversize input by truncating name part, not suffix */
if (namlen + suflen >= NAMEDATALEN)
namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen);
/* We use palloc0 here to ensure result is zero-padded */
result = (Name) palloc0(NAMEDATALEN);
memcpy(NameStr(*result), NameStr(*nam), namlen);
memcpy(NameStr(*result) + namlen, suffix, suflen);
PG_RETURN_NAME(result);
}