2013-02-27 54 views
1

我们有这样的命名查询:如何让EclipseLink为UPDATE WHERE子句输出有效的Informix SQL?

UPDATE Foo f SET f.x = 0 WHERE f.x = :invoiceId 

Foo在这种情况下是一个超类的实体,使用表每类继承的策略。

是EclipseLink的生成SQL是:

UPDATE foo_subclass SET x = ? 
WHERE EXISTS(SELECT t0.id 
       FROM foo_superclass t0, foo_subclass t1 
       WHERE ((t1.x = ?) AND ((t1.id = t0.id) AND (t0.DTYPE = ?))) 

(该?插槽正确填写。)

在Informix上11.70,我们得到一个错误,该子查询不能访问被更改的表。

这里是我能找到的Informix上限制子查询的文档:http://publib.boulder.ibm.com/infocenter/idshelp/v115/index.jsp?topic=%2Fcom.ibm.sqls.doc%2Fids_sqs_2005.htm

其它数据库还具有在这样的子查询的限制,所以尽管这表现为一个Informix问题,我敢肯定,如果我们对此反对,比如MySQL,我们会得到一个类似的错误。

我如何获得EclipseLink来履行这些限制?是否有更好的查询我应该使用?

+0

您正在使用哪个版本的Informix?你参考11.50信息中心,所以我猜你正在使用11.50。但是,由于11.70中的等效页面([UPDATE的WHERE子句中的子查询](http://publib.boulder.ibm.com/infocenter/idshelp/v117/topic/com.ibm.sqls.doc/ids_sqs_2005.htm ))包含相同的信息,但这次可能不是主要问题(但总是陈述您正在使用的Informix的版本,以及平台;它通常很重要)。 – 2013-02-28 01:52:39

+0

修改答案;这是11.70。 – 2013-02-28 14:07:56

+0

EclipseLink在连接时检测哪个DatabasePlattform(应打印到日志中)?它能正确检测Informix吗? – MRalwasser 2013-02-28 16:34:17

回答

1

找到了答案。看起来EclipseLink不得不为MySQL处理这种情况,它也有类似的问题。

的答案是,你InformixPlatform子类中,你需要重写以下方法来解决这个问题:

  1. supportsLocalTemporaryTables():这需要返回true
  2. shouldAlwaysUseTempStorageForModifyAll():这需要返回true
  3. dontBindUpdateAllQueryUsingTempTables需要返回true
  4. getCreateTempTableSqlPrefix():这需要返回CREATE TEMP TABLE 
  5. getCreateTempTableSqlSuffix():这需要返回 WITH NO LOG
  6. isInformixOuterJoin():需要返回false
  7. getTempTableForTable(DatabaseTable):这需要做到这一点:

    return new DatabaseTable("TL_" + table.getName(), "" /* no table qualifier */, table.shouldUseDelimiters(), this.getStartDelimiter(), this.getEndDelimiter()); 
    

此外,你需要重写以下方法以及适当的InformixPlatform行为:

  1. appendBoolean(Boolean, Writer):股票Informix平台不会正确写出布尔文字。你需要做的是:

    if (Boolean.TRUE.equals(booleanValue)) { 
        writer.write("'t'"); 
    } else { 
        writer.write("'f'"); 
    } 
    
  2. 你需要重写writeUpdateOriginalFromTempTableSql以便它包含为H2Platform的越权做了同样的代码:

    @Override 
    public void writeUpdateOriginalFromTempTableSql(final Writer writer, final DatabaseTable table, final Collection pkFields, final Collection assignedFields) throws IOException { 
        writer.write("UPDATE "); 
        final String tableName = table.getQualifiedNameDelimited(this);  
        writer.write(tableName); 
        writer.write(" SET "); 
        final int size = assignedFields.size(); 
        if (size > 1) { 
        writer.write("(");    
        } 
        writeFieldsList(writer, assignedFields, this); 
        if (size > 1) { 
        writer.write(")");    
        } 
        writer.write(" = (SELECT ");   
        writeFieldsList(writer, assignedFields, this); 
        writer.write(" FROM "); 
        final String tempTableName = this.getTempTableForTable(table).getQualifiedNameDelimited(this); 
        writer.write(tempTableName); 
        writeAutoJoinWhereClause(writer, null, tableName, pkFields, this); 
        writer.write(") WHERE EXISTS(SELECT "); 
        writer.write(((DatabaseField)pkFields.iterator().next()).getNameDelimited(this)); 
        writer.write(" FROM "); 
        writer.write(tempTableName); 
        writeAutoJoinWhereClause(writer, null, tableName, pkFields, this); 
        writer.write(")"); 
    } 
    

最后,你的构造需要请致电this.setShouldBindLiterals(false)

随着这些变化,Informix似乎很高兴。

+0

情节变厚;还有更多的东西去这里。 (对于接下来的那些)。还需要重写其他几个方法,包括临时表前缀和后缀方法(在最后添加'WITH NO LOG')。现在Informix平台在插入之前删除临时表。接下来要解决这个问题。很明显这个平台还没有经过多年测试。 – 2013-03-01 17:36:51

+0

接下来,Informix不支持具有模式/所有者前缀的合格“TEMP TABLE”名称。这与EclipseLink忽略(!)来自实际尝试CREATE TEMP TABLE操作的语句(!!)的事实意味着尝试创建具有模式前缀的临时表所产生的语法错误被隐藏/吞噬。即将到来的更多补丁。 – 2013-03-01 18:58:58

+0

提交的问题:https://bugs.eclipse.org/bugs/show_bug.cgi?id = 402180 – 2013-03-01 19:40:48

1

相反的:

UPDATE foo_subclass SET x = ? 
WHERE EXISTS(SELECT t0.id 
       FROM foo_superclass t0, foo_subclass t1 
       WHERE ((t1.x = ?) AND ((t1.id = t0.id) AND (t0.DTYPE = ?))) 

做到这一点:

UPDATE 
    foo_subclass SET x = ? 
WHERE 
    foo_subclass.x = ? AND 
    EXISTS(SELECT t0.id 
     FROM foo_superclass t0 
     WHERE ((foo_subclass.id = t0.id) AND (t0.DTYPE = ?)) 

注意,在11.50,你不能使用别名foo_subclass。它在11.70允许。 我假设“id”是主键(或至少是唯一标识符)。

+0

谢谢,但我不认为我可以。 EclipseLink控制SQL语法。我们在11.70上跑。是的,在我的例子中'id'是所讨论的表的主键。 – 2013-02-28 01:25:45

+0

我可以问一下语法问题是什么?为什么Informix不像EclipseLink创建的SQL? – 2013-02-28 01:26:19

+0

@LairdNelson:这不是一个语法问题;这是一个语义问题。限制背后的关注点是在查询正在处理时表是否发生更改,从而导致要更新的数据集中存在稳定性问题。这些问题有多严重,围绕着他们是否有一种半途而废的方式,可供讨论,但自古以来就一直存在这种限制。 – 2013-02-28 01:57:22