为什么atttypmod与character_maximum_length不同?

时间:2018-09-17 21:41:08

标签: postgresql postgresql-9.4 information-schema

我正在将一些information_schema查询转换为系统目录查询,但字符最大长度却得到了不同的结果。

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

返回我期望的结果,例如:

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 :(得分:3)

对于类型charvarchar,从结果中减去4是很安全的。 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的视图定义。