Erw*_*ter 11 postgresql datatypes cte debugging cast
在讨论这个问题的递归 CTE 解决方案时:
@ypercube偶然发现了一个令人惊讶的异常,这导致我们调查类型修饰符的处理。我们发现了令人惊讶的行为。
即使被指示不要这样做。最基本的例子:
SELECT 'vc8'::varchar(8)::varchar
Run Code Online (Sandbox Code Playgroud)
人们可能会期望varchar
(没有修饰符),至少我会。但结果是varchar(8)
(带修饰符)。下面的小提琴中有许多相关的案例。
不需要,所以这在相反的一面出错:
SELECT ARRAY['vc8']::varchar(8)[]
, ARRAY['vc8']::varchar(8)[] || 'vc8'::varchar(8)
Run Code Online (Sandbox Code Playgroud)
第一个表达式varchar(8)[]
按预期产生。
但是第二个,在连接另一个之后varchar(8)
被淡化到只是varchar[]
(没有修饰符)。来自array_append()
,下面小提琴中的示例的类似行为。
在大多数情况下,所有这些都无关紧要。Postgres 不会丢失数据,并且当分配给列时,该值无论如何都会被强制转换为正确的类型。然而,相反方向的错误最终会导致一个令人惊讶的异常:
鉴于此简化表:
CREATE TABLE a (
vc8 varchar(8) -- with modifier
, vc varchar -- without
);
INSERT INTO a VALUES ('a', 'a'), ('bb', 'bb');
Run Code Online (Sandbox Code Playgroud)
虽然此 rCTE 对varchar
列有效vc
,但对varchar(8)
列失败vc8
:
WITH RECURSIVE cte AS (
(
SELECT ARRAY[vc8] AS arr -- produces varchar(8)[]
FROM a
ORDER BY vc8
LIMIT 1
)
UNION ALL
(
SELECT a.vc8 || c.arr -- produces varchar[] !!
FROM cte c
JOIN a ON a.vc8 > c.arr[1]
ORDER BY vc8
LIMIT 1
)
)
TABLE cte;
Run Code Online (Sandbox Code Playgroud)
错误:递归查询“cte”第 1 列在非递归项中具有类型字符变化 (8)[] 但总体类型字符变化 [] 提示:将非递归项的输出转换为正确的类型。职位:103
一种快速的解决方法是强制转换为text
.
一个普通的UNION
查询不会出现同样的问题:它满足于没有修饰符的类型,它保证保留所有信息。但 rCTE 更挑剔。
此外,您不会遇到更常用max(vc8)
而不是ORDER BY
/ 的问题LIMIT 1
,因为max()
朋友们会立即适应text
(或没有修饰符的相应基类型)。
SQL Fiddle展示了 3 件事:
varchar
(不带修饰符)。varchar(n)
(with 修饰符)引发异常。小提琴适用于第 9.3 页。对于第 9.4.4 页,我在本地得到了相同的结果。
我从演示表达式创建了表,以便能够显示包括修饰符在内的确切数据类型。虽然 pgAdmin 开箱即用地显示了此信息,但它无法从 sqlfiddle 获得。值得注意的是,它在psql
(!) 中也不可用。这是 psql 中已知的缺点,之前已经在 pgsql-hackers 上讨论过一个可能的解决方案- 但尚未实现。这可能是尚未检测到并修复该问题的原因之一。
在 SQL 级别,您可以使用pg_typeof()
获取类型(但不能使用修饰符)。
这三个问题合在一起就搞砸了。
准确地说,问题1.不直接涉及,但它破坏了看似明显的修复,在非递归术语中使用强制转换:ARRAY[vc8]::varchar[]
或类似的,这增加了混乱。
这些项目中的哪一个是错误、故障或它应该是怎样的?
我是否遗漏了什么或者我们应该报告一个错误?
这是由于关系属性pg_class
(在和中定义pg_attribute
,或从select
语句动态定义)支持修饰符(通过pg_attribute.atttypmod
),而函数参数则不支持。当通过函数处理时,修饰符会丢失,并且由于所有运算符都是通过函数处理的,因此当由运算符处理时,修饰符也会丢失。
具有输出值或返回记录集或等效函数的函数returns table(...)
也无法保留定义中包含的任何修饰符。但是,return setof <type>
将保留(实际上,可能类型转换为)为type
in定义的任何修饰符的表pg_attribute
。
归档时间: |
|
查看次数: |
1825 次 |
最近记录: |