JOOQ& Firebird - 超出实施限制

时间:2017-02-20 09:31:34

标签: java sql firebird jooq

背景:我使用jOOQ访问Firebird数据库。 Firebird 2.x的行大小限制为64KB。我以前从未达到过限制,但是这个特定的数据库使用UTF8,这意味着限制缩小到大约16K字符。

这就是我使用jOOQ的方式:

  1. 根据需要加载或创建POJO(生成)。例如:

    Book book = context.fetchOne("select * from book where book_id = ?",  1).into(Book.class);
    
  2. 根据需要使用图书对象。

  3. 如果用户保存更改,则将其存储为记录。

    BookRecord rec = context.newRecord(Tables.BOOK, book); 
    context.executeUpdate(rec);
    
  4. 步骤3在executeUpdate()方法失败,因为某种方式jOOQ将所有空的VARCHAR字段转换为VARCHAR(4000)。错误消息是

      

    " SQL错误代码= -204。超出实施限制。块大小   超出实施限制"。

    这是一个已知的Firebird限制,遗憾的是没有任何关于它的事情。

    在表格中,我有大约8个空VARCHAR(512)字段,在UTF8中应该大约为8x4x512(或16KB),但是由于jOOQ将其解释为VARCHAR(4000),所以& #39; s 8x4x4000(128KB)显然超出限制。

    如果我将NULL或空字段设置为某个随机字符串,那么jOOQ会将其转换为精确的字符串长度。 (" ABC"将被投射到varchar(3)

    所以我的问题是:如果没有jOOQ将我的空字段转换为executeUpdate(),如何让VARCHAR(4000)工作?

1 个答案:

答案 0 :(得分:2)

这些演员阵容在jOOQ中具有历史意义,因为有些数据库很难单独从绑定变量推断数据类型,因为在查询执行之前它们不能延迟任何决策:

SELECT ? -- What's the type? Unknown at parse time.

这就是jOOQ为这些数据库生成显式强制转换的原因,其中包括Firebird:

SELECT cast(? as varchar(4000)) -- Now, the type is clear

目前,即使在语句/子句中也可以这样做,其中类型可以从上下文中推断出来,包括

INSERT INTO t(a, b) VALUES (?, ?)
--            ^  ^          |  |
--            +--|----------+  |
--               +-------------+ Bind types can be inferred from column type

就Firebird而言,不幸的是,这种做法很快就会遇到上述尺寸限制。在jOOQ中有一些未决的功能要求可以改进这一点,但在jOOQ 3.9中尚未实现:

解决方法

如果你想修改jOOQ,那么演员决定是在DefaultBinding.sql(BindingSQLContext)。您将看到有几个选项如何覆盖当前行为:

  1. 使用Setting.paramCastMode == NEVER关闭投射(可从jOOQ 3.10获取#1735
  2. 覆盖RenderContext.castMode()以永远不会产生
  3. 在您自己的自定义绑定中覆盖整个方法
  4. 修补逻辑以永不应用任何演员
  5. 在SQL字符串中实施cast\(\?[^)]*\)替换? /api/v1/bars?page[size]=-1