db-ddlutils-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From to...@apache.org
Subject svn commit: r360485 - in /db/ddlutils/trunk/src/java/org/apache/ddlutils: dynabean/DynaSqlIterator.java platform/ModelBasedResultSetIterator.java platform/PlatformImplBase.java
Date Sun, 01 Jan 2006 14:43:13 GMT
Author: tomdz
Date: Sun Jan  1 06:43:05 2006
New Revision: 360485

URL: http://svn.apache.org/viewcvs?rev=360485&view=rev
Log:
Renamed and moved resultset iterator
Moved method that extracts values from a resultset to the platform to make it easier to customize
it for specific databases

Added:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/ModelBasedResultSetIterator.java
Removed:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/dynabean/DynaSqlIterator.java
Modified:
    db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java

Added: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/ModelBasedResultSetIterator.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/ModelBasedResultSetIterator.java?rev=360485&view=auto
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/ModelBasedResultSetIterator.java
(added)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/ModelBasedResultSetIterator.java
Sun Jan  1 06:43:05 2006
@@ -0,0 +1,353 @@
+package org.apache.ddlutils.platform;
+
+/*
+ * Copyright 1999-2005 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.
+ */
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.NoSuchElementException;
+
+import org.apache.commons.beanutils.BasicDynaBean;
+import org.apache.commons.beanutils.BasicDynaClass;
+import org.apache.commons.beanutils.DynaBean;
+import org.apache.commons.beanutils.DynaClass;
+import org.apache.commons.beanutils.DynaProperty;
+import org.apache.commons.collections.map.ListOrderedMap;
+import org.apache.ddlutils.DynaSqlException;
+import org.apache.ddlutils.dynabean.SqlDynaBean;
+import org.apache.ddlutils.dynabean.SqlDynaClass;
+import org.apache.ddlutils.model.Column;
+import org.apache.ddlutils.model.Database;
+import org.apache.ddlutils.model.Table;
+
+/**
+ * This is an iterator that is specifically targeted at traversing result sets.
+ * If the query is against a known table, then {@link org.apache.ddlutils.dynabean.SqlDynaBean}
instances
+ * are created from the rows, otherwise normal {@link org.apache.commons.beanutils.DynaBean}
instances
+ * are created.
+ * 
+ * @author Thomas Dudziak
+ * @version $Revision: 289996 $
+ */
+public class ModelBasedResultSetIterator implements Iterator
+{
+    /** The platform. */
+    private PlatformImplBase _platform;
+    /** The base result set. */
+    private ResultSet _resultSet;
+    /** The dyna class to use for creating beans. */
+    private DynaClass _dynaClass;
+    /** Maps column names to properties. */
+    private Map _columnsToProperties = new ListOrderedMap();
+    /** Whether the next call to hasNext or next needs advancement. */
+    private boolean _needsAdvancing = true;
+    /** Whether we're already at the end of the result set. */
+    private boolean _isAtEnd = false;
+    /** Whether to close the statement and connection after finishing. */
+    private boolean _cleanUpAfterFinish;
+
+    /**
+     * Creates a new iterator.
+     * 
+     * @param platform           The platform
+     * @param model              The database model
+     * @param resultSet          The result set
+     * @param queryHints         The tables that were queried in the query that produced
the given result set
+     *                           (optional)
+     * @param cleanUpAfterFinish Whether to close the statement and connection after finishing
+     *                           the iteration, upon on exception, or when this iterator
is garbage collected
+     */
+    public ModelBasedResultSetIterator(PlatformImplBase platform, Database model, ResultSet
resultSet, Table[] queryHints, boolean cleanUpAfterFinish) throws DynaSqlException
+    {
+        if (resultSet != null)
+        {
+            _platform           = platform;
+            _resultSet          = resultSet;
+            _cleanUpAfterFinish = cleanUpAfterFinish;
+
+            try
+            {
+                initFromMetaData(model, queryHints);
+            }
+            catch (SQLException ex)
+            {
+                cleanUp();
+                throw new DynaSqlException("Could not read the metadata of the result set",
ex);
+            }
+        }
+        else
+        {
+            _isAtEnd = true;
+        }
+    }
+
+    /**
+     * Initializes this iterator from the resultset metadata.
+     * 
+     * @param model      The database model
+     * @param queryHints The tables that were queried in the query that produced the given
result set
+     */
+    private void initFromMetaData(Database model, Table[] queryHints) throws SQLException
+    {
+        ResultSetMetaData metaData           = _resultSet.getMetaData();
+        String            tableName          = null;
+        boolean           singleKnownTable   = true;
+        boolean           caseSensitive      = _platform.getPlatformInfo().isUseDelimitedIdentifiers();
+        Map               preparedQueryHints = prepareQueryHints(queryHints, caseSensitive);
+
+        for (int idx = 1; idx <= metaData.getColumnCount(); idx++)
+        {
+            String columnName    = metaData.getColumnName(idx);
+            String tableOfColumn = metaData.getTableName(idx);
+            Table  table         = null;
+
+            if ((tableOfColumn != null) && (tableOfColumn.length() > 0))
+            {
+                // the JDBC driver gave us enough meta data info
+                table = model.findTable(tableOfColumn, caseSensitive);
+            }
+            else
+            {
+                // not enough info in the meta data of the result set, lets try the
+                // user-supplied query hints
+                table         = (Table)preparedQueryHints.get(caseSensitive ? columnName
: columnName.toLowerCase());
+                tableOfColumn = (table == null ? null : table.getName());
+            }
+            if (tableName == null)
+            {
+                tableName = tableOfColumn;
+            }
+            else if (!tableName.equals(tableOfColumn))
+            {
+                singleKnownTable = false;
+            }
+
+            String propName = columnName;
+
+            if (table != null)
+            {
+                Column column = table.findColumn(columnName, caseSensitive);
+
+                if (column != null)
+                {
+                    propName = column.getName();
+                }
+            }
+            _columnsToProperties.put(columnName, propName);
+        }
+        if (singleKnownTable && (tableName != null))
+        {
+            _dynaClass = model.getDynaClassFor(tableName);
+        }
+        else
+        {
+            DynaProperty[] props = new DynaProperty[_columnsToProperties.size()];
+            int            idx   = 0;
+
+            for (Iterator it = _columnsToProperties.values().iterator(); it.hasNext(); idx++)
+            {
+                props[idx] = new DynaProperty((String)it.next());
+            }
+            _dynaClass = new BasicDynaClass("result", BasicDynaBean.class, props);
+        }
+    }
+
+    /**
+     * Prepares the query hints by extracting the column names and using them as keys
+     * into the resulting map pointing to the corresponding table.
+     *  
+     * @param queryHints    The query hints
+     * @param caseSensitive Whether the case of the column names is important
+     * @return The column name -> table map
+     */
+    private Map prepareQueryHints(Table[] queryHints, boolean caseSensitive)
+    {
+        Map result = new HashMap();
+
+        for (int tableIdx = 0; (queryHints != null) && (tableIdx < queryHints.length);
tableIdx++)
+        {
+            for (int columnIdx = 0; columnIdx < queryHints[tableIdx].getColumnCount();
columnIdx++)
+            {
+                String columnName = queryHints[tableIdx].getColumn(columnIdx).getName();
+
+                if (!caseSensitive)
+                {
+                    columnName = columnName.toLowerCase();
+                }
+                if (!result.containsKey(columnName))
+                {
+                    result.put(columnName, queryHints[tableIdx]);
+                }
+            }
+        }
+        return result;
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public boolean hasNext() throws DynaSqlException
+    {
+        advanceIfNecessary();
+        return !_isAtEnd;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    public Object next() throws DynaSqlException
+    {
+        advanceIfNecessary();
+        if (_isAtEnd)
+        {
+            throw new NoSuchElementException("No more elements in the resultset");
+        }
+        else
+        {
+            try
+            {
+                DynaBean bean  = _dynaClass.newInstance();
+                Table    table = null;
+
+                if (bean instanceof SqlDynaBean)
+                {
+                    SqlDynaClass dynaClass = (SqlDynaClass)((SqlDynaBean)bean).getDynaClass();
+
+                    table = dynaClass.getTable();
+                }
+
+                for (Iterator it = _columnsToProperties.entrySet().iterator(); it.hasNext();)
+                {
+                    Map.Entry entry      = (Map.Entry)it.next();
+                    String    columnName = (String)entry.getKey();
+                    String    propName   = (String)entry.getKey();
+                    Object    value      = _platform.getObjectFromResultSet(_resultSet, columnName,
table);
+
+                    bean.set(propName, value);
+                }
+                _needsAdvancing = true;
+                return bean;
+            }
+            catch (Exception ex)
+            {
+                cleanUp();
+                throw new DynaSqlException("Exception while reading the row from the resultset",
ex);
+            }
+        }
+    }
+    
+    /**
+     * Advances the result set if necessary.
+     */
+    private void advanceIfNecessary() throws DynaSqlException
+    {
+        if (_needsAdvancing && !_isAtEnd)
+        {
+            try
+            {
+                _isAtEnd        = !_resultSet.next();
+                _needsAdvancing = false;
+            }
+            catch (SQLException ex)
+            {
+                cleanUp();
+                throw new DynaSqlException("Could not retrieve next row from result set",
ex);
+            }
+            if (_isAtEnd)
+            {
+                cleanUp();
+            }
+        }
+    }
+    
+    /**
+     * {@inheritDoc}
+     */
+    public void remove() throws DynaSqlException
+    {
+        try
+        {
+            _resultSet.deleteRow();
+        }
+        catch (SQLException ex)
+        {
+            cleanUp();
+            throw new DynaSqlException("Failed to delete current row", ex);
+        }
+    }
+
+    /**
+     * Closes the resources (connection, statement, resultset).
+     */
+    public void cleanUp()
+    {
+        if (_cleanUpAfterFinish && (_resultSet != null))
+        {
+            try
+            {
+                Statement  stmt = _resultSet.getStatement();
+                Connection conn = stmt.getConnection();
+
+                // also closes the resultset
+                stmt.close();
+                conn.close();
+            }
+            catch (SQLException ex)
+            {
+                // we ignore it
+            }
+            _resultSet = null;
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    protected void finalize() throws Throwable
+    {
+        cleanUp();
+    }
+
+    /**
+     * Determines whether the connection is still open.
+     * 
+     * @return <code>true</code> if the connection is still open
+     */
+    public boolean isConnectionOpen()
+    {
+        if (_resultSet == null)
+        {
+            return false;
+        }
+        try
+        {
+            Statement  stmt = _resultSet.getStatement();
+            Connection conn = stmt.getConnection();
+
+            return !conn.isClosed();
+        }
+        catch (SQLException ex)
+        {
+            return false;
+        }
+    }
+}

Modified: db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java
URL: http://svn.apache.org/viewcvs/db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java?rev=360485&r1=360484&r2=360485&view=diff
==============================================================================
--- db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java (original)
+++ db/ddlutils/trunk/src/java/org/apache/ddlutils/platform/PlatformImplBase.java Sun Jan
 1 06:43:05 2006
@@ -20,12 +20,15 @@
 import java.io.StringWriter;
 import java.lang.reflect.InvocationTargetException;
 import java.math.BigDecimal;
+import java.sql.Blob;
+import java.sql.Clob;
 import java.sql.Connection;
 import java.sql.PreparedStatement;
 import java.sql.ResultSet;
 import java.sql.SQLException;
 import java.sql.SQLWarning;
 import java.sql.Statement;
+import java.sql.Types;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
@@ -44,13 +47,13 @@
 import org.apache.ddlutils.DynaSqlException;
 import org.apache.ddlutils.Platform;
 import org.apache.ddlutils.PlatformInfo;
-import org.apache.ddlutils.dynabean.DynaSqlIterator;
 import org.apache.ddlutils.dynabean.SqlDynaClass;
 import org.apache.ddlutils.dynabean.SqlDynaProperty;
 import org.apache.ddlutils.model.Column;
 import org.apache.ddlutils.model.Database;
 import org.apache.ddlutils.model.Table;
 import org.apache.ddlutils.model.TypeMap;
+import org.apache.ddlutils.util.Jdbc3Utils;
 import org.apache.ddlutils.util.JdbcSupport;
 
 /**
@@ -1523,6 +1526,14 @@
             // Derby doesn't like BigDecimal's in setObject
             statement.setBigDecimal(sqlIndex, (BigDecimal)value);
         }
+        else if (value instanceof Float)
+        {
+            statement.setFloat(sqlIndex, ((Float)value).floatValue());
+        }
+        else if (value instanceof Double)
+        {
+            statement.setDouble(sqlIndex, ((Double)value).doubleValue());
+        }
         else
         {
             statement.setObject(sqlIndex, value, typeCode);
@@ -1530,6 +1541,137 @@
     }
 
     /**
+     * Helper method esp. for the {@link ModelBasedResultSetIterator} class that retrieves
+     * the value for a column from the given result set. If a table was specified,
+     * and it contains the column, then the jdbc type defined for the column is used for
extracting
+     * the value, otherwise the object directly retrieved from the result set is returned.<br/>
+     * The method is defined here rather than in the {@link ModelBasedResultSetIterator}
class
+     * so that concrete platforms can modify its behavior.
+     * 
+     * @param resultSet  The result set
+     * @param columnName The name of the column
+     * @param table      The table
+     * @return The value
+     */
+    protected Object getObjectFromResultSet(ResultSet resultSet, String columnName, Table
table) throws SQLException
+    {
+        Column column = (table == null ? null : table.findColumn(columnName, getPlatformInfo().isCaseSensitive()));
+        Object value  = null;
+
+        if (column != null)
+        {
+            int originalJdbcType = column.getTypeCode();
+            int targetJdbcType   = getPlatformInfo().getTargetJdbcType(originalJdbcType);
+            int jdbcType         = originalJdbcType;
+
+            // in general we're trying to retrieve the value using the original type
+            // but sometimes we also need the target type:
+            if ((originalJdbcType == Types.BLOB) && (targetJdbcType != Types.BLOB))
+            {
+                // we should not use the Blob interface if the database doesn't map to this
type 
+                jdbcType = targetJdbcType;
+            }
+            if ((originalJdbcType == Types.CLOB) && (targetJdbcType != Types.CLOB))
+            {
+                // we should not use the Clob interface if the database doesn't map to this
type 
+                jdbcType = targetJdbcType;
+            }
+            switch (jdbcType)
+            {
+                case Types.CHAR:
+                case Types.VARCHAR:
+                case Types.LONGVARCHAR:
+                    value = resultSet.getString(columnName);
+                    break;
+                case Types.NUMERIC:
+                case Types.DECIMAL:
+                    value = resultSet.getBigDecimal(columnName);
+                    break;
+                case Types.BIT:
+                    value = new Boolean(resultSet.getBoolean(columnName));
+                    break;
+                case Types.TINYINT:
+                case Types.SMALLINT:
+                case Types.INTEGER:
+                    value = new Integer(resultSet.getInt(columnName));
+                    break;
+                case Types.BIGINT:
+                    value = new Long(resultSet.getLong(columnName));
+                    break;
+                case Types.REAL:
+                    value = new Float(resultSet.getFloat(columnName));
+                    break;
+                case Types.FLOAT:
+                case Types.DOUBLE:
+                    value = new Double(resultSet.getDouble(columnName));
+                    break;
+                case Types.BINARY:
+                case Types.VARBINARY:
+                case Types.LONGVARBINARY:
+                    value = resultSet.getBytes(columnName);
+                    break;
+                case Types.DATE:
+                    value = resultSet.getDate(columnName);
+                    break;
+                case Types.TIME:
+                    value = resultSet.getTime(columnName);
+                    break;
+                case Types.TIMESTAMP:
+                    value = resultSet.getTimestamp(columnName);
+                    break;
+                case Types.CLOB:
+                    Clob clob = resultSet.getClob(columnName);
+
+                    if ((clob == null) || (clob.length() > Integer.MAX_VALUE))
+                    {
+                        value = clob;
+                    }
+                    else
+                    {
+                        value = clob.getSubString(1l, (int)clob.length());
+                    }
+                    break;
+                case Types.BLOB:
+                    Blob blob = resultSet.getBlob(columnName);
+
+                    if ((blob == null) || (blob.length() > Integer.MAX_VALUE))
+                    {
+                        value = blob;
+                    }
+                    else
+                    {
+                        value = blob.getBytes(1l, (int)blob.length());
+                    }
+                    break;
+                case Types.ARRAY:
+                    value = resultSet.getArray(columnName);
+                    break;
+                case Types.REF:
+                    value = resultSet.getRef(columnName);
+                    break;
+                default:
+                    // special handling for Java 1.4/JDBC 3 types
+                    if (Jdbc3Utils.supportsJava14JdbcTypes() &&
+                        (jdbcType == Jdbc3Utils.determineBooleanTypeCode()))
+                    {
+                        value = new Boolean(resultSet.getBoolean(columnName));
+                    }
+                    else
+                    {
+                        value = resultSet.getObject(columnName);
+                    }
+                    break;
+            }
+        }
+        else
+        {
+            value = resultSet.getObject(columnName);
+        }
+        return value;
+    }
+
+    
+    /**
      * Creates an iterator over the given result set.
      *
      * @param model      The database model
@@ -1538,8 +1680,8 @@
      *                   given result set (optional)
      * @return The iterator
      */
-    protected DynaSqlIterator createResultSetIterator(Database model, ResultSet resultSet,
Table[] queryHints)
+    protected ModelBasedResultSetIterator createResultSetIterator(Database model, ResultSet
resultSet, Table[] queryHints)
     {
-        return new DynaSqlIterator(getPlatformInfo(), model, resultSet, queryHints, true);
+        return new ModelBasedResultSetIterator(this, model, resultSet, queryHints, true);
     }
 }



Mime
View raw message