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;
我的问题是
- 显示
search_path
returns 全名但激活新的 63 字节名称模式。这是怎么发生的?
select
语句能够 select table deepak
即使给出了错误的模式名称。怎么可能?
我也检查了 information_schema.schemata
和 pg_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.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
。
这个截断从一开始就引发了 NOTICE
(从 2000 年 6 月开始 commit 0672a3c081),所以如果你没有看到那个通知我会很惊讶(除非你设置 client_min_messages
到 warning
或 error
).
search_path
是一个没有长度限制的常规 C 字符串,因此它可以包含超过 63 个字节的模式名称,但由于条目被强制转换为 name
,多余的字符实际上被忽略了。
这不太好,我认为消息至少应该是 WARNING
。您可能希望通过黑客邮件列表提出它(或为其编写补丁)。将级别提高到 ERROR
将是最干净的解决方案,但不利于向后兼容性。
我在 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
returns 全名但激活新的 63 字节名称模式。这是怎么发生的? select
语句能够 selecttable deepak
即使给出了错误的模式名称。怎么可能?
我也检查了 information_schema.schemata
和 pg_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.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
。
这个截断从一开始就引发了 NOTICE
(从 2000 年 6 月开始 commit 0672a3c081),所以如果你没有看到那个通知我会很惊讶(除非你设置 client_min_messages
到 warning
或 error
).
search_path
是一个没有长度限制的常规 C 字符串,因此它可以包含超过 63 个字节的模式名称,但由于条目被强制转换为 name
,多余的字符实际上被忽略了。
这不太好,我认为消息至少应该是 WARNING
。您可能希望通过黑客邮件列表提出它(或为其编写补丁)。将级别提高到 ERROR
将是最干净的解决方案,但不利于向后兼容性。