| /* |
| * 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.sql; |
| |
| import java.sql.ResultSet; |
| import java.sql.SQLException; |
| import java.util.BitSet; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Iterator; |
| import java.util.List; |
| |
| import org.apache.openjpa.jdbc.conf.JDBCConfiguration; |
| 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.schema.ForeignKey; |
| import org.apache.openjpa.jdbc.schema.Table; |
| import org.apache.openjpa.kernel.exps.Context; |
| import org.apache.openjpa.kernel.exps.Value; |
| import org.apache.openjpa.lib.util.Localizer; |
| import org.apache.openjpa.util.InternalException; |
| import org.apache.openjpa.util.UnsupportedException; |
| import org.apache.openjpa.util.UserException; |
| |
| /** |
| * A logical union made up of multiple distinct selects whose results are |
| * combined in memory. |
| * |
| * @author Abe White |
| */ |
| public class LogicalUnion |
| implements Union { |
| |
| private static final Localizer _loc = Localizer.forPackage |
| (LogicalUnion.class); |
| |
| protected final UnionSelect[] sels; |
| protected final DBDictionary dict; |
| protected final ClassMapping[] mappings; |
| protected final BitSet desc = new BitSet(); |
| private boolean _distinct = true; |
| |
| |
| /** |
| * Constructor. |
| * |
| * @param conf system configuration |
| * @param sels the number of SQL selects to union together |
| */ |
| public LogicalUnion(JDBCConfiguration conf, int sels) { |
| this(conf, sels, null); |
| } |
| |
| /** |
| * Constructor used to seed the internal selects. |
| */ |
| public LogicalUnion(JDBCConfiguration conf, Select[] seeds) { |
| this(conf, seeds.length, seeds); |
| } |
| |
| /** |
| * Delegate constructor. |
| */ |
| protected LogicalUnion(JDBCConfiguration conf, int sels, Select[] seeds) { |
| if (sels == 0) |
| throw new InternalException("sels == 0"); |
| |
| dict = conf.getDBDictionaryInstance(); |
| mappings = new ClassMapping[sels]; |
| this.sels = new UnionSelect[sels]; |
| |
| SelectImpl seed; |
| for (int i = 0; i < sels; i++) { |
| seed = (seeds == null) |
| ? (SelectImpl) conf.getSQLFactoryInstance().newSelect() |
| : (SelectImpl) seeds[i]; |
| this.sels[i] = newUnionSelect(seed, i); |
| } |
| } |
| |
| /** |
| * Create a new union select with the given delegate and union position. |
| */ |
| protected UnionSelect newUnionSelect(SelectImpl seed, int pos) { |
| return new UnionSelect(seed, pos); |
| } |
| |
| @Override |
| public Select[] getSelects() { |
| return sels; |
| } |
| |
| @Override |
| public boolean isUnion() { |
| return false; |
| } |
| |
| @Override |
| public void abortUnion() { |
| } |
| |
| @Override |
| public String getOrdering() { |
| return null; |
| } |
| |
| @Override |
| public JDBCConfiguration getConfiguration() { |
| return sels[0].getConfiguration(); |
| } |
| |
| public DBDictionary getDBDictionary() { |
| return dict; |
| } |
| |
| @Override |
| public SQLBuffer toSelect(boolean forUpdate, JDBCFetchConfiguration fetch) { |
| return dict.toSelect(sels[0], forUpdate, fetch); |
| } |
| |
| @Override |
| public SQLBuffer getSQL() { |
| return sels.length == 1 ? sels[0].getSQL() : null; |
| } |
| |
| @Override |
| public SQLBuffer toSelectCount() { |
| return dict.toSelectCount(sels[0]); |
| } |
| |
| @Override |
| public boolean getAutoDistinct() { |
| return sels[0].getAutoDistinct(); |
| } |
| |
| @Override |
| public void setAutoDistinct(boolean distinct) { |
| for (UnionSelect sel : sels) { |
| sel.setAutoDistinct(distinct); |
| } |
| } |
| |
| @Override |
| public boolean isDistinct() { |
| return _distinct; |
| } |
| |
| @Override |
| public void setDistinct(boolean distinct) { |
| _distinct = distinct; |
| } |
| |
| @Override |
| public boolean isLRS() { |
| return sels[0].isLRS(); |
| } |
| |
| @Override |
| public void setLRS(boolean lrs) { |
| for (UnionSelect sel : sels) { |
| sel.setLRS(lrs); |
| } |
| } |
| |
| @Override |
| public int getExpectedResultCount() { |
| return sels[0].getExpectedResultCount(); |
| } |
| |
| @Override |
| public void setExpectedResultCount(int expectedResultCount, |
| boolean force) { |
| for (UnionSelect sel : sels) { |
| sel.setExpectedResultCount(expectedResultCount, force); |
| } |
| } |
| |
| @Override |
| public int getJoinSyntax() { |
| return sels[0].getJoinSyntax(); |
| } |
| |
| @Override |
| public void setJoinSyntax(int syntax) { |
| for (UnionSelect sel : sels) { |
| sel.setJoinSyntax(syntax); |
| } |
| } |
| |
| @Override |
| public boolean supportsRandomAccess(boolean forUpdate) { |
| if (sels.length == 1) |
| return sels[0].supportsRandomAccess(forUpdate); |
| return false; |
| } |
| |
| @Override |
| public boolean supportsLocking() { |
| if (sels.length == 1) |
| return sels[0].supportsLocking(); |
| for (UnionSelect sel : sels) |
| if (!sel.supportsLocking()) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public boolean hasMultipleSelects() { |
| if (sels != null && sels.length > 1) |
| return true; |
| return sels[0].hasMultipleSelects(); |
| } |
| |
| @Override |
| public int getCount(JDBCStore store) |
| throws SQLException { |
| int count = 0; |
| for (UnionSelect sel : sels) { |
| count += sel.getCount(store); |
| } |
| return count; |
| } |
| |
| @Override |
| public Result execute(JDBCStore store, JDBCFetchConfiguration fetch) |
| throws SQLException { |
| if (fetch == null) |
| fetch = store.getFetchConfiguration(); |
| return execute(store, fetch, fetch.getReadLockLevel()); |
| } |
| |
| @Override |
| public Result execute(JDBCStore store, JDBCFetchConfiguration fetch, |
| int lockLevel) |
| throws SQLException { |
| if (fetch == null) |
| fetch = store.getFetchConfiguration(); |
| |
| if (sels.length == 1) { |
| Result res = sels[0].execute(store, fetch, lockLevel); |
| ((AbstractResult) res).setBaseMapping(mappings[0]); |
| return res; |
| } |
| |
| if (getExpectedResultCount() == 1) { |
| AbstractResult res; |
| for (int i = 0; i < sels.length; i++) { |
| res = (AbstractResult) sels[i].execute(store, fetch, |
| lockLevel); |
| res.setBaseMapping(mappings[i]); |
| res.setIndexOf(i); |
| |
| // if we get to the last select, just return its result |
| if (i == sels.length - 1) |
| return res; |
| |
| // return the first result that has a row |
| try { |
| if (!res.next()) |
| res.close(); |
| else { |
| res.pushBack(); |
| return res; |
| } |
| } |
| catch (SQLException se) { |
| res.close(); |
| throw se; |
| } |
| } |
| } |
| |
| // create a single result from each select in our fake union, merging |
| // them as needed |
| AbstractResult[] res = new AbstractResult[sels.length]; |
| List[] orderIdxs = null; |
| try { |
| List l; |
| for (int i = 0; i < res.length; i++) { |
| res[i] = (AbstractResult) sels[i].execute(store, fetch, |
| lockLevel); |
| res[i].setBaseMapping(mappings[i]); |
| res[i].setIndexOf(i); |
| |
| l = sels[i].getSelectedOrderIndexes(); |
| if (l != null) { |
| if (orderIdxs == null) |
| orderIdxs = new List[sels.length]; |
| orderIdxs[i] = l; |
| } |
| } |
| } catch (SQLException se) { |
| for (int i = 0; res[i] != null; i++) |
| res[i].close(); |
| throw se; |
| } |
| |
| // if multiple selects have ordering, use a comparator to collate |
| ResultComparator comp = null; |
| if (orderIdxs != null) |
| comp = new ResultComparator(orderIdxs, desc, dict); |
| return new MergedResult(res, comp); |
| } |
| |
| @Override |
| public void select(Union.Selector selector) { |
| for (int i = 0; i < sels.length; i++) |
| selector.select(sels[i], i); |
| } |
| |
| @Override |
| public String toString() { |
| return toSelect(false, null).getSQL(); |
| } |
| |
| /** |
| * A callback used to create the selects in a SQL union. |
| */ |
| public interface Selector { |
| |
| /** |
| * Populate the <code>i</code>th select in the union. |
| */ |
| void select(Select sel, int i); |
| } |
| |
| /** |
| * A select that is part of a logical union. |
| */ |
| public class UnionSelect |
| implements Select { |
| |
| protected final SelectImpl sel; |
| protected final int pos; |
| protected int orders = 0; |
| protected List orderIdxs = null; |
| |
| public UnionSelect(SelectImpl sel, int pos) { |
| this.sel = sel; |
| this.pos = pos; |
| sel.setRecordOrderedIndexes(true); |
| } |
| |
| /** |
| * Delegate select. |
| */ |
| public SelectImpl getDelegate() { |
| return sel; |
| } |
| |
| /** |
| * Return the indexes of the data in the select clause this query is |
| * ordered by. |
| */ |
| public List getSelectedOrderIndexes() { |
| if (orderIdxs == null) |
| orderIdxs = sel.getOrderedIndexes(); |
| return orderIdxs; |
| } |
| |
| @Override |
| public JDBCConfiguration getConfiguration() { |
| return sel.getConfiguration(); |
| } |
| |
| @Override |
| public int indexOf() { |
| return pos; |
| } |
| |
| @Override |
| public SQLBuffer toSelect(boolean forUpdate, |
| JDBCFetchConfiguration fetch) { |
| return sel.toSelect(forUpdate, fetch); |
| } |
| |
| @Override |
| public SQLBuffer getSQL() { |
| return sel.getSQL(); |
| } |
| |
| @Override |
| public SQLBuffer toSelectCount() { |
| return sel.toSelectCount(); |
| } |
| |
| @Override |
| public boolean getAutoDistinct() { |
| return sel.getAutoDistinct(); |
| } |
| |
| @Override |
| public void setAutoDistinct(boolean distinct) { |
| sel.setAutoDistinct(distinct); |
| } |
| |
| @Override |
| public boolean isDistinct() { |
| return sel.isDistinct(); |
| } |
| |
| @Override |
| public void setDistinct(boolean distinct) { |
| sel.setDistinct(distinct); |
| } |
| |
| @Override |
| public boolean isLRS() { |
| return sel.isLRS(); |
| } |
| |
| @Override |
| public void setLRS(boolean lrs) { |
| sel.setLRS(lrs); |
| } |
| |
| @Override |
| public int getJoinSyntax() { |
| return sel.getJoinSyntax(); |
| } |
| |
| @Override |
| public void setJoinSyntax(int joinSyntax) { |
| sel.setJoinSyntax(joinSyntax); |
| } |
| |
| @Override |
| public boolean supportsRandomAccess(boolean forUpdate) { |
| return sel.supportsRandomAccess(forUpdate); |
| } |
| |
| @Override |
| public boolean supportsLocking() { |
| return sel.supportsLocking(); |
| } |
| |
| @Override |
| public boolean hasMultipleSelects() { |
| return sel.hasMultipleSelects(); |
| } |
| |
| @Override |
| public int getCount(JDBCStore store) |
| throws SQLException { |
| return sel.getCount(store); |
| } |
| |
| @Override |
| public Result execute(JDBCStore store, JDBCFetchConfiguration fetch) |
| throws SQLException { |
| return sel.execute(store, fetch); |
| } |
| |
| @Override |
| public Result execute(JDBCStore store, JDBCFetchConfiguration fetch, |
| int lockLevel) |
| throws SQLException { |
| return sel.execute(store, fetch, lockLevel); |
| } |
| |
| @Override |
| public List getSubselects() { |
| return Collections.EMPTY_LIST; |
| } |
| |
| @Override |
| public Select getParent() { |
| return null; |
| } |
| |
| @Override |
| public String getSubselectPath() { |
| return null; |
| } |
| |
| @Override |
| public void setParent(Select parent, String path) { |
| throw new UnsupportedException(_loc.get("union-element")); |
| } |
| |
| @Override |
| public void setHasSubselect(boolean hasSub) { |
| sel.setHasSubselect(hasSub); |
| } |
| |
| @Override |
| public boolean getHasSubselect() { |
| return sel.getHasSubselect(); |
| } |
| |
| @Override |
| public Select getFromSelect() { |
| return null; |
| } |
| |
| @Override |
| public void setFromSelect(Select sel) { |
| throw new UnsupportedException(_loc.get("union-element")); |
| } |
| |
| @Override |
| public boolean hasEagerJoin(boolean toMany) { |
| return sel.hasEagerJoin(toMany); |
| } |
| |
| @Override |
| public boolean hasJoin(boolean toMany) { |
| return sel.hasJoin(toMany); |
| } |
| |
| @Override |
| public boolean isSelected(Table table) { |
| return sel.isSelected(table); |
| } |
| |
| @Override |
| public Collection getTableAliases() { |
| return sel.getTableAliases(); |
| } |
| |
| @Override |
| public List getSelects() { |
| return sel.getSelects(); |
| } |
| |
| @Override |
| public List getSelectAliases() { |
| return sel.getSelectAliases(); |
| } |
| |
| @Override |
| public List getIdentifierAliases() { |
| return sel.getIdentifierAliases(); |
| } |
| |
| @Override |
| public SQLBuffer getOrdering() { |
| return sel.getOrdering(); |
| } |
| |
| @Override |
| public SQLBuffer getGrouping() { |
| return sel.getGrouping(); |
| } |
| |
| @Override |
| public SQLBuffer getWhere() { |
| return sel.getWhere(); |
| } |
| |
| @Override |
| public SQLBuffer getHaving() { |
| return sel.getHaving(); |
| } |
| |
| @Override |
| public void addJoinClassConditions() { |
| sel.addJoinClassConditions(); |
| } |
| |
| @Override |
| public Joins getJoins() { |
| return sel.getJoins(); |
| } |
| |
| @Override |
| public Iterator getJoinIterator() { |
| return sel.getJoinIterator(); |
| } |
| |
| @Override |
| public long getStartIndex() { |
| return sel.getStartIndex(); |
| } |
| |
| @Override |
| public long getEndIndex() { |
| return sel.getEndIndex(); |
| } |
| |
| @Override |
| public void setRange(long start, long end) { |
| sel.setRange(start, end); |
| } |
| |
| @Override |
| public String getColumnAlias(Column col) { |
| return sel.getColumnAlias(col); |
| } |
| |
| @Override |
| public String getColumnAlias(Column col, Joins joins) { |
| return sel.getColumnAlias(col, joins); |
| } |
| |
| @Override |
| public String getColumnAlias(Column col, Object alias) { |
| return sel.getColumnAlias(col, alias); |
| } |
| |
| @Override |
| public String getColumnAlias(String col, Table table) { |
| return sel.getColumnAlias(col, table); |
| } |
| |
| @Override |
| public String getColumnAlias(String col, Table table, Joins joins) { |
| return sel.getColumnAlias(col, table, joins); |
| } |
| |
| @Override |
| public boolean isAggregate() { |
| return sel.isAggregate(); |
| } |
| |
| @Override |
| public void setAggregate(boolean agg) { |
| sel.setAggregate(agg); |
| } |
| |
| @Override |
| public boolean isLob() { |
| return sel.isLob(); |
| } |
| |
| @Override |
| public void setLob(boolean lob) { |
| sel.setLob(lob); |
| } |
| |
| @Override |
| public void selectPlaceholder(String sql) { |
| sel.selectPlaceholder(sql); |
| } |
| |
| @Override |
| public void clearSelects() { |
| sel.clearSelects(); |
| } |
| |
| @Override |
| public boolean select(SQLBuffer sql, Object id) { |
| return sel.select(sql, id); |
| } |
| |
| @Override |
| public boolean select(SQLBuffer sql, Object id, Joins joins) { |
| return sel.select(sql, id, joins); |
| } |
| |
| @Override |
| public boolean select(String sql, Object id) { |
| return sel.select(sql, id); |
| } |
| |
| @Override |
| public boolean select(String sql, Object id, Joins joins) { |
| return sel.select(sql, id, joins); |
| } |
| |
| @Override |
| public boolean select(Column col) { |
| return sel.select(col); |
| } |
| |
| @Override |
| public boolean select(Column col, Joins joins) { |
| return sel.select(col, joins); |
| } |
| |
| @Override |
| public int select(Column[] cols) { |
| return sel.select(cols); |
| } |
| |
| @Override |
| public int select(Column[] cols, Joins joins) { |
| return sel.select(cols, joins); |
| } |
| |
| @Override |
| public void select(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch, int eager) { |
| select(mapping, subclasses, store, fetch, eager, null, false); |
| } |
| |
| @Override |
| public void select(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch, int eager, |
| Joins joins) { |
| select(mapping, subclasses, store, fetch, eager, joins, false); |
| } |
| |
| private void select(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch, int eager, |
| Joins joins, boolean identifier) { |
| // if this is the first (primary) mapping selected for this |
| // SELECT, record it so we can figure out what the result type is |
| // since the discriminator might not be selected |
| if (mappings[pos] == null) |
| mappings[pos] = mapping; |
| |
| sel.select(this, mapping, subclasses, store, fetch, eager, |
| joins, identifier); |
| } |
| |
| @Override |
| public boolean selectIdentifier(Column col) { |
| return sel.selectIdentifier(col); |
| } |
| |
| @Override |
| public boolean selectIdentifier(Column col, Joins joins) { |
| return sel.selectIdentifier(col, joins); |
| } |
| |
| @Override |
| public int selectIdentifier(Column[] cols) { |
| return sel.selectIdentifier(cols); |
| } |
| |
| @Override |
| public int selectIdentifier(Column[] cols, Joins joins) { |
| return sel.selectIdentifier(cols, joins); |
| } |
| |
| @Override |
| public void selectIdentifier(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch, int eager) { |
| select(mapping, subclasses, store, fetch, eager, null, true); |
| } |
| |
| @Override |
| public void selectIdentifier(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch, int eager, |
| Joins joins) { |
| select(mapping, subclasses, store, fetch, eager, joins, true); |
| } |
| |
| @Override |
| public int selectPrimaryKey(ClassMapping mapping) { |
| return sel.selectPrimaryKey(mapping); |
| } |
| |
| @Override |
| public int selectPrimaryKey(ClassMapping mapping, Joins joins) { |
| return sel.selectPrimaryKey(mapping, joins); |
| } |
| |
| @Override |
| public int orderByPrimaryKey(ClassMapping mapping, boolean asc, |
| boolean select) { |
| return orderByPrimaryKey(mapping, asc, null, select); |
| } |
| |
| @Override |
| public int orderByPrimaryKey(ClassMapping mapping, boolean asc, |
| Joins joins, boolean select) { |
| ClassMapping pks = mapping; |
| while (!pks.isPrimaryKeyObjectId(true)) |
| pks = pks.getJoinablePCSuperclassMapping(); |
| Column[] cols = pks.getPrimaryKeyColumns(); |
| recordOrderColumns(cols, asc); |
| return sel.orderByPrimaryKey(mapping, asc, joins, select, |
| isUnion()); |
| } |
| |
| /** |
| * Record that we're ordering by a SQL expression. |
| */ |
| protected void recordOrder(Object ord, boolean asc) { |
| if (ord == null) |
| return; |
| orderIdxs = null; |
| |
| int idx = orders++; |
| if (desc.get(idx) && asc) |
| throw new UserException(_loc.get("incompat-ordering")); |
| if (!asc) |
| desc.set(idx); |
| } |
| |
| /** |
| * Record that we're ordering by the given columns. |
| */ |
| protected void recordOrderColumns(Column[] cols, boolean asc) { |
| for (Column col : cols) { |
| recordOrder(col, asc); |
| } |
| } |
| |
| @Override |
| public boolean orderBy(Column col, boolean asc, boolean select) { |
| return orderBy(col, asc, null, select); |
| } |
| |
| @Override |
| public boolean orderBy(Column col, boolean asc, Joins joins, |
| boolean select) { |
| recordOrder(col, asc); |
| return sel.orderBy(col, asc, joins, select, isUnion()); |
| } |
| |
| @Override |
| public int orderBy(Column[] cols, boolean asc, boolean select) { |
| return orderBy(cols, asc, null, select); |
| } |
| |
| @Override |
| public int orderBy(Column[] cols, boolean asc, Joins joins, |
| boolean select) { |
| recordOrderColumns(cols, asc); |
| return sel.orderBy(cols, asc, joins, select, isUnion()); |
| } |
| |
| @Override |
| public boolean orderBy(SQLBuffer sql, boolean asc, boolean select, |
| Value selAs) { |
| return orderBy(sql, asc, null, select, selAs); |
| } |
| |
| @Override |
| public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins, |
| boolean select, Value selAs) { |
| recordOrder(sql.getSQL(false), asc); |
| return sel.orderBy(sql, asc, joins, select, isUnion(), selAs); |
| } |
| |
| @Override |
| public boolean orderBy(String sql, boolean asc, boolean select) { |
| return orderBy(sql, asc, null, select); |
| } |
| |
| @Override |
| public boolean orderBy(String sql, boolean asc, Joins joins, |
| boolean select) { |
| recordOrder(sql, asc); |
| return sel.orderBy(sql, asc, joins, select, isUnion()); |
| } |
| |
| @Override |
| public void clearOrdering() { |
| sel.clearOrdering(); |
| } |
| |
| @Override |
| public void wherePrimaryKey(Object oid, ClassMapping mapping, |
| JDBCStore store) { |
| sel.wherePrimaryKey(oid, mapping, store); |
| } |
| |
| @Override |
| public void whereForeignKey(ForeignKey fk, Object oid, |
| ClassMapping mapping, JDBCStore store) { |
| sel.whereForeignKey(fk, oid, mapping, store); |
| } |
| |
| @Override |
| public void where(Joins joins) { |
| sel.where(joins); |
| } |
| |
| @Override |
| public void where(SQLBuffer sql) { |
| sel.where(sql); |
| } |
| |
| @Override |
| public void where(SQLBuffer sql, Joins joins) { |
| sel.where(sql, joins); |
| } |
| |
| @Override |
| public void where(String sql) { |
| sel.where(sql); |
| } |
| |
| @Override |
| public void where(String sql, Joins joins) { |
| sel.where(sql, joins); |
| } |
| |
| @Override |
| public void having(SQLBuffer sql) { |
| sel.having(sql); |
| } |
| |
| @Override |
| public void having(SQLBuffer sql, Joins joins) { |
| sel.having(sql, joins); |
| } |
| |
| @Override |
| public void having(String sql) { |
| sel.having(sql); |
| } |
| |
| @Override |
| public void having(String sql, Joins joins) { |
| sel.having(sql, joins); |
| } |
| |
| @Override |
| public void groupBy(SQLBuffer sql) { |
| sel.groupBy(sql); |
| } |
| |
| @Override |
| public void groupBy(SQLBuffer sql, Joins joins) { |
| sel.groupBy(sql, joins); |
| } |
| |
| @Override |
| public void groupBy(String sql) { |
| sel.groupBy(sql); |
| } |
| |
| @Override |
| public void groupBy(String sql, Joins joins) { |
| sel.groupBy(sql, joins); |
| } |
| |
| @Override |
| public void groupBy(Column col) { |
| sel.groupBy(col); |
| } |
| |
| @Override |
| public void groupBy(Column col, Joins joins) { |
| sel.groupBy(col, joins); |
| } |
| |
| @Override |
| public void groupBy(Column[] cols) { |
| sel.groupBy(cols); |
| } |
| |
| @Override |
| public void groupBy(Column[] cols, Joins joins) { |
| sel.groupBy(cols, joins); |
| } |
| |
| @Override |
| public void groupBy(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch) { |
| sel.groupBy(mapping, subclasses, store, fetch); |
| } |
| |
| @Override |
| public void groupBy(ClassMapping mapping, int subclasses, |
| JDBCStore store, JDBCFetchConfiguration fetch, Joins joins) { |
| sel.groupBy(mapping, subclasses, store, fetch, joins); |
| } |
| |
| @Override |
| public SelectExecutor whereClone(int sels) { |
| return sel.whereClone(sels); |
| } |
| |
| @Override |
| public SelectExecutor fullClone(int sels) { |
| return sel.fullClone(sels); |
| } |
| |
| @Override |
| public SelectExecutor eagerClone(FieldMapping key, int eagerType, |
| boolean toMany, int sels) { |
| SelectExecutor ex = sel.eagerClone(key, eagerType, toMany, sels); |
| return (ex == sel) ? this : ex; |
| } |
| |
| @Override |
| public SelectExecutor getEager(FieldMapping key) { |
| SelectExecutor ex = sel.getEager(key); |
| return (ex == sel) ? this : ex; |
| } |
| |
| @Override |
| public Joins newJoins() { |
| return sel.newJoins(); |
| } |
| |
| @Override |
| public Joins newOuterJoins() { |
| return sel.newOuterJoins(); |
| } |
| |
| @Override |
| public void append(SQLBuffer buf, Joins joins) { |
| sel.append(buf, joins); |
| } |
| |
| @Override |
| public Joins and(Joins joins1, Joins joins2) { |
| return sel.and(joins1, joins2); |
| } |
| |
| @Override |
| public Joins or(Joins joins1, Joins joins2) { |
| return sel.or(joins1, joins2); |
| } |
| |
| @Override |
| public Joins outer(Joins joins) { |
| return sel.outer(joins); |
| } |
| |
| @Override |
| public String toString() { |
| return sel.toString(); |
| } |
| |
| @Override |
| public int getExpectedResultCount() { |
| return sel.getExpectedResultCount(); |
| } |
| |
| @Override |
| public void setExpectedResultCount(int expectedResultCount, |
| boolean force) { |
| sel.setExpectedResultCount(expectedResultCount, force); |
| } |
| |
| @Override |
| public void setContext(Context context) { |
| sel.setContext(context); |
| } |
| |
| @Override |
| public Context ctx() { |
| return sel.ctx(); |
| } |
| |
| @Override |
| public void setSchemaAlias(String schemaAlias) { |
| sel.setSchemaAlias(schemaAlias); |
| } |
| |
| @Override |
| public void logEagerRelations() { |
| sel.logEagerRelations(); |
| } |
| @Override |
| public void setTablePerClassMeta(ClassMapping meta) { |
| } |
| |
| @Override |
| public ClassMapping getTablePerClassMeta() { |
| return sel.getTablePerClassMeta(); |
| } |
| |
| @Override |
| public void setJoinedTableClassMeta(List meta) { |
| sel.setJoinedTableClassMeta(meta); |
| } |
| |
| @Override |
| public List getJoinedTableClassMeta() { |
| return sel.getJoinedTableClassMeta(); |
| } |
| |
| @Override |
| public void setExcludedJoinedTableClassMeta(List meta) { |
| sel.setExcludedJoinedTableClassMeta(meta); |
| } |
| |
| @Override |
| public List getExcludedJoinedTableClassMeta() { |
| return sel.getExcludedJoinedTableClassMeta(); |
| } |
| |
| @Override |
| public DBDictionary getDictionary() { |
| return dict; |
| } |
| } |
| |
| /** |
| * Comparator for collating ordered results when faking a union. |
| */ |
| private static class ResultComparator |
| implements MergedResult.ResultComparator { |
| |
| private final List[] _orders; |
| private final BitSet _desc; |
| private final DBDictionary _dict; |
| |
| public ResultComparator(List[] orders, BitSet desc, DBDictionary dict) { |
| _orders = orders; |
| _desc = desc; |
| _dict = dict; |
| } |
| |
| @Override |
| public Object getOrderingValue(Result res, int idx) { |
| // if one value just return it |
| ResultSet rs = ((ResultSetResult) res).getResultSet(); |
| if (_orders[idx].size() == 1) |
| return getOrderingValue(rs, _orders[idx].get(0)); |
| |
| // return array of values |
| Object[] vals = new Object[_orders[idx].size()]; |
| for (int i = 0; i < vals.length; i++) |
| vals[i] = getOrderingValue(rs, _orders[idx].get(i)); |
| return vals; |
| } |
| |
| /** |
| * Extract value at given index from result set. |
| */ |
| private Object getOrderingValue(ResultSet rs, Object i) { |
| try { |
| return _dict.getObject(rs, (Integer) i + 1, null); |
| } catch (SQLException se) { |
| throw SQLExceptions.getStore(se, _dict); |
| } |
| } |
| |
| @Override |
| public int compare(Object o1, Object o2) { |
| if (o1 == o2) |
| return 0; |
| if (o1 == null) |
| return (_desc.get(0)) ? -1 : 1; |
| if (o2 == null) |
| return (_desc.get(0)) ? 1 : -1; |
| |
| int cmp; |
| if (!(o1 instanceof Object[])) { |
| if (!(o2 instanceof Object[])) { |
| cmp = ((Comparable) o1).compareTo(o2); |
| return (_desc.get(0)) ? -cmp : cmp; |
| } |
| |
| cmp = ((Comparable) o1).compareTo(((Object[]) o2)[0]); |
| if (cmp != 0) |
| return (_desc.get(0)) ? -cmp : cmp; |
| return -1; |
| } |
| |
| if (!(o2 instanceof Object[])) { |
| cmp = ((Comparable) ((Object[]) o1)[0]).compareTo(o2); |
| if (cmp != 0) |
| return (_desc.get(0)) ? -cmp : cmp; |
| return 1; |
| } |
| |
| Object[] a1 = (Object[]) o1; |
| Object[] a2 = (Object[]) o2; |
| for (int i = 0; i < a1.length; i++) { |
| cmp = ((Comparable) a1[i]).compareTo(a2[i]); |
| if (cmp != 0) |
| return (_desc.get(i)) ? -cmp : cmp; |
| } |
| return a1.length - a2.length; |
| } |
| } |
| } |