All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.objectstyle.cayenne.access.jdbc.SQLTemplateAction Maven / Gradle / Ivy

There is a newer version: 1.2.4
Show newest version
/* ====================================================================
 * 
 * The ObjectStyle Group Software License, version 1.1
 * ObjectStyle Group - http://objectstyle.org/
 * 
 * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
 * of the software. All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 * 
 * 3. The end-user documentation included with the redistribution, if any,
 *    must include the following acknowlegement:
 *    "This product includes software developed by independent contributors
 *    and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
 *    Alternately, this acknowlegement may appear in the software itself,
 *    if and wherever such third-party acknowlegements normally appear.
 * 
 * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
 *    or promote products derived from this software without prior written
 *    permission. For written permission, email
 *    "andrus at objectstyle dot org".
 * 
 * 5. Products derived from this software may not be called "ObjectStyle"
 *    or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
 *    names without prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 * 
 * This software consists of voluntary contributions made by many
 * individuals and hosted on ObjectStyle Group web site.  For more
 * information on the ObjectStyle Group, please see
 * .
 */

package org.objectstyle.cayenne.access.jdbc;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.IteratorUtils;
import org.objectstyle.cayenne.CayenneException;
import org.objectstyle.cayenne.access.OperationObserver;
import org.objectstyle.cayenne.access.QueryLogger;
import org.objectstyle.cayenne.access.types.ExtendedTypeMap;
import org.objectstyle.cayenne.dba.DbAdapter;
import org.objectstyle.cayenne.query.SQLAction;
import org.objectstyle.cayenne.query.SQLTemplate;
import org.objectstyle.cayenne.util.Util;

/**
 * Implements a strategy for execution of SQLTemplates.
 * 
 * @author Andrus Adamchik
 * @since 1.2 replaces SQLTemplateExecutionPlan
 */
public class SQLTemplateAction implements SQLAction {

    protected DbAdapter adapter;
    protected boolean removingLineBreaks;
    protected SQLTemplate query;

    public SQLTemplateAction(SQLTemplate query, DbAdapter adapter) {
        this.query = query;
        this.adapter = adapter;
    }

    /**
     * Returns DbAdapter associated with this execution plan object.
     */
    public DbAdapter getAdapter() {
        return adapter;
    }

    /**
     * Runs a SQLTemplate query, collecting all results. If a callback expects an iterated
     * result, result processing is stopped after the first ResultSet is encountered.
     */
    public void performAction(Connection connection, OperationObserver callback)
            throws SQLException, Exception {

        String template = extractTemplateString();

        // sanity check - misconfigured templates
        if (template == null) {
            throw new CayenneException("No template string configured for adapter "
                    + getAdapter().getClass().getName());
        }

        boolean loggable = QueryLogger.isLoggable();
        int size = query.parametersSize();

        SQLTemplateProcessor templateProcessor = new SQLTemplateProcessor();

        // zero size indicates a one-shot query with no parameters
        // so fake a single entry batch...
        int batchSize = (size > 0) ? size : 1;

        List counts = new ArrayList(batchSize);
        Iterator it = (size > 0) ? query.parametersIterator() : IteratorUtils
                .singletonIterator(Collections.EMPTY_MAP);
        for (int i = 0; i < batchSize; i++) {
            Map nextParameters = (Map) it.next();

            SQLStatement compiled = templateProcessor.processTemplate(
                    template,
                    nextParameters);

            if (loggable) {
                QueryLogger.logQuery(compiled.getSql(), Arrays.asList(compiled
                        .getBindings()));
            }

            execute(connection, callback, compiled, counts);
        }

        // notify of combined counts of all queries inside SQLTemplate multipled by the
        // number of parameter sets...
        if (counts != null) {
            int[] ints = new int[counts.size()];
            for (int i = 0; i < ints.length; i++) {
                ints[i] = ((Integer) counts.get(i)).intValue();
            }

            callback.nextBatchCount(query, ints);
        }
    }

    protected void execute(
            Connection connection,
            OperationObserver callback,
            SQLStatement compiled,
            Collection updateCounts) throws SQLException, Exception {

        long t1 = System.currentTimeMillis();
        boolean iteratedResult = callback.isIteratedResult();
        PreparedStatement statement = connection.prepareStatement(compiled.getSql());
        try {
            bind(statement, compiled.getBindings());

            // process a mix of results
            boolean isResultSet = statement.execute();
            boolean firstIteration = true;
            while (true) {

                if (firstIteration) {
                    firstIteration = false;
                }
                else {
                    isResultSet = statement.getMoreResults();
                }

                if (isResultSet) {

                    ResultSet resultSet = statement.getResultSet();

                    if (resultSet != null) {

                        try {
                            processSelectResult(
                                    compiled,
                                    connection,
                                    statement,
                                    resultSet,
                                    callback,
                                    t1);
                        }
                        finally {
                            if (iteratedResult) {
                                break;
                            }
                            else {
                                resultSet.close();
                            }
                        }
                    }
                }
                else {
                    int updateCount = statement.getUpdateCount();
                    if (updateCount == -1) {
                        break;
                    }

                    updateCounts.add(new Integer(updateCount));
                    QueryLogger.logUpdateCount(updateCount);
                }
            }
        }
        finally {
            if (!iteratedResult) {
                statement.close();
            }
        }
    }

    protected void processSelectResult(
            SQLStatement compiled,
            Connection connection,
            Statement statement,
            ResultSet resultSet,
            OperationObserver callback,
            long startTime) throws Exception {

        boolean iteratedResult = callback.isIteratedResult();

        ExtendedTypeMap types = adapter.getExtendedTypes();
        RowDescriptor descriptor = (compiled.getResultColumns().length > 0)
                ? new RowDescriptor(compiled.getResultColumns(), types)
                : new RowDescriptor(resultSet, types);

        JDBCResultIterator result = new JDBCResultIterator(
                connection,
                statement,
                resultSet,
                descriptor,
                query.getFetchLimit());

        if (!iteratedResult) {
            List resultRows = result.dataRows(false);
            QueryLogger.logSelectCount(resultRows.size(), System.currentTimeMillis()
                    - startTime);

            callback.nextDataRows(query, resultRows);
        }
        else {
            try {
                result.setClosingConnection(true);
                callback.nextDataRows(query, result);
            }
            catch (Exception ex) {
                result.close();
                throw ex;
            }
        }
    }

    /**
     * Extracts a template string from a SQLTemplate query. Exists mainly for the benefit
     * of subclasses that can customize returned template.
     * 
     * @since 1.2
     */
    protected String extractTemplateString() {
        String sql = query.getTemplate(getAdapter().getClass().getName());
        return isRemovingLineBreaks() ? Util.stripLineBreaks(sql, " ") : sql;
    }

    /**
     * Binds parameters to the PreparedStatement.
     */
    protected void bind(PreparedStatement preparedStatement, ParameterBinding[] bindings)
            throws SQLException, Exception {
        // bind parameters
        if (bindings.length > 0) {
            int len = bindings.length;
            for (int i = 0; i < len; i++) {
                adapter.bindParameter(
                        preparedStatement,
                        bindings[i].getValue(),
                        i + 1,
                        bindings[i].getJdbcType(),
                        bindings[i].getPrecision());
            }
        }
    }

    /**
     * Returns whether line breaks are removed when the query is executed. Some databases
     * (like DB2) can't handle multiline queries.
     */
    public boolean isRemovingLineBreaks() {
        return removingLineBreaks;
    }

    public void setRemovingLineBreaks(boolean removingLineBreaks) {
        this.removingLineBreaks = removingLineBreaks;
    }

    /**
     * Returns a SQLTemplate for this action.
     */
    public SQLTemplate getQuery() {
        return query;
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy