abstractsqlcommand.java

来自「java实现浏览器等本地桌面的功能」· Java 代码 · 共 256 行

JAVA
256
字号
/* * $Id: AbstractSqlCommand.java,v 1.6 2005/10/10 17:01:15 rbair Exp $ * * Copyright 2005 Sun Microsystems, Inc., 4150 Network Circle, * Santa Clara, California 95054, U.S.A. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2.1 of the License, or (at your option) any later version. *  * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU * Lesser General Public License for more details. *  * You should have received a copy of the GNU Lesser General Public * License along with this library; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */package org.jdesktop.dataset.provider.sql;import java.sql.PreparedStatement;import java.util.ArrayList;import java.util.HashMap;import java.util.HashSet;import java.util.List;import java.util.Map;import java.util.Set;import org.jdesktop.dataset.DataCommand;import org.jdesktop.dataset.DataRow;/** * <p>An AbstractSqlCommand is a {@link org.jdesktop.dataset.DataCommand} meant to  * be used with a {@link SQLDataProvider} by defining  * methods to generate a SELECT, INSERT, UPDATE or DELETE statement. How these * SQL statements are built is up to the concrete implementation of an * AbstractSqlCommand. * * <p>The methods for retrieving the SQL statements (as PreparedStatements) are * all protected, meaning they can be accessed by subclasses as well as classes * within this package. Thus, within the package, the AbstractSqlCommand defines * an interface for preparing a PreparedStatement for consumers of the command. * * <p>An AbstractSqlCommand also defines methods to normalize SQL statements to  * make them easier to process using JDBC--namely, to convert between named- * parameter style statements and index-based parameterized statements.  * * <p>AbstractSqlCommand is useful in defining the structure of a concrete SQLCommand * or TableCommand, and is not meant to be used on its own. * * @author rbair */public abstract class AbstractSqlCommand extends DataCommand {        /**     * @param conn An active JDBCDataConnection to use to prepare the statement     * @return A PreparedStatement, ready to execute, for the SELECT SQL statement.     */    protected abstract PreparedStatement getSelectStatement(JDBCDataConnection conn) throws Exception;    /**     * @param conn An active JDBCDataConnection to use to prepare the statement     * @param row The {@link DataRow} that will be inserted     * @return A PreparedStatement, ready to execute, for the INSERT SQL statement.     */    protected abstract PreparedStatement getInsertStatement(JDBCDataConnection conn, DataRow row) throws Exception;    /**     * @param conn An active JDBCDataConnection to use to prepare the statement     * @param row The {@link DataRow} that will be updated     * @return A PreparedStatement, ready to execute, for the UPDATE SQL statement.     */    protected abstract PreparedStatement getUpdateStatement(JDBCDataConnection conn, DataRow row) throws Exception;    /**     * @param conn An active JDBCDataConnection to use to prepare the statement     * @param row The {@link DataRow} that will be deleted     * @return A PreparedStatement, ready to execute, for the DELETE SQL statement.     */    protected abstract PreparedStatement getDeleteStatement(JDBCDataConnection conn, DataRow row) throws Exception;        /**      * Generates a new String for a SQL statement, replacing named parameters      * with ? symbols, as required by the      * {@link java.sql.Connection#prepareStatement(String)} method. The Map     * parameter is populated with parameter names, mapped to a List     * of indexes numbering that parameter within the SQL statement. Thus, as each     * named parameter is replaced, we get a list of the position that parameter      * had within the statement; the List of indexes can then be used on a call to      * {@link PreparedStatement#setObject(int, Object)}, using the index in the list     * as the index parameter in setObject().     *     * @param sql A SQL statement with 1 or more named parameters.     * @param indexes An empty Map which will be populated with a list of parameter     * names, and the number of that parameter within the SQL statement.     * @return A SQL statement ready to use in the JDBC prepareStatement() method; note     * that the Map parameter is also populated in this method call.     */    protected String constructSql(String sql, Map<String,List<Integer>> indexes) {        //replace all of the named parameters in the sql with their        //corrosponding values. This is done by first converting the sql        //to proper JDBC sql by inserting '?' for each and every param.        //As this is done, a record is kept of which parameters go with        //which indexes. Then, the parameter values are applied.        StringBuilder buffer = new StringBuilder(sql);        //variable containing the index of the current parameter. So,        //for the first named param this is 0, then 1 for the next, and so on        int paramIndex = 0;        //iterate through the buffer looking for a colon outside of any        //single or double quotes. This represents the beginning of a named        //parameter        boolean inSingleQuote = false;        boolean inDoubleQuote = false;        for (int i=0; i<buffer.length(); i++) {            char c = buffer.charAt(i);            if (c == '\'') {                inSingleQuote = !inSingleQuote;            } else if (c == '\"') {                inDoubleQuote = !inDoubleQuote;            } else if (c == ':' && !inSingleQuote && !inDoubleQuote) {                //found the beginning of a named param. find the whole                //name by looking from here to the first whitespace                //character                int firstCharIndex = i;                i++;                boolean found = false;                while (!found) {                    if (i >= buffer.length()) {                        //I've gotten to the end of the string, so I must                        //now have the entire variable name                        found = true;                    } else {                        char next = buffer.charAt(i);                        if (next == ' ' || next == '\n' || next == '\t' || next == '\r' || next == ',' || next == ')') {                            found = true;                        }                    }                    i++;                }                //ok, i-1 is the index following the last character in this sequence.                String paramName = buffer.substring(firstCharIndex+1, i-1);                //now that I have the name, replace it with a ? and add it                //to the map of paramName->index values.                buffer.replace(firstCharIndex, i-1, "?");                if (!indexes.containsKey(paramName)) {                    indexes.put(paramName, new ArrayList<Integer>());                }                List<Integer> list = indexes.get(paramName);                list.add(paramIndex++);                //reposition "i" to a valid value since a lot of chars were                //just removed                i = firstCharIndex + 1;            }        }        return buffer.toString();    }    /**     * Creates a PreparedStatement from a SQL statement, setting parameter     * values using the supplied Map of parameter names to values. If there are     * parameters in the SQL that require values assigned in the PreparedStatements,     * the parameter in the SQL should appear as ":<parameter-name>", and the     * parameter name should be assigned a value in the Map argument to this     * method.     *     * @param sql A SQL statement, including named parameters if desired.     * @param values A Map of parameter names to Object values for the parameter--     * the values used for each parameter when this statement is executed.     * @param conn An valid JDBCDataConnection.     * @return A PreparedStatement build from the SQL argument, with parameters     * assigned.     * @throws Exception if any error occurs during execution.     */    protected PreparedStatement prepareStatement(String sql, Map<String,Object> values, JDBCDataConnection conn) throws Exception {        //map containing the indexes for each named param        Map<String,List<Integer>> indexes = new HashMap<String,List<Integer>>();        PreparedStatement ps = conn.prepareStatement(constructSql(sql, indexes));        //now, apply the given set of parameters        for (String paramName : getParameterNames(new String[]{sql})) {            List<Integer> list = indexes.get(paramName);            if (list != null) {                for (int index : list) {                    ps.setObject(index + 1, values.get(paramName));                }            }        }        // TODO: should check that we have values for all parameters in the SQL, and that no parameters in the Map are unused (PWW 04/25/05)        return ps;    }    /**     * Searches the statements for param names, and returns the unique set of	 * param names.     *     * @param statements An array of SQL statements, optionally with named      * parameters embedded, in the form ":<parameter-name>".     * @return Array of parameter names, unique across all the statements.    */	public String[] getParameterNames(String[] statements) {		StringBuilder buffer = new StringBuilder();		for (String s : statements) {			buffer.append(s);		    buffer.append("\n");		}		Set<String> names = new HashSet<String>();        // TODO: this search routine is redundant with constructSQL above (PWW 04/25/05)                //iterate through the buffer looking for a colon outside of any        //single or double quotes. This represents the beginning of a named        //parameter        boolean inSingleQuote = false;        boolean inDoubleQuote = false;        for (int i=0; i<buffer.length(); i++) {            char c = buffer.charAt(i);            if (c == '\'') {                inSingleQuote = !inSingleQuote;            } else if (c == '\"') {                inDoubleQuote = !inDoubleQuote;            } else if (c == ':' && !inSingleQuote && !inDoubleQuote) {                //found the beginning of a named param. find the whole                //name by looking from here to the first whitespace                //character                int firstCharIndex = i;                i++;                boolean found = false;                while (!found) {                    if (i >= buffer.length()) {                        //I've gotten to the end of the string, so I must                        //now have the entire variable name                        found = true;                    } else {                        char next = buffer.charAt(i);                        if (next == ' ' || next == '\n' || next == '\t' || next == '\r' || next == ',' || next == ')') {                            found = true;                        }                    }                    i++;                }                //ok, i-1 is the index following the last character in this sequence.                String paramName = buffer.substring(firstCharIndex+1, i-1);                names.add(paramName);            }        }        String[] results = new String[names.size()];        return names.toArray(results);	}}

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?