【问题标题】:PostgreSQL Schema length and Search_PathPostgreSQL Schema 长度和 Search_Path
【发布时间】:2019-04-03 06:57:08
【问题描述】:

我在 Postgres 上创建了一个长度大于 63 bytes 个字符的新模式。

CREATE SCHEMA "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz";

以上语句创建了一个架构abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghi

Postgres 自动删除了多余的字节并创建了仅包含 63 个字节的架构(我原以为会出错)。

然后我运行以下命令:

SET search_path TO 'abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz';
SHOW search_path;

CREATE TABLE deepak(item varchar);
INSERT INTO deepak SELECT 'a';

TABLE "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz".deepak;

我的问题是

  • Show search_path 返回全名,但激活新的 63 字节名称模式。这是怎么发生的?
  • select 语句能够选择 table deepak 即使在给出错误的模式名称之后。怎么可能?

我也检查了information_schema.schematapg_tables。这些表中存在 63 字节的名称。

【问题讨论】:

标签: postgresql namespaces identifier truncation


【解决方案1】:

这背后的原因是所有对象名称都是数据类型name。比较pg_namespace的定义,即包含schema的系统目录:

\d pg_namespace
            Table "pg_catalog.pg_namespace"
  Column  |   Type    | Collation | Nullable | Default 
----------+-----------+-----------+----------+---------
 nspname  | name      |           | not null | 
 nspowner | oid       |           | not null | 
 nspacl   | aclitem[] |           |          | 
Indexes:
    "pg_namespace_nspname_index" UNIQUE, btree (nspname)
    "pg_namespace_oid_index" UNIQUE, btree (oid)

name定义在src/include/c.h中(NAMEDATALEN是64,但是最后一个字节是0,所以有效长度是63):

/*
 * Representation of a Name: effectively just a C string, but null-padded to
 * exactly NAMEDATALEN bytes.  The use of a struct is historical.
 */
typedef struct nameData
{
    char        data[NAMEDATALEN];
} NameData;
typedef NameData *Name;

#define NameStr(name)   ((name).data)

当解析器处理一个标识符时,它会将其截断为NAMEDATALEN-1

这种截断从一开始就引发了NOTICEcommit 0672a3c081 从 2000 年 6 月开始),所以如果您没有看到该通知,我会感到惊讶(除非您将 client_min_messages 设置为 warning 或 @ 987654333@).

search_path 是一个没有长度限制的常规 C 字符串,因此它可以包含超过 63 个字节的模式名称,但由于条目被强制转换为 name,因此多余的字符将被有效地忽略。

这并不漂亮,我认为消息至少应该是WARNING。您可能希望将其与黑客邮件列表一起提出(或为其编写补丁)。将级别提高到ERROR 将是最干净的解决方案,但不利于向后兼容。

【讨论】:

    【解决方案2】:

    您使用的是哪个版本的 Postgres,更重要的是您使用哪个客户端连接到 Postgres?

    在 Postgres 11 下,使用 psql,Postgres 将模式名称截断为 63 个字节,但它告诉我它会这样做:

    test=> CREATE SCHEMA "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz";
    NOTICE:  identifier "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz" will be truncated to "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghi"
    CREATE SCHEMA
    test=> SET search_path TO 'abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz';
    SET
    test=> SHOW search_path;
                                       search_path                                    
    ----------------------------------------------------------------------------------
     abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz
    (1 row)
    
    test=> CREATE TABLE deepak(item varchar);
    CREATE TABLE
    test=> INSERT INTO deepak SELECT 'a';
    INSERT 0 1
    test=> \dt deepak
                                          List of relations
                                 Schema                              |  Name  | Type  |  Owner   
    -----------------------------------------------------------------+--------+-------+----------
     abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghi | deepak | table | laetitia
    (1 row)
    
    test=> TABLE "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz".deepak;
    NOTICE:  identifier "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz" will be truncated to "abcdefghijklmnopqrstuvwxyz_abcdefghijklmnopqrstuvwxyz_abcdefghi"
     item 
    ------
     a
    (1 row)
    

    由于它总是截断标识符,所以查询很好...您希望得到一个错误吗?或者如果架构名称在search_path 中被截断会更清楚吗?

    【讨论】:

    • 我认为 Postgres 应该拒绝创建名称过长的模式(或表)。 “静默”截断数据不是 Postgres 通常会做的——当我尝试将 80 个字符放入 varchar(63) 列时,我也会收到错误消息。
    • 我理解这种观点,并且可以创建一个补丁来纠正这种行为。但是,如上所示,Postgres 不会“静默”地截断标识符。它显示通知级别消息。
    猜你喜欢
    • 1970-01-01
    • 2015-10-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-10
    • 2022-06-22
    • 2014-10-23
    • 1970-01-01
    相关资源
    最近更新 更多