Почему atttypmod отличается от character_maximum_length? - PullRequest
0 голосов
/ 18 сентября 2018

Я конвертирую некоторые запросы information_schema в запросы системного каталога и получаю разные результаты для максимальной длины символа.

SELECT column_name, 
    data_type , 
    character_maximum_length AS "maxlen"
FROM information_schema.columns 
WHERE table_name = 'x'

возвращает ожидаемые результаты, например ::1004

city    character varying   255
company character varying   1000

Эквивалентный каталогный запрос

SELECT attname,
       atttypid::regtype  AS datatype,
       NULLIF(atttypmod, -1) AS maxlen
FROM   pg_attribute
WHERE  CAST(attrelid::regclass AS varchar) = 'x'
AND    attnum > 0
AND    NOT attisdropped

Кажется, чтобы вернуть каждую длину + 4:

city    character varying   259
company character varying   1004

Почему разница? Безопасно ли всегда просто вычитать 4 из результата?

1 Ответ

0 голосов
/ 18 сентября 2018

Можно сказать, что можно вычесть 4 из результата для типов char и varchar.Что делает information_schema.columns представление под капотом, так это то, что оно вызывает функцию informatoin_schema._pg_char_max_length (, в этом ваша разница, поскольку вы не ), тело которой:

CREATE OR REPLACE FUNCTION information_schema._pg_char_max_length(typid oid, typmod integer)
 RETURNS integer
 LANGUAGE sql
 IMMUTABLE PARALLEL SAFE STRICT
AS $function$SELECT
  CASE WHEN $2 = -1 /* default typmod */
       THEN null
       WHEN $1 IN (1042, 1043) /* char, varchar */
       THEN $2 - 4
       WHEN $1 IN (1560, 1562) /* bit, varbit */
       THEN $2
       ELSE null
  END$function$

Тосказал, что для chars и varchars это всегда вычитает 4. Это делает ваш запрос не эквивалентным в той степени, в которой ему действительно нужно объединение с pg_type, чтобы установить typid столбца и обернуть значение в функции, чтобывернуть правильные значения.Это связано с тем, что в игру вступает больше вещей, чем просто.Если вы хотите упростить, вы можете сделать это без объединения (хотя это не будет пуленепробиваемым):

SELECT attname,
       atttypid::regtype  AS datatype,
       NULLIF(information_schema._pg_char_max_length(atttypid, atttypmod), -1) AS maxlen
FROM   pg_attribute
WHERE  CAST(attrelid::regclass AS varchar) = 'x'
AND    attnum > 0
AND    NOT attisdropped

Это должно сделать это для вас.Если вы хотите продолжить расследование, обратитесь к определению вида information_schema.columns.

...