KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xalan > lib > sql > SQLQueryParser


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 /*
17  * $Id: SQLQueryParser.java,v 1.4 2004/02/11 17:56:35 minchau Exp $
18  */

19
20 /**
21   * This is used by the SQLDocumentHandler for processing JDBC queries.
22   * This prepares JDBC PreparedStatement or CallableStatements and the
23   * input/output of parameters from/to variables.
24   *
25  */

26
27 package org.apache.xalan.lib.sql;
28
29 import java.util.*;
30 import java.sql.*;
31 import org.apache.xpath.objects.*;
32 import org.apache.xalan.extensions.ExpressionContext;
33 import org.apache.xml.utils.QName;
34 import javax.xml.transform.TransformerException JavaDoc;
35
36
37
38 public class SQLQueryParser
39 {
40   /**
41    * If the parser used inline parser to pull out variables then
42    * this will be true. The default is not to use the Inline Parser.
43    */

44   private boolean m_InlineVariables = false;
45
46   /**
47    *
48    */

49   private boolean m_IsCallable = false;
50
51   /**
52    *
53    */

54   private String JavaDoc m_OrigQuery = null;
55
56   /**
57    *
58    */

59   private StringBuffer JavaDoc m_ParsedQuery = null;
60
61   /**
62    *
63    */

64   private Vector m_Parameters = null;
65
66   /**
67    *
68    */

69   private boolean m_hasOutput = false;
70
71   /**
72    *
73    */

74   private boolean m_HasParameters;
75
76   public static final int NO_OVERRIDE = 0;
77   public static final int NO_INLINE_PARSER = 1;
78   public static final int INLINE_PARSER = 2;
79
80   /**
81    * The SQLStatement Parser will be created as a psuedo SINGLETON per
82    * XConnection. Since we are only caching the Query and its parsed results
83    * we may be able to use this as a real SINGLETON. It all depends on how
84    * Statement Caching will play out.
85    */

86   public SQLQueryParser()
87   {
88     init();
89   }
90
91   /**
92    * Constructor, used to create a new parser entry
93    */

94   private SQLQueryParser(String JavaDoc query)
95   {
96     m_OrigQuery = query;
97   }
98
99   /**
100    * On a per Xconnection basis, we will create a SQLStatemenetParser, from
101    * this parser, individual parsers will be created. The Init method is defined
102    * to initialize all the internal structures that maintains the pool of parsers.
103    */

104   private void init()
105   {
106     // Do nothing for now.
107
}
108
109   /**
110    * Produce an SQL Statement Parser based on the incomming query.
111    *
112    * For now we will just create a new object, in the future we may have this
113    * interface cache the queries so that we can take advantage of a preparsed
114    * String.
115    *
116    * If the Inline Parser is not enabled in the Options, no action will be
117    * taken on the parser. This option can be set by the Stylesheet. If the
118    * option is not set or cleared, a default value will be set determined
119    * by the way variables were passed into the system.
120    */

121   public SQLQueryParser parse(XConnection xconn, String JavaDoc query, int override)
122   {
123     SQLQueryParser parser = new SQLQueryParser(query);
124
125     // Try to implement caching here, if we found a parser in the cache
126
// then just return the instance otherwise
127
parser.parse(xconn, override);
128
129     return parser;
130   }
131
132
133
134   /**
135    * Produce an SQL Statement Parser based on the incomming query.
136    *
137    * For now we will just create a new object, in the future we may have this
138    * interface cache the queries so that we can take advantage of a preparsed
139    * String.
140    *
141    * If the Inline Parser is not enabled in the Options, no action will be
142    * taken on the parser. This option can be set by the Stylesheet. If the
143    * option is not set or cleared, a default value will be set determined
144    * by the way variables were passed into the system.
145    */

146   private void parse(XConnection xconn, int override)
147   {
148     // Grab the Feature here. We could maintain it from the Parent Parser
149
// but that may cause problems if a single XConnection wants to maintain
150
// both Inline Variable Statemens along with NON inline variable statements.
151

152     m_InlineVariables = "true".equals(xconn.getFeature("inline-variables"));
153     if (override == NO_INLINE_PARSER) m_InlineVariables = false;
154     else if (override == INLINE_PARSER) m_InlineVariables = true;
155
156     if (m_InlineVariables) inlineParser();
157
158   }
159
160   /**
161    * If a SQL Statement does not have any parameters, then it can be executed
162    * directly. Most SQL Servers use this as a performance advantage since no
163    * parameters need to be parsed then bound.
164    */

165   public boolean hasParameters()
166   {
167     return m_HasParameters;
168   }
169
170   /**
171    * If the Inline Parser is used, the parser will note if this stastement is
172    * a plain SQL Statement or a Called Procedure. Called Procudures generally
173    * have output parameters and require special handling.
174    *
175    * Called Procudures that are not processed with the Inline Parser will
176    * still be executed but under the context of a PreparedStatement and
177    * not a CallableStatement. Called Procudures that have output parameters
178    * MUST be handled with the Inline Parser.
179    */

180   public boolean isCallable()
181   {
182     return m_IsCallable;
183   }
184
185
186   /**
187    *
188    */

189   public Vector getParameters()
190   {
191     return m_Parameters;
192   }
193
194   /**
195    * The XConnection will use this method to store the Parameters
196    * that were supplied by the style sheet in the case where the
197    * inline parser was not used
198    */

199   public void setParameters(Vector p)
200   {
201     m_HasParameters = true;
202     m_Parameters = p;
203   }
204
205   /**
206    * Return a copy of the parsed SQL query that will be set to the
207    * Database system to execute. If the inline parser was not used,
208    * then the original query will be returned.
209    */

210   public String JavaDoc getSQLQuery()
211   {
212     if (m_InlineVariables) return m_ParsedQuery.toString();
213     else return m_OrigQuery;
214   }
215
216
217   /**
218    * The SQL Statement Parser, when an Inline Parser is used, tracks the XSL
219    * variables used to populate a statement. The data use to popoulate a
220    * can also be provided. If the data is provided, it will overide the
221    * populastion using XSL variables. When the Inline PArser is not used, then
222    * the Data will always be provided.
223    *
224    */

225   public void populateStatement(PreparedStatement stmt, ExpressionContext ctx)
226   {
227     // Set input parameters from variables.
228
// for ( int indx = returnParm ? 1 : 0 ; indx < m_Parameters.size() ; indx++ )
229

230     for ( int indx = 0 ; indx < m_Parameters.size() ; indx++ )
231     {
232       QueryParameter parm = (QueryParameter) m_Parameters.elementAt(indx);
233
234       try
235       {
236
237         if (m_InlineVariables)
238         {
239           XObject value = (XObject)ctx.getVariableOrParam(new QName(parm.getName()));
240
241           if (value != null)
242           {
243             stmt.setObject(
244               indx + 1,
245               value.object(),
246               parm.getType(), 4); // Currently defaulting scale to 4 - should read this!
247
}
248           else
249           {
250             stmt.setNull(indx + 1, parm.getType());
251           }
252         }
253         else
254         {
255           String JavaDoc value = parm.getValue();
256
257           if (value != null)
258           {
259             stmt.setObject(
260               indx + 1,
261               value,
262               parm.getType(), 4); // Currently defaulting scale to 4 - should read this!
263
}
264           else
265           {
266             stmt.setNull(indx + 1, parm.getType());
267           }
268         }
269       }
270       catch (Exception JavaDoc tx)
271       {
272 // if ( ! parm.isOutput() ) throw new SQLException(tx.toString());
273
}
274     }
275
276   }
277
278   public void registerOutputParameters(CallableStatement cstmt) throws SQLException
279   {
280     // Register output parameters if call.
281
if ( m_IsCallable && m_hasOutput )
282     {
283       for ( int indx = 0 ; indx < m_Parameters.size() ; indx++ )
284       {
285         QueryParameter parm = (QueryParameter) m_Parameters.elementAt(indx);
286         if ( parm.isOutput() )
287         {
288           //System.out.println("chrysalisSQLStatement() Registering output parameter for parm " + indx);
289
cstmt.registerOutParameter(indx + 1, parm.getType());
290         }
291       }
292     }
293  }
294
295   /**
296    *
297    */

298   protected void inlineParser()
299   {
300     QueryParameter curParm = null;
301     int state = 0;
302     StringBuffer JavaDoc tok = new StringBuffer JavaDoc();
303     boolean firstword = true;
304
305     if (m_Parameters == null) m_Parameters = new Vector();
306
307     if (m_ParsedQuery == null) m_ParsedQuery = new StringBuffer JavaDoc();
308
309     for ( int idx = 0 ; idx < m_OrigQuery.length() ; idx++ )
310     {
311       char ch = m_OrigQuery.charAt(idx);
312       switch ( state )
313       {
314
315         case 0: // Normal
316
if ( ch == '\'' ) state = 1;
317           else if ( ch == '?' ) state = 4;
318           else if ( firstword && (Character.isLetterOrDigit(ch) || ch == '#') )
319           {
320             tok.append(ch);
321             state = 3;
322           }
323           m_ParsedQuery.append(ch);
324           break;
325
326         case 1: // In String
327
if ( ch == '\'' ) state = 0;
328           else if ( ch == '\\' ) state = 2;
329           m_ParsedQuery.append(ch);
330           break;
331
332         case 2: // In escape
333
state = 1;
334           m_ParsedQuery.append(ch);
335           break;
336
337         case 3: // First word
338
if ( Character.isLetterOrDigit(ch) || ch == '#' || ch == '_' ) tok.append(ch);
339           else
340           {
341             if ( tok.toString().equalsIgnoreCase("call") )
342             {
343               m_IsCallable = true;
344               if ( curParm != null )
345               {
346                 // returnParm = true;
347
curParm.setIsOutput(true);
348                 // hasOutput = true;
349
}
350             }
351             firstword = false;
352             tok = new StringBuffer JavaDoc();
353             if ( ch == '\'' ) state = 1;
354             else if ( ch == '?' ) state = 4;
355             else state = 0;
356           }
357
358           m_ParsedQuery.append(ch);
359           break;
360
361         case 4: // Get variable definition
362
if ( ch == '[' ) state = 5;
363           break;
364
365         case 5: // Read variable type.
366
if ( !Character.isWhitespace(ch) && ch != '=' )
367           {
368             tok.append(Character.toUpperCase(ch));
369           }
370           else if ( tok.length() > 0 )
371           {
372             // OK we have at least one parameter.
373
m_HasParameters = true;
374
375             curParm = new QueryParameter();
376
377             curParm.setTypeName(tok.toString());
378 // curParm.type = map_type(curParm.typeName);
379
m_Parameters.addElement(curParm);
380             tok = new StringBuffer JavaDoc();
381             if ( ch == '=' ) state = 7;
382             else state = 6;
383           }
384           break;
385
386         case 6: // Look for '='
387
if ( ch == '=' ) state = 7;
388           break;
389
390         case 7: // Read variable name.
391
if ( !Character.isWhitespace(ch) && ch != ']' ) tok.append(ch);
392           else if ( tok.length() > 0 )
393           {
394             curParm.setName(tok.toString());
395             tok = new StringBuffer JavaDoc();
396             if ( ch == ']' )
397             {
398               //param_output.addElement(new Boolean(false));
399
state = 0;
400             }
401             else state = 8;
402           }
403           break;
404
405         case 8: // Look for "OUTput.
406
if ( !Character.isWhitespace(ch) && ch != ']' )
407           {
408             tok.append(ch);
409           }
410           else if ( tok.length() > 0 )
411           {
412             tok.setLength(3);
413             if ( tok.toString().equalsIgnoreCase("OUT") )
414             {
415               curParm.setIsOutput(true);
416               m_hasOutput = true;
417             }
418
419             tok = new StringBuffer JavaDoc();
420             if ( ch == ']' )
421             {
422               state = 0;
423             }
424           }
425           break;
426       }
427     }
428
429
430     // Prepare statement or call.
431
if ( m_IsCallable )
432     {
433       m_ParsedQuery.insert(0, '{');
434       m_ParsedQuery.append('}');
435     }
436
437   }
438
439 }
440
441
Popular Tags