EclipseLink1.1.3 + Oracleでのおはなし。

下のようなJPQLを動的に生成しました。

SELECT e FROM Employee e LEFT OUTER JOIN FETCH e.company

するとあろうことか、下記のようなSQLが。

SELECT * FROM EMPLOYEE t0, COMPANY t1 WHERE t0.COMPANY_ID =* t1.ID
ORA-00936: 式がありません。 

なんじゃそりゃあ!
Oracleなんだから外部結合の演算子は"(+)="でしょう?
当然OraclePlatform(Oracle11Platform)を使用した上でこの挙動です。
しかも再現性は超不安定で、サーバーを起動してから上記のJPQLを実行する最初の1回でまれに発生します。
わけがわからなくて困っていたのですが、ようやく解決しました。


DatasourcePlatform

    public Map getPlatformOperators() {
        if (platformOperators == null) {
            synchronized (this) {
                if (platformOperators == null) {
                    initializePlatformOperators();
                }
            }
        }
        return platformOperators;
    }

    protected void initializePlatformOperators() {
        this.platformOperators = new HashMap();

        // Outer join
        addOperator(ExpressionOperator.equalOuterJoin());

        〜 省略 〜
    }

ExpressionOperator

    public static ExpressionOperator equalOuterJoin() {
        return simpleRelation(EqualOuterJoin, "=*");
    }

OraclePlatform

    protected void initializePlatformOperators() {
        super.initializePlatformOperators();
        addOperator(operatorOuterJoin());

        〜 省略 〜
    }

    protected ExpressionOperator operatorOuterJoin() {
        ExpressionOperator result = new ExpressionOperator();
        result.setSelector(ExpressionOperator.EqualOuterJoin);
        Vector v = oracle.toplink.internal.helper.NonSynchronizedVector.newInstance(2);
        v.addElement(" (+) = ");
        result.printsAs(v);
        result.bePostfix();
        result.setNodeClass(RelationExpression.class);
        return result;

    }

double-checked locking?
そんなかわいいもんじゃあなかった。
機能してないよ!
この排他制御機能してないよ!


つまり…OraclePlatform#initializePlatformOperators()の1行目の

    super.initializePlatformOperators();

が実行されて、DatasourcePlatform#initializePlatformOperators()の1行目の

    this.platformOperators = new HashMap();

が実行されてしまうと、DatasourcePlatform#getPlatformOperators()の1行目の

    if (platformOperators == null) {

がtrueでなくなってしまい、中途半端にしか初期化されていないplatformOperatorsがreturnされる可能性があるわけですね!
一時はどうなることかと思ったけど、原因がわかってよかったです。