2013-02-27 53 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