⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sqlparser.java

📁 第三方的SQL Server and Sybase的jdbc dirver,速度更快
💻 JAVA
📖 第 1 页 / 共 3 页
字号:
// jTDS JDBC Driver for Microsoft SQL Server and Sybase// Copyright (C) 2004 The jTDS Project//// 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA//package net.sourceforge.jtds.jdbc;import java.sql.SQLException;import java.util.ArrayList;import java.util.HashMap;import net.sourceforge.jtds.jdbc.cache.SimpleLRUCache;import net.sourceforge.jtds.jdbc.cache.SQLCacheKey;/** * Process JDBC escape strings and parameter markers in the SQL string. * <p> * This code recognizes the following escapes: * <ol> * <li>Date      {d 'yyyy-mm-dd'} * <li>Time      {t 'hh:mm:ss'} * <li>Timestamp {ts 'yyyy-mm-dd hh:mm:ss.nnn'} * <li>ESCAPE    {escape 'x'} * <li>Function  {fn xxxx([arg,arg...])} * NB The concat(arg, arg) operator is converted to (arg + arg) * <li>OuterJoin {oj .....} * <li>Call      {?=call proc [arg, arg...]} * or        {call proc [arg, arg...]} * </ol> * Notes: * <ol> * <li>This code is designed to be as efficient as possible and as * result the validation done here is limited. * <li>SQL comments are parsed correctly thanks to code supplied by * Joel Fouse. * </ol> * * @author Mike Hutchinson * @version $Id: SQLParser.java,v 1.25 2005/05/25 09:24:03 alin_sinpalean Exp $ */class SQLParser {    /**     * Serialized version of a parsed SQL query (the value stored in the cache     * for a parsed SQL).     * <p/>     * Holds the parsed SQL query and the names, positions and return value and     * unicode flags for the parameters.     */    private static class CachedSQLQuery {        final String[]  parsedSql;        final String[]  paramNames;        final int[]     paramMarkerPos;        final boolean[] paramIsRetVal;        final boolean[] paramIsUnicode;        CachedSQLQuery(String[] parsedSql, ArrayList params) {            this.parsedSql = parsedSql;            if (params != null) {                final int size = params.size();                paramNames     = new String[size];                paramMarkerPos = new int[size];                paramIsRetVal  = new boolean[size];                paramIsUnicode = new boolean[size];                for (int i = 0; i < size; i++) {                    ParamInfo paramInfo = (ParamInfo) params.get(i);                    paramNames[i]     = paramInfo.name;                    paramMarkerPos[i] = paramInfo.markerPos;                    paramIsRetVal[i]  = paramInfo.isRetVal;                    paramIsUnicode[i] = paramInfo.isUnicode;                }            } else {                paramNames = null;                paramMarkerPos = null;                paramIsRetVal = null;                paramIsUnicode = null;            }        }    }    /** LRU cache of previously parsed SQL */    private static SimpleLRUCache cache;    /** Original SQL string */    private final String sql;    /** Input buffer with SQL statement. */    private final char[] in;    /** Current position in input buffer. */    private int s;    /** Length of input buffer. */    private final int len;    /** Output buffer to contain parsed SQL. */    private final char[] out;    /** Current position in output buffer. */    private int d;    /**     * Parameter list to be populated or <code>null</code> if no parameters     * are expected.     */    private final ArrayList params;    /** Current expected terminator character. */    private char terminator;    /** Procedure name in call escape. */    private String procName;    /** First SQL keyword or identifier in statement. */    private String keyWord;    /** First table name in from clause */    private String tableName;    /** Connection object for server specific parsing. */    private final ConnectionJDBC2 connection;    /**     * Parse the SQL statement processing JDBC escapes and parameter markers.     *     * @param extractTable     *            true to return the first table name in the FROM clause of a select     * @return The processed SQL statement, any procedure name, the first SQL     *         keyword and (optionally) the first table name as     *         elements 0 1, 2 and 3 of the returned <code>String[]</code>.     * @throws SQLException if a parse error occurs     */    static String[] parse(String sql, ArrayList paramList,                          ConnectionJDBC2 connection, boolean extractTable)            throws SQLException {    	// Don't cache extract table parse requests, just process it    	if (extractTable) {    		SQLParser parser = new SQLParser(sql, paramList, connection);    		return parser.parse(extractTable);    	}        SimpleLRUCache cache = getCache(connection);        SQLCacheKey cacheKey = new SQLCacheKey(sql, connection);        // By not synchronizing on the cache, we're admitting that the possibility of multiple        // parses of the same statement can occur.  However, it is 1) unlikely under normal        // usage, and 2) harmless to the cache.  By avoiding a synchronization block around        // the get()-parse()-put(), we reduce the contention greatly in the nominal case.        CachedSQLQuery cachedQuery = (CachedSQLQuery) cache.get(cacheKey);        if (cachedQuery == null) {            // Parse and cache SQL            SQLParser parser = new SQLParser(sql, paramList, connection);            cachedQuery = new CachedSQLQuery(parser.parse(extractTable),                    paramList);            cache.put(cacheKey, cachedQuery);        } else {            // Create full ParamInfo objects out of cached object            final int length = (cachedQuery.paramNames == null)                    ? 0 : cachedQuery.paramNames.length;            for (int i = 0; i < length; i++) {                ParamInfo paramInfo = new ParamInfo(cachedQuery.paramNames[i],                                                    cachedQuery.paramMarkerPos[i],                                                    cachedQuery.paramIsRetVal[i],                                                    cachedQuery.paramIsUnicode[i]);                paramList.add(paramInfo);            }        }        return cachedQuery.parsedSql;    }    // --------------------------- Private Methods --------------------------------    /**     * Retrieves the statement cache, creating it if required.     *     * @return the cache as a <code>SimpleLRUCache</code>     */    private synchronized static SimpleLRUCache getCache(ConnectionJDBC2 connection) {        if (cache == null) {            int maxStatements = connection.getMaxStatements();            maxStatements = Math.max(0, maxStatements);            maxStatements = Math.min(1000, maxStatements);            cache = new SimpleLRUCache(maxStatements);        }        return cache;    }    /** Lookup table to test if character is part of an identifier. */    private static boolean identifierChar[] = {            false, false, false, false, false, false, false, false,            false, false, false, false, false, false, false, false,            false, false, false, false, false, false, false, false,            false, false, false, false, false, false, false, false,            false, false, false, true,  true,  false, false, false,            false, false, false, false, false, false, false, false,            true,  true,  true,  true,  true,  true,  true,  true,            true,  true,  false, false, false, false, false, false,            true,  true,  true,  true,  true,  true,  true,  true,            true,  true,  true,  true,  true,  true,  true,  true,            true,  true,  true,  true,  true,  true,  true,  true,            true,  true,  true,  false, false, false, false, true,            false, true,  true,  true,  true,  true,  true,  true,            true,  true,  true,  true,  true,  true,  true,  true,            true,  true,  true,  true,  true,  true,  true,  true,            true,  true,  true,  false, false, false, false, false    };    /**     * Determines if character could be part of an SQL identifier.     * <p/>     * Characters > 127 are assumed to be unicode letters in other     * languages than english which is reasonable in this application.     * @param ch the character to test.     * @return <code>boolean</code> true if ch in A-Z a-z 0-9 @ $ # _.     */    private static boolean isIdentifier(int ch) {        return ch > 127 || identifierChar[ch];    }    /**     * Constructs a new parser object to process the supplied SQL.     *     * @param sqlIn     the SQL statement to parse     * @param paramList the parameter list array to populate or     *                  <code>null</code> if no parameters are expected     * @param connection the parent Connection object     */    private SQLParser(String sqlIn, ArrayList paramList, ConnectionJDBC2 connection) {        sql = sqlIn;        in  = sql.toCharArray();        len = in.length;        out = new char[len + 256]; // Allow extra for curdate/curtime        params = paramList;        procName = "";        this.connection = connection;    }    /**     * Inserts a String literal in the output buffer.     *     * @param txt The text to insert.     */    private void copyLiteral(String txt) throws SQLException {        final int len = txt.length();        for (int i = 0; i < len; i++) {            final char c = txt.charAt(i);            if (c == '?') {                if (params == null) {                    throw new SQLException(                            Messages.get("error.parsesql.unexpectedparam",                                    String.valueOf(s)),                            "2A000");                }                // param marker embedded in escape                ParamInfo pi = new ParamInfo(d, connection.isUseUnicode());                params.add(pi);            }            out[d++] = c;        }    }    /**     * Copies over an embedded string literal unchanged.     */    private void copyString() {        char saveTc = terminator;        char tc = in[s];        if (tc == '[') {            tc = ']';        }        terminator = tc;        out[d++] = in[s++];        while (in[s] != tc) {            out[d++] = in[s++];        }        out[d++] = in[s++];        terminator = saveTc;    }    /**     * Copies over possible SQL keyword eg 'SELECT'     */    private String copyKeyWord() {        int start = d;        while (s < len && isIdentifier(in[s])) {            out[d++] = in[s++];        }        return String.valueOf(out, start, d - start).toLowerCase();    }    /**     * Builds a new parameter item.     *     * @param name Optional parameter name or null.     * @param pos The parameter marker position in the output buffer.     */    private void copyParam(String name, int pos) throws SQLException {        if (params == null) {            throw new SQLException(                    Messages.get("error.parsesql.unexpectedparam",                            String.valueOf(s)),                    "2A000");        }        ParamInfo pi = new ParamInfo(pos, connection.isUseUnicode());        pi.name = name;        if (pos >= 0) {            out[d++] = in[s++];        } else {            pi.isRetVal = true;            s++;        }        params.add(pi);    }    /**     * Copies an embedded stored procedure identifier over to the output buffer.     *     * @return The identifier as a <code>String</code>.     */    private String copyProcName() throws SQLException {        int start = d;        do {            if (in[s] == '"' || in[s] == '[') {                copyString();            } else {                char c = in[s++];                while (isIdentifier(c) || c == ';') {                    out[d++] = c;                    c = in[s++];                }                s--;            }            if (in[s] == '.') {                while (in[s] == '.') {                    out[d++] = in[s++];                }            } else {                break;            }        } while (true);        if (d == start) {            // Procedure name expected but found something else            throw new SQLException(                    Messages.get("error.parsesql.syntax",                            "call",                            String.valueOf(s)),                    "22025");        }        return new String(out, start, d - start);    }    /**     * Copies an embedded parameter name to the output buffer.     *     * @return The identifier as a <code>String</code>.     */    private String copyParamName() {        int start = d;        char c = in[s++];        while (isIdentifier(c)) {            out[d++] = c;            c = in[s++];

⌨️ 快捷键说明

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