johng 2003/06/19 11:01:48 Added: java/src/org/apache/xalan/lib/sql SQLQueryParser.java Log: Added code by Art Welsh to hande the inline variable parser. SQL Statements can describe an XSL variable name along with its type inside the statement instead of using the addParameter methods. Revision Changes Path 1.1 xml-xalan/java/src/org/apache/xalan/lib/sql/SQLQueryParser.java Index: SQLQueryParser.java =================================================================== /* * The Apache Software License, Version 1.1 * * * Copyright (c) 1999-2003 The Apache Software Foundation. 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 acknowledgment: * "This product includes software developed by the * Apache Software Foundation (http://www.apache.org/)." * Alternately, this acknowledgment may appear in the software itself, * if and wherever such third-party acknowledgments normally appear. * * 4. The names "Xalan" and "Apache Software Foundation" must * not be used to endorse or promote products derived from this * software without prior written permission. For written * permission, please contact [EMAIL PROTECTED] * * 5. Products derived from this software may not be called "Apache", * nor may "Apache" appear in their name, without prior written * permission of the Apache Software Foundation. * * 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 APACHE SOFTWARE FOUNDATION 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 on behalf of the Apache Software Foundation and was * originally based on software copyright (c) 1999, Lotus * Development Corporation., http://www.lotus.com. For more * information on the Apache Software Foundation, please see * <http://www.apache.org/>. * */ /** * This is used by the SQLDocumentHandler for processing JDBC queries. * This prepares JDBC PreparedStatement or CallableStatements and the * input/output of parameters from/to variables. * */ package org.apache.xalan.lib.sql; import java.util.*; import java.sql.*; import org.apache.xpath.objects.*; import org.apache.xalan.extensions.ExpressionContext; import org.apache.xml.utils.QName; import javax.xml.transform.TransformerException; public class SQLQueryParser { /** * If the parser used inline parser to pull out variables then * this will be true. The default is not to use the Inline Parser. */ private boolean m_InlineVariables = false; /** * */ private boolean m_IsCallable = false; /** * */ private String m_OrigQuery = null; /** * */ private StringBuffer m_ParsedQuery = null; /** * */ private Vector m_Parameters = null; /** * */ private boolean m_hasOutput = false; /** * */ private boolean m_HasParameters; public static int NO_OVERRIDE = 0; public static int NO_INLINE_PARSER = 1; public static int INLINE_PARSER = 2; /** * The SQLStatement Parser will be created as a psuedo SINGLETON per * XConnection. Since we are only caching the Query and its parsed results * we may be able to use this as a real SINGLETON. It all depends on how * Statement Caching will play out. */ public SQLQueryParser() { init(); } /** * Constructor, used to create a new parser entry */ private SQLQueryParser(String query) { m_OrigQuery = query; } /** * On a per Xconnection basis, we will create a SQLStatemenetParser, from * this parser, individual parsers will be created. The Init method is defined * to initialize all the internal structures that maintains the pool of parsers. */ private void init() { // Do nothing for now. } /** * Produce an SQL Statement Parser based on the incomming query. * * For now we will just create a new object, in the future we may have this * interface cache the queries so that we can take advantage of a preparsed * String. * * If the Inline Parser is not enabled in the Options, no action will be * taken on the parser. This option can be set by the Stylesheet. If the * option is not set or cleared, a default value will be set determined * by the way variables were passed into the system. */ public SQLQueryParser parse(XConnection xconn, String query, int override) { SQLQueryParser parser = new SQLQueryParser(query); // Try to implement caching here, if we found a parser in the cache // then just return the instance otherwise parser.parse(xconn, override); return parser; } /** * Produce an SQL Statement Parser based on the incomming query. * * For now we will just create a new object, in the future we may have this * interface cache the queries so that we can take advantage of a preparsed * String. * * If the Inline Parser is not enabled in the Options, no action will be * taken on the parser. This option can be set by the Stylesheet. If the * option is not set or cleared, a default value will be set determined * by the way variables were passed into the system. */ private void parse(XConnection xconn, int override) { // Grab the Feature here. We could maintain it from the Parent Parser // but that may cause problems if a single XConnection wants to maintain // both Inline Variable Statemens along with NON inline variable statements. m_InlineVariables = "true".equals(xconn.getFeature("inline-variables")); if (override == NO_INLINE_PARSER) m_InlineVariables = false; else if (override == INLINE_PARSER) m_InlineVariables = true; if (m_InlineVariables) inlineParser(); } /** * If a SQL Statement does not have any parameters, then it can be executed * directly. Most SQL Servers use this as a performance advantage since no * parameters need to be parsed then bound. */ public boolean hasParameters() { return m_HasParameters; } /** * If the Inline Parser is used, the parser will note if this stastement is * a plain SQL Statement or a Called Procedure. Called Procudures generally * have output parameters and require special handling. * * Called Procudures that are not processed with the Inline Parser will * still be executed but under the context of a PreparedStatement and * not a CallableStatement. Called Procudures that have output parameters * MUST be handled with the Inline Parser. */ public boolean isCallable() { return m_IsCallable; } /** * */ public Vector getParameters() { return m_Parameters; } /** * The XConnection will use this method to store the Parameters * that were supplied by the style sheet in the case where the * inline parser was not used */ public void setParameters(Vector p) { m_HasParameters = true; m_Parameters = p; } /** * Return a copy of the parsed SQL query that will be set to the * Database system to execute. If the inline parser was not used, * then the original query will be returned. */ public String getSQLQuery() { if (m_InlineVariables) return m_ParsedQuery.toString(); else return m_OrigQuery; } /** * The SQL Statement Parser, when an Inline Parser is used, tracks the XSL * variables used to populate a statement. The data use to popoulate a * can also be provided. If the data is provided, it will overide the * populastion using XSL variables. When the Inline PArser is not used, then * the Data will always be provided. * */ public void populateStatement(PreparedStatement stmt, ExpressionContext ctx) { // Set input parameters from variables. // for ( int indx = returnParm ? 1 : 0 ; indx < m_Parameters.size() ; indx++ ) for ( int indx = 0 ; indx < m_Parameters.size() ; indx++ ) { QueryParameter parm = (QueryParameter) m_Parameters.elementAt(indx); try { if (m_InlineVariables) { XObject value = (XObject)ctx.getVariableOrParam(new QName(parm.getName())); if (value != null) { stmt.setObject( indx + 1, value.object(), parm.getType(), 4); // Currently defaulting scale to 4 - should read this! } else { stmt.setNull(indx + 1, parm.getType()); } } else { String value = parm.getValue(); if (value != null) { stmt.setObject( indx + 1, value, parm.getType(), 4); // Currently defaulting scale to 4 - should read this! } else { stmt.setNull(indx + 1, parm.getType()); } } } catch (Exception tx) { // if ( ! parm.isOutput() ) throw new SQLException(tx.toString()); } } } public void registerOutputParameters(CallableStatement cstmt) throws SQLException { // Register output parameters if call. if ( m_IsCallable && m_hasOutput ) { for ( int indx = 0 ; indx < m_Parameters.size() ; indx++ ) { QueryParameter parm = (QueryParameter) m_Parameters.elementAt(indx); if ( parm.isOutput() ) { //System.out.println("chrysalisSQLStatement() Registering output parameter for parm " + indx); cstmt.registerOutParameter(indx + 1, parm.getType()); } } } } /** * */ protected void inlineParser() { QueryParameter curParm = null; int state = 0; StringBuffer tok = new StringBuffer(); boolean firstword = true; if (m_ParsedQuery == null) m_ParsedQuery = new StringBuffer(); for ( int idx = 0 ; idx < m_OrigQuery.length() ; idx++ ) { char ch = m_OrigQuery.charAt(idx); switch ( state ) { case 0: // Normal if ( ch == '\'' ) state = 1; else if ( ch == '?' ) state = 4; else if ( firstword && (Character.isLetterOrDigit(ch) || ch == '#') ) { tok.append(ch); state = 3; } m_ParsedQuery.append(ch); break; case 1: // In String if ( ch == '\'' ) state = 0; else if ( ch == '\\' ) state = 2; m_ParsedQuery.append(ch); break; case 2: // In escape state = 1; m_ParsedQuery.append(ch); break; case 3: // First word if ( Character.isLetterOrDigit(ch) || ch == '#' || ch == '_' ) tok.append(ch); else { if ( tok.toString().equalsIgnoreCase("call") ) { m_IsCallable = true; if ( curParm != null ) { // returnParm = true; curParm.setIsOutput(true); // hasOutput = true; } } firstword = false; tok = new StringBuffer(); if ( ch == '\'' ) state = 1; else if ( ch == '?' ) state = 4; else state = 0; } m_ParsedQuery.append(ch); break; case 4: // Get variable definition if ( ch == '[' ) state = 5; break; case 5: // Read variable type. if ( !Character.isWhitespace(ch) && ch != '=' ) { tok.append(Character.toUpperCase(ch)); } else if ( tok.length() > 0 ) { // OK we have at least one parameter. m_HasParameters = true; curParm = new QueryParameter(); curParm.setTypeName(tok.toString()); // curParm.type = map_type(curParm.typeName); m_Parameters.addElement(curParm); tok = new StringBuffer(); if ( ch == '=' ) state = 7; else state = 6; } break; case 6: // Look for '=' if ( ch == '=' ) state = 7; break; case 7: // Read variable name. if ( !Character.isWhitespace(ch) && ch != ']' ) tok.append(ch); else if ( tok.length() > 0 ) { curParm.setName(tok.toString()); tok = new StringBuffer(); if ( ch == ']' ) { //param_output.addElement(new Boolean(false)); state = 0; } else state = 8; } break; case 8: // Look for "OUTput. if ( !Character.isWhitespace(ch) && ch != ']' ) { tok.append(ch); } else if ( tok.length() > 0 ) { tok.setLength(3); if ( tok.toString().equalsIgnoreCase("OUT") ) { curParm.setIsOutput(true); m_hasOutput = true; } tok = new StringBuffer(); if ( ch == ']' ) { state = 0; } } break; } } // Prepare statement or call. if ( m_IsCallable ) { m_ParsedQuery.insert(0, '{'); m_ParsedQuery.append('}'); } } }
--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]
