PostgreSQL模式长度和Search_Path

时间:2019-04-03 06:57:08

标签: postgresql namespaces identifier truncation

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

我的问题是

  • 显示search_path返回全名,但使新的63字节的名称架构处于活动状态。这是怎么发生的?
  • 即使提供了错误的架构名称,
  • select语句也可以选择table deepak。怎么可能?

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

2 个答案:

答案 0 :(得分:0)

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

在带有psql的Postgres 11下,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中被截断了?

答案 1 :(得分:0)

其原因是所有对象名称均为数据类型name。比较pg_namespace的定义,该定义是包含架构的系统目录:

\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)

namesrc/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

从2000年6月开始(commit 0672a3c081)开始,这种删减方法就产生了NOTICE,因此,如果您没有看到该通知,我会感到惊讶(除非您设置了client_min_messageswarningerror)。

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

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