8.4. 二进制数据类型

bytea数据类型允许存储二进制串,参见表 8-6。

表 8-6. 二进制数据类型
名字 存储尺寸 描述
bytea 1或4字节外加真正的二进制串 变长二进制串

二进制串是一个八位位组(或字节)的序列。 二进制串和字符串的区别有两个: 首先,二进制串明确允许存储零值的字节以及其它"不可打印的"字节(通常是位于范围 32 到 126 之外的字节)。 字符串不允许零字节,并且也不允许那些对于数据库的选定字符集编码是非法的任何其它字节值或者字节值序列。 第二,对二进制串的操作会处理实际上的字节,而字符串的处理和取决于区域设置。 简单说,二进制字串适用于存储那些程序员认为是"裸字节"的数据,而字符串适合存储文本。

bytea类型支持两种用于输入和输出的外部格式:PostgreSQL的历史的"逃逸"格式和"十六进制"格式。在输入时这两种格式总是会被接受。输出格式则取决于配置参数bytea_output,其默认值为十六进制(注意十六进制格式是在PostgreSQL 9.0中被引入的,早期的版本和某些工具无法理解它)。

SQL标准定义了一种不同的二进制串类型, 叫做BLOB或者BINARY LARGE OBJECT。其输入格式和bytea不同,但是提供的函数和操作符大多一样。

8.4.1. bytea的十六进制格式

"十六进制"格式将二进制数据编码为每个字节2个十六进制位,最高有效位在前。整个串以序列\x开头(用以和逃逸格式区分)。在某些情景中,开头的反斜线可能需要通过双写来逃逸,在相同的情况中逃逸格式必须要双写反斜线,下文描述了细节。十六进制位可以是大写也可以是小写,在位对之间可以有空白(但是在位对内部以及开头的\x序列中不能有空白)。十六进制格式和很多外部应用及协议相兼容,并且其转换速度要比逃逸格式更快,因此人们更愿意用它。

  • 例子:
    SELECT E'\\xDEADBEEF';
    

8.4.2. bytea的逃逸格式

"逃逸"格式是bytea类型的传统**PostgreSQL**格式。它采用将二进制串表示成ASCII字符序列的方法,而将那些无法用ASCII字符表示的字节转换成特殊的逃逸语句。从应用的角度来看,如果将字节表示为字符有意义,那么这种表示将很方便。但是在实际中,这常常是令人困扰的,因为它使二进制串和字符串之间的区别变得模糊,并且这种特别的逃逸机制也有点难于处理。因此这种格式可能会在大部分新应用中避免使用。

在逃逸模式下输入bytea值时,某些值的字节必须被逃逸,而所有的字节值都可以被逃逸。通常,要逃逸一个字节,需要把它转换成与它的三位八进制值, 并且前导一个反斜线(或者两个反斜线,如果使用逃逸串语法将值写成一个字面含义)。反斜线本身(字节值92)也可以用双写的反斜线表示。表 8-7显示了必须被逃逸的字符,并给出了可以使用的替代逃逸序列。

表 8-7. bytea文字逃逸字节
十进制字节值 描述 逃逸输入表示 例子 输出表示
0 0字节 E'\\000' SELECT E'\000'::bytea; \000
39 单引号 ''''E'\\047' SELECT E'''::bytea; '
92 反斜线 E'\\\\'E'\\134' SELECT E'\\'::bytea; \\
0到31和127到255 "不可打印的"字节 E'\\xxx'(八进制值) SELECT E'\001'::bytea; \001

逃逸"不可打印的"字节的要求取决于区域设置。在某些实例中,你可以不理睬它们,让它们保持未逃逸的状态。注意在表 8-7的每一个例子中的结果的长度正好是一个字节,即使其输出表示有时超过一个字符。

如表 8-7中所示,要求多个反斜线的原因是写成一个串文字的输入串在PostgreSQL服务器中必须经过两个分析阶段。每一对中的第一个反斜线被串文字分析器(假设使用了逃逸串语法)解释为一个逃逸字符并且因此被消耗,只留下该对中的第二个反斜线(美元符号包围的串可以被用于防止这一层的逃逸)。剩下的反斜线接着被bytea输入函数识别为开始一个三位八进制值或逃逸另一个反斜线。例如,一个传递给服务器的串文字是E'\001',它在通过逃逸串分析器后变成\001。\001接着被送给bytea输入函数,这里它被转换成一个十进制值为1的单字节。注意单引号字符串不会被bytea特殊对待,因此它遵循串文字的正常规则(参见 4.1. 词法结构 第 2.1 节)。

Bytea字节有时在输出时被逃逸。通常,每一个"不可打印的"字节会被转换成与之等效的三位八进制值并且前置一个反斜线。大部分"可打印的"字节被表示为它们在客户端字符集中的标准表示形式。十进制值为92(反斜线)的字节在输出时被双写。详情请见表 8-8。

表 8-8. bytea输出逃逸字节
十进制字节值 描述 逃逸的输出表示 例子 输出结果
92 反斜线 \\ SELECT E'\\134'::bytea; \\
0到31和127到255 "不可打印的"字节 \xxx(八进制值) SELECT E'\\001'::bytea; \001
32到126 "可打印的"字节 客户端字符集表示 SELECT E'\\176'::bytea; ~

根据你使用的**PostgreSQL**前端,你在逃逸和未逃逸bytea串方面可能需要做额外的工作。例如,如果你的接口自动翻译换行和回车,你可能也不得不逃逸它们。