| /* |
| * 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(); |
| } |
| } |
| } |
| |