为什么atttypmod与character_maximum_length不同?

Mat*_*t S 4 postgresql information-schema postgresql-9.4

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

SELECT column_name, 
    data_type , 
    character_maximum_length AS "maxlen"
FROM information_schema.columns 
WHERE table_name = 'x'
Run Code Online (Sandbox Code Playgroud)

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

city    character varying   255
company character varying   1000
Run Code Online (Sandbox Code Playgroud)

等效目录查询

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
Run Code Online (Sandbox Code Playgroud)

似乎返回每个长度+ 4:

city    character varying   259
company character varying   1004
Run Code Online (Sandbox Code Playgroud)

为什么会有所不同?总是简单地从结果中减去4是否安全?

Kam*_*ski 5

您可以说从类型char和的结果中减去4是安全的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$
Run Code Online (Sandbox Code Playgroud)

就是说,对于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
Run Code Online (Sandbox Code Playgroud)

这应该为您做。如果您希望进一步调查此问题,请参阅的视图定义information_schema.columns