是否可以将 varchar(32) 的字段转换为 Firebird 数据库中的 BLOB

Is it possible to convert a field of varchar(32) to BLOB in Firebird database

我想保留已保存到 Table 字段 varchar(32) 中的数据,并将其转换为 Firebird 数据库中的 BLOB。 我正在使用一个软件:IBExpert .... 如果可以的话,怎么做?

假设您有 table TEST,其中一列 NAME:

create table test (name varchar(32));
insert into test values('test1');
insert into test values('test2');
insert into test values('test3');
commit;
select * from test;

可以通过以下脚本将列从 varchar 更改为 BLOB:

alter table test add name_blob blob;
update test set name_blob = name;
commit;
alter table test drop name;
alter table test alter column name_blob to name;
commit;
select * from test;

特别是在 IBExpert 中,通过直接修改系统 tables 可以很容易地使用 Firebird 2.1Firebird 2.5(此 "obsolete" 方法在Firebird 3 但没有引入任何东西来替代它。

这在两个方向上都有效,VARCHARBLOBBLOBVARCHAR

您必须有一个 DOMAIN - 即命名数据类型,在 SQL 中,并且该域应该是 BLOB 类型 - 然后是 IBExpert如果您在数据库选项中设置 Firebird 2.x,它本身会发出 Firebird 2.x 执行的命令。

如果您没有 IB Expert 那么您必须发出以下命令:

CREATE DOMAIN T_TEXT_BLOB AS   -- prerequisite
BLOB SUB_TYPE 1; 

update RDB$RELATION_FIELDS     -- the very action
set RDB$FIELD_SOURCE = 'T_TEXT_BLOB'  
   /* the name of the blob domain to be set as the field's new data type */
where RDB$FIELD_SOURCE = '.....' /* name of the column */
  and RDB$RELATION_NAME = '....' /* name of the table */

另请参阅:

当您创建列或更改其数据类型而没有明确命名类型(如 varchar(10))时,Firebird 会在后台创建自动管理的每列一个用户域,名称如 RDB345,所以虽然你也可以这样做,但也许明确命名 domain 会更实用也更安全。

然而,此方法在 Firebird 3 上失败,您必须复制整个 table,如上面的 Maxim 所示。

FB 开发人员对某些 "bugs" 和 "it never worked properly" 发出警告,但拒绝提供详细信息。


更新 我终于重现了跟踪器中提到的错误。

至少在 Firebird 2.1 中引用计数被破坏了 w.r.t。 BLOB 负载。 所以诀窍似乎是立即将隐式 blob 重写为显式,欺骗 Firebird 认为我们为所有 BLOB 值提供了 新内容

假设上面 Maxim 的回答中的名字...

触发和演示错误 获取 "vanilla" VarChar 数据库,应用上述转换,并发出以下命令:

  • update test set name = name -- 试图强制数据转换,但却强制 Firebird 引用计数错误
  • select cast( name as VarChar(200) ) from test - 或者实际上任何试图实际读取字段内容的命令 - 任何此类尝试都会因臭名昭著的 invalid BLOB ID Firebird 错误而被击落。

要解决错误,我们必须防止 Firebird 发生(损坏的)引用计数。所以,我们必须做一个假更新,调用表达式求值器,这样 Firebird 优化器就会失去对值来源的跟踪,并且无法意识到数据并没有真正改变。

  • update test set name = '' || name || '' -- 真正强制数据覆盖和转换,绕过BLOB引用计数。

  • select cast( name as VarChar(200) ) from test - 现在就像一个魅力(尽管 200 太短了,你会遇到 "overflow" 错误

update 命令可以是任何其他触发表达式求值器,例如 update test set name = cast( name as VarChar( NNN ) ) - 但您需要为特定 table 的特定列设计足够大的 NNN。因此,字符串与空字符串的连接是通用的并且可以工作,至少在 Firebird 2.1 上是这样。


以上代表Firebird 2.1.7 Win32。我没有设法用 Firebird 2.5.8 Win64 触发 "invalid BLOB id" - 它 "just worked"。 至少使用单连接模式更新脚本,无论如何这是进行数据库升级的预期方式。 也许如果我在进行模式升级的同时会有用户积极工作——FB 2.5 也会被破坏,不知道。

是不顾FB开发人员的提示,使用这种快捷方式有风险,还是使用"official" Maxim的回答,可能卸载然后重新创建恰好有"dependencies"的一半数据库要删除的字段,保持到 reader.