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 [34/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/Result.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Result.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,572 @@
+/*
+ * 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.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.meta.JavaSQLTypes;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.lib.util.Closeable;
+
+/**
+ * A result from the execution of a query or stored procedure. This
+ * interface is aligned closely with the {@link java.sql.ResultSet}, so you
+ * can expect like-named methods to have similar semantics. However, the
+ * interface has been distilled and simplified, so a result object could
+ * easily mask information sources other than a result set.
+ *  For more flexible customization of data loading, see the
+ * {@link org.apache.openjpa.kernel.PCResultObjectProvider}.
+ *
+ * @author Abe White
+ * @see ResultSetResult
+ */
+public interface Result
+    extends Closeable {
+
+    /**
+     * The eager result for the given key, or null if none.
+     */
+    public Object getEager(FieldMapping key);
+
+    /**
+     * The eager result for the given key, or null if none.
+     */
+    public void putEager(FieldMapping key, Object res);
+
+    /**
+     * Return a new joins instance to use for traversing to related data.
+     */
+    public Joins newJoins();
+
+    /**
+     * Free the resources used by this result; do <strong>not</strong>
+     * close the SQL connection.
+     */
+    public void close();
+
+    /**
+     * If true, then any results loaded from this Result
+     * will be locked in the database.
+     */
+    public boolean isLocking();
+
+    /**
+     * Return true if the result supports random access.
+     */
+    public boolean supportsRandomAccess()
+        throws SQLException;
+
+    /**
+     * Move to the given <strong>0-based</strong> row in the result, or
+     * return false if the row does not exist. This method will only be
+     * called if the result supports random access.
+     */
+    public boolean absolute(int row)
+        throws SQLException;
+
+    /**
+     * Advance to the next row, or return false if there are no more rows
+     * in the result.
+     */
+    public boolean next()
+        throws SQLException;
+
+    /**
+     * Push back the last result. In other words, just ignore the next call
+     * to {@link #next}. After the first time this method is called,
+     * additional calls before a call to {@link #next} or {@link #absolute}
+     * should have no further affect.
+     */
+    public void pushBack()
+        throws SQLException;
+
+    /**
+     * Return the number of rows in this result.
+     */
+    public int size()
+        throws SQLException;
+
+    /**
+     * Return true if the given id or column is available in the result.
+     */
+    public boolean contains(Object obj)
+        throws SQLException;
+
+    /**
+     * Return true if all the given ids or columns are available in the result.
+     */
+    public boolean containsAll(Object[] objs)
+        throws SQLException;
+
+    /**
+     * Return true if the given column is available in the result.
+     */
+    public boolean contains(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return true if all the given columns are available in the result.
+     */
+    public boolean containsAll(Column[] cols, Joins joins)
+        throws SQLException;
+
+    /**
+     * If this is the result of a UNION used to select a hierarchy of
+     * mappings, the base mapping represented by the current row.
+     * This information is not available after getting any eager results
+     * from the row.
+     */
+    public ClassMapping getBaseMapping();
+
+    /**
+     * If this is the result of a UNION used to select a hierarchy of
+     * mappings, the base mapping represented by the current row.
+     * This information is not available after getting any eager results
+     * from the row.
+     */
+    public void setBaseMapping(ClassMapping mapping);
+
+    /**
+     * The index of the select within the UNION that the current row
+     * corresponds to, or 0.
+     */
+    public int indexOf();
+
+    /**
+     * Load a pc object using the given store manager.
+     */
+    public Object load(ClassMapping mapping, JDBCStore store,
+        JDBCFetchState fetchState)
+        throws SQLException;
+
+    /**
+     * Load a pc object using the given store manager.
+     */
+    public Object load(ClassMapping mapping, JDBCStore store,
+        JDBCFetchState fetchState, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Array getArray(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public InputStream getAsciiStream(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public BigDecimal getBigDecimal(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public BigInteger getBigInteger(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public InputStream getBinaryStream(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Blob getBlob(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public boolean getBoolean(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public byte getByte(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public byte[] getBytes(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public Calendar getCalendar(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public char getChar(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Reader getCharacterStream(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Clob getClob(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public Date getDate(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public java.sql.Date getDate(Object obj, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public double getDouble(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public float getFloat(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public int getInt(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public Locale getLocale(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public long getLong(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public Number getNumber(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     *
+     * @param obj the column or id whose data to fetch
+     * @param metaType the type code from {@link org.apache.openjpa.meta.JavaTypes} or
+     * {@link JavaSQLTypes} for the type of the data; if
+     * <code>obj</code> is a column, you may specify -1
+     * to use the column's recorded java type
+     * @param arg some JDBC data access methods use an argument, such
+     * as a {@link Calendar} or {@link Map}
+     */
+    public Object getObject(Object obj, int metaType, Object arg)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Object getSQLObject(Object obj, Map map)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Ref getRef(Object obj, Map map)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public short getShort(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id.
+     */
+    public String getString(Object obj)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Time getTime(Object obj, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column or id; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Timestamp getTimestamp(Object obj, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Array getArray(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public InputStream getAsciiStream(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public BigDecimal getBigDecimal(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public BigInteger getBigInteger(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public InputStream getBinaryStream(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Blob getBlob(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public boolean getBoolean(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public byte getByte(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public byte[] getBytes(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public Calendar getCalendar(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public char getChar(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Reader getCharacterStream(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Clob getClob(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public Date getDate(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public java.sql.Date getDate(Column col, Calendar cal, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public double getDouble(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public float getFloat(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public int getInt(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public Locale getLocale(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public long getLong(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public Number getNumber(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     *
+     * @param col the column whose data to fetch
+     * @param arg some JDBC data access methods use an argument, such
+     * as a {@link Calendar} or {@link Map}
+     */
+    public Object getObject(Column col, Object arg, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Object getSQLObject(Column col, Map map, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Ref getRef(Column col, Map map, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public short getShort(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column.
+     */
+    public String getString(Column col, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Time getTime(Column col, Calendar cal, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return the value stored in the given column; may not be supported
+     * by results that are not backed by a SQL result set.
+     */
+    public Timestamp getTimestamp(Column col, Calendar cal, Joins joins)
+        throws SQLException;
+
+    /**
+     * Return true if the last value fetched was null.
+     */
+    public boolean wasNull()
+        throws SQLException;
+
+    /**
+     * Informs this receiver about the application element for which a
+     * subsequent data request will be made.
+     */
+    public void startDataRequest(Object mapping);
+
+    /**
+     * Ends a data request. Must be called in conjunction with
+     * {@link #startDataRequest}. The calls can be nested as follws<br />
+     * <pre> startDataRequest (relation); startDataRequest (relationsField);
+     * getObject("COLUMN_Y"); endDataRequest (); endDataRequest ();
+     * </pre>
+     */
+    public void endDataRequest();
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ResultSetResult.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,488 @@
+/*
+ * 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.Connection;
+import java.sql.Ref;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.sql.Types;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+import java.util.Map;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
+import org.apache.openjpa.jdbc.schema.Column;
+import org.apache.openjpa.meta.JavaTypes;
+import serp.util.Numbers;
+
+/**
+ * Base {@link Result} implementation wrapped around a result set.
+ * Column objects, column names, or column indexes (as <code>Number</code>
+ * instances) can be used to retrieve result set data.
+ *
+ * @author Abe White
+ */
+public class ResultSetResult
+    extends AbstractResult {
+
+    private final Connection _conn;
+    private final Statement _stmnt;
+    private final ResultSet _rs;
+    private final DBDictionary _dict;
+    private boolean _closeConn = true;
+    private int _row = -1;
+    private int _size = -1;
+
+    // optional; used to deserialize blobs containing refs to persistent objs
+    private JDBCStore _store = null;
+
+    /**
+     * Constructor.
+     */
+    public ResultSetResult(Connection conn, Statement stmnt,
+        ResultSet rs, DBDictionary dict) {
+        if (stmnt == null)
+            try {
+                stmnt = rs.getStatement();
+            } catch (Throwable t) {
+            }
+
+        _conn = conn;
+        _stmnt = stmnt;
+        _rs = rs;
+        _dict = dict;
+    }
+
+    /**
+     * Constructor.
+     */
+    public ResultSetResult(Connection conn, Statement stmnt,
+        ResultSet rs, JDBCStore store) {
+        this(conn, stmnt, rs, store.getDBDictionary());
+        setStore(store);
+    }
+
+    /**
+     * JDBC 2 constructor. Relies on being able to retrieve the statement
+     * from the result set, and the connection from the statement.
+     */
+    public ResultSetResult(ResultSet rs, DBDictionary dict)
+        throws SQLException {
+        _stmnt = rs.getStatement();
+        _conn = _stmnt.getConnection();
+        _rs = rs;
+        _dict = dict;
+    }
+
+    /**
+     * JDBC 2 constructor. Relies on being able to retrieve the statement
+     * from the result set, and the connection from the statement.
+     */
+    public ResultSetResult(ResultSet rs, JDBCStore store)
+        throws SQLException {
+        this(rs, store.getDBDictionary());
+        setStore(store);
+    }
+
+    /**
+     * Return the statement that produced this result.
+     */
+    public Statement getStatement() {
+        return _stmnt;
+    }
+
+    /**
+     * Return the backing result set.
+     */
+    public ResultSet getResultSet() {
+        return _rs;
+    }
+
+    /**
+     * Return the dictionary in use.
+     */
+    public DBDictionary getDBDictionary() {
+        return _dict;
+    }
+
+    /**
+     * Optional store manager used to deserialize blobs containing
+     * references to persistent objects.
+     */
+    public JDBCStore getStore() {
+        return _store;
+    }
+
+    /**
+     * Optional store manager used to deserialize blobs containing
+     * references to persistent objects.
+     */
+    public void setStore(JDBCStore store) {
+        _store = store;
+    }
+
+    /**
+     * Whether to close the backing connection when this result is closed.
+     * Defaults to true.
+     */
+    public boolean getCloseConnection() {
+        return _closeConn;
+    }
+
+    /**
+     * Whether to close the backing connection when this result is closed.
+     * Defaults to true.
+     */
+    public void setCloseConnection(boolean closeConn) {
+        _closeConn = closeConn;
+    }
+
+    public void close() {
+        super.close();
+        try {
+            _rs.close();
+        } catch (SQLException se) {
+        }
+        if (_stmnt != null)
+            try {
+                _stmnt.close();
+            } catch (SQLException se) {
+            }
+        if (_closeConn)
+            try {
+                _conn.close();
+            } catch (SQLException se) {
+            }
+    }
+
+    public boolean supportsRandomAccess()
+        throws SQLException {
+        return _rs.getType() != ResultSet.TYPE_FORWARD_ONLY;
+    }
+
+    protected boolean absoluteInternal(int row)
+        throws SQLException {
+        if (row == ++_row)
+            return _rs.next();
+
+        // random access
+        _rs.absolute(row + 1);
+        if (_rs.getRow() == 0) {
+            _row = -1;
+            return false;
+        }
+        _row = row;
+        return true;
+    }
+
+    protected boolean nextInternal()
+        throws SQLException {
+        _row++;
+        return _rs.next();
+    }
+
+    public int size()
+        throws SQLException {
+        if (_size == -1) {
+            _rs.last();
+            _size = _rs.getRow();
+            if (_row == -1)
+                _rs.beforeFirst();
+            else
+                _rs.absolute(_row + 1);
+        }
+        return _size;
+    }
+
+    protected boolean containsInternal(Object obj, Joins joins)
+        throws SQLException {
+        return ((Number) translate(obj, joins)).intValue() > 0;
+    }
+
+    protected Array getArrayInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getArray(_rs, ((Number) obj).intValue());
+    }
+
+    protected InputStream getAsciiStreamInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getAsciiStream(_rs, ((Number) obj).intValue());
+    }
+
+    protected BigDecimal getBigDecimalInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getBigDecimal(_rs, ((Number) obj).intValue());
+    }
+
+    protected Number getNumberInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getNumber(_rs, ((Number) obj).intValue());
+    }
+
+    protected BigInteger getBigIntegerInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getBigInteger(_rs, ((Number) obj).intValue());
+    }
+
+    protected InputStream getBinaryStreamInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getBinaryStream(_rs, ((Number) obj).intValue());
+    }
+
+    protected Blob getBlobInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getBlob(_rs, ((Number) obj).intValue());
+    }
+
+    protected boolean getBooleanInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getBoolean(_rs, ((Number) obj).intValue());
+    }
+
+    protected byte getByteInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getByte(_rs, ((Number) obj).intValue());
+    }
+
+    protected byte[] getBytesInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getBytes(_rs, ((Number) obj).intValue());
+    }
+
+    protected Calendar getCalendarInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getCalendar(_rs, ((Number) obj).intValue());
+    }
+
+    protected char getCharInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getChar(_rs, ((Number) obj).intValue());
+    }
+
+    protected Reader getCharacterStreamInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getCharacterStream(_rs, ((Number) obj).intValue());
+    }
+
+    protected Clob getClobInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getClob(_rs, ((Number) obj).intValue());
+    }
+
+    protected Date getDateInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getDate(_rs, ((Number) obj).intValue());
+    }
+
+    protected java.sql.Date getDateInternal(Object obj, Calendar cal,
+        Joins joins)
+        throws SQLException {
+        return _dict.getDate(_rs, ((Number) obj).intValue(), cal);
+    }
+
+    protected double getDoubleInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getDouble(_rs, ((Number) obj).intValue());
+    }
+
+    protected float getFloatInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getFloat(_rs, ((Number) obj).intValue());
+    }
+
+    protected int getIntInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getInt(_rs, ((Number) obj).intValue());
+    }
+
+    protected Locale getLocaleInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getLocale(_rs, ((Number) obj).intValue());
+    }
+
+    protected long getLongInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getLong(_rs, ((Number) obj).intValue());
+    }
+
+    protected Object getObjectInternal(Object obj, int metaTypeCode,
+        Object arg, Joins joins)
+        throws SQLException {
+        if (metaTypeCode == -1 && obj instanceof Column)
+            metaTypeCode = ((Column) obj).getJavaType();
+
+        Object val = null;
+        switch (metaTypeCode) {
+            case JavaTypes.BOOLEAN:
+            case JavaTypes.BOOLEAN_OBJ:
+                val = (getBooleanInternal(obj, joins)) ? Boolean.TRUE
+                    : Boolean.FALSE;
+                break;
+            case JavaTypes.BYTE:
+            case JavaTypes.BYTE_OBJ:
+                val = new Byte(getByteInternal(obj, joins));
+                break;
+            case JavaTypes.CHAR:
+            case JavaTypes.CHAR_OBJ:
+                val = new Character(getCharInternal(obj, joins));
+                break;
+            case JavaTypes.DOUBLE:
+            case JavaTypes.DOUBLE_OBJ:
+                val = new Double(getDoubleInternal(obj, joins));
+                break;
+            case JavaTypes.FLOAT:
+            case JavaTypes.FLOAT_OBJ:
+                val = new Float(getFloatInternal(obj, joins));
+                break;
+            case JavaTypes.INT:
+            case JavaTypes.INT_OBJ:
+                val = Numbers.valueOf(getIntInternal(obj, joins));
+                break;
+            case JavaTypes.LONG:
+            case JavaTypes.LONG_OBJ:
+                val = Numbers.valueOf(getLongInternal(obj, joins));
+                break;
+            case JavaTypes.SHORT:
+            case JavaTypes.SHORT_OBJ:
+                val = new Short(getShortInternal(obj, joins));
+                break;
+            case JavaTypes.STRING:
+                return getStringInternal(obj, joins);
+            case JavaTypes.OBJECT:
+                return _dict
+                    .getBlobObject(_rs, ((Number) obj).intValue(), _store);
+            case JavaTypes.DATE:
+                return getDateInternal(obj, joins);
+            case JavaTypes.CALENDAR:
+                return getCalendarInternal(obj, joins);
+            case JavaTypes.BIGDECIMAL:
+                return getBigDecimalInternal(obj, joins);
+            case JavaTypes.NUMBER:
+                return getNumberInternal(obj, joins);
+            case JavaTypes.BIGINTEGER:
+                return getBigIntegerInternal(obj, joins);
+            case JavaTypes.LOCALE:
+                return getLocaleInternal(obj, joins);
+            case JavaSQLTypes.SQL_ARRAY:
+                return getArrayInternal(obj, joins);
+            case JavaSQLTypes.ASCII_STREAM:
+                return getAsciiStreamInternal(obj, joins);
+            case JavaSQLTypes.BINARY_STREAM:
+                return getBinaryStreamInternal(obj, joins);
+            case JavaSQLTypes.BLOB:
+                return getBlobInternal(obj, joins);
+            case JavaSQLTypes.BYTES:
+                return getBytesInternal(obj, joins);
+            case JavaSQLTypes.CHAR_STREAM:
+                return getCharacterStreamInternal(obj, joins);
+            case JavaSQLTypes.CLOB:
+                return getClobInternal(obj, joins);
+            case JavaSQLTypes.SQL_DATE:
+                return getDateInternal(obj, (Calendar) arg, joins);
+            case JavaSQLTypes.SQL_OBJECT:
+                return getSQLObjectInternal(obj, (Map) arg, joins);
+            case JavaSQLTypes.REF:
+                return getRefInternal(obj, (Map) arg, joins);
+            case JavaSQLTypes.TIME:
+                return getTimeInternal(obj, (Calendar) arg, joins);
+            case JavaSQLTypes.TIMESTAMP:
+                return getTimestampInternal(obj, (Calendar) arg, joins);
+            default:
+                if (obj instanceof Column) {
+                    Column col = (Column) obj;
+                    if (col.getType() == Types.BLOB
+                        || col.getType() == Types.VARBINARY) {
+                        return _dict
+                            .getBlobObject(_rs, ((Number) obj).intValue(),
+                                _store);
+                    }
+                }
+                return _dict.getObject(_rs, ((Number) obj).intValue(), null);
+        }
+        return (_rs.wasNull()) ? null : val;
+    }
+
+    protected Object getSQLObjectInternal(Object obj, Map map, Joins joins)
+        throws SQLException {
+        return _dict.getObject(_rs, ((Number) obj).intValue(), map);
+    }
+
+    protected Ref getRefInternal(Object obj, Map map, Joins joins)
+        throws SQLException {
+        return _dict.getRef(_rs, ((Number) obj).intValue(), map);
+    }
+
+    protected short getShortInternal(Object obj, Joins joins)
+        throws SQLException {
+        return _dict.getShort(_rs, ((Number) obj).intValue());
+    }
+
+    protected String getStringInternal(Object obj, Joins joins)
+        throws SQLException {
+        if (obj instanceof Column && ((Column) obj).getType() == Types.CLOB)
+            return _dict.getClobString(_rs, ((Number) obj).intValue());
+        return _dict.getString(_rs, ((Number) obj).intValue());
+    }
+
+    protected Time getTimeInternal(Object obj, Calendar cal, Joins joins)
+        throws SQLException {
+        return _dict.getTime(_rs, ((Number) obj).intValue(), cal);
+    }
+
+    protected Timestamp getTimestampInternal(Object obj, Calendar cal,
+        Joins joins)
+        throws SQLException {
+        return _dict.getTimestamp(_rs, ((Number) obj).intValue(), cal);
+    }
+
+    public boolean wasNull()
+        throws SQLException {
+        return _rs.wasNull();
+    }
+
+    protected Object translate(Object obj, Joins joins)
+        throws SQLException {
+        if (obj instanceof Number)
+            return obj;
+        return Numbers.valueOf(findObject(obj, joins));
+    }
+
+    /**
+     * Return the 1-based result set index for the given column or id, or a
+     * non-positive number if the column is not contained in this result.
+     */
+    protected int findObject(Object obj, Joins joins)
+        throws SQLException {
+        try {
+            return getResultSet().findColumn(obj.toString());
+        } catch (SQLException se) {
+            return 0;
+        }
+    }
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Row.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Row.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Row.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/Row.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,520 @@
+/*
+ * 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.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+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;
+
+/**
+ * Logical representation of a table row for insert/update/delete. The
+ * {@link org.apache.openjpa.jdbc.kernel.UpdateManager} is responsible for implementing
+ * rows to do something useful when the values are set.
+ *
+ * @author Abe White
+ */
+public interface Row {
+
+    /**
+     * Symbolic constant reserved for situations when a row operation
+     * is unknown.
+     */
+    public static final int ACTION_UNKNOWN = -1;
+
+    /**
+     * Mark the row for update.
+     */
+    public static final int ACTION_UPDATE = 0;
+
+    /**
+     * Mark the row for inserttion.
+     */
+    public static final int ACTION_INSERT = 1;
+
+    /**
+     * Mark the row for deletion.
+     */
+    public static final int ACTION_DELETE = 2;
+
+    /**
+     * Return the table for this row.
+     */
+    public Table getTable();
+
+    /**
+     * Return the action for this row.
+     */
+    public int getAction();
+
+    /**
+     * Return the failed object to include in optimistic lock exceptions.
+     */
+    public Object getFailedObject();
+
+    /**
+     * Set the failed object to include in the optimistic lock exception
+     * that will be thrown if this update results in an update count of 0
+     * when executed. Leave null to avoid checking the update count.
+     */
+    public void setFailedObject(Object failed);
+
+    /**
+     * Whether this row has information set on it.
+     */
+    public boolean isValid();
+
+    /**
+     * Whether this row has information set on it.
+     */
+    public void setValid(boolean valid);
+
+    /**
+     * Return the instance that controls this row. The
+     * {@link #setPrimaryKey} method does not necessarily have to be called
+     * to know the owning instance, nor does this row's table have to have
+     * an actual primary key.
+     */
+    public OpenJPAStateManager getPrimaryKey();
+
+    /**
+     * Set the primary key to represent the given object.
+     */
+    public void setPrimaryKey(OpenJPAStateManager sm)
+        throws SQLException;
+
+    /**
+     * Set the primary key to represent the given object.
+     *
+     * @param io information on which columns are settable; may be null
+     */
+    public void setPrimaryKey(ColumnIO io, OpenJPAStateManager sm)
+        throws SQLException;
+
+    /**
+     * Set the primary key equality criteria for this row.
+     */
+    public void wherePrimaryKey(OpenJPAStateManager sm)
+        throws SQLException;
+
+    /**
+     * Set the value of the given foreign key to the given object.
+     * If the related type uses table-per-class mappings, the foreign key may
+     * be targeted at an independent superclass table.
+     */
+    public void setForeignKey(ForeignKey fk, OpenJPAStateManager sm)
+        throws SQLException;
+
+    /**
+     * Set the value of the given foreign key to the given object.
+     * If the related type uses table-per-class mappings, the foreign key may
+     * be targeted at an independent superclass table.
+     *
+     * @param io information on which columns are settable; may be null
+     */
+    public void setForeignKey(ForeignKey fk, ColumnIO io,
+        OpenJPAStateManager sm)
+        throws SQLException;
+
+    /**
+     * Set the foreign key equality criteria to link to the given object.
+     * If the related type uses table-per-class mappings, the foreign key may
+     * be targeted at an independent superclass table.
+     */
+    public void whereForeignKey(ForeignKey fk, OpenJPAStateManager sm)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setArray(Column col, Array val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setAsciiStream(Column col, InputStream val, int length)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setBigDecimal(Column col, BigDecimal val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setBigInteger(Column col, BigInteger val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setBinaryStream(Column col, InputStream val, int length)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setBlob(Column col, Blob val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setBoolean(Column col, boolean val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setByte(Column col, byte val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setBytes(Column col, byte[] val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setCalendar(Column col, Calendar val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setChar(Column col, char val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setCharacterStream(Column col, Reader val, int length)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setClob(Column col, Clob val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setDate(Column col, Date val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setDate(Column col, java.sql.Date val, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setDouble(Column col, double val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setFloat(Column col, float val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setInt(Column col, int val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setLong(Column col, long val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setLocale(Column col, Locale val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setNull(Column col)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     *
+     * @param overrideDefault whether to set this column to null even if this
+     * is an insert and the column has a default
+     */
+    public void setNull(Column col, boolean overrideDefault)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setNumber(Column col, Number val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     *
+     * @param col the column being set
+     * @param val the value for the column
+     */
+    public void setObject(Column col, Object val)
+        throws SQLException;
+
+    /**
+     * Set a DB understood value for the given column.
+     * The value will not be parameterized and instead be inserted as raw SQL.
+     */
+    public void setRaw(Column col, String value)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column to the identity of given instance,
+     * using the given callback to create the column value. This method is
+     * used for mappings that store some serialized form of id values, but must
+     * make sure that the related object's id is assigned (which might
+     * require an insert if the instance uses auto-increment) before it is
+     * serialized.
+     */
+    public void setRelationId(Column col, OpenJPAStateManager sm,
+        RelationId rel)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setShort(Column col, short val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setString(Column col, String val)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setTime(Column col, Time val, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Set the value of the given column in this row.
+     */
+    public void setTimestamp(Column col, Timestamp val, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereArray(Column col, Array val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereAsciiStream(Column col, InputStream val, int length)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereBigDecimal(Column col, BigDecimal val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereBigInteger(Column col, BigInteger val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereBinaryStream(Column col, InputStream val, int length)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereBlob(Column col, Blob val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereBoolean(Column col, boolean val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereByte(Column col, byte val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereBytes(Column col, byte[] val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereCalendar(Column col, Calendar val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereChar(Column col, char val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereCharacterStream(Column col, Reader val, int length)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereClob(Column col, Clob val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereDate(Column col, Date val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereDate(Column col, java.sql.Date val, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereDouble(Column col, double val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereFloat(Column col, float val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereInt(Column col, int val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereLong(Column col, long val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereLocale(Column col, Locale val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereNull(Column col)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereNumber(Column col, Number val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     *
+     * @param col the column being set
+     * @param val the value for the column
+     */
+    public void whereObject(Column col, Object val)
+        throws SQLException;
+
+    /**
+     * Set a DB understood where condition for the given column.
+     * The value will not be parameterized and instead be inserted as raw SQL.
+     */
+    public void whereRaw(Column col, String value)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereShort(Column col, short val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereString(Column col, String val)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereTime(Column col, Time val, Calendar cal)
+        throws SQLException;
+
+    /**
+     * Set an equality condition on the value of the given column in this row.
+     */
+    public void whereTimestamp(Column col, Timestamp val, Calendar cal)
+        throws SQLException;
+}

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowImpl.java Wed Jul 19 14:34:44 2006
@@ -0,0 +1,941 @@
+/*
+ * 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.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.Date;
+import java.util.Locale;
+
+import org.apache.openjpa.jdbc.kernel.JDBCStore;
+import org.apache.openjpa.jdbc.meta.ClassMapping;
+import org.apache.openjpa.jdbc.meta.JavaSQLTypes;
+import org.apache.openjpa.jdbc.meta.Joinable;
+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;
+import org.apache.openjpa.meta.JavaTypes;
+import org.apache.openjpa.util.InternalException;
+import serp.util.Numbers;
+
+/**
+ * Basic {@link Row} implementation.
+ *
+ * @author Abe White
+ * @nojavadoc
+ */
+public class RowImpl
+    implements Row, Cloneable {
+
+    protected static final Object NULL = new Object();
+    protected static final int VALID = 2 << 0;
+
+    private static final int RAW = Integer.MIN_VALUE;
+
+    protected byte flags = 0;
+    private final Table _table;
+    private final int _action;
+    private final Object[] _vals;
+    private final int[] _types;
+
+    private String _sql = null;
+
+    /**
+     * Constructor.
+     *
+     * @param table the table the row is a part of
+     * @param action the action on the row
+     */
+    public RowImpl(Table table, int action) {
+        _table = table;
+        _action = action;
+
+        // we need room for values and types for all columns; if an update or
+        // delete, then we need to double that for where column conditions
+        int len = table.getColumns().length;
+        if (action != ACTION_INSERT)
+            len *= 2;
+        _vals = new Object[len];
+        _types = new int[len];
+    }
+
+    public Table getTable() {
+        return _table;
+    }
+
+    public int getAction() {
+        return _action;
+    }
+
+    public boolean isValid() {
+        return (flags & VALID) != 0;
+    }
+
+    public void setValid(boolean valid) {
+        if (valid)
+            flags |= VALID;
+        else
+            flags &= ~VALID;
+    }
+
+    /**
+     * This implementation does not track primary keys.
+     */
+    public OpenJPAStateManager getPrimaryKey() {
+        return null;
+    }
+
+    /**
+     * This implementation does not track failed objects.
+     */
+    public Object getFailedObject() {
+        return null;
+    }
+
+    /**
+     * This implementation does not track failed objects.
+     */
+    public void setFailedObject(Object failed) {
+        throw new InternalException();
+    }
+
+    /**
+     * Secondary rows cannot be dependent.
+     */
+    public boolean isDependent() {
+        return false;
+    }
+
+    /**
+     * Return the value set for update on the given column.
+     */
+    public Object getSet(Column col) {
+        return _vals[getSetIndex(col)];
+    }
+
+    /**
+     * Return the value set for where on the given column.
+     */
+    public Object getWhere(Column col) {
+        return _vals[getWhereIndex(col)];
+    }
+
+    public void setPrimaryKey(OpenJPAStateManager sm)
+        throws SQLException {
+        setPrimaryKey(null, sm);
+    }
+
+    public void setPrimaryKey(ColumnIO io, OpenJPAStateManager sm)
+        throws SQLException {
+        flushPrimaryKey(sm, io, true);
+    }
+
+    public void wherePrimaryKey(OpenJPAStateManager sm)
+        throws SQLException {
+        flushPrimaryKey(sm, null, false);
+    }
+
+    /**
+     * Flush the primary key values.
+     */
+    private void flushPrimaryKey(OpenJPAStateManager sm, ColumnIO io,
+        boolean set)
+        throws SQLException {
+        ClassMapping mapping = (ClassMapping) sm.getMetaData();
+        while (mapping.getTable() != _table)
+            mapping = mapping.getPCSuperclassMapping();
+        Column[] cols = mapping.getPrimaryKeyColumns();
+        flushJoinValues(sm, cols, cols, io, set);
+    }
+
+    public void setForeignKey(ForeignKey fk, OpenJPAStateManager sm)
+        throws SQLException {
+        setForeignKey(fk, null, sm);
+    }
+
+    public void setForeignKey(ForeignKey fk, ColumnIO io,
+        OpenJPAStateManager sm)
+        throws SQLException {
+        flushForeignKey(fk, io, sm, true);
+    }
+
+    public void whereForeignKey(ForeignKey fk, OpenJPAStateManager sm)
+        throws SQLException {
+        flushForeignKey(fk, null, sm, false);
+    }
+
+    /**
+     * Clear a circular foreign key.
+     */
+    public void clearForeignKey(ForeignKey fk)
+        throws SQLException {
+        _sql = null;
+        Column[] cols = fk.getColumns();
+        for (int i = 0; i < cols.length; i++)
+            _vals[getSetIndex(cols[i])] = null;
+    }
+
+    /**
+     * Flush the foreign key values.
+     */
+    private void flushForeignKey(ForeignKey fk, ColumnIO io,
+        OpenJPAStateManager sm, boolean set)
+        throws SQLException {
+        flushJoinValues(sm, fk.getPrimaryKeyColumns(), fk.getColumns(),
+            io, set);
+        if (sm != null) {
+            Column[] cols = fk.getConstantColumns();
+            int len = fk.getColumns().length;
+            Object obj;
+            int type;
+            for (int i = 0; i < cols.length; i++) {
+                obj = fk.getConstant(cols[i]);
+                type = cols[i].getJavaType();
+                if (set && canSet(io, i + len, obj == null))
+                    setObject(cols[i], obj, type, false);
+                else if (!set)
+                    whereObject(cols[i], obj, type);
+            }
+        }
+    }
+
+    /**
+     * Flush the given instance value to the given columns. Note that
+     * foreign keys may include columns also mapped by simple values. We
+     * use a priority mechanism to ensure that we do not let the nulling
+     * of a foreign key null columns also owned by simple values.
+     *
+     * @param to the instance being joined to
+     * @param toCols the columns being joined to
+     * @param fromCols the columns being joined from
+     * @param io information about I/O capabilities in this context
+     * @param set whether this should be flushed as an update or
+     * as a where condition
+     */
+    private void flushJoinValues(OpenJPAStateManager to, Column[] toCols,
+        Column[] fromCols, ColumnIO io, boolean set)
+        throws SQLException {
+        if (to == null) {
+            for (int i = 0; i < fromCols.length; i++) {
+                if (set && canSet(io, i, true))
+                    setNull(fromCols[i]);
+                else if (!set)
+                    whereNull(fromCols[i]);
+            }
+            return;
+        }
+        if (set && !canSetAny(io, fromCols.length, false))
+            return;
+
+        ClassMapping toMapping = (ClassMapping) to.getMetaData();
+        Joinable join;
+        Object val;
+        for (int i = 0; i < toCols.length; i++) {
+            // don't even translate join value if unsettable
+            if (set) {
+                if (_action == ACTION_INSERT && fromCols[i].isAutoAssigned())
+                    continue;
+                if (!canSet(io, i, false))
+                    continue;
+            }
+
+            join = toMapping.assertJoinable(toCols[i]);
+            val = join.getJoinValue(to, toCols[i], (JDBCStore) to.
+                getContext().getStoreManager().getInnermostDelegate());
+            if (set && val == null) {
+                if (canSet(io, i, true))
+                    setNull(fromCols[i]);
+            } else if (set && val instanceof Raw)
+                setRaw(fromCols[i], val.toString());
+            else if (set)
+                setObject(fromCols[i], val, toCols[i].getJavaType(), false);
+            else if (val == null)
+                whereNull(fromCols[i]);
+            else if (val instanceof Raw)
+                whereRaw(fromCols[i], val.toString());
+            else
+                whereObject(fromCols[i], val, toCols[i].getJavaType());
+        }
+    }
+
+    /**
+     * Return true if any of the given column indexes are settable.
+     */
+    protected boolean canSetAny(ColumnIO io, int i, boolean nullValue) {
+        if (io == null)
+            return true;
+        if (_action == ACTION_INSERT)
+            return io.isAnyInsertable(i, nullValue);
+        if (_action == ACTION_UPDATE)
+            return io.isAnyUpdatable(i, nullValue);
+        return true;
+    }
+
+    /**
+     * Return true if the given column index is settable.
+     */
+    protected boolean canSet(ColumnIO io, int i, boolean nullValue) {
+        if (io == null)
+            return true;
+        if (_action == ACTION_INSERT)
+            return io.isInsertable(i, nullValue);
+        if (_action == ACTION_UPDATE)
+            return io.isUpdatable(i, nullValue);
+        return true;
+    }
+
+    public void setRelationId(Column col, OpenJPAStateManager sm,
+        RelationId rel)
+        throws SQLException {
+        setObject(col, rel.toRelationDataStoreValue(sm, col),
+            col.getJavaType(), false);
+    }
+
+    /**
+     * Clear a circular relation id.
+     */
+    public void clearRelationId(Column col)
+        throws SQLException {
+        _sql = null;
+        _vals[getSetIndex(col)] = null;
+    }
+
+    public void setArray(Column col, Array val)
+        throws SQLException {
+        setObject(col, val, JavaSQLTypes.ARRAY, false);
+    }
+
+    public void setAsciiStream(Column col, InputStream val, int length)
+        throws SQLException {
+        setObject(col, (val == null) ? null : new Sized(val, length),
+            JavaSQLTypes.ASCII_STREAM, false);
+    }
+
+    public void setBigDecimal(Column col, BigDecimal val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.BIGDECIMAL, false);
+    }
+
+    public void setBigInteger(Column col, BigInteger val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.BIGINTEGER, false);
+    }
+
+    public void setBinaryStream(Column col, InputStream val, int length)
+        throws SQLException {
+        setObject(col, (val == null) ? null : new Sized(val, length),
+            JavaSQLTypes.BINARY_STREAM, false);
+    }
+
+    public void setBlob(Column col, Blob val)
+        throws SQLException {
+        setObject(col, val, JavaSQLTypes.BLOB, false);
+    }
+
+    public void setBoolean(Column col, boolean val)
+        throws SQLException {
+        setObject(col, ((val) ? Boolean.TRUE : Boolean.FALSE),
+            JavaTypes.BOOLEAN, false);
+    }
+
+    public void setByte(Column col, byte val)
+        throws SQLException {
+        setObject(col, new Byte(val), JavaTypes.BYTE, false);
+    }
+
+    public void setBytes(Column col, byte[] val)
+        throws SQLException {
+        setObject(col, val, JavaSQLTypes.BYTES, false);
+    }
+
+    public void setCalendar(Column col, Calendar val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.CALENDAR, false);
+    }
+
+    public void setChar(Column col, char val)
+        throws SQLException {
+        setObject(col, new Character(val), JavaTypes.CHAR, false);
+    }
+
+    public void setCharacterStream(Column col, Reader val, int length)
+        throws SQLException {
+        setObject(col, (val == null) ? null : new Sized(val, length),
+            JavaSQLTypes.CHAR_STREAM, false);
+    }
+
+    public void setClob(Column col, Clob val)
+        throws SQLException {
+        setObject(col, val, JavaSQLTypes.CLOB, false);
+    }
+
+    public void setDate(Column col, Date val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.DATE, false);
+    }
+
+    public void setDate(Column col, java.sql.Date val, Calendar cal)
+        throws SQLException {
+        Object obj;
+        if (val == null || cal == null)
+            obj = val;
+        else
+            obj = new Calendard(val, cal);
+        setObject(col, obj, JavaSQLTypes.SQL_DATE, false);
+    }
+
+    public void setDouble(Column col, double val)
+        throws SQLException {
+        setObject(col, new Double(val), JavaTypes.DOUBLE, false);
+    }
+
+    public void setFloat(Column col, float val)
+        throws SQLException {
+        setObject(col, new Float(val), JavaTypes.FLOAT, false);
+    }
+
+    public void setInt(Column col, int val)
+        throws SQLException {
+        setObject(col, Numbers.valueOf(val), JavaTypes.INT, false);
+    }
+
+    public void setLong(Column col, long val)
+        throws SQLException {
+        setObject(col, Numbers.valueOf(val), JavaTypes.LONG, false);
+    }
+
+    public void setLocale(Column col, Locale val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.LOCALE, false);
+    }
+
+    public void setNull(Column col)
+        throws SQLException {
+        setNull(col, false);
+    }
+
+    public void setNull(Column col, boolean overrideDefault)
+        throws SQLException {
+        setObject(col, null, col.getJavaType(), overrideDefault);
+    }
+
+    public void setNumber(Column col, Number val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.NUMBER, false);
+    }
+
+    public void setRaw(Column col, String val)
+        throws SQLException {
+        setObject(col, val, RAW, false);
+    }
+
+    public void setShort(Column col, short val)
+        throws SQLException {
+        setObject(col, new Short(val), JavaTypes.SHORT, false);
+    }
+
+    public void setString(Column col, String val)
+        throws SQLException {
+        setObject(col, val, JavaTypes.STRING, false);
+    }
+
+    public void setTime(Column col, Time val, Calendar cal)
+        throws SQLException {
+        Object obj;
+        if (val == null || cal == null)
+            obj = val;
+        else
+            obj = new Calendard(val, cal);
+        setObject(col, obj, JavaSQLTypes.TIME, false);
+    }
+
+    public void setTimestamp(Column col, Timestamp val, Calendar cal)
+        throws SQLException {
+        Object obj;
+        if (val == null || cal == null)
+            obj = val;
+        else
+            obj = new Calendard(val, cal);
+        setObject(col, obj, JavaSQLTypes.TIMESTAMP, false);
+    }
+
+    public void setObject(Column col, Object val)
+        throws SQLException {
+        if (val instanceof Raw)
+            setObject(col, val, RAW, false);
+        else
+            setObject(col, val, col.getJavaType(), false);
+    }
+
+    public void whereArray(Column col, Array val)
+        throws SQLException {
+        whereObject(col, val, JavaSQLTypes.SQL_ARRAY);
+    }
+
+    public void whereAsciiStream(Column col, InputStream val, int length)
+        throws SQLException {
+        whereObject(col, (val == null) ? null : new Sized(val, length),
+            JavaSQLTypes.ASCII_STREAM);
+    }
+
+    public void whereBigDecimal(Column col, BigDecimal val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.BIGDECIMAL);
+    }
+
+    public void whereBigInteger(Column col, BigInteger val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.BIGINTEGER);
+    }
+
+    public void whereBinaryStream(Column col, InputStream val, int length)
+        throws SQLException {
+        whereObject(col, (val == null) ? null : new Sized(val, length),
+            JavaSQLTypes.BINARY_STREAM);
+    }
+
+    public void whereBlob(Column col, Blob val)
+        throws SQLException {
+        whereObject(col, val, JavaSQLTypes.BLOB);
+    }
+
+    public void whereBoolean(Column col, boolean val)
+        throws SQLException {
+        whereObject(col, ((val) ? Boolean.TRUE : Boolean.FALSE),
+            JavaTypes.BOOLEAN);
+    }
+
+    public void whereByte(Column col, byte val)
+        throws SQLException {
+        whereObject(col, new Byte(val), JavaTypes.BYTE);
+    }
+
+    public void whereBytes(Column col, byte[] val)
+        throws SQLException {
+        whereObject(col, val, JavaSQLTypes.BYTES);
+    }
+
+    public void whereCalendar(Column col, Calendar val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.CALENDAR);
+    }
+
+    public void whereChar(Column col, char val)
+        throws SQLException {
+        whereObject(col, new Character(val), JavaTypes.CHAR);
+    }
+
+    public void whereCharacterStream(Column col, Reader val, int length)
+        throws SQLException {
+        whereObject(col, (val == null) ? null : new Sized(val, length),
+            JavaSQLTypes.CHAR_STREAM);
+    }
+
+    public void whereClob(Column col, Clob val)
+        throws SQLException {
+        whereObject(col, val, JavaSQLTypes.CLOB);
+    }
+
+    public void whereDate(Column col, Date val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.DATE);
+    }
+
+    public void whereDate(Column col, java.sql.Date val, Calendar cal)
+        throws SQLException {
+        Object obj;
+        if (val == null || cal == null)
+            obj = val;
+        else
+            obj = new Calendard(val, cal);
+        whereObject(col, obj, JavaSQLTypes.SQL_DATE);
+    }
+
+    public void whereDouble(Column col, double val)
+        throws SQLException {
+        whereObject(col, new Double(val), JavaTypes.DOUBLE);
+    }
+
+    public void whereFloat(Column col, float val)
+        throws SQLException {
+        whereObject(col, new Float(val), JavaTypes.FLOAT);
+    }
+
+    public void whereInt(Column col, int val)
+        throws SQLException {
+        whereObject(col, Numbers.valueOf(val), JavaTypes.INT);
+    }
+
+    public void whereLong(Column col, long val)
+        throws SQLException {
+        whereObject(col, Numbers.valueOf(val), JavaTypes.LONG);
+    }
+
+    public void whereLocale(Column col, Locale val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.LOCALE);
+    }
+
+    public void whereNull(Column col)
+        throws SQLException {
+        whereObject(col, null, col.getJavaType());
+    }
+
+    public void whereNumber(Column col, Number val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.NUMBER);
+    }
+
+    public void whereRaw(Column col, String val)
+        throws SQLException {
+        whereObject(col, val, RAW);
+    }
+
+    public void whereShort(Column col, short val)
+        throws SQLException {
+        whereObject(col, new Short(val), JavaTypes.SHORT);
+    }
+
+    public void whereString(Column col, String val)
+        throws SQLException {
+        whereObject(col, val, JavaTypes.STRING);
+    }
+
+    public void whereTime(Column col, Time val, Calendar cal)
+        throws SQLException {
+        Object obj;
+        if (val == null || cal == null)
+            obj = val;
+        else
+            obj = new Calendard(val, cal);
+        whereObject(col, obj, JavaSQLTypes.TIME);
+    }
+
+    public void whereTimestamp(Column col, Timestamp val, Calendar cal)
+        throws SQLException {
+        Object obj;
+        if (val == null || cal == null)
+            obj = val;
+        else
+            obj = new Calendard(val, cal);
+        whereObject(col, obj, JavaSQLTypes.TIMESTAMP);
+    }
+
+    public void whereObject(Column col, Object val)
+        throws SQLException {
+        if (val instanceof Raw)
+            whereObject(col, val, RAW);
+        else
+            whereObject(col, val, col.getJavaType());
+    }
+
+    /**
+     * All set column methods delegate to this one. Set the given object
+     * unless this is an insert and the given column is auto-assigned.
+     */
+    protected void setObject(Column col, Object val, int metaType,
+        boolean overrideDefault)
+        throws SQLException {
+        // never set auto increment columns and honor column defaults
+        if (_action == ACTION_INSERT) {
+            if (col.isAutoAssigned())
+                return;
+            if (!overrideDefault && col.getDefaultString() != null)
+                return;
+        }
+        if (val == null && col.isNotNull())
+            val = JavaSQLTypes.getEmptyValue(col.getJavaType());
+        flush(col, val, metaType, true);
+    }
+
+    /**
+     * All where column methods delegate to this one.
+     */
+    protected void whereObject(Column col, Object val, int metaType)
+        throws SQLException {
+        flush(col, val, metaType, false);
+    }
+
+    /**
+     * Flush the given value as a set or where condition.
+     */
+    private void flush(Column col, Object val, int metaType, boolean set) {
+        int idx = (set) ? getSetIndex(col) : getWhereIndex(col);
+        _types[idx] = metaType;
+        if (val == null)
+            _vals[idx] = NULL;
+        else
+            _vals[idx] = val;
+        if (set || _action == ACTION_DELETE)
+            setValid(true);
+    }
+
+    /**
+     * Return the SQL for the operation on this row.
+     */
+    public String getSQL(DBDictionary dict) {
+        if (!isValid())
+            return "";
+        if (_sql == null)
+            _sql = generateSQL(dict);
+        return _sql;
+    }
+
+    /**
+     * Generate the SQL for this row; the result of this method is cached.
+     */
+    protected String generateSQL(DBDictionary dict) {
+        switch (getAction()) {
+            case ACTION_UPDATE:
+                return getUpdateSQL(dict);
+            case ACTION_INSERT:
+                return getInsertSQL(dict);
+            default:
+                return getDeleteSQL(dict);
+        }
+    }
+
+    /**
+     * Return the SQL for a prepared statement update on this row.
+     */
+    private String getUpdateSQL(DBDictionary dict) {
+        StringBuffer buf = new StringBuffer();
+        buf.append("UPDATE ").append(dict.getFullName(getTable(), false)).
+            append(" SET ");
+
+        Column[] cols = getTable().getColumns();
+        boolean hasVal = false;
+        for (int i = 0; i < cols.length; i++) {
+            if (_vals[i] == null)
+                continue;
+
+            if (hasVal)
+                buf.append(", ");
+            buf.append(cols[i]);
+            if (_types[i] == RAW)
+                buf.append(" = ").append(_vals[i]);
+            else
+                buf.append(" = ?");
+            hasVal = true;
+        }
+
+        appendWhere(buf);
+        return buf.toString();
+    }
+
+    /**
+     * Return the SQL for a prepared statement insert on this row.
+     */
+    private String getInsertSQL(DBDictionary dict) {
+        StringBuffer buf = new StringBuffer();
+        StringBuffer vals = new StringBuffer();
+        buf.append("INSERT INTO ").
+            append(dict.getFullName(getTable(), false)).append(" (");
+
+        Column[] cols = getTable().getColumns();
+        boolean hasVal = false;
+        for (int i = 0; i < cols.length; i++) {
+            if (_vals[i] == null)
+                continue;
+
+            if (hasVal) {
+                buf.append(", ");
+                vals.append(", ");
+            }
+            buf.append(cols[i]);
+            if (_types[i] == RAW)
+                vals.append(_vals[i]);
+            else
+                vals.append("?");
+            hasVal = true;
+        }
+
+        buf.append(") VALUES (").append(vals.toString()).append(")");
+        return buf.toString();
+    }
+
+    /**
+     * Return the SQL for a prepared statement delete on this row.
+     */
+    private String getDeleteSQL(DBDictionary dict) {
+        StringBuffer buf = new StringBuffer();
+        buf.append("DELETE FROM ").
+            append(dict.getFullName(getTable(), false));
+        appendWhere(buf);
+        return buf.toString();
+    }
+
+    /**
+     * Appends the where clause onto the given sql buffer.
+     */
+    private void appendWhere(StringBuffer buf) {
+        Column[] cols = getTable().getColumns();
+        boolean hasWhere = false;
+        for (int i = 0; i < cols.length; i++) {
+            if (_vals[getWhereIndex(cols[i])] == null)
+                continue;
+
+            if (!hasWhere)
+                buf.append(" WHERE ");
+            else
+                buf.append(" AND ");
+
+            // sqlserver seems to have problems using null parameters in the
+            // where clause
+            if (_vals[getWhereIndex(cols[i])] == NULL)
+                buf.append(cols[i]).append(" IS NULL");
+            else if (_types[i] == RAW)
+                buf.append(cols[i]).append(" = ").append(_vals[i]);
+            else
+                buf.append(cols[i]).append(" = ?");
+            hasWhere = true;
+        }
+    }
+
+    /**
+     * The number of parameters that will be set for this row.
+     */
+    public int getParameterCount() {
+        return _vals.length;
+    }
+
+    /**
+     * Flush the row's values to the given prepared statement.
+     */
+    public void flush(PreparedStatement stmnt, DBDictionary dict,
+        JDBCStore store)
+        throws SQLException {
+        flush(stmnt, 1, dict, store);
+    }
+
+    /**
+     * Flush the row's values to the given prepared statement.
+     */
+    public void flush(PreparedStatement stmnt, int idx, DBDictionary dict,
+        JDBCStore store)
+        throws SQLException {
+        Column[] cols = getTable().getColumns();
+
+        // this simple method works because the SQL is always prepared
+        // based on the indexing of the columns in the table object -- the
+        // same ordering we use when storing values and meta types. skip
+        // updates when setting params for DELETEs; the updates are just there
+        // to let us eval fk constraints
+        int i = (getAction() == ACTION_DELETE) ? cols.length : 0;
+        Column col;
+        Object val;
+        int half = _vals.length / 2;
+        for (; i < _vals.length; i++) {
+            if (_vals[i] == null)
+                continue;
+
+            // we don't set null params in the WHERE clause; we use the NULL
+            // keyword instead to satisfy sqlserver
+            if (_vals[i] == NULL && getAction() != ACTION_INSERT && i >= half)
+                continue;
+
+            // if this is an update the vals array will be 2 x the cols
+            // array length; it repeats for where values
+            if (i < cols.length)
+                col = cols[i];
+            else
+                col = cols[i - cols.length];
+
+            val = _vals[i];
+            if (val == NULL)
+                val = null;
+
+            if (val == null || _types[i] != RAW) {
+                dict.setTyped(stmnt, idx, val, col, _types[i], store);
+                idx++;
+            }
+        }
+    }
+
+    /**
+     * The array value array index for the given column's value.
+     */
+    private int getSetIndex(Column col) {
+        return col.getIndex();
+    }
+
+    /**
+     * The array value array index for the given column's value.
+     */
+    private int getWhereIndex(Column col) {
+        return col.getIndex() + getTable().getColumns().length;
+    }
+
+    /**
+     * Performs a proper deep clone.
+     */
+    public Object clone() {
+        RowImpl clone = newInstance(getTable(), getAction());
+        copyInto(clone, false);
+        return clone;
+    }
+
+    /**
+     * Return a new row.
+     */
+    protected RowImpl newInstance(Table table, int action) {
+        return new RowImpl(table, action);
+    }
+
+    /**
+     * Copy all values from this row into the given one.
+     *
+     * @param whereOnly if true, only copy where conditions
+     */
+    public void copyInto(RowImpl row, boolean whereOnly) {
+        int action = getAction();
+        int rowAction = row.getAction();
+
+        int start;
+        int len;
+        if (whereOnly) {
+            if (action == ACTION_INSERT || rowAction == ACTION_INSERT)
+                start = len = 0;
+            else
+                start = len = _vals.length / 2;
+        } else {
+            start = 0;
+            if (rowAction == ACTION_INSERT && action != ACTION_INSERT)
+                len = _vals.length / 2;
+            else
+                len = _vals.length;
+        }
+
+        System.arraycopy(_vals, start, row._vals, start, len);
+        System.arraycopy(_types, start, row._types, start, len);
+        if (isValid())
+            row.setValid(true);
+    }
+}
+

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

Added: incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManager.java
URL: http://svn.apache.org/viewvc/incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManager.java?rev=423615&view=auto
==============================================================================
--- incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManager.java (added)
+++ incubator/openjpa/trunk/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/RowManager.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 java.sql.SQLException;
+
+import org.apache.openjpa.jdbc.schema.Table;
+import org.apache.openjpa.kernel.OpenJPAStateManager;
+
+/**
+ * Manages rows during an insert/update/delete process. Row managers
+ * do not have to be threadsafe.
+ *
+ * @author Abe White
+ */
+public interface RowManager {
+
+    /**
+     * Return the row for the given table and owner object, or null if
+     * <code>create</code> is false and the row has not already been created.
+     * The action must be one of {@link Row#ACTION_INSERT},
+     * {@link Row#ACTION_UPDATE}, {@link Row#ACTION_DELETE}.
+     */
+    public Row getRow(Table table, int action, OpenJPAStateManager sm,
+        boolean create);
+
+    /**
+     * Return a row for the given secondary table.
+     * The action must be one of {@link Row#ACTION_INSERT},
+     * {@link Row#ACTION_UPDATE}, {@link Row#ACTION_DELETE}.
+     * Note that secondary rows are not considered when creating the foreign
+     * key dependency graph, with can cause constraint violations when using
+     * the <code>UPDATE</code> action. Only use this action if the secondary
+     * row does not have restrict-action foreign keys. Otherwise use both
+     * a delete and then an insert to perform the update.
+     */
+    public Row getSecondaryRow(Table table, int action);
+
+    /**
+     * Flush the secondary row; after flushing the row is available for reuse.
+     * It will retain all previously set values.
+     */
+    public void flushSecondaryRow(Row row)
+        throws SQLException;
+
+    /**
+     * Return a logical row representing an update that should be made to
+     * all rows of the given table. The action must be one of
+     * {@link Row#ACTION_UPDATE}, {@link Row#ACTION_DELETE}.
+     */
+    public Row getAllRows(Table table, int action);
+
+    /**
+     * Flush the logical row.
+     */
+    public void flushAllRows(Row row)
+        throws SQLException;
+}

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