openjpa-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From p..@apache.org
Subject svn commit: r423615 [35/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/...
Date Wed, 19 Jul 2006 21:35:07 GMT
Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManagerImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManagerImpl.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManagerImpl.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManagerImpl.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,258 @@
+/*
+ * 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.SQLException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+import org.apache.openjpa.lib.util.Localizer;
+import org.apache.openjpa.util.InternalException;
+
+/**
+ * Manages SQL rows during an insert/update/delete process.
+ *
+ * @author Abe White
+ * @nojavadoc
+ */
+public class RowManagerImpl
+    implements RowManager {
+
+    private static final Localizer _loc = Localizer.forPackage
+        (RowManagerImpl.class);
+
+    private Map _inserts = null;
+    private Map _updates = null;
+    private Map _deletes = null;
+    private Collection _secondaryUpdates = null;
+    private Collection _secondaryDeletes = null;
+    private Collection _allRowUpdates = null;
+    private Collection _allRowDeletes = null;
+
+    // we maintain a list of the order of all primary rows if the user
+    // wants to be able to fetch them in order
+    private final List _primaryOrder;
+
+    // track whether we're dealing with any auto-inc columns
+    private boolean _auto = false;
+
+    // cache the last key and primary row; when looping over
+    // all the field mappings of a class each one will probably ask for the
+    // same key, so avoid the key creation and row lookup when possible
+    private Key _key = null;
+    private PrimaryRow _row = null;
+
+    /**
+     * Constructor.
+     *
+     * @param order whether to keep track of the order in which rows are added
+     */
+    public RowManagerImpl(boolean order) {
+        _primaryOrder = (order) ? new ArrayList() : null;
+    }
+
+    /**
+     * Whether any primary rows have auto-assign constraints.
+     */
+    public boolean hasAutoAssignConstraints() {
+        return _auto;
+    }
+
+    /**
+     * Return the ordered primary rows. Only available if ordering requested
+     * on construction.
+     */
+    public List getOrdered() {
+        return (_primaryOrder == null) ? Collections.EMPTY_LIST : _primaryOrder;
+    }
+
+    /**
+     * Return all inserted primary rows.
+     */
+    public Collection getInserts() {
+        return (_inserts == null) ? Collections.EMPTY_LIST : _inserts.values();
+    }
+
+    /**
+     * Return all updated primary rows.
+     */
+    public Collection getUpdates() {
+        return (_updates == null) ? Collections.EMPTY_LIST : _updates.values();
+    }
+
+    /**
+     * Return all deleted primary rows.
+     */
+    public Collection getDeletes() {
+        return (_deletes == null) ? Collections.EMPTY_LIST : _deletes.values();
+    }
+
+    /**
+     * Return all inserted and updated secondary rows.
+     */
+    public Collection getSecondaryUpdates() {
+        return (_secondaryUpdates == null) ? Collections.EMPTY_LIST
+            : _secondaryUpdates;
+    }
+
+    /**
+     * Return all deleted secondary rows.
+     */
+    public Collection getSecondaryDeletes() {
+        return (_secondaryDeletes == null) ? Collections.EMPTY_LIST
+            : _secondaryDeletes;
+    }
+
+    /**
+     * Return any 'all row' updates.
+     */
+    public Collection getAllRowUpdates() {
+        return (_allRowUpdates == null) ? Collections.EMPTY_LIST
+            : _allRowUpdates;
+    }
+
+    /**
+     * Return any 'all row' deletes.
+     */
+    public Collection getAllRowDeletes() {
+        return (_allRowDeletes == null) ? Collections.EMPTY_LIST
+            : _allRowDeletes;
+    }
+
+    public Row getSecondaryRow(Table table, int action) {
+        return new SecondaryRow(table, action);
+    }
+
+    public void flushSecondaryRow(Row row)
+        throws SQLException {
+        if (!row.isValid())
+            return;
+
+        SecondaryRow srow = (SecondaryRow) row;
+        if (srow.getAction() == Row.ACTION_DELETE) {
+            if (_secondaryDeletes == null)
+                _secondaryDeletes = new ArrayList();
+            _secondaryDeletes.add(srow.clone());
+        } else {
+            if (_secondaryUpdates == null)
+                _secondaryUpdates = new ArrayList();
+            _secondaryUpdates.add(srow.clone());
+        }
+    }
+
+    public Row getAllRows(Table table, int action) {
+        return new RowImpl(table, action);
+    }
+
+    public void flushAllRows(Row row) {
+        if (!row.isValid())
+            return;
+
+        switch (row.getAction()) {
+            case Row.ACTION_UPDATE:
+                if (_allRowUpdates == null)
+                    _allRowUpdates = new ArrayList();
+                _allRowUpdates.add(row);
+                break;
+            case Row.ACTION_DELETE:
+                if (_allRowDeletes == null)
+                    _allRowDeletes = new ArrayList();
+                _allRowDeletes.add(row);
+                break;
+            default:
+                throw new InternalException("action = " + row.getAction());
+        }
+    }
+
+    public Row getRow(Table table, int action, OpenJPAStateManager sm,
+        boolean create) {
+        if (sm == null)
+            return null;
+
+        // check if request matches cached version
+        if (_key != null && _key.table == table && _key.sm == sm
+            && _row != null && _row.getAction() == action)
+            return _row;
+
+        Map map;
+        if (action == Row.ACTION_DELETE) {
+            if (_deletes == null && create)
+                _deletes = new HashMap();
+            map = _deletes;
+        } else if (action == Row.ACTION_INSERT) {
+            if (_inserts == null && create)
+                _inserts = new HashMap();
+            map = _inserts;
+        } else {
+            if (_updates == null && create)
+                _updates = new HashMap();
+            map = _updates;
+        }
+        if (map == null)
+            return null;
+
+        _key = new Key(table, sm);
+        _row = (PrimaryRow) map.get(_key);
+
+        if (_row == null && create) {
+            _row = new PrimaryRow(table, action, sm);
+            map.put(_key, _row);
+            if (_primaryOrder != null) {
+                _row.setIndex(_primaryOrder.size());
+                _primaryOrder.add(_row);
+            }
+
+            if (!_auto && action == Row.ACTION_INSERT)
+                _auto = table.getAutoAssignedColumns().length > 0;
+        }
+
+        if (_row != null)
+            _row.setFailedObject(sm.getManagedInstance());
+        return _row;
+    }
+
+    /**
+     * Key for hashing virtual rows.
+     */
+    private static class Key {
+
+        public final Table table;
+        public final OpenJPAStateManager sm;
+
+        public Key(Table table, OpenJPAStateManager sm) {
+            this.table = table;
+            this.sm = sm;
+        }
+
+        public int hashCode() {
+            return (table.hashCode() + sm.hashCode()) % Integer.MAX_VALUE;
+        }
+
+        public boolean equals(Object other) {
+            if (other == this)
+                return true;
+
+            Key key = (Key) other;
+            return table == key.table && sm == key.sm;
+        }
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManagerImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,609 @@
+/*
+ * 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.Serializable;
+import java.sql.CallableStatement;
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.Iterator;
+import java.util.List;
+
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.Sequence;
+import org.apache.openjpa.jdbc.schema.Table;
+import serp.util.Numbers;
+
+/**
+ * Buffer for SQL statements that can be used to create
+ * java.sql.PreparedStatements.
+ *
+ * @author Marc Prud'hommeaux
+ * @author Abe White
+ * @since 2.4
+ */
+public final class SQLBuffer
+    implements Serializable, Cloneable {
+
+    private static final String PARAMETER_TOKEN = "?";
+
+    private final DBDictionary _dict;
+    private final StringBuffer _sql = new StringBuffer();
+    private List _subsels = null;
+    private List _params = null;
+    private List _cols = null;
+
+    /**
+     * Default constructor.
+     */
+    public SQLBuffer(DBDictionary dict) {
+        _dict = dict;
+    }
+
+    /**
+     * Copy constructor.
+     */
+    public SQLBuffer(SQLBuffer buf) {
+        _dict = buf._dict;
+        append(buf);
+    }
+
+    /**
+     * Perform a shallow clone of this SQL Buffer.
+     */
+    public Object clone() {
+        return new SQLBuffer(this);
+    }
+
+    /**
+     * Return true if the buffer is emtpy.
+     */
+    public boolean isEmpty() {
+        return _sql.length() == 0;
+    }
+
+    /**
+     * Append all SQL and parameters of the given buffer.
+     */
+    public SQLBuffer append(SQLBuffer buf) {
+        append(buf, _sql.length(), (_params == null) ? 0 : _params.size(),
+            true);
+        return this;
+    }
+
+    /**
+     * Append all SQL and parameters of the given buffer at the given positions.
+     */
+    private void append(SQLBuffer buf, int sqlIndex, int paramIndex,
+        boolean subsels) {
+        if (subsels) {
+            // only allow appending of buffers with subselects, not insertion
+            if (_subsels != null && !_subsels.isEmpty()
+                && sqlIndex != _sql.length())
+                throw new IllegalStateException();
+            if (buf._subsels != null && !buf._subsels.isEmpty()) {
+                if (sqlIndex != _sql.length())
+                    throw new IllegalStateException();
+                if (_subsels == null)
+                    _subsels = new ArrayList(buf._subsels.size());
+                for (int i = 0; i < buf._subsels.size(); i++)
+                    _subsels.add(((Subselect) buf._subsels.get(i)).
+                        clone(sqlIndex, paramIndex));
+            }
+        }
+
+        if (sqlIndex == _sql.length())
+            _sql.append(buf._sql.toString());
+        else
+            _sql.insert(sqlIndex, buf._sql.toString());
+
+        if (buf._params != null) {
+            if (_params == null)
+                _params = new ArrayList();
+            if (_cols == null && buf._cols != null) {
+                _cols = new ArrayList();
+                while (_cols.size() < _params.size())
+                    _cols.add(null);
+            }
+
+            if (paramIndex == _params.size()) {
+                _params.addAll(buf._params);
+                if (buf._cols != null)
+                    _cols.addAll(buf._cols);
+                else if (_cols != null)
+                    while (_cols.size() < _params.size())
+                        _cols.add(null);
+            } else {
+                _params.addAll(paramIndex, buf._params);
+                if (buf._cols != null)
+                    _cols.addAll(paramIndex, buf._cols);
+                else if (_cols != null)
+                    while (_cols.size() < _params.size())
+                        _cols.add(paramIndex, null);
+            }
+        }
+    }
+
+    public SQLBuffer append(Table table) {
+        _sql.append(_dict.getFullName(table, false));
+        return this;
+    }
+
+    public SQLBuffer append(Sequence seq) {
+        _sql.append(_dict.getFullName(seq));
+        return this;
+    }
+
+    public SQLBuffer append(Column col) {
+        _sql.append(col.getName());
+        return this;
+    }
+
+    public SQLBuffer append(String s) {
+        _sql.append(s);
+        return this;
+    }
+
+    /**
+     * Append a subselect. This delays resolution of the select SQL.
+     */
+    public SQLBuffer append(Select sel, JDBCFetchConfiguration fetch) {
+        return append(sel, fetch, false);
+    }
+
+    /**
+     * Append a subselect count. This delays resolution of the select SQL.
+     */
+    public SQLBuffer appendCount(Select sel, JDBCFetchConfiguration fetch) {
+        return append(sel, fetch, true);
+    }
+
+    /**
+     * Append a subselect. This delays resolution of the select SQL.
+     */
+    private SQLBuffer append(Select sel, JDBCFetchConfiguration fetch,
+        boolean count) {
+        _sql.append("(");
+        Subselect sub = new Subselect();
+        sub.select = sel;
+        sub.fetch = fetch;
+        sub.count = count;
+        sub.sqlIndex = _sql.length();
+        sub.paramIndex = (_params == null) ? 0 : _params.size();
+        _sql.append(")");
+
+        if (_subsels == null)
+            _subsels = new ArrayList(2);
+        _subsels.add(sub);
+        return this;
+    }
+
+    /**
+     * Replace a subselect.
+     */
+    public boolean replace(Select old, Select sel) {
+        if (_subsels == null)
+            return false;
+        Subselect sub;
+        for (int i = 0; i < _subsels.size(); i++) {
+            sub = (Subselect) _subsels.get(i);
+            if (sub.select == old) {
+                sub.select = sel;
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(Object o) {
+        return appendValue(o, null);
+    }
+
+    /**
+     * Append a parameter value for a specific column.
+     */
+    public SQLBuffer appendValue(Object o, Column col) {
+        if (o == null)
+            _sql.append("NULL");
+        else if (o instanceof Raw)
+            _sql.append(o.toString());
+        else {
+            _sql.append(PARAMETER_TOKEN);
+
+            // initialize param and col lists; we hold off on col list until
+            // we get the first non-null col
+            if (_params == null)
+                _params = new ArrayList();
+            if (col != null && _cols == null) {
+                _cols = new ArrayList();
+                while (_cols.size() < _params.size())
+                    _cols.add(null);
+            }
+
+            _params.add(o);
+            if (_cols != null)
+                _cols.add(col);
+        }
+        return this;
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(boolean b) {
+        return appendValue(b, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(boolean b, Column col) {
+        return appendValue((b) ? Boolean.TRUE : Boolean.FALSE, col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(byte b) {
+        return appendValue(b, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(byte b, Column col) {
+        return appendValue(new Byte(b), col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(char c) {
+        return appendValue(c, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(char c, Column col) {
+        return appendValue(new Character(c), col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(double d) {
+        return appendValue(d, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(double d, Column col) {
+        return appendValue(new Double(d), col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(float f) {
+        return appendValue(f, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(float f, Column col) {
+        return appendValue(new Float(f), col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(int i) {
+        return appendValue(i, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(int i, Column col) {
+        return appendValue(Numbers.valueOf(i), col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(long l) {
+        return appendValue(l, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(long l, Column col) {
+        return appendValue(Numbers.valueOf(l), col);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(short s) {
+        return appendValue(s, null);
+    }
+
+    /**
+     * Append a parameter value.
+     */
+    public SQLBuffer appendValue(short s, Column col) {
+        return appendValue(new Short(s), col);
+    }
+
+    /**
+     * Return the list of parameter values.
+     */
+    public List getParameters() {
+        return (_params == null) ? Collections.EMPTY_LIST : _params;
+    }
+
+    /**
+     * Return the SQL for this buffer.
+     */
+    public String getSQL() {
+        return getSQL(false);
+    }
+
+    /**
+     * Returns the SQL for this buffer.
+     *
+     * @param replaceParams if true, then replace parameters with the
+     * actual parameter values
+     */
+    public String getSQL(boolean replaceParams) {
+        if (_subsels != null && !_subsels.isEmpty()) {
+            // add subsels backwards so that the stored insertion points of
+            // later subsels remain valid
+            Subselect sub;
+            SQLBuffer buf;
+            for (int i = _subsels.size() - 1; i >= 0; i--) {
+                sub = (Subselect) _subsels.get(i);
+                if (sub.count)
+                    buf = sub.select.toSelectCount();
+                else
+                    buf = sub.select.toSelect(false, sub.fetch);
+                append(buf, sub.sqlIndex, sub.paramIndex, false);
+            }
+            _subsels.clear();
+        }
+
+        String sql = _sql.toString();
+        if (!replaceParams || _params == null || _params.isEmpty())
+            return sql;
+
+        StringBuffer buf = new StringBuffer();
+        Iterator pi = _params.iterator();
+        for (int i = 0; i < sql.length(); i++) {
+            if (sql.charAt(i) != '?') {
+                buf.append(sql.charAt(i));
+                continue;
+            }
+
+            Object param = pi.hasNext() ? pi.next() : null;
+            if (param == null)
+                buf.append("NULL");
+            else if (param instanceof Number || param instanceof Boolean)
+                buf.append(param);
+            else if (param instanceof String || param instanceof Character)
+                buf.append("'").append(param).append("'");
+            else
+                buf.append("?");
+        }
+        return buf.toString();
+    }
+
+    /**
+     * Create and populate the parameters of a prepared statement using
+     * the SQL in this buffer.
+     */
+    public PreparedStatement prepareStatement(Connection conn)
+        throws SQLException {
+        return prepareStatement(conn, ResultSet.TYPE_FORWARD_ONLY,
+            ResultSet.CONCUR_READ_ONLY);
+    }
+
+    /**
+     * Create and populate the parameters of a prepared statement using
+     * the SQL in this buffer.
+     */
+    public PreparedStatement prepareStatement(Connection conn, int rsType,
+        int rsConcur)
+        throws SQLException {
+        return prepareStatement(conn, null, rsType, rsConcur);
+    }
+
+    /**
+     * Create and populate the parameters of a prepred statement using the
+     * SQL in this buffer and the given fetch configuration.
+     */
+    public PreparedStatement prepareStatement(Connection conn,
+        JDBCFetchConfiguration fetch, int rsType, int rsConcur)
+        throws SQLException {
+        if (rsType == -1 && fetch == null)
+            rsType = ResultSet.TYPE_FORWARD_ONLY;
+        else if (rsType == -1)
+            rsType = fetch.getResultSetType();
+        if (rsConcur == -1)
+            rsConcur = ResultSet.CONCUR_READ_ONLY;
+
+        PreparedStatement stmnt;
+        if (rsType == ResultSet.TYPE_FORWARD_ONLY
+            && rsConcur == ResultSet.CONCUR_READ_ONLY)
+            stmnt = conn.prepareStatement(getSQL());
+        else
+            stmnt = conn.prepareStatement(getSQL(), rsType, rsConcur);
+        try {
+            setParameters(stmnt);
+            if (fetch != null) {
+                if (fetch.getFetchBatchSize() > 0)
+                    stmnt.setFetchSize(fetch.getFetchBatchSize());
+                if (rsType != ResultSet.TYPE_FORWARD_ONLY
+                    && fetch.getFetchDirection() != ResultSet.FETCH_FORWARD)
+                    stmnt.setFetchDirection(fetch.getFetchDirection());
+            }
+            return stmnt;
+        } catch (SQLException se) {
+            try {
+                stmnt.close();
+            } catch (SQLException se2) {
+            }
+            throw se;
+        }
+    }
+
+    /**
+     * Create and populate the parameters of a prepared statement using
+     * the SQL in this buffer.
+     */
+    public CallableStatement prepareCall(Connection conn)
+        throws SQLException {
+        return prepareCall(conn, ResultSet.TYPE_FORWARD_ONLY,
+            ResultSet.CONCUR_READ_ONLY);
+    }
+
+    /**
+     * Create and populate the parameters of a prepared statement using
+     * the SQL in this buffer.
+     */
+    public CallableStatement prepareCall(Connection conn, int rsType,
+        int rsConcur)
+        throws SQLException {
+        return prepareCall(conn, null, rsType, rsConcur);
+    }
+
+    /**
+     * Create and populate the parameters of a prepred statement using the
+     * SQL in this buffer and the given fetch configuration.
+     */
+    public CallableStatement prepareCall(Connection conn,
+        JDBCFetchConfiguration fetch, int rsType, int rsConcur)
+        throws SQLException {
+        if (rsType == -1 && fetch == null)
+            rsType = ResultSet.TYPE_FORWARD_ONLY;
+        else if (rsType == -1)
+            rsType = fetch.getResultSetType();
+        if (rsConcur == -1)
+            rsConcur = ResultSet.CONCUR_READ_ONLY;
+
+        CallableStatement stmnt;
+        if (rsType == ResultSet.TYPE_FORWARD_ONLY
+            && rsConcur == ResultSet.CONCUR_READ_ONLY)
+            stmnt = conn.prepareCall(getSQL());
+        else
+            stmnt = conn.prepareCall(getSQL(), rsType, rsConcur);
+        try {
+            setParameters(stmnt);
+            if (fetch != null) {
+                if (fetch.getFetchBatchSize() > 0)
+                    stmnt.setFetchSize(fetch.getFetchBatchSize());
+                if (rsType != ResultSet.TYPE_FORWARD_ONLY
+                    && fetch.getFetchDirection() != ResultSet.FETCH_FORWARD)
+                    stmnt.setFetchDirection(fetch.getFetchDirection());
+            }
+            return stmnt;
+        } catch (SQLException se) {
+            try {
+                stmnt.close();
+            } catch (SQLException se2) {
+            }
+            throw se;
+        }
+    }
+
+    /**
+     * Populate the parameters of an existing PreparedStatement
+     * with values from this buffer.
+     */
+    public void setParameters(PreparedStatement ps)
+        throws SQLException {
+        if (_params == null)
+            return;
+
+        Column col;
+        for (int i = 0; i < _params.size(); i++) {
+            col = (_cols == null) ? null : (Column) _cols.get(i);
+            _dict.setUnknown(ps, i + 1, _params.get(i), col);
+        }
+    }
+
+    public int hashCode() {
+        int hash = _sql.hashCode();
+        return (_params == null) ? hash : hash ^ _params.hashCode();
+    }
+
+    /**
+     * Compare internal SQL without resolving subselects or stringifying
+     * parameters.
+     */
+    public boolean sqlEquals(String sql) {
+        return _sql.toString().equals(sql);
+    }
+
+    public boolean equals(Object other) {
+        if (other == this)
+            return true;
+        if (!(other instanceof SQLBuffer))
+            return false;
+
+        SQLBuffer buf = (SQLBuffer) other;
+        return _sql.equals(buf._sql)
+            && ObjectUtils.equals(_params, buf._params);
+    }
+
+    /**
+     * Represents a subselect.
+     */
+    private static class Subselect {
+
+        public Select select;
+        public JDBCFetchConfiguration fetch;
+        public boolean count;
+        public int sqlIndex;
+        public int paramIndex;
+
+        public Subselect clone(int sqlIndex, int paramIndex) {
+            if (sqlIndex == 0 && paramIndex == 0)
+                return this;
+
+            Subselect sub = new Subselect();
+            sub.select = select;
+            sub.fetch = fetch;
+            sub.count = count;
+            sub.sqlIndex = this.sqlIndex + sqlIndex;
+            sub.paramIndex = this.paramIndex + paramIndex;
+            return sub;
+        }
+    }
+}
+

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLBuffer.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,103 @@
+/*
+ * 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.SQLException;
+import java.util.LinkedList;
+import java.util.List;
+
+import org.apache.openjpa.util.OpenJPAException;
+import org.apache.openjpa.util.StoreException;
+
+/**
+ * Helper class for converting a {@link SQLException} into
+ * the appropriate OpenJPA type.
+ *
+ * @author Marc Prud'hommeaux
+ * @nojavadoc
+ */
+public class SQLExceptions {
+
+    private static final SQLException[] EMPTY_EXCEPS = new SQLException[0];
+
+    /**
+     * Convert the specified exception into a {@link StoreException}.
+     */
+    public static OpenJPAException getStore(SQLException se) {
+        return getStore(se, null, null);
+    }
+
+    /**
+     * Convert the specified exception into a {@link OpenJPAException}.
+     */
+    public static OpenJPAException getStore(SQLException se, Object failed) {
+        return getStore(se, failed, null);
+    }
+
+    /**
+     * Convert the specified exception into a {@link StoreException}.
+     */
+    public static OpenJPAException getStore(SQLException se,
+        DBDictionary dict) {
+        return getStore(se.getMessage(), se, dict);
+    }
+
+    /**
+     * Convert the specified exception into a {@link StoreException}.
+     */
+    public static OpenJPAException getStore(SQLException se, Object failed,
+        DBDictionary dict) {
+        return getStore(se.getMessage(), se, failed, dict);
+    }
+
+    /**
+     * Convert the specified exception into a {@link StoreException}.
+     */
+    public static OpenJPAException getStore(String msg, SQLException se,
+        DBDictionary dict) {
+        return getStore(msg, se, null, dict);
+    }
+
+    /**
+     * Convert the specified exception into a {@link StoreException}.
+     */
+    public static OpenJPAException getStore(String msg, SQLException se,
+        Object failed, DBDictionary dict) {
+        if (msg == null)
+            msg = se.getClass().getName();
+        SQLException[] ses = getSQLExceptions(se);
+        if (dict == null)
+            return new StoreException(msg).setFailedObject(failed).
+                setNestedThrowables(ses);
+        return dict.newStoreException(msg, ses, failed);
+    }
+
+    /**
+     * Returns an array of {@link SQLException} instances for the
+     * specified exception.
+     */
+    private static SQLException[] getSQLExceptions(SQLException se) {
+        if (se == null)
+            return EMPTY_EXCEPS;
+
+        List errs = new LinkedList();
+        while (se != null && !errs.contains(se)) {
+            errs.add(se);
+            se = se.getNextException();
+        }
+        return (SQLException[]) errs.toArray(new SQLException[errs.size()]);
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactory.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactory.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactory.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactory.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,43 @@
+/*
+ * 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;
+
+/**
+ * Factory for SQL constructs.
+ *
+ * @author Abe White
+ */
+public interface SQLFactory {
+
+    /**
+     * Select factory.
+     */
+    public Select newSelect();
+
+    /**
+     * Union factory.
+     *
+     * @param selects the number of selects in the union
+     */
+    public Union newUnion(int selects);
+
+    /**
+     * Union factory.
+     *
+     * @param selects the members of the union
+     */
+    public Union newUnion(Select[] selects);
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactory.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactoryImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactoryImpl.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactoryImpl.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactoryImpl.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,60 @@
+/*
+ * 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.conf.JDBCConfiguration;
+import org.apache.openjpa.lib.conf.Configurable;
+import org.apache.openjpa.lib.conf.Configuration;
+
+/**
+ * Default factory for SQL abstraction constructs.
+ *
+ * @author Abe White
+ */
+public class SQLFactoryImpl
+    implements SQLFactory, Configurable {
+
+    private JDBCConfiguration _conf = null;
+
+    /**
+     * System configuration.
+     */
+    public JDBCConfiguration getConfiguration() {
+        return _conf;
+    }
+
+    public Select newSelect() {
+        return new SelectImpl(_conf);
+    }
+
+    public Union newUnion(int selects) {
+        return new LogicalUnion(_conf, selects);
+    }
+
+    public Union newUnion(Select[] selects) {
+        return new LogicalUnion(_conf, selects);
+    }
+
+    public void setConfiguration(Configuration conf) {
+        _conf = (JDBCConfiguration) conf;
+    }
+
+    public void startConfiguration() {
+    }
+
+    public void endConfiguration() {
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLFactoryImpl.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,124 @@
+/*
+ * 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.Connection;
+import java.sql.DatabaseMetaData;
+import java.sql.SQLException;
+import java.sql.Types;
+
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.lib.util.Localizer;
+
+/**
+ * Dictionary for MS SQLServer.
+ */
+public class SQLServerDictionary
+    extends AbstractSQLServerDictionary {
+
+    public static final String VENDOR_MICROSOFT = "microsoft";
+    public static final String VENDOR_NETDIRECT = "netdirect";
+    public static final String VENDOR_JTDS = "jtds";
+
+    private static final Localizer _loc = Localizer.forPackage
+        (SQLServerDictionary.class);
+
+    /**
+     * Flag whether to treat UNIQUEIDENTIFIER as VARBINARY or VARCHAR
+     */
+    public boolean uniqueIdentifierAsVarbinary = true;
+
+    public SQLServerDictionary() {
+        platform = "Microsoft SQL Server";
+
+        // SQLServer locks on a table-by-table basis
+        forUpdateClause = null;
+        tableForUpdateClause = "WITH (UPDLOCK)";
+
+        supportsNullTableForGetColumns = false;
+        requiresAliasForSubselect = true;
+
+        stringLengthFunction = "LEN({0})";
+    }
+
+    public void connectedConfiguration(Connection conn)
+        throws SQLException {
+        super.connectedConfiguration(conn);
+
+        DatabaseMetaData meta = conn.getMetaData();
+        String driverName = meta.getDriverName();
+        String url = meta.getURL();
+        if (driverVendor == null) {
+            if ("NetDirect JSQLConnect".equals(driverName))
+                driverVendor = VENDOR_NETDIRECT;
+            else if (driverName != null && driverName.startsWith("jTDS"))
+                driverVendor = VENDOR_JTDS;
+            else if ("SQLServer".equals(driverName)) {
+                if (url != null && url.startsWith("jdbc:microsoft:sqlserver:"))
+                    driverVendor = VENDOR_MICROSOFT;
+                else if (url != null
+                    && url.startsWith("jdbc:datadirect:sqlserver:"))
+                    driverVendor = VENDOR_DATADIRECT;
+                else
+                    driverVendor = VENDOR_OTHER;
+            } else
+                driverVendor = VENDOR_OTHER;
+        }
+
+        // warn about using cursors
+        if ((VENDOR_MICROSOFT.equalsIgnoreCase(driverVendor)
+            || VENDOR_DATADIRECT.equalsIgnoreCase(driverVendor))
+            && url.toLowerCase().indexOf("selectmethod=cursor") == -1)
+            log.warn(_loc.get("sqlserver-cursor", url));
+
+        // warn about prepared statement caching if using ms driver
+        String props = conf.getConnectionFactoryProperties();
+        if (props == null)
+            props = "";
+        if (VENDOR_MICROSOFT.equalsIgnoreCase(driverVendor)
+            && props.toLowerCase().indexOf("maxcachedstatements=0") == -1)
+            log.warn(_loc.get("sqlserver-cachedstmnts"));
+    }
+
+    public Column[] getColumns(DatabaseMetaData meta, String catalog,
+        String schemaName, String tableName, String columnName, Connection conn)
+        throws SQLException {
+        Column[] cols = super.getColumns(meta, catalog, schemaName, tableName,
+            columnName, conn);
+
+        // for opta driver, which reports nvarchar as unknown type
+        for (int i = 0; cols != null && i < cols.length; i++) {
+            String typeName = cols[i].getTypeName();
+            if (typeName == null)
+                continue;
+
+            typeName = typeName.toUpperCase();
+
+            if ("NVARCHAR".equals(typeName))
+                cols[i].setType(Types.VARCHAR);
+            else if ("UNIQUEIDENTIFIER".equals(typeName)) {
+                if (uniqueIdentifierAsVarbinary)
+                    cols[i].setType(Types.VARBINARY);
+                else
+                    cols[i].setType(Types.VARCHAR);
+            } else if ("NCHAR".equals(typeName))
+                cols[i].setType(Types.CHAR);
+            else if ("NTEXT".equals(typeName))
+                cols[i].setType(Types.CLOB);
+        }
+        return cols;
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLServerDictionary.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SecondaryRow.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SecondaryRow.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SecondaryRow.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SecondaryRow.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,184 @@
+/*
+ * 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.SQLException;
+
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.RelationId;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.jdbc.schema.ColumnIO;
+import org.apache.openjpa.jdbc.schema.ForeignKey;
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+/**
+ * Secondary table row that tracks foreign keys to auto-inc columns.
+ *
+ * @author Abe White
+ * @nojavadoc
+ */
+public class SecondaryRow
+    extends RowImpl {
+
+    private OpenJPAStateManager[] _fks = null;
+    private ColumnIO[] _fkIO = null;
+    private OpenJPAStateManager[] _rels = null;
+    private RelationId[] _callbacks = null;
+
+    /**
+     * Constructor; supply table and action.
+     */
+    public SecondaryRow(Table table, int action) {
+        super(table, action);
+    }
+
+    public void setForeignKey(ForeignKey fk, OpenJPAStateManager sm)
+        throws SQLException {
+        setForeignKey(fk, null, sm);
+    }
+
+    public void setForeignKey(ForeignKey fk, ColumnIO io,
+        OpenJPAStateManager sm)
+        throws SQLException {
+        if (!delayForeignKey(fk, sm)) {
+            super.setForeignKey(fk, io, sm);
+            return;
+        }
+
+        // force valid
+        if (canSetAny(io, fk.getColumns().length
+            + fk.getConstantColumns().length, false))
+            setValid(true);
+
+        // record foreig key for delayed flush
+        if (_fks == null)
+            _fks = new OpenJPAStateManager[getTable().getForeignKeys().length];
+        _fks[fk.getIndex()] = sm;
+
+        if (_fkIO != null)
+            _fkIO[fk.getIndex()] = io;
+        else if (io != null
+            && ((getAction() == ACTION_INSERT
+            && !io.isAllInsertable(fk, false))
+            || (getAction() != ACTION_INSERT
+            && !io.isAllUpdatable(fk, false)))) {
+            _fkIO = new ColumnIO[_fks.length];
+            _fkIO[fk.getIndex()] = io;
+        }
+    }
+
+    /**
+     * Record foreign keys to new auto-inc instances; flush them only when
+     * we have to generate our SQL to give the instance a chance to finalize
+     * its values.
+     */
+    private boolean delayForeignKey(ForeignKey fk, OpenJPAStateManager sm) {
+        return fk.isPrimaryKeyAutoAssigned() && getAction() != ACTION_DELETE
+            && sm != null && sm.isNew() && !sm.isFlushed();
+    }
+
+    public void setRelationId(Column col, OpenJPAStateManager sm,
+        RelationId rel)
+        throws SQLException {
+        if (sm == null || sm.getObjectId() != null || !sm.isNew()
+            || sm.isFlushed() || !isPrimaryKeyAutoAssigned(sm))
+            super.setRelationId(col, sm, rel);
+        else {
+            if (_rels == null) {
+                Column[] cols = getTable().getRelationIdColumns();
+                _rels = new OpenJPAStateManager[cols.length];
+                _callbacks = new RelationId[cols.length];
+            }
+            int idx = getRelationIdIndex(col);
+            _rels[idx] = sm;
+            _callbacks[idx] = rel;
+        }
+    }
+
+    /**
+     * Return the index into our relation id array of the value for the
+     * given column.
+     */
+    private int getRelationIdIndex(Column col) {
+        Column[] cols = getTable().getRelationIdColumns();
+        for (int i = 0; i < cols.length; i++)
+            if (cols[i] == col)
+                return i;
+        return -1;
+    }
+
+    /**
+     * Return true if any primary key columns of the given instance are
+     * auto-assigned.
+     */
+    private static boolean isPrimaryKeyAutoAssigned(OpenJPAStateManager sm) {
+        ClassMapping cls = (ClassMapping) sm.getMetaData();
+        while (cls.getJoinablePCSuperclassMapping() != null)
+            cls = cls.getJoinablePCSuperclassMapping();
+        Column[] cols = cls.getPrimaryKeyColumns();
+        for (int i = 0; i < cols.length; i++)
+            if (cols[i].isAutoAssigned())
+                return true;
+        return false;
+    }
+
+    protected String generateSQL(DBDictionary dict) {
+        try {
+            if (_fks != null) {
+                ForeignKey[] fks = getTable().getForeignKeys();
+                ColumnIO io;
+                for (int i = 0; i < _fks.length; i++) {
+                    if (_fks[i] != null) {
+                        io = (_fkIO == null) ? null : _fkIO[i];
+                        super.setForeignKey(fks[i], io, _fks[i]);
+                    }
+                }
+            }
+            if (_rels != null) {
+                Column[] cols = getTable().getRelationIdColumns();
+                for (int i = 0; i < _rels.length; i++)
+                    if (_rels[i] != null)
+                        super.setRelationId(cols[i], _rels[i], _callbacks[i]);
+            }
+        }
+        catch (SQLException se) {
+            throw SQLExceptions.getStore(se, dict);
+        }
+        return super.generateSQL(dict);
+    }
+
+    protected RowImpl newInstance(Table table, int action) {
+        return new SecondaryRow(table, action);
+    }
+
+    public void copyInto(RowImpl row, boolean whereOnly) {
+        super.copyInto(row, whereOnly);
+        if (_fks == null || whereOnly || row.getAction() == ACTION_DELETE
+            || !(row instanceof SecondaryRow))
+            return;
+
+        SecondaryRow srow = (SecondaryRow) row;
+        if (srow._fks == null)
+            srow._fks = new OpenJPAStateManager[_fks.length];
+        System.arraycopy(_fks, 0, srow._fks, 0, _fks.length);
+        if (_fkIO != null) {
+            if (srow._fkIO == null)
+                srow._fkIO = new ColumnIO[_fkIO.length];
+            System.arraycopy(_fkIO, 0, srow._fkIO, 0, _fkIO.length);
+        }
+    }
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SecondaryRow.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,668 @@
+/*
+ * 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.Collection;
+import java.util.Iterator;
+import java.util.List;
+
+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;
+
+/**
+ * Abstraction of a SQL SELECT statement.
+ *
+ * @author Abe White
+ */
+public interface Select
+    extends SelectExecutor {
+
+    /**
+     * Constant indicating to batch the select using an inner join.
+     */
+    public static final int EAGER_INNER = 0;
+
+    /**
+     * Constant indicating to batch the select using an outer join.
+     */
+    public static final int EAGER_OUTER = 1;
+
+    /**
+     * Constant indicating to use a separate select executed in parallel.
+     */
+    public static final int EAGER_PARALLEL = 2;
+
+    /**
+     * Constant indicating a select can be made without joins.
+     */
+    public static final int TYPE_JOINLESS = 3;
+
+    /**
+     * Constant indicating a two-part select and load.
+     */
+    public static final int TYPE_TWO_PART = 4;
+
+    /**
+     * Constant indicating to add conditions to the selcet to select this
+     * class and joinable subclasses only.
+     */
+    public static final int SUBS_JOINABLE = 1;
+
+    /**
+     * Constant indicating to add conditions to the select to select this
+     * class only.
+     */
+    public static final int SUBS_NONE = 2;
+
+    /**
+     * Constant indicating to select subclasses but without adding any
+     * class conditions to the select.
+     */
+    public static final int SUBS_ANY_JOINABLE = 3;
+
+    /**
+     * Constant indicating to select this class but without adding any
+     * class conditions to the select.
+     */
+    public static final int SUBS_EXACT = 4;
+
+    /**
+     * The alias to use for the from select, if any.
+     */
+    public static final String FROM_SELECT_ALIAS = "s";
+
+    /**
+     * The index of this select within the UNION, or 0.
+     */
+    public int indexOf();
+
+    /**
+     * Return this select's subselects, or empty collection if none.
+     */
+    public List getSubselects();
+
+    /**
+     * Return the parent of this select, if it is a subselect.
+     */
+    public Select getParent();
+
+    /**
+     * Return the subselect path for this select, if it is a subselect.
+     */
+    public String getSubselectPath();
+
+    /**
+     * Turn this select into a subselect of the given instance.
+     */
+    public void setParent(Select parent, String path);
+
+    /**
+     * Another select instance that creates a temporary table from which
+     * this select pulls data.
+     */
+    public Select getFromSelect();
+
+    /**
+     * Another select instance that creates a temporary table from which
+     * this select pulls data.
+     */
+    public void setFromSelect(Select sel);
+
+    /**
+     * Whether this select has an eager join of the specified type.
+     */
+    public boolean hasEagerJoin(boolean toMany);
+
+    /**
+     * Whether this select has a join of the specified type.
+     */
+    public boolean hasJoin(boolean toMany);
+
+    /**
+     * Return whether the given table is being used in this select.
+     */
+    public boolean isSelected(Table table);
+
+    /**
+     * Return the set of all used table aliases.
+     */
+    public Collection getTableAliases();
+
+    /**
+     * Return the aliases of all selected columns and all selected buffers,
+     * in the order they were selected. Each alias may be either a string
+     * or a {@link SQLBuffer}.
+     */
+    public List getSelectAliases();
+
+    /**
+     * Get the aliases for identifier columns that can be used in COUNT
+     * selects to find the number of matches. Each alias will be a
+     * string. If no identifier columns have been nominated, then all
+     * column alises are returned.
+     */
+    public List getIdentifierAliases();
+
+    /**
+     * Return the ordering SQL for this select.
+     */
+    public SQLBuffer getOrdering();
+
+    /**
+     * Return the grouping SQL for this select.
+     */
+    public SQLBuffer getGrouping();
+
+    /**
+     * Return the WHERE clause, minus any necessary end joins.
+     */
+    public SQLBuffer getWhere();
+
+    /**
+     * Return the HAVING clause, or null if none.
+     */
+    public SQLBuffer getHaving();
+
+    /**
+     * Return the top-level joins for this select.
+     */
+    public Joins getJoins();
+
+    /**
+     * Return the top-level {@link Join} elements for this select.
+     */
+    public Iterator getJoinIterator();
+
+    /**
+     * The result start index.
+     */
+    public long getStartIndex();
+
+    /**
+     * The result end index.
+     */
+    public long getEndIndex();
+
+    /**
+     * Set the result range for this select.
+     */
+    public void setRange(long start, long end);
+
+    /**
+     * Return the alias for the given column.
+     */
+    public String getColumnAlias(Column col);
+
+    /**
+     * Return the alias for the given column.
+     */
+    public String getColumnAlias(Column col, Joins joins);
+
+    /**
+     * Return the alias for the given column.
+     */
+    public String getColumnAlias(String col, Table table);
+
+    /**
+     * Return the alias for the given column.
+     */
+    public String getColumnAlias(String col, Table table, Joins joins);
+
+    /**
+     * Return true if this is an aggregate select.
+     */
+    public boolean isAggregate();
+
+    /**
+     * Set to true for aggregate selects.
+     */
+    public void setAggregate(boolean agg);
+
+    /**
+     * Return true if this select includes a LOB.
+     */
+    public boolean isLob();
+
+    /**
+     * Set to true for selects that include LOB columns.
+     */
+    public void setLob(boolean lob);
+
+    /**
+     * Clear the existing column selects.
+     */
+    public void clearSelects();
+
+    /**
+     * Select the given SQL as a placeholder for a UNION element.
+     */
+    public void selectPlaceholder(String sql);
+
+    /**
+     * Select the given SQL; the given id object is an identifier
+     * to use when retrieving the corresponding value from a {@link Result}.
+     *
+     * @return true if selected
+     */
+    public boolean select(SQLBuffer sql, Object id);
+
+    /**
+     * Select the given SQL; the given id object is an identifier
+     * to use when retrieving the corresponding value from a {@link Result}.
+     *
+     * @return true if selected
+     */
+    public boolean select(SQLBuffer sql, Object id, Joins joins);
+
+    /**
+     * Select the given SQL; the given id object is an identifier
+     * to use when retrieving the corresponding value from a {@link Result}.
+     *
+     * @return true if selected
+     */
+    public boolean select(String sql, Object id);
+
+    /**
+     * Select the given SQL; the given id object is an identifier
+     * to use when retrieving the corresponding value from a {@link Result}.
+     *
+     * @return true if selected
+     */
+    public boolean select(String sql, Object id, Joins joins);
+
+    /**
+     * Select the given column.
+     *
+     * @return true if selected
+     */
+    public boolean select(Column col);
+
+    /**
+     * Select the given column.
+     *
+     * @return true if selected
+     */
+    public boolean select(Column col, Joins joins);
+
+    /**
+     * Select the given columns.
+     *
+     * @return bit set of indexes of columns that were selected
+     */
+    public int select(Column[] cols);
+
+    /**
+     * Select the given columns.
+     *
+     * @return bit set of indexes of columns that were selected
+     */
+    public int select(Column[] cols, Joins joins);
+
+    /**
+     * Select the columns of the given mapping, possibly including subclasses.
+     * This method should be called after all where conditions are added in
+     * case the given mapping batches other selects.
+     */
+    public void select(ClassMapping mapping, int subclasses,
+        JDBCStore store, JDBCFetchState fetchState, int eager);
+
+    /**
+     * Select the columns of the given mapping, possibly including subclasses.
+     * This method should be called after all where conditions are added in
+     * case the given mapping batches other selects.
+     */
+    public void select(ClassMapping mapping, int subclasses,
+        JDBCStore store, JDBCFetchState fetchState, int eager,
+        Joins joins);
+
+    /**
+     * Select the given column as one that can be used to get a count of
+     * distinct matches. It is not necessary to designate distinct identifiers
+     * when eagerly traversing the entire result of the select or when
+     * not using an LRSSize setting of <code>count</code>.
+     *
+     * @return true if selected
+     */
+    public boolean selectIdentifier(Column col);
+
+    /**
+     * Select the given column as one that can be used to get a count of
+     * distinct matches. It is not necessary to designate distinct identifiers
+     * when eagerly traversing the entire result of the select or when
+     * not using an LRSSize setting of <code>count</code>.
+     *
+     * @return true if selected
+     */
+    public boolean selectIdentifier(Column col, Joins joins);
+
+    /**
+     * Select the given columns as ones that can be used to get a count of
+     * distinct matches. It is not necessary to designate distinct identifiers
+     * when eagerly traversing the entire result of the select or when
+     * not using an LRSSize setting of <code>count</code>.
+     *
+     * @return bit set of indexes of columns that were selected
+     */
+    public int selectIdentifier(Column[] cols);
+
+    /**
+     * Select the given columns as ones that can be used to get a count of
+     * distinct matches. It is not necessary to designate distinct identifiers
+     * when eagerly traversing the entire result of the select or when
+     * not using an LRSSize setting of <code>count</code>.
+     *
+     * @return bit set of indexes of columns that were selected
+     */
+    public int selectIdentifier(Column[] cols, Joins joins);
+
+    /**
+     * Select the columns of the given mapping, possibly including subclasses.
+     * This method should be called after all where conditions are added in
+     * case the given mapping batches other selects.
+     * The primary key columns of the mapping can be used to get a count of
+     * distinct matches. It is not necessary to designate distinct identifiers
+     * when eagerly traversing the entire result of the select or when
+     * not using an LRSSize setting of <code>count</code>.
+     */
+    public void selectIdentifier(ClassMapping mapping, int subclasses,
+        JDBCStore store, JDBCFetchState fetchState, int eager);
+
+    /**
+     * Select the columns of the given mapping, possibly including subclasses.
+     * This method should be called after all where conditions are added in
+     * case the given mapping batches other selects.
+     * The primary key columns of the mapping can be used to get a count of
+     * distinct matches. It is not necessary to designate distinct identifiers
+     * when eagerly traversing the entire result of the select or when
+     * not using an LRSSize setting of <code>count</code>.
+     */
+    public void selectIdentifier(ClassMapping mapping, int subclasses,
+        JDBCStore store, JDBCFetchState fetchState, int eager,
+        Joins joins);
+
+    /**
+     * Select the primary key columns of the given mapping, joining to
+     * superclasses as necessary to get all columns needed to construct
+     * an object id.
+     *
+     * @return bit set of indexes of pk columns that were selected
+     */
+    public int selectPrimaryKey(ClassMapping mapping);
+
+    /**
+     * Select the primary key columns of the given mapping, joining to
+     * superclasses as necessary to get all columns needed to construct
+     * an object id.
+     *
+     * @return bit set of indexes of pk columns that were selected
+     */
+    public int selectPrimaryKey(ClassMapping mapping, Joins joins);
+
+    /**
+     * Clear odering conditions.
+     */
+    public void clearOrdering();
+
+    /**
+     * Order on the primary key columns of the given mapping,
+     * joining to superclasses as necessary to get all columns needed to
+     * construct an object id.
+     * Optionally selects ordering data if not already selected.
+     */
+    public int orderByPrimaryKey(ClassMapping mapping, boolean asc,
+        boolean sel);
+
+    /**
+     * Select and order on the primary key columns of the given mapping,
+     * joining to superclasses as necessary to get all columns needed to
+     * construct an object id.
+     * Optionally selects ordering data if not already selected.
+     */
+    public int orderByPrimaryKey(ClassMapping mapping, boolean asc,
+        Joins joins, boolean sel);
+
+    /**
+     * Order by the given column.
+     * Optionally selects ordering data if not already selected.
+     */
+    public boolean orderBy(Column col, boolean asc, boolean sel);
+
+    /**
+     * Order by the given column.
+     * Optionally selects ordering data if not already selected.
+     */
+    public boolean orderBy(Column col, boolean asc, Joins joins,
+        boolean sel);
+
+    /**
+     * Order by the given columns.
+     * Optionally selects ordering data if not already selected.
+     */
+    public int orderBy(Column[] cols, boolean asc, boolean sel);
+
+    /**
+     * Order by the given columns.
+     * Optionally selects ordering data if not already selected.
+     */
+    public int orderBy(Column[] cols, boolean asc, Joins joins, boolean sel);
+
+    /**
+     * Add an ORDER BY clause.
+     * Optionally selects ordering data if not already selected.
+     */
+    public boolean orderBy(SQLBuffer sql, boolean asc, boolean sel);
+
+    /**
+     * Add an ORDER BY clause.
+     * Optionally selects ordering data if not already selected.
+     */
+    public boolean orderBy(SQLBuffer sql, boolean asc, Joins joins,
+        boolean sel);
+
+    /**
+     * Add an ORDER BY clause.
+     * Optionally selects ordering data if not already selected.
+     */
+    public boolean orderBy(String sql, boolean asc, boolean sel);
+
+    /**
+     * Add an ORDER BY clause.
+     * Optionally selects ordering data if not already selected.
+     */
+    public boolean orderBy(String sql, boolean asc, Joins joins, boolean sel);
+
+    /**
+     * Add where conditions setting the mapping's primary key to the given
+     * oid values. If the given mapping does not use oid values for its
+     * primary key, we will recursively join to its superclass until we find
+     * an ancestor that does.
+     */
+    public void wherePrimaryKey(Object oid, ClassMapping mapping,
+        JDBCStore store);
+
+    /**
+     * Add where conditions setting the given foreign key to the given
+     * oid values.
+     *
+     * @see #wherePrimaryKey
+     */
+    public void whereForeignKey(ForeignKey fk, Object oid,
+        ClassMapping mapping, JDBCStore store);
+
+    /**
+     * Add the given where conditions.
+     */
+    public void where(Joins joins);
+
+    /**
+     * Add the given where conditions.
+     */
+    public void where(SQLBuffer sql);
+
+    /**
+     * Add the given where conditions.
+     */
+    public void where(SQLBuffer sql, Joins joins);
+
+    /**
+     * Add the given where conditions.
+     */
+    public void where(String sql);
+
+    /**
+     * Add the given where conditions.
+     */
+    public void where(String sql, Joins joins);
+
+    /**
+     * Add the given having conditions.
+     */
+    public void having(SQLBuffer sql);
+
+    /**
+     * Add the given having conditions.
+     */
+    public void having(SQLBuffer sql, Joins joins);
+
+    /**
+     * Add the given having conditions.
+     */
+    public void having(String sql);
+
+    /**
+     * Add the given having conditions.
+     */
+    public void having(String sql, Joins joins);
+
+    /**
+     * Group by the given column.
+     * Optionally selects grouping data if not already selected.
+     */
+    public boolean groupBy(Column col, boolean sel);
+
+    /**
+     * Group by the given column.
+     * Optionally selects grouping data if not already selected.
+     */
+    public boolean groupBy(Column col, Joins joins, boolean sel);
+
+    /**
+     * Group by the given columns.
+     * Optionally selects grouping data if not already selected.
+     */
+    public int groupBy(Column[] cols, boolean sel);
+
+    /**
+     * Group by the given columns.
+     * Optionally selects grouping data if not already selected.
+     */
+    public int groupBy(Column[] cols, Joins joins, boolean sel);
+
+    /**
+     * Add a GROUP BY clause.
+     * Optionally selects grouping data if not already selected.
+     */
+    public boolean groupBy(SQLBuffer sql, boolean sel);
+
+    /**
+     * Add a GROUP BY clause.
+     * Optionally selects grouping data if not already selected.
+     */
+    public boolean groupBy(SQLBuffer sql, Joins joins, boolean sel);
+
+    /**
+     * Add a GROUP BY clause.
+     * Optionally selects grouping data if not already selected.
+     */
+    public boolean groupBy(String sql, boolean sel);
+
+    /**
+     * Add a GROUP BY clause.
+     * Optionally selects grouping data if not already selected.
+     */
+    public boolean groupBy(String sql, Joins joins, boolean sel);
+
+    /**
+     * Return a SELECT with the same joins and where conditions as this one.
+     *
+     * @param sels number of selects to UNION together; ignored if &lt;= 1
+     */
+    public SelectExecutor whereClone(int sels);
+
+    /**
+     * Return a SELECT that is a complete clone of this one.
+     *
+     * @param sels number of selects to UNION together; ignored if &lt;= 1
+     */
+    public SelectExecutor fullClone(int sels);
+
+    /**
+     * Return a select that will be eagerly executed with this one, or null if
+     * the	select cannot be created for the given key and join type.
+     * If the join type is inner or outer, then this select instance will be
+     * returned. Otherwise, the returned select will have a clone of this
+     * select's where conditions and joins but will be independent.
+     *
+     * @param key the key for the eager select
+     * @param eagerType one of the EAGER_* constants
+     * @param toMany whether the eager join is to-many
+     * @param sels number of selects to UNION together; ignored if &lt;= 1
+     */
+    public SelectExecutor eagerClone(FieldMapping key, int eagerType,
+        boolean toMany, int sels);
+
+    /**
+     * Return the eager select for the given key.
+     */
+    public SelectExecutor getEager(FieldMapping key);
+
+    /**
+     * Return a new instance to use for joining.
+     */
+    public Joins newJoins();
+
+    /**
+     * Append the given joins to the given buffer.
+     */
+    public void append(SQLBuffer buf, Joins joins);
+
+    /**
+     * AND the given joins together. The given joins will be hollowed in the
+     * process.
+     */
+    public Joins and(Joins joins1, Joins joins2);
+
+    /**
+     * OR the given joins together. The common joins will be removed in the
+     * process.
+     */
+    public Joins or(Joins joins1, Joins joins2);
+
+    /**
+     * Return a join set making the given joins outer joins.
+     */
+    public Joins outer(Joins joins);
+
+    /**
+     * Implement toString to generate SQL string for profiling/debuggging.
+     */
+    public String toString();
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Select.java
------------------------------------------------------------------------------
    svn:executable = *

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,122 @@
+/*
+ * 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.SQLException;
+
+import org.apache.openjpa.jdbc.conf.JDBCConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCFetchConfiguration;
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+
+/**
+ * Interface for configuring and executing a SQL select.
+ *
+ * @author Abe White
+ */
+public interface SelectExecutor {
+
+    /**
+     * Return the select configuration.
+     */
+    public JDBCConfiguration getConfiguration();
+
+    /**
+     * Return this select as a SQL statement formatted for the current
+     * dictionary.
+     */
+    public SQLBuffer toSelect(boolean forUpdate, JDBCFetchConfiguration fetch);
+
+    /**
+     * Return this select as a COUNT SQL statement formatted for the current
+     * dictionary.
+     */
+    public SQLBuffer toSelectCount();
+
+    /**
+     * Whether to automatically make results distinct when relational joins
+     * would otherwise introduce duplicates.
+     */
+    public boolean getAutoDistinct();
+
+    /**
+     * Whether to automatically make results distinct when relational joins
+     * would otherwise introduce duplicates.
+     */
+    public void setAutoDistinct(boolean distinct);
+
+    /**
+     * Whether this is a SELECT DISTINCT / UNION ALL.
+     */
+    public boolean isDistinct();
+
+    /**
+     * Whether this is a SELECT DISTINCT / UNION ALL.
+     */
+    public void setDistinct(boolean distinct);
+
+    /**
+     * Whether the result of this select should be treated as a large
+     * result set.
+     */
+    public boolean isLRS();
+
+    /**
+     * Whether the result of this select should be treated as a large
+     * result set.
+     */
+    public void setLRS(boolean lrs);
+
+    /**
+     * The join syntax for this select, as one of the syntax constants from
+     * {@link JoinSyntaxes}.
+     */
+    public int getJoinSyntax();
+
+    /**
+     * The join syntax for this select, as one of the syntax constants from
+     * {@link JoinSyntaxes}.
+     */
+    public void setJoinSyntax(int joinSyntax);
+
+    /**
+     * Return whether this select can support a random access result set type.
+     */
+    public boolean supportsRandomAccess(boolean forUpdate);
+
+    /**
+     * Whether this select can be executed for update.
+     */
+    public boolean supportsLocking();
+
+    /**
+     * Return the number of instances matching this select.
+     */
+    public int getCount(JDBCStore store)
+        throws SQLException;
+
+    /**
+     * Execute this select in the context of the given store manager.
+     */
+    public Result execute(JDBCStore store, JDBCFetchConfiguration fetch)
+        throws SQLException;
+
+    /**
+     * Execute this select in the context of the given store manager.
+     */
+    public Result execute(JDBCStore store, JDBCFetchConfiguration fetch,
+        int lockLevel)
+        throws SQLException;
+}

Propchange: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SelectExecutor.java
------------------------------------------------------------------------------
    svn:executable = *



Mime
View raw message