Table of Contents
本文作者是个有趣的人,总要找一些别人想不到的角度去想问题,下面介绍的是,要在 postgresql 数据库中,创建看起来名称为空的库,schema,role,table等,然后在表中插入看起来没有数据的数据。
1.介绍
作为读者-我喜欢做的一件事,就是挑战PostgreSQL到极致。前段时间我发了关于《It’s beer o’clock for PostgreSQL》的帖子。《Not so equal texts in PostgreSQL - and how to compare texts in a more elaborate way》是另一个有趣的例子。在某些时候,我也会写关于《与星共舞》的博客。
今天什么都不是。空的。所有的数据都去哪儿了?
不久前,我在Twitter上发布了这张截图(由于访问不到Twitter所以无法贴上来),据我所知,没有人找到正确答案。
截图看起来好像什么也没有。空的名称、空的架构名称、空的角色名称、空的数据库名称,甚至没有数据。然而,这一切以某种方式联系到一起。让我们来深挖背后原因。
并不是一无所有,它是有一些“东西”的,但是你看不见。我的目的是要有尽可能多的 “” (空格或零字符)。
在计算机中,可以有一个空的空格字符,也称为"零宽度"。对于计算机来说,这当然是一个符合规则的字符。打印出来的时候什么都没有。
以下的尝试就是找到巧妙地将"空的空格字符或零宽度空间"用于名称和数据的方法。
2.如何得到一个零宽度?
在编辑器中构建这个示例时,在将它粘贴到psql shell之前,我使用了emptycharacter.com网站。它有一个按钮,复制一个空白到剪贴板。还有其他的方式和网站,只是这个对我来说很有效。
3.如何构建DDL?
在我的例子中,大多数对象的名称都是一个零空间宽度。这包括数据库名、角色名、模式名和类型名:
CREATE ROLE "" WITH login;
CREATE DATABASE "" WITH OWNER "";
\c ""
CREATE SCHEMA "";
SET search_path TO "";
CREATE TYPE ""."" AS ("" TEXT);
但是,表名要使用两个零宽度的空格宽度:否则它与前面创建的类型冲突,后者已经是一个零宽度的空格宽度。这两个对象都在零宽度的空白模式中,因为搜索路径被设置为该模式。
CREATE TABLE ""."" ("" ""."" UNIQUE);
ALTER TABLE ""."" OWNER TO "";
\dt
\d+ "".""
=# \dt
List of relations
Schema | Name | Type | Owner
--------+------+-------+-------
| | table |
(1 row)
=# \d+ "".""
Table "."
Column | Type | Collation | Nullable | Default | Storage | Stats target | Description
--------+------+-----------+----------+---------+----------+--------------+-------------
| "" | | | | extended | |
Indexes:
"__key" UNIQUE CONSTRAINT, btree ("")
Access method: heap
目前为止,看起来是如此的空。
4.我还需要更多的 “空”
只有空的结构是不够的,我也想要空数据。在我的示例中,我构建了5条INSERT语句,它们显然都没有向表中插入任何东西,但也没有违反UNIQUE约束。
此时您可能已经猜到了:5个INSERT语句插入了5个不同数量的零宽度空格。必须使用ROW()构造函数,因为我之前创建了一个基于基本TEXT类型的新类型。关于ROW()这种类型的细节我将在我的 “Advanced Datatypes” 演讲中解释。
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
当我查询数据时,看起来里面什么都没有。但是通过LENGTH()函数查询它,里面显示其中的数据最多有5个字符。
=# SELECT "", LENGTH(("")."") FROM ""."";
| length
---------+--------
() | 1
() | 2
() | 3
() | 4
() | 5
(5 rows)
5.总结
All in all this was rather easy to build, once I figured out the part with the non-printable zero-.width whitespace. The only problem was the tablename which could not be the same as the type name (which I wanted in there because otherwise the \d will show TEXT and not a seemingly empty type).
Full example
Here is the full source code for this example:
总之,这是相当容易建立,就是我需要找出不可显示的零宽度的空格。唯一的问题是表名不能与类型名相同(我想应该是\d显示TEXT,而不是一个看似空的类型)。
下面是这个例子的完整源代码:
\set ON_ERROR_STOP on
\c postgres
-- DROP DATABASE "";
-- DROP ROLE "";
CREATE ROLE "" WITH login;
CREATE DATABASE "" WITH OWNER "";
\c ""
CREATE SCHEMA "";
SET search_path TO "";
CREATE TYPE ""."" AS ("" TEXT);
CREATE TABLE ""."" ("" ""."" UNIQUE);
ALTER TABLE ""."" OWNER TO "";
\dt
\d+ "".""
-- INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
INSERT INTO ""."" VALUES (ROW(''));
SELECT "", LENGTH(("")."") FROM ""."";
原文标题:My PostgreSQL database is empty!
原文作者:Andreas ‘ads’ Scherbaum
原文地址:https://andreas.scherbaum.la/blog/archives/1113-My-PostgreSQL-database-is-empty!.html




