PostgreSQL 架构长度和 Search_Path

PostgreSQL Schema length and Search_Path

我在 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;

我的问题是

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

您使用的是哪个版本的 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 中被截断会更清楚吗?

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

\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.hNAMEDATALEN是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

这个截断从一开始就引发了 NOTICE(从 2000 年 6 月开始 commit 0672a3c081),所以如果你没有看到那个通知我会很惊讶(除非你设置 client_min_messageswarningerror).

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

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