You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by pc...@apache.org on 2006/07/19 23:35:07 UTC
svn commit: r423615 [32/44] - in /incubator/openjpa/trunk: ./
openjpa-jdbc-5/ openjpa-jdbc-5/src/ openjpa-jdbc-5/src/main/
openjpa-jdbc-5/src/main/java/ openjpa-jdbc-5/src/main/java/org/
openjpa-jdbc-5/src/main/java/org/apache/ openjpa-jdbc-5/src/main/...
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSet.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSet.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSet.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSet.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,403 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.util.ArrayList;
+import java.util.BitSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.NoSuchElementException;
+
+import org.apache.commons.lang.ObjectUtils;
+
+/**
+ * Set type that recognizes that inner joins should take precedence
+ * over otherwise equal outer joins.
+ *
+ * @author Abe White
+ */
+class JoinSet {
+
+ // the joins are stored as an adjacency list graph. it's a reasonably
+ // efficient representation with O(1) lookup, add, remove operations for
+ // typical sets of joins, and it means we'd have to create a graph anyway
+ // when joinIterator() is called
+ private final List _graph = new ArrayList();
+ private int _size = 0;
+ private List _sorted = null;
+
+ public JoinSet() {
+ }
+
+ public JoinSet(JoinSet copy) {
+ for (int i = 0; i < copy._graph.size(); i++) {
+ if (copy._graph.get(i) == null)
+ _graph.add(null);
+ else
+ _graph.add(((Node) copy._graph.get(i)).clone());
+ }
+ _size = copy._size;
+ _sorted = copy._sorted;
+ }
+
+ /**
+ * Return the recorded join matching the given join's aliases.
+ */
+ public Join getRecordedJoin(Join join) {
+ if (join == null)
+ return null;
+ Node node = getNode(join, join.getIndex1());
+ return (node == null) ? null : node.join;
+ }
+
+ /**
+ * Return the node for the specified join and index.
+ */
+ private Node getNode(Join join, int idx) {
+ if (_graph.size() <= idx)
+ return null;
+ Node node = (Node) _graph.get(idx);
+ for (; node != null; node = node.next)
+ if (node.join.equals(join))
+ return node;
+ return null;
+ }
+
+ /**
+ * Return the logical last join.
+ */
+ public Join last() {
+ if (_size == 0)
+ return null;
+ Node node = (Node) _graph.get(_graph.size() - 1);
+ while (node.next != null)
+ node = node.next;
+ return node.join;
+ }
+
+ /**
+ * Iterator over joins that prepares them for SQL translation.
+ */
+ public Iterator joinIterator() {
+ if (_size < 2)
+ return iterator();
+ if (_sorted != null)
+ return _sorted.iterator();
+
+ List sorted = new ArrayList(_size);
+ LinkedList queue = new LinkedList();
+ BitSet seen = new BitSet(_graph.size() * _graph.size()
+ + _graph.size());
+
+ // traverse graph
+ Node n;
+ int idx, sidx;
+ for (int i = 0; i < _graph.size(); i++) {
+ // seed queue with next set of disconnected joins
+ for (n = (Node) _graph.get(i); n != null; n = n.next) {
+ sidx = getSeenIndex(n.join);
+ if (!seen.get(sidx)) {
+ seen.set(sidx);
+ queue.add(n);
+ }
+ }
+ if (queue.isEmpty())
+ continue;
+
+ // traverse from those joins to reachables
+ while (!queue.isEmpty()) {
+ n = (Node) queue.removeFirst();
+
+ // don't repeat a join to a table we've already joined, but
+ // do traverse through it in the graph (the first indexes of
+ // the seeen bitset are reserved for joined-to tables)
+ idx = (n.forward) ? n.join.getIndex2() : n.join.getIndex1();
+ if (!seen.get(idx)) {
+ sorted.add((n.forward) ? n.join : n.join.reverse());
+ seen.set(idx);
+ }
+
+ for (n = (Node) _graph.get(idx); n != null; n = n.next) {
+ sidx = getSeenIndex(n.join);
+ if (!seen.get(sidx)) {
+ seen.set(sidx);
+ queue.add(n);
+ }
+ }
+ }
+ }
+ _sorted = sorted;
+ return _sorted.iterator();
+ }
+
+ /**
+ * We create a unique index for recording seen nodes by
+ * treating the joined indexes as a base (max-index) number.
+ */
+ private int getSeenIndex(Join join) {
+ // we reserve indexes 0..._graph.size() for joined tables
+ return join.getIndex1() * _graph.size() + join.getIndex2()
+ + _graph.size();
+ }
+
+ public boolean add(Join join) {
+ if (join.getType() == Join.TYPE_OUTER) {
+ // outer shouldn't override any other join type
+ if (!contains(join)) {
+ addNode(join);
+ return true;
+ }
+ return false;
+ }
+
+ // replace any existing join with this one
+ Node node = getNode(join, join.getIndex1());
+ if (node != null) {
+ node.join = join;
+ getNode(join, join.getIndex2()).join = join;
+ _sorted = null;
+ } else
+ addNode(join);
+ return true;
+ }
+
+ public boolean addAll(JoinSet js) {
+ if (js.isEmpty())
+ return false;
+
+ boolean added = false;
+ for (Iterator itr = js.iterator(); itr.hasNext();)
+ added = add((Join) itr.next()) || added;
+ return added;
+ }
+
+ /**
+ * Add the give join to our graph.
+ */
+ private void addNode(Join join) {
+ _sorted = null;
+
+ int size = Math.max(join.getIndex1(), join.getIndex2()) + 1;
+ while (_graph.size() < size)
+ _graph.add(null);
+
+ Node node = (Node) _graph.get(join.getIndex1());
+ if (node == null)
+ _graph.set(join.getIndex1(), new Node(join, true));
+ else {
+ while (node.next != null)
+ node = node.next;
+ node.next = new Node(join, true);
+ }
+
+ node = (Node) _graph.get(join.getIndex2());
+ if (node == null)
+ _graph.set(join.getIndex2(), new Node(join, false));
+ else {
+ while (node.next != null)
+ node = node.next;
+ node.next = new Node(join, false);
+ }
+ _size++;
+ }
+
+ public Iterator iterator() {
+ return new Iterator() {
+ private Node _next = null;
+ private int _idx = -1;
+
+ public boolean hasNext() {
+ if (_next != null)
+ return true;
+
+ while (++_idx < _graph.size()) {
+ _next = (Node) _graph.get(_idx);
+ while (_next != null && !_next.forward)
+ _next = _next.next;
+ if (_next != null)
+ return true;
+ }
+ return false;
+ }
+
+ public Object next() {
+ if (!hasNext())
+ throw new NoSuchElementException();
+ Join j = _next.join;
+ do {
+ _next = _next.next;
+ } while (_next != null && !_next.forward);
+ return j;
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ public boolean remove(Join join) {
+ if (join == null || _graph.size() <= join.getIndex1())
+ return false;
+ if (remove(join, join.getIndex1())) {
+ _size--;
+ return remove(join, join.getIndex2());
+ }
+ return false;
+ }
+
+ /**
+ * Each join is recorded one at its first index and once at its second;
+ * remove the join at one of its indexes.
+ */
+ private boolean remove(Join join, int idx) {
+ Node node = (Node) _graph.get(idx);
+ for (Node prev = null; node != null; prev = node, node = node.next) {
+ if (!node.join.equals(join))
+ continue;
+
+ if (prev != null)
+ prev.next = node.next;
+ else {
+ _graph.set(idx, node.next);
+ // trim to size
+ while (!_graph.isEmpty() && _graph.get(idx) == null
+ && idx == _graph.size() - 1)
+ _graph.remove(idx--);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public boolean removeAll(JoinSet js) {
+ boolean remd = false;
+ for (Iterator itr = js.iterator(); itr.hasNext();)
+ remd = remove((Join) itr.next()) || remd;
+ return remd;
+ }
+
+ public boolean retainAll(JoinSet js) {
+ boolean remd = false;
+ Join join;
+ for (Iterator itr = iterator(); itr.hasNext();) {
+ join = (Join) itr.next();
+ if (!js.contains(join))
+ remd = remove(join);
+ }
+ return remd;
+ }
+
+ public void clear() {
+ _graph.clear();
+ _sorted = null;
+ _size = 0;
+ }
+
+ public boolean contains(Join join) {
+ return getRecordedJoin(join) != null;
+ }
+
+ public boolean containsAll(JoinSet js) {
+ if (js._size > _size || js._graph.size() > _graph.size())
+ return false;
+ for (Iterator itr = js.iterator(); itr.hasNext();)
+ if (!contains((Join) itr.next()))
+ return false;
+ return true;
+ }
+
+ public boolean isEmpty() {
+ return _size == 0;
+ }
+
+ public int size() {
+ return _size;
+ }
+
+ public boolean equals(Object other) {
+ if (other == this)
+ return true;
+ if (!(other instanceof JoinSet))
+ return false;
+ return _graph.equals(((JoinSet) other)._graph);
+ }
+
+ public int hashCode() {
+ return _graph.hashCode();
+ }
+
+ public String toString() {
+ StringBuffer buf = new StringBuffer();
+ buf.append("[");
+ for (Iterator itr = iterator(); itr.hasNext();) {
+ buf.append("<").append(itr.next()).append(">");
+ if (itr.hasNext())
+ buf.append(", ");
+ }
+ return buf.append("]").toString();
+ }
+
+ /**
+ * A graph node.
+ */
+ private static class Node
+ implements Cloneable {
+
+ public Join join;
+ public Node next;
+ public boolean forward;
+
+ public Node(Join join, boolean forward) {
+ this.join = join;
+ this.forward = forward;
+ }
+
+ public int hashCode() {
+ int rs = 17;
+ rs = 37 * rs + join.hashCode();
+ if (next != null)
+ rs = 37 * rs + next.hashCode();
+ return rs;
+ }
+
+ public boolean equals(Object other) {
+ if (!(other instanceof Node))
+ return false;
+ Node node = (Node) other;
+ return ObjectUtils.equals(join, node.join)
+ && ObjectUtils.equals(next, node.next);
+ }
+
+ public Object clone() {
+ try {
+ Node node = (Node) super.clone();
+ if (node.next != null)
+ node.next = (Node) node.next.clone();
+ return node;
+ } catch (CloneNotSupportedException cnse) {
+ // can't happen
+ return null;
+ }
+ }
+
+ public String toString() {
+ return join + "(" + ((forward) ? "forward" : "backward") + ")"
+ + "; next: " + next;
+ }
+ }
+}
Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSet.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSyntaxes.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSyntaxes.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSyntaxes.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSyntaxes.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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;
+
+/**
+ * Constants for ways of describing joins in SQL.
+ *
+ * @author Abe White
+ */
+public interface JoinSyntaxes {
+
+ /**
+ * ANSI SQL 92 join syntax; outer joins are supported.
+ */
+ public static final int SYNTAX_SQL92 = 0;
+
+ /**
+ * Traditional join syntax; outer joins are not supported.
+ */
+ public static final int SYNTAX_TRADITIONAL = 1;
+
+ /**
+ * Native database join syntax; outer joins are supported.
+ */
+ public static final int SYNTAX_DATABASE = 2;
+}
Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/JoinSyntaxes.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,71 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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 org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.Table;
+
+/**
+ * Tracks joins made when traversing relations in a select.
+ *
+ * @author Abe White
+ */
+public interface Joins {
+
+ /**
+ * Whether we have any joins.
+ */
+ public boolean isEmpty();
+
+ /**
+ * Perform a cross join on the given tables.
+ */
+ public Joins crossJoin(Table localTable, Table foreignTable);
+
+ /**
+ * Join the columns of the given foreign key.
+ */
+ public Joins join(ForeignKey fk, boolean inverse, boolean toMany);
+
+ /**
+ * Join the columns of the given foreign key.
+ */
+ public Joins outerJoin(ForeignKey fk, boolean inverse, boolean toMany);
+
+ /**
+ * Join the columns of the given foreign key, which represents a relation
+ * via the given field name.
+ */
+ public Joins joinRelation(String name, ForeignKey fk, boolean inverse,
+ boolean toMany);
+
+ /**
+ * Join the columns of the given foreign key, which represents a relation
+ * via the given field name.
+ */
+ public Joins outerJoinRelation(String name, ForeignKey fk, boolean inverse,
+ boolean toMany);
+
+ /**
+ * Set the variable name being traversed into with the next join.
+ */
+ public Joins setVariable(String var);
+
+ /**
+ * Set the subquery alias.
+ */
+ public Joins setSubselect(String alias);
+}
Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Joins.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,900 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.JDBCFetchState;
+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.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;
+ private boolean _single = false;
+
+ /**
+ * 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) ? new SelectImpl(conf)
+ : (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);
+ }
+
+ public Select[] getSelects() {
+ return sels;
+ }
+
+ public boolean isSingleResult() {
+ return _single;
+ }
+
+ public void setSingleResult(boolean single) {
+ _single = single;
+ }
+
+ public boolean isUnion() {
+ return false;
+ }
+
+ public void abortUnion() {
+ }
+
+ public String getOrdering() {
+ return null;
+ }
+
+ public JDBCConfiguration getConfiguration() {
+ return sels[0].getConfiguration();
+ }
+
+ public SQLBuffer toSelect(boolean forUpdate, JDBCFetchConfiguration fetch) {
+ return dict.toSelect(sels[0], forUpdate, fetch);
+ }
+
+ public SQLBuffer toSelectCount() {
+ return dict.toSelectCount(sels[0]);
+ }
+
+ public boolean getAutoDistinct() {
+ return sels[0].getAutoDistinct();
+ }
+
+ public void setAutoDistinct(boolean distinct) {
+ for (int i = 0; i < sels.length; i++)
+ sels[i].setAutoDistinct(distinct);
+ }
+
+ public boolean isDistinct() {
+ return _distinct;
+ }
+
+ public void setDistinct(boolean distinct) {
+ _distinct = distinct;
+ }
+
+ public boolean isLRS() {
+ return sels[0].isLRS();
+ }
+
+ public void setLRS(boolean lrs) {
+ for (int i = 0; i < sels.length; i++)
+ sels[i].setLRS(lrs);
+ }
+
+ public int getJoinSyntax() {
+ return sels[0].getJoinSyntax();
+ }
+
+ public void setJoinSyntax(int syntax) {
+ for (int i = 0; i < sels.length; i++)
+ sels[i].setJoinSyntax(syntax);
+ }
+
+ public boolean supportsRandomAccess(boolean forUpdate) {
+ if (sels.length == 1)
+ return sels[0].supportsRandomAccess(forUpdate);
+ return false;
+ }
+
+ public boolean supportsLocking() {
+ if (sels.length == 1)
+ return sels[0].supportsLocking();
+ for (int i = 0; i < sels.length; i++)
+ if (!sels[i].supportsLocking())
+ return false;
+ return true;
+ }
+
+ public int getCount(JDBCStore store)
+ throws SQLException {
+ int count = 0;
+ for (int i = 0; i < sels.length; i++)
+ count += sels[i].getCount(store);
+ return count;
+ }
+
+ public Result execute(JDBCStore store, JDBCFetchConfiguration fetch)
+ throws SQLException {
+ if (fetch == null)
+ fetch = store.getFetchConfiguration();
+ return execute(store, fetch, fetch.getReadLockLevel());
+ }
+
+ 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 (_single) {
+ 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);
+ }
+
+ public void select(Union.Selector selector) {
+ for (int i = 0; i < sels.length; i++)
+ selector.select(sels[i], i);
+ }
+
+ public String toString() {
+ return toSelect(false, null).getSQL();
+ }
+
+ /**
+ * A callback used to create the selects in a SQL union.
+ */
+ public static interface Selector {
+
+ /**
+ * Populate the <code>i</code>th select in the union.
+ */
+ public void select(Select sel, int i);
+ }
+
+ /**
+ * A select that is part of a logical union.
+ */
+ protected 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;
+ }
+
+ public JDBCConfiguration getConfiguration() {
+ return sel.getConfiguration();
+ }
+
+ public int indexOf() {
+ return pos;
+ }
+
+ public SQLBuffer toSelect(boolean forUpdate,
+ JDBCFetchConfiguration fetch) {
+ return sel.toSelect(forUpdate, fetch);
+ }
+
+ public SQLBuffer toSelectCount() {
+ return sel.toSelectCount();
+ }
+
+ public boolean getAutoDistinct() {
+ return sel.getAutoDistinct();
+ }
+
+ public void setAutoDistinct(boolean distinct) {
+ sel.setAutoDistinct(distinct);
+ }
+
+ public boolean isDistinct() {
+ return sel.isDistinct();
+ }
+
+ public void setDistinct(boolean distinct) {
+ sel.setDistinct(distinct);
+ }
+
+ public boolean isLRS() {
+ return sel.isLRS();
+ }
+
+ public void setLRS(boolean lrs) {
+ sel.setLRS(lrs);
+ }
+
+ public int getJoinSyntax() {
+ return sel.getJoinSyntax();
+ }
+
+ public void setJoinSyntax(int joinSyntax) {
+ sel.setJoinSyntax(joinSyntax);
+ }
+
+ public boolean supportsRandomAccess(boolean forUpdate) {
+ return sel.supportsRandomAccess(forUpdate);
+ }
+
+ public boolean supportsLocking() {
+ return sel.supportsLocking();
+ }
+
+ public int getCount(JDBCStore store)
+ throws SQLException {
+ return sel.getCount(store);
+ }
+
+ public Result execute(JDBCStore store, JDBCFetchConfiguration fetch)
+ throws SQLException {
+ return sel.execute(store, fetch);
+ }
+
+ public Result execute(JDBCStore store, JDBCFetchConfiguration fetch,
+ int lockLevel)
+ throws SQLException {
+ return sel.execute(store, fetch, lockLevel);
+ }
+
+ public List getSubselects() {
+ return Collections.EMPTY_LIST;
+ }
+
+ public Select getParent() {
+ return null;
+ }
+
+ public String getSubselectPath() {
+ return null;
+ }
+
+ public void setParent(Select parent, String path) {
+ throw new UnsupportedException(_loc.get("union-element"));
+ }
+
+ public Select getFromSelect() {
+ return null;
+ }
+
+ public void setFromSelect(Select sel) {
+ throw new UnsupportedException(_loc.get("union-element"));
+ }
+
+ public boolean hasEagerJoin(boolean toMany) {
+ return sel.hasEagerJoin(toMany);
+ }
+
+ public boolean hasJoin(boolean toMany) {
+ return sel.hasJoin(toMany);
+ }
+
+ public boolean isSelected(Table table) {
+ return sel.isSelected(table);
+ }
+
+ public Collection getTableAliases() {
+ return sel.getTableAliases();
+ }
+
+ public List getSelectAliases() {
+ return sel.getSelectAliases();
+ }
+
+ public List getIdentifierAliases() {
+ return sel.getIdentifierAliases();
+ }
+
+ public SQLBuffer getOrdering() {
+ return sel.getOrdering();
+ }
+
+ public SQLBuffer getGrouping() {
+ return sel.getGrouping();
+ }
+
+ public SQLBuffer getWhere() {
+ return sel.getWhere();
+ }
+
+ public SQLBuffer getHaving() {
+ return sel.getHaving();
+ }
+
+ public Joins getJoins() {
+ return sel.getJoins();
+ }
+
+ public Iterator getJoinIterator() {
+ return sel.getJoinIterator();
+ }
+
+ public long getStartIndex() {
+ return sel.getStartIndex();
+ }
+
+ public long getEndIndex() {
+ return sel.getEndIndex();
+ }
+
+ public void setRange(long start, long end) {
+ sel.setRange(start, end);
+ }
+
+ public String getColumnAlias(Column col) {
+ return sel.getColumnAlias(col);
+ }
+
+ public String getColumnAlias(Column col, Joins joins) {
+ return sel.getColumnAlias(col, joins);
+ }
+
+ public String getColumnAlias(String col, Table table) {
+ return sel.getColumnAlias(col, table);
+ }
+
+ public String getColumnAlias(String col, Table table, Joins joins) {
+ return sel.getColumnAlias(col, table, joins);
+ }
+
+ public boolean isAggregate() {
+ return sel.isAggregate();
+ }
+
+ public void setAggregate(boolean agg) {
+ sel.setAggregate(agg);
+ }
+
+ public boolean isLob() {
+ return sel.isLob();
+ }
+
+ public void setLob(boolean lob) {
+ sel.setLob(lob);
+ }
+
+ public void selectPlaceholder(String sql) {
+ sel.selectPlaceholder(sql);
+ }
+
+ public void clearSelects() {
+ sel.clearSelects();
+ }
+
+ public boolean select(SQLBuffer sql, Object id) {
+ return sel.select(sql, id);
+ }
+
+ public boolean select(SQLBuffer sql, Object id, Joins joins) {
+ return sel.select(sql, id, joins);
+ }
+
+ public boolean select(String sql, Object id) {
+ return sel.select(sql, id);
+ }
+
+ public boolean select(String sql, Object id, Joins joins) {
+ return sel.select(sql, id, joins);
+ }
+
+ public boolean select(Column col) {
+ return sel.select(col);
+ }
+
+ public boolean select(Column col, Joins joins) {
+ return sel.select(col, joins);
+ }
+
+ public int select(Column[] cols) {
+ return sel.select(cols);
+ }
+
+ public int select(Column[] cols, Joins joins) {
+ return sel.select(cols, joins);
+ }
+
+ public void select(ClassMapping mapping, int subclasses,
+ JDBCStore store, JDBCFetchState fetchState, int eager) {
+ select(mapping, subclasses, store, fetchState, eager, null, false);
+ }
+
+ public void select(ClassMapping mapping, int subclasses,
+ JDBCStore store, JDBCFetchState fetchState, int eager,
+ Joins joins) {
+ select(mapping, subclasses, store, fetchState, eager, joins,
+ false);
+ }
+
+ private void select(ClassMapping mapping, int subclasses,
+ JDBCStore store, JDBCFetchState fetchState, 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, fetchState, eager,
+ joins, identifier);
+ }
+
+ public boolean selectIdentifier(Column col) {
+ return sel.selectIdentifier(col);
+ }
+
+ public boolean selectIdentifier(Column col, Joins joins) {
+ return sel.selectIdentifier(col, joins);
+ }
+
+ public int selectIdentifier(Column[] cols) {
+ return sel.selectIdentifier(cols);
+ }
+
+ public int selectIdentifier(Column[] cols, Joins joins) {
+ return sel.selectIdentifier(cols, joins);
+ }
+
+ public void selectIdentifier(ClassMapping mapping, int subclasses,
+ JDBCStore store, JDBCFetchState fetchState, int eager) {
+ select(mapping, subclasses, store, fetchState, eager, null, true);
+ }
+
+ public void selectIdentifier(ClassMapping mapping, int subclasses,
+ JDBCStore store, JDBCFetchState fetchState, int eager,
+ Joins joins) {
+ select(mapping, subclasses, store, fetchState, eager, joins, true);
+ }
+
+ public int selectPrimaryKey(ClassMapping mapping) {
+ return sel.selectPrimaryKey(mapping);
+ }
+
+ public int selectPrimaryKey(ClassMapping mapping, Joins joins) {
+ return sel.selectPrimaryKey(mapping, joins);
+ }
+
+ public int orderByPrimaryKey(ClassMapping mapping, boolean asc,
+ boolean select) {
+ return orderByPrimaryKey(mapping, asc, null, select);
+ }
+
+ 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 (int i = 0; i < cols.length; i++)
+ recordOrder(cols[i], asc);
+ }
+
+ public boolean orderBy(Column col, boolean asc, boolean select) {
+ return orderBy(col, asc, null, select);
+ }
+
+ public boolean orderBy(Column col, boolean asc, Joins joins,
+ boolean select) {
+ recordOrder(col, asc);
+ return sel.orderBy(col, asc, joins, select, isUnion());
+ }
+
+ public int orderBy(Column[] cols, boolean asc, boolean select) {
+ return orderBy(cols, asc, null, select);
+ }
+
+ public int orderBy(Column[] cols, boolean asc, Joins joins,
+ boolean select) {
+ recordOrderColumns(cols, asc);
+ return sel.orderBy(cols, asc, joins, select, isUnion());
+ }
+
+ public boolean orderBy(SQLBuffer sql, boolean asc, boolean select) {
+ return orderBy(sql, asc, null, select);
+ }
+
+ public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins,
+ boolean select) {
+ recordOrder(sql.getSQL(false), asc);
+ return sel.orderBy(sql, asc, joins, select, isUnion());
+ }
+
+ public boolean orderBy(String sql, boolean asc, boolean select) {
+ return orderBy(sql, asc, null, select);
+ }
+
+ public boolean orderBy(String sql, boolean asc, Joins joins,
+ boolean select) {
+ recordOrder(sql, asc);
+ return sel.orderBy(sql, asc, joins, select, isUnion());
+ }
+
+ public void clearOrdering() {
+ sel.clearOrdering();
+ }
+
+ public void wherePrimaryKey(Object oid, ClassMapping mapping,
+ JDBCStore store) {
+ sel.wherePrimaryKey(oid, mapping, store);
+ }
+
+ public void whereForeignKey(ForeignKey fk, Object oid,
+ ClassMapping mapping, JDBCStore store) {
+ sel.whereForeignKey(fk, oid, mapping, store);
+ }
+
+ public void where(Joins joins) {
+ sel.where(joins);
+ }
+
+ public void where(SQLBuffer sql) {
+ sel.where(sql);
+ }
+
+ public void where(SQLBuffer sql, Joins joins) {
+ sel.where(sql, joins);
+ }
+
+ public void where(String sql) {
+ sel.where(sql);
+ }
+
+ public void where(String sql, Joins joins) {
+ sel.where(sql, joins);
+ }
+
+ public void having(SQLBuffer sql) {
+ sel.having(sql);
+ }
+
+ public void having(SQLBuffer sql, Joins joins) {
+ sel.having(sql, joins);
+ }
+
+ public void having(String sql) {
+ sel.having(sql);
+ }
+
+ public void having(String sql, Joins joins) {
+ sel.having(sql, joins);
+ }
+
+ public boolean groupBy(SQLBuffer sql, boolean select) {
+ return sel.groupBy(sql, null, select);
+ }
+
+ public boolean groupBy(SQLBuffer sql, Joins joins, boolean select) {
+ return sel.groupBy(sql, joins, select);
+ }
+
+ public boolean groupBy(String sql, boolean select) {
+ return sel.groupBy(sql, null, select);
+ }
+
+ public boolean groupBy(String sql, Joins joins, boolean select) {
+ return sel.groupBy(sql, joins, select);
+ }
+
+ public boolean groupBy(Column col, boolean select) {
+ return sel.groupBy(col, null, select);
+ }
+
+ public boolean groupBy(Column col, Joins joins, boolean select) {
+ return sel.groupBy(col, joins, select);
+ }
+
+ public int groupBy(Column[] cols, boolean select) {
+ return sel.groupBy(cols, null, select);
+ }
+
+ public int groupBy(Column[] cols, Joins joins, boolean select) {
+ return sel.groupBy(cols, joins, select);
+ }
+
+ public SelectExecutor whereClone(int sels) {
+ return sel.whereClone(sels);
+ }
+
+ public SelectExecutor fullClone(int sels) {
+ return sel.fullClone(sels);
+ }
+
+ public SelectExecutor eagerClone(FieldMapping key, int eagerType,
+ boolean toMany, int sels) {
+ SelectExecutor ex = sel.eagerClone(key, eagerType, toMany, sels);
+ return (ex == sel) ? this : ex;
+ }
+
+ public SelectExecutor getEager(FieldMapping key) {
+ SelectExecutor ex = sel.getEager(key);
+ return (ex == sel) ? this : ex;
+ }
+
+ public Joins newJoins() {
+ return sel.newJoins();
+ }
+
+ public void append(SQLBuffer buf, Joins joins) {
+ sel.append(buf, joins);
+ }
+
+ public Joins and(Joins joins1, Joins joins2) {
+ return sel.and(joins1, joins2);
+ }
+
+ public Joins or(Joins joins1, Joins joins2) {
+ return sel.or(joins1, joins2);
+ }
+
+ public Joins outer(Joins joins) {
+ return sel.outer(joins);
+ }
+
+ public String toString() {
+ return sel.toString();
+ }
+ }
+
+ /**
+ * 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;
+ }
+
+ 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).intValue() + 1, null);
+ } catch (SQLException se) {
+ throw SQLExceptions.getStore(se, _dict);
+ }
+ }
+
+ 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;
+ }
+ }
+}
Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/LogicalUnion.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,534 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.Clob;
+import java.sql.Ref;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Comparator;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.kernel.JDBCFetchState;
+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.util.UnsupportedException;
+
+/**
+ * Result that merges multiple result delegates. Support exists for
+ * maintaining ordering of the internally-held results, provided that each
+ * of the individual results is itself ordered.
+ *
+ * @author Abe White
+ */
+public class MergedResult
+ implements Result {
+
+ private static final byte NEXT = 0;
+ private static final byte CURRENT = 1;
+ private static final byte DONE = 2;
+
+ private final Result[] _res;
+ private final byte[] _status;
+ private final ResultComparator _comp;
+ private final Object[] _order;
+ private int _idx = 0;
+ private boolean _pushedBack = false;
+
+ /**
+ * Constructor; supply delegates.
+ */
+ public MergedResult(Result[] res) {
+ this(res, null);
+ }
+
+ /**
+ * Constructor; supply delegates and comparator for ordering results.
+ */
+ public MergedResult(Result[] res, ResultComparator comp) {
+ _res = res;
+ _comp = comp;
+ _order = (comp == null) ? null : new Object[res.length];
+ _status = (comp == null) ? null : new byte[res.length];
+ }
+
+ public Object getEager(FieldMapping key) {
+ return _res[_idx].getEager(key);
+ }
+
+ public void putEager(FieldMapping key, Object res) {
+ _res[_idx].putEager(key, res);
+ }
+
+ public Joins newJoins() {
+ return _res[_idx].newJoins();
+ }
+
+ public void close() {
+ for (int i = 0; i < _res.length; i++)
+ _res[i].close();
+ }
+
+ public boolean isLocking() {
+ return _res[_idx].isLocking();
+ }
+
+ public boolean supportsRandomAccess()
+ throws SQLException {
+ return false;
+ }
+
+ public boolean absolute(int row)
+ throws SQLException {
+ throw new UnsupportedException();
+ }
+
+ public boolean next()
+ throws SQLException {
+ if (_pushedBack) {
+ _pushedBack = false;
+ return true;
+ }
+
+ if (_comp == null) {
+ while (!_res[_idx].next()) {
+ if (_idx == _res.length - 1)
+ return false;
+ _idx++;
+ }
+ return true;
+ }
+
+ // ordering is involved; extract order values from each result
+ boolean hasValue = false;
+ for (int i = 0; i < _status.length; i++) {
+ switch (_status[i]) {
+ case NEXT:
+ if (_res[i].next()) {
+ hasValue = true;
+ _status[i] = CURRENT;
+ _order[i] = _comp.getOrderingValue(_res[i], i);
+ } else
+ _status[i] = DONE;
+ break;
+ case CURRENT:
+ hasValue = true;
+ break;
+ }
+ }
+
+ // all results exhausted
+ if (!hasValue)
+ return false;
+
+ // for all results with values, find the 'least' one according to
+ // the comparator
+ int least = -1;
+ Object orderVal = null;
+ int cmp;
+ for (int i = 0; i < _order.length; i++) {
+ if (_status[i] != CURRENT)
+ continue;
+ if (least == -1 || _comp.compare(_order[i], orderVal) < 0) {
+ least = i;
+ orderVal = _order[i];
+ }
+ }
+
+ // make the current result the one with the least value, and clear
+ // the cached value for that result
+ _idx = least;
+ _order[least] = null;
+ _status[least] = NEXT;
+ return true;
+ }
+
+ public void pushBack()
+ throws SQLException {
+ _pushedBack = true;
+ }
+
+ public int size()
+ throws SQLException {
+ int size = 0;
+ for (int i = 0; i < _res.length; i++)
+ size += _res[i].size();
+ return size;
+ }
+
+ public boolean contains(Object obj)
+ throws SQLException {
+ return _res[_idx].contains(obj);
+ }
+
+ public boolean containsAll(Object[] objs)
+ throws SQLException {
+ return _res[_idx].containsAll(objs);
+ }
+
+ public boolean contains(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].contains(col, joins);
+ }
+
+ public boolean containsAll(Column[] cols, Joins joins)
+ throws SQLException {
+ return _res[_idx].containsAll(cols, joins);
+ }
+
+ public ClassMapping getBaseMapping() {
+ return _res[_idx].getBaseMapping();
+ }
+
+ public void setBaseMapping(ClassMapping mapping) {
+ _res[_idx].setBaseMapping(mapping);
+ }
+
+ public int indexOf() {
+ return _res[_idx].indexOf();
+ }
+
+ public Object load(ClassMapping mapping, JDBCStore store,
+ JDBCFetchState fetchState)
+ throws SQLException {
+ return _res[_idx].load(mapping, store, fetchState);
+ }
+
+ public Object load(ClassMapping mapping, JDBCStore store,
+ JDBCFetchState fetchState, Joins joins)
+ throws SQLException {
+ return _res[_idx].load(mapping, store, fetchState, joins);
+ }
+
+ public Array getArray(Object obj)
+ throws SQLException {
+ return _res[_idx].getArray(obj);
+ }
+
+ public InputStream getAsciiStream(Object obj)
+ throws SQLException {
+ return _res[_idx].getAsciiStream(obj);
+ }
+
+ public BigDecimal getBigDecimal(Object obj)
+ throws SQLException {
+ return _res[_idx].getBigDecimal(obj);
+ }
+
+ public BigInteger getBigInteger(Object obj)
+ throws SQLException {
+ return _res[_idx].getBigInteger(obj);
+ }
+
+ public InputStream getBinaryStream(Object obj)
+ throws SQLException {
+ return _res[_idx].getBinaryStream(obj);
+ }
+
+ public Blob getBlob(Object obj)
+ throws SQLException {
+ return _res[_idx].getBlob(obj);
+ }
+
+ public boolean getBoolean(Object obj)
+ throws SQLException {
+ return _res[_idx].getBoolean(obj);
+ }
+
+ public byte getByte(Object obj)
+ throws SQLException {
+ return _res[_idx].getByte(obj);
+ }
+
+ public byte[] getBytes(Object obj)
+ throws SQLException {
+ return _res[_idx].getBytes(obj);
+ }
+
+ public Calendar getCalendar(Object obj)
+ throws SQLException {
+ return _res[_idx].getCalendar(obj);
+ }
+
+ public char getChar(Object obj)
+ throws SQLException {
+ return _res[_idx].getChar(obj);
+ }
+
+ public Reader getCharacterStream(Object obj)
+ throws SQLException {
+ return _res[_idx].getCharacterStream(obj);
+ }
+
+ public Clob getClob(Object obj)
+ throws SQLException {
+ return _res[_idx].getClob(obj);
+ }
+
+ public Date getDate(Object obj)
+ throws SQLException {
+ return _res[_idx].getDate(obj);
+ }
+
+ public java.sql.Date getDate(Object obj, Calendar cal)
+ throws SQLException {
+ return _res[_idx].getDate(obj, cal);
+ }
+
+ public double getDouble(Object obj)
+ throws SQLException {
+ return _res[_idx].getDouble(obj);
+ }
+
+ public float getFloat(Object obj)
+ throws SQLException {
+ return _res[_idx].getFloat(obj);
+ }
+
+ public int getInt(Object obj)
+ throws SQLException {
+ return _res[_idx].getInt(obj);
+ }
+
+ public Locale getLocale(Object obj)
+ throws SQLException {
+ return _res[_idx].getLocale(obj);
+ }
+
+ public long getLong(Object obj)
+ throws SQLException {
+ return _res[_idx].getLong(obj);
+ }
+
+ public Number getNumber(Object obj)
+ throws SQLException {
+ return _res[_idx].getNumber(obj);
+ }
+
+ public Object getObject(Object obj, int metaType, Object arg)
+ throws SQLException {
+ return _res[_idx].getObject(obj, metaType, arg);
+ }
+
+ public Object getSQLObject(Object obj, Map map)
+ throws SQLException {
+ return _res[_idx].getSQLObject(obj, map);
+ }
+
+ public Ref getRef(Object obj, Map map)
+ throws SQLException {
+ return _res[_idx].getRef(obj, map);
+ }
+
+ public short getShort(Object obj)
+ throws SQLException {
+ return _res[_idx].getShort(obj);
+ }
+
+ public String getString(Object obj)
+ throws SQLException {
+ return _res[_idx].getString(obj);
+ }
+
+ public Time getTime(Object obj, Calendar cal)
+ throws SQLException {
+ return _res[_idx].getTime(obj, cal);
+ }
+
+ public Timestamp getTimestamp(Object obj, Calendar cal)
+ throws SQLException {
+ return _res[_idx].getTimestamp(obj, cal);
+ }
+
+ public Array getArray(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getArray(col, joins);
+ }
+
+ public InputStream getAsciiStream(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getAsciiStream(col, joins);
+ }
+
+ public BigDecimal getBigDecimal(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getBigDecimal(col, joins);
+ }
+
+ public BigInteger getBigInteger(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getBigInteger(col, joins);
+ }
+
+ public InputStream getBinaryStream(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getBinaryStream(col, joins);
+ }
+
+ public Blob getBlob(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getBlob(col, joins);
+ }
+
+ public boolean getBoolean(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getBoolean(col, joins);
+ }
+
+ public byte getByte(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getByte(col, joins);
+ }
+
+ public byte[] getBytes(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getBytes(col, joins);
+ }
+
+ public Calendar getCalendar(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getCalendar(col, joins);
+ }
+
+ public char getChar(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getChar(col, joins);
+ }
+
+ public Reader getCharacterStream(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getCharacterStream(col, joins);
+ }
+
+ public Clob getClob(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getClob(col, joins);
+ }
+
+ public Date getDate(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getDate(col, joins);
+ }
+
+ public java.sql.Date getDate(Column col, Calendar cal, Joins joins)
+ throws SQLException {
+ return _res[_idx].getDate(col, cal, joins);
+ }
+
+ public double getDouble(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getDouble(col, joins);
+ }
+
+ public float getFloat(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getFloat(col, joins);
+ }
+
+ public int getInt(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getInt(col, joins);
+ }
+
+ public Locale getLocale(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getLocale(col, joins);
+ }
+
+ public long getLong(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getLong(col, joins);
+ }
+
+ public Number getNumber(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getNumber(col, joins);
+ }
+
+ public Object getObject(Column col, Object arg, Joins joins)
+ throws SQLException {
+ return _res[_idx].getObject(col, arg, joins);
+ }
+
+ public Object getSQLObject(Column col, Map map, Joins joins)
+ throws SQLException {
+ return _res[_idx].getSQLObject(col, map, joins);
+ }
+
+ public Ref getRef(Column col, Map map, Joins joins)
+ throws SQLException {
+ return _res[_idx].getRef(col, map, joins);
+ }
+
+ public short getShort(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getShort(col, joins);
+ }
+
+ public String getString(Column col, Joins joins)
+ throws SQLException {
+ return _res[_idx].getString(col, joins);
+ }
+
+ public Time getTime(Column col, Calendar cal, Joins joins)
+ throws SQLException {
+ return _res[_idx].getTime(col, cal, joins);
+ }
+
+ public Timestamp getTimestamp(Column col, Calendar cal, Joins joins)
+ throws SQLException {
+ return _res[_idx].getTimestamp(col, cal, joins);
+ }
+
+ public boolean wasNull()
+ throws SQLException {
+ return _res[_idx].wasNull();
+ }
+
+ public void startDataRequest(Object mapping) {
+ for (int i = 0; i < _res.length; i++)
+ _res[i].startDataRequest(mapping);
+ }
+
+ public void endDataRequest() {
+ for (int i = 0; i < _res.length; i++)
+ _res[i].endDataRequest();
+ }
+
+ /**
+ * Comparator for ordering result rows.
+ */
+ public static interface ResultComparator
+ extends Comparator {
+
+ /**
+ * Return the ordering value of the current row of the given result.
+ */
+ public Object getOrderingValue(Result res, int idx);
+ }
+}
Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MergedResult.java
------------------------------------------------------------------------------
svn:executable = *
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,166 @@
+/*
+ * Copyright 2006 The Apache Software Foundation.
+ *
+ * Licensed 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.sql.Types;
+import java.util.Arrays;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.Index;
+import org.apache.openjpa.jdbc.schema.PrimaryKey;
+import org.apache.openjpa.jdbc.schema.Table;
+
+/**
+ * Dictionary for MySQL.
+ */
+public class MySQLDictionary
+ extends DBDictionary {
+
+ /**
+ * The MySQL table type to use when creating tables; defaults to innodb.
+ */
+ public String tableType = "innodb";
+
+ /**
+ * Whether to use clobs. Some older versions of MySQL do not handle
+ * clobs properly so we default to false here.
+ */
+ public boolean useClobs = true;
+
+ /**
+ * Whether the driver automatically deserializes blobs.
+ */
+ public boolean driverDeserializesBlobs = true;
+
+ public MySQLDictionary() {
+ platform = "MySQL";
+ validationSQL = "SELECT NOW()";
+ distinctCountColumnSeparator = ",";
+
+ supportsDeferredConstraints = false;
+ constraintNameMode = CONS_NAME_MID;
+ supportsMultipleNontransactionalResultSets = false;
+ supportsSubselect = false; // old versions
+ requiresAliasForSubselect = true; // new versions
+ supportsSelectStartIndex = true;
+ supportsSelectEndIndex = true;
+ allowsAliasInBulkClause = false;
+
+ concatenateFunction = "CONCAT({0},{1})";
+
+ maxTableNameLength = 64;
+ maxColumnNameLength = 64;
+ maxIndexNameLength = 64;
+ maxConstraintNameLength = 64;
+ maxIndexesPerTable = 32;
+ schemaCase = SCHEMA_CASE_PRESERVE;
+
+ supportsAutoAssign = true;
+ lastGeneratedKeyQuery = "SELECT LAST_INSERT_ID()";
+ autoAssignClause = "AUTO_INCREMENT";
+
+ clobTypeName = "TEXT";
+ longVarcharTypeName = "TEXT";
+ longVarbinaryTypeName = "LONG VARBINARY";
+ timestampTypeName = "DATETIME";
+ fixedSizeTypeNameSet.addAll(Arrays.asList(new String[]{
+ "BOOL", "LONG VARBINARY", "MEDIUMBLOB", "LONGBLOB",
+ "TINYBLOB", "LONG VARCHAR", "MEDIUMTEXT", "LONGTEXT", "TEXT",
+ "TINYTEXT", "DOUBLE PRECISION", "ENUM", "SET", "DATETIME",
+ }));
+ reservedWordSet.addAll(Arrays.asList(new String[]{
+ "INT1", "INT2", "INT4", "FLOAT1", "FLOAT2", "FLOAT4",
+ "AUTO_INCREMENT", "BINARY", "BLOB", "CHANGE", "ENUM", "INFILE",
+ "LOAD", "MEDIUMINT", "OPTION", "OUTFILE", "REPLACE",
+ "SET", "STARTING", "TEXT", "UNSIGNED", "ZEROFILL",
+ }));
+ }
+
+ public String[] getCreateTableSQL(Table table) {
+ String[] sql = super.getCreateTableSQL(table);
+ if (tableType != null && tableType.length() > 0)
+ sql[0] = sql[0] + " TYPE = " + tableType;
+ return sql;
+ }
+
+ public String[] getDropIndexSQL(Index index) {
+ return new String[]{ "DROP INDEX " + getFullName(index) + " ON "
+ + getFullName(index.getTable(), false) };
+ }
+
+ public String[] getAddPrimaryKeySQL(PrimaryKey pk) {
+ String[] sql = super.getAddPrimaryKeySQL(pk);
+
+ // mysql requires that a column be declared NOT NULL before
+ // it can be made a primary key.
+ Column[] cols = pk.getColumns();
+ String[] ret = new String[cols.length + sql.length];
+ for (int i = 0; i < cols.length; i++) {
+ ret[i] = "ALTER TABLE " + getFullName(cols[i].getTable(), false)
+ + " CHANGE " + cols[i].getName()
+ + " " + cols[i].getName() // name twice
+ + " " + getTypeName(cols[i]) + " NOT NULL";
+ }
+
+ System.arraycopy(sql, 0, ret, cols.length, sql.length);
+ return ret;
+ }
+
+ protected String getForeignKeyConstraintSQL(ForeignKey fk) {
+ // mysql does not support composite foreign keys
+ if (fk.getColumns().length > 1)
+ return null;
+ return super.getForeignKeyConstraintSQL(fk);
+ }
+
+ protected void appendSelectRange(SQLBuffer buf, long start, long end) {
+ buf.append(" LIMIT ").appendValue(start).append(", ");
+ if (end == Long.MAX_VALUE)
+ buf.appendValue(Long.MAX_VALUE);
+ else
+ buf.appendValue(end - start);
+ }
+
+ protected Column newColumn(ResultSet colMeta)
+ throws SQLException {
+ Column col = super.newColumn(colMeta);
+ if (col.isNotNull() && "0".equals(col.getDefaultString()))
+ col.setDefaultString(null);
+ return col;
+ }
+
+ public Object getBlobObject(ResultSet rs, int column, JDBCStore store)
+ throws SQLException {
+ // if the user has set a get-blob strategy explicitly or the driver
+ // does not automatically deserialize, delegate to super
+ if (useGetBytesForBlobs || useGetObjectForBlobs
+ || !driverDeserializesBlobs)
+ return super.getBlobObject(rs, column, store);
+
+ // most mysql drivers deserialize on getObject
+ return rs.getObject(column);
+ }
+
+ public int getPreferredType(int type) {
+ if (type == Types.CLOB && !useClobs)
+ return Types.LONGVARCHAR;
+ return super.getPreferredType(type);
+ }
+}
Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/MySQLDictionary.java
------------------------------------------------------------------------------
svn:executable = *