blob: 995a8107b3b01b7869da33b61391b0799710e4b3 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.apache.openjpa.jdbc.meta.strats;
import java.sql.SQLException;
import java.util.Iterator;
import java.util.NoSuchElementException;
import org.apache.openjpa.jdbc.kernel.EagerFetchModes;
import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
import org.apache.openjpa.jdbc.kernel.JDBCStore;
import org.apache.openjpa.jdbc.meta.ClassMapping;
import org.apache.openjpa.jdbc.meta.FieldMapping;
import org.apache.openjpa.jdbc.schema.Column;
import org.apache.openjpa.jdbc.sql.Joins;
import org.apache.openjpa.jdbc.sql.Result;
import org.apache.openjpa.jdbc.sql.SQLBuffer;
import org.apache.openjpa.jdbc.sql.SQLExceptions;
import org.apache.openjpa.jdbc.sql.Select;
import org.apache.openjpa.jdbc.sql.Union;
import org.apache.openjpa.kernel.OpenJPAStateManager;
import org.apache.openjpa.lib.util.Closeable;
import org.apache.openjpa.lib.util.Localizer;
import org.apache.openjpa.util.AbstractLRSProxyCollection;
import org.apache.openjpa.util.InvalidStateException;
/**
* Large result set collection.
*
* @author Abe White
*/
public class LRSProxyCollection
extends AbstractLRSProxyCollection {
private static final Localizer _loc = Localizer.forPackage
(LRSProxyCollection.class);
private final LRSCollectionFieldStrategy _strat;
public LRSProxyCollection(LRSCollectionFieldStrategy strat) {
super(strat.getFieldMapping().getElement().getDeclaredType(),
strat.getFieldMapping().getOrderColumn() != null);
_strat = strat;
}
@Override
protected int count() {
final ClassMapping[] elems = _strat.getIndependentElementMappings
(false);
final OpenJPAStateManager sm = assertOwner();
final JDBCStore store = getStore();
Union union = store.getSQLFactory().newUnion
(Math.max(1, elems.length));
union.select(new Union.Selector() {
@Override
public void select(Select sel, int idx) {
ClassMapping elem = (elems.length == 0) ? null : elems[idx];
sel.whereForeignKey(_strat.getJoinForeignKey(elem),
sm.getObjectId(), _strat.getFieldMapping().
getDefiningMapping(), store);
}
});
try {
return union.getCount(store);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, store.getDBDictionary());
}
}
@Override
protected boolean has(final Object obj) {
final ClassMapping[] elems = _strat.getIndependentElementMappings
(false);
final OpenJPAStateManager sm = assertOwner();
final JDBCStore store = getStore();
Union union = store.getSQLFactory().newUnion
(Math.max(1, elems.length));
union.select(new Union.Selector() {
@Override
public void select(Select sel, int idx) {
ClassMapping elem = (elems.length == 0) ? null : elems[idx];
sel.whereForeignKey(_strat.getJoinForeignKey(elem),
sm.getObjectId(), _strat.getFieldMapping().
getDefiningMapping(), store);
Object val = _strat.toDataStoreValue(obj, store);
Column[] cols = _strat.getElementColumns(elem);
Object[] vals = (cols.length == 1) ? null : (Object[]) val;
SQLBuffer sql = new SQLBuffer(store.getDBDictionary());
for (int i = 0; i < cols.length; i++) {
if (i > 0)
sql.append(" AND ");
sql.append(sel.getColumnAlias(cols[i]));
if (vals == null)
sql.append((val == null) ? " IS " : " = ").
appendValue(val, cols[i]);
else
sql.append((vals[i] == null) ? " IS " : " = ").
appendValue(vals[i], cols[i]);
}
sel.where(sql);
}
});
try {
return union.getCount(store) > 0;
} catch (SQLException se) {
throw SQLExceptions.getStore(se, store.getDBDictionary());
}
}
@Override
protected Iterator itr() {
final ClassMapping[] elems = _strat.getIndependentElementMappings(true);
final OpenJPAStateManager sm = assertOwner();
final JDBCStore store = getStore();
final JDBCFetchConfiguration fetch = store.getFetchConfiguration();
final Joins[] resJoins = new Joins[Math.max(1, elems.length)];
final FieldMapping fm = _strat.getFieldMapping();
Union union = store.getSQLFactory().newUnion
(Math.max(1, elems.length));
if (fetch.getSubclassFetchMode(fm.getElementMapping().
getTypeMapping()) != EagerFetchModes.EAGER_JOIN)
union.abortUnion();
union.setLRS(true);
union.select(new Union.Selector() {
@Override
public void select(Select sel, int idx) {
ClassMapping elem = (elems.length == 0) ? null : elems[idx];
sel.whereForeignKey(_strat.getJoinForeignKey(elem),
sm.getObjectId(), fm.getDefiningMapping(), store);
// order before select in case we're faking union with
// multiple selects; order vals used to merge results
fm.orderLocal(sel, elem, null);
resJoins[idx] = _strat.joinElementRelation(sel.newJoins(),
elem);
fm.orderRelation(sel, elem, resJoins[idx]);
_strat.selectElement(sel, elem, store, fetch, EagerFetchModes.EAGER_JOIN,
resJoins[idx]);
}
});
try {
Result res = union.execute(store, fetch);
return new ResultIterator(sm, store, fetch, res, resJoins);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, store.getDBDictionary());
}
}
private OpenJPAStateManager assertOwner() {
OpenJPAStateManager sm = getOwner();
if (sm == null)
throw new InvalidStateException(_loc.get("lrs-no-owner",
_strat.getFieldMapping()));
return sm;
}
private JDBCStore getStore() {
return (JDBCStore) getOwner().getContext().getStoreManager().
getInnermostDelegate();
}
/**
* Closeable iterator built around a JDBC result.
*/
private class ResultIterator
implements Iterator, Closeable {
private final OpenJPAStateManager _sm;
private final JDBCStore _store;
private final JDBCFetchConfiguration _fetch;
private final Result _res;
private final Joins[] _joins;
private Boolean _next = null;
public ResultIterator(OpenJPAStateManager sm, JDBCStore store,
JDBCFetchConfiguration fetch, Result res, Joins[] joins) {
_sm = sm;
_store = store;
_fetch = fetch;
_res = res;
_joins = joins;
}
@Override
public boolean hasNext() {
if (_next == null) {
try {
_next = (_res.next()) ? Boolean.TRUE : Boolean.FALSE;
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _store.getDBDictionary());
}
}
return _next;
}
@Override
public Object next() {
if (!hasNext())
throw new NoSuchElementException();
try {
_next = null;
return _strat.loadElement(_sm, _store, _fetch, _res,
_joins[_res.indexOf()]);
} catch (SQLException se) {
throw SQLExceptions.getStore(se, _store.getDBDictionary());
}
}
@Override
public void remove() {
throw new UnsupportedOperationException();
}
@Override
public void close() {
_next = Boolean.FALSE;
_res.close();
}
}
}