Skip to content

Commit 5bbee34

Browse files
committed
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
1 parent 7b14bcc commit 5bbee34

File tree

4 files changed

+51
-10
lines changed

4 files changed

+51
-10
lines changed

src/backend/catalog/information_schema.sql

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -416,7 +416,7 @@ CREATE VIEW check_constraint_routine_usage AS
416416
CAST(c.conname AS sql_identifier) AS constraint_name,
417417
CAST(current_database() AS sql_identifier) AS specific_catalog,
418418
CAST(np.nspname AS sql_identifier) AS specific_schema,
419-
CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name
419+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name
420420
FROM pg_namespace nc, pg_constraint c, pg_depend d, pg_proc p, pg_namespace np
421421
WHERE nc.oid = c.connamespace
422422
AND c.contype = 'c'
@@ -1115,7 +1115,7 @@ GRANT SELECT ON key_column_usage TO PUBLIC;
11151115
CREATE VIEW parameters AS
11161116
SELECT CAST(current_database() AS sql_identifier) AS specific_catalog,
11171117
CAST(n_nspname AS sql_identifier) AS specific_schema,
1118-
CAST(proname || '_' || CAST(p_oid AS text) AS sql_identifier) AS specific_name,
1118+
CAST(nameconcatoid(proname, p_oid) AS sql_identifier) AS specific_name,
11191119
CAST((ss.x).n AS cardinal_number) AS ordinal_position,
11201120
CAST(
11211121
CASE WHEN proargmodes IS NULL THEN 'IN'
@@ -1320,7 +1320,7 @@ CREATE VIEW routine_privileges AS
13201320
CAST(grantee.rolname AS sql_identifier) AS grantee,
13211321
CAST(current_database() AS sql_identifier) AS specific_catalog,
13221322
CAST(n.nspname AS sql_identifier) AS specific_schema,
1323-
CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name,
1323+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name,
13241324
CAST(current_database() AS sql_identifier) AS routine_catalog,
13251325
CAST(n.nspname AS sql_identifier) AS routine_schema,
13261326
CAST(p.proname AS sql_identifier) AS routine_name,
@@ -1409,7 +1409,7 @@ GRANT SELECT ON role_routine_grants TO PUBLIC;
14091409
CREATE VIEW routines AS
14101410
SELECT CAST(current_database() AS sql_identifier) AS specific_catalog,
14111411
CAST(n.nspname AS sql_identifier) AS specific_schema,
1412-
CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name,
1412+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name,
14131413
CAST(current_database() AS sql_identifier) AS routine_catalog,
14141414
CAST(n.nspname AS sql_identifier) AS routine_schema,
14151415
CAST(p.proname AS sql_identifier) AS routine_name,
@@ -1964,7 +1964,7 @@ CREATE VIEW transforms AS
19641964
CAST(t.typname AS sql_identifier) AS udt_name,
19651965
CAST(current_database() AS sql_identifier) AS specific_catalog,
19661966
CAST(np.nspname AS sql_identifier) AS specific_schema,
1967-
CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name,
1967+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name,
19681968
CAST(l.lanname AS sql_identifier) AS group_name,
19691969
CAST('FROM SQL' AS character_data) AS transform_type
19701970
FROM pg_type t JOIN pg_transform x ON t.oid = x.trftype
@@ -1980,7 +1980,7 @@ CREATE VIEW transforms AS
19801980
CAST(t.typname AS sql_identifier) AS udt_name,
19811981
CAST(current_database() AS sql_identifier) AS specific_catalog,
19821982
CAST(np.nspname AS sql_identifier) AS specific_schema,
1983-
CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name,
1983+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name,
19841984
CAST(l.lanname AS sql_identifier) AS group_name,
19851985
CAST('TO SQL' AS character_data) AS transform_type
19861986
FROM pg_type t JOIN pg_transform x ON t.oid = x.trftype
@@ -2495,7 +2495,7 @@ CREATE VIEW view_routine_usage AS
24952495
CAST(v.relname AS sql_identifier) AS table_name,
24962496
CAST(current_database() AS sql_identifier) AS specific_catalog,
24972497
CAST(np.nspname AS sql_identifier) AS specific_schema,
2498-
CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier) AS specific_name
2498+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier) AS specific_name
24992499

25002500
FROM pg_namespace nv, pg_class v, pg_depend dv,
25012501
pg_depend dp, pg_proc p, pg_namespace np
@@ -2712,7 +2712,8 @@ CREATE VIEW element_types AS
27122712
UNION ALL
27132713

27142714
/* parameters */
2715-
SELECT pronamespace, CAST(proname || '_' || CAST(oid AS text) AS sql_identifier),
2715+
SELECT pronamespace,
2716+
CAST(nameconcatoid(proname, oid) AS sql_identifier),
27162717
'ROUTINE'::text, (ss.x).n, (ss.x).x, 0
27172718
FROM (SELECT p.pronamespace, p.proname, p.oid,
27182719
_pg_expandarray(coalesce(p.proallargtypes, p.proargtypes::oid[])) AS x
@@ -2721,7 +2722,8 @@ CREATE VIEW element_types AS
27212722
UNION ALL
27222723

27232724
/* result types */
2724-
SELECT p.pronamespace, CAST(p.proname || '_' || CAST(p.oid AS text) AS sql_identifier),
2725+
SELECT p.pronamespace,
2726+
CAST(nameconcatoid(p.proname, p.oid) AS sql_identifier),
27252727
'ROUTINE'::text, 0, p.prorettype, 0
27262728
FROM pg_proc p
27272729

src/backend/utils/adt/name.c

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,3 +364,38 @@ current_schemas(PG_FUNCTION_ARGS)
364364

365365
PG_RETURN_POINTER(array);
366366
}
367+
368+
/*
369+
* SQL-function nameconcatoid(name, oid) returns name
370+
*
371+
* This is used in the information_schema to produce specific_name columns,
372+
* which are supposed to be unique per schema. We achieve that (in an ugly
373+
* way) by appending the object's OID. The result is the same as
374+
* ($1::text || '_' || $2::text)::name
375+
* except that, if it would not fit in NAMEDATALEN, we make it do so by
376+
* truncating the name input (not the oid).
377+
*/
378+
Datum
379+
nameconcatoid(PG_FUNCTION_ARGS)
380+
{
381+
Name nam = PG_GETARG_NAME(0);
382+
Oid oid = PG_GETARG_OID(1);
383+
Name result;
384+
char suffix[20];
385+
int suflen;
386+
int namlen;
387+
388+
suflen = snprintf(suffix, sizeof(suffix), "_%u", oid);
389+
namlen = strlen(NameStr(*nam));
390+
391+
/* Truncate oversize input by truncating name part, not suffix */
392+
if (namlen + suflen >= NAMEDATALEN)
393+
namlen = pg_mbcliplen(NameStr(*nam), namlen, NAMEDATALEN - 1 - suflen);
394+
395+
/* We use palloc0 here to ensure result is zero-padded */
396+
result = (Name) palloc0(NAMEDATALEN);
397+
memcpy(NameStr(*result), NameStr(*nam), namlen);
398+
memcpy(NameStr(*result) + namlen, suffix, suflen);
399+
400+
PG_RETURN_NAME(result);
401+
}

src/include/catalog/catversion.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,6 @@
5353
*/
5454

5555
/* yyyymmddN */
56-
#define CATALOG_VERSION_NO 201812192
56+
#define CATALOG_VERSION_NO 201812201
5757

5858
#endif

src/include/catalog/pg_proc.dat

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -716,6 +716,10 @@
716716
proname => 'bttextnamecmp', proleakproof => 't', prorettype => 'int4',
717717
proargtypes => 'text name', prosrc => 'bttextnamecmp' },
718718

719+
{ oid => '266', descr => 'concatenate name and oid',
720+
proname => 'nameconcatoid', prorettype => 'name', proargtypes => 'name oid',
721+
prosrc => 'nameconcatoid' },
722+
719723
{ oid => '274',
720724
descr => 'current date and time - increments during transactions',
721725
proname => 'timeofday', provolatile => 'v', prorettype => 'text',

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy