为什么Postgres在为列设置默认函数时双引用第一个函数标识符?
我在Rails项目中有一个默认表达式的遗留表。该表达式会随机选取一个四位数字并将其转换为字符串。在我的测试中,我一直在打字这个确切的语句转换成PSQL设置默认表情:当我做\d owners
这为什么Postgres在为列设置默认函数时双引用第一个函数标识符?
alter table owners alter column signing_code set default
substring(to_char(((random() * ((10000 - 1))::double precision) +
(1)::double precision), '0000'::text), '....$'::text);
那么,什么是Postgres的决定是我实际的默认表情:
default "substring"(to_char(((random() * ((10000 - 1))::double
precision) + (1)::double precision), '0000'::text), '....$'::text)
公告围绕第一个函数标识符substring
的双引号。这会导致两个问题的Rails架构转储/负载:
- 当倾倒架构DB/schema.rb,无效红宝石产生,因为双引号没有逃过
- 即使你正确地逃脱报价当将模式加载回数据库时,Rails错误地将整个表达式设置为默认的字符串值,而不是表达式(即它用单引号括起表达式)
有没有办法让Postgres不是在我的情况下双引号嵌套函数调用中的第一个函数?这将是一个很好的解决方法,否则我会向Rails项目提交一个错误。
为什么substring
函数被双引号并不重要,这两个表达式在功能上是等价的。 PostgreSQL将解析默认表达式,然后保存解析后的版本,在此过程中,substring
标识符会被双引号引用。你可以看到,如果你添加一个CHECK约束类似的这样的事情发生:
check (c in (1, 2, 3))
在桌子上做一个\d
与约束为您提供:
CHECK (c = ANY (ARRAY[1, 2, 3]))
PostgreSQL的平移in
表达为等效= ANY
表达式,因为这就是它想要在内部工作。这两个表达式在功能上是等同的。
真正的问题是ActiveRecord不知道如何处理比单个文字值更复杂的默认表达式。 AR对于什么样的默认设置做出了一个无效的假设,然后盲目地沉溺于一团糟。
当您处理超出最简单的DDL SQL之外的任何事情时,最好的办法是使用db/structure.sql
而不是db/schema.rb
。 structure.sql
使用数据库的本地转储/恢复工具,因此它可以理解并保留数据库知道的所有信息。
切换到structure.sql
很简单:使用db:structure:dump
rake任务
config.active_record.schema_format = :sql
转储structure.sql
:
更新
config/application.rb
使用正确的格式。从您的源代码树和版本控制中删除
db/schema.rb
。将
db/structure.sql
添加到修订控件。-
重新训练你的手指使用不同的耙任务倾销和恢复模式:
-
db:structure:dump
而不是db:schema:dump
。 -
db:structure:load
而不是db:schema:load
。
-
我总是structure.sql
为schema.rb
对我多么希望我的数据库工作太有限开始。