KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > lutris > dods > builder > generator > query > QueryBuilder


1 /*
2  * Enhydra Java Application Server Project
3  *
4  * The contents of this file are subject to the Enhydra Public License
5  * Version 1.1 (the "License"); you may not use this file except in
6  * compliance with the License. You may obtain a copy of the License on
7  * the Enhydra web site ( http://www.enhydra.org/ ).
8  *
9  * Software distributed under the License is distributed on an "AS IS"
10  * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
11  * the License for the specific terms governing rights and limitations
12  * under the License.
13  *
14  * The Initial Developer of the Enhydra Application Server is Lutris
15  * Technologies, Inc. The Enhydra Application Server and portions created
16  * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
17  * All Rights Reserved.
18  *
19  * Contributor(s):
20  *
21  * $Id: QueryBuilder.java,v 1.10 2005/05/26 08:08:10 predrag Exp $
22  *
23  * contains WebDocWf extension for extended wildcard support
24  *
25  * conatins WebDocWf extension for row counters
26  *
27  */

28 package com.lutris.dods.builder.generator.query;
29
30 import java.math.BigDecimal JavaDoc;
31 import java.sql.PreparedStatement JavaDoc;
32 import java.sql.ResultSet JavaDoc;
33 import java.sql.SQLException JavaDoc;
34 import java.util.BitSet JavaDoc;
35 import java.util.Date JavaDoc;
36 import java.util.Enumeration JavaDoc;
37 import java.util.Hashtable JavaDoc;
38 import java.util.Vector JavaDoc;
39
40 import org.enhydra.dods.Common;
41 import org.enhydra.dods.CommonConstants;
42 import org.enhydra.dods.DODS;
43 import org.enhydra.dods.cache.CacheConstants;
44
45 import com.lutris.appserver.server.sql.CoreDataStruct;
46 import com.lutris.appserver.server.sql.DBConnection;
47 import com.lutris.appserver.server.sql.DBQuery;
48 import com.lutris.appserver.server.sql.DatabaseManagerException;
49 import com.lutris.appserver.server.sql.ExtendedDBConnection;
50 import com.lutris.appserver.server.sql.ExtendedQuery;
51 import com.lutris.appserver.server.sql.ObjectId;
52 import com.lutris.appserver.server.sql.ObjectIdException;
53 import com.lutris.appserver.server.sql.StandardDatabaseManager;
54 import com.lutris.appserver.server.sql.standard.DriverSpecificConstants;
55 import com.lutris.appserver.server.sql.standard.StandardLogicalDatabase;
56 import com.lutris.dods.builder.generator.dataobject.GenericDO;
57 import com.lutris.logging.Logger;
58
59 /**
60  * @author Jay Gunter
61  * <PRE>
62  * A QueryBuilder is a helper-object used by the xxxQuery classes.
63  *
64  * Stand-alone usage:
65  *
66  * QueryBuilder qb;
67  * qb = new QueryBuilder( "cats" );
68  * or
69  * qb = new QueryBuilder( "cats", "name, age" );
70  * ...
71  * qb.addWhereClause( "owner.name", "Smith",
72  * QueryBuilder.NOT_NULL,
73  * QueryBuilder.EXACT_MATCH );
74  * qb.addWhereClause( "paws", 3, QueryBuilder.GREATER_THAN );
75  * qb.addTwoColumnWhereClause(
76  * "cat.ownerId", "owner.Id", QueryBuilder.EQUAL );
77  * ResultSet rs = qb.executeQuery( conn );
78  * ...
79  * qb.reset();
80  *
81  * </PRE>
82  *
83  *
84  * @version $Revision: 1.10 $
85  */

86 public class QueryBuilder implements ExtendedQuery {
87     // Special values for whereClauses:
88
private static final String JavaDoc OR = " OR ";
89     private static final String JavaDoc OPEN_PAREN = " ( ";
90     private static final String JavaDoc CLOSE_PAREN = " ) ";
91     // Comparison operator passed as 3rd arg to addWhereClause( int|float|double )
92
public static final String JavaDoc EQUAL = "=";
93     public static String JavaDoc NOT_EQUAL = "!=";
94     public static final String JavaDoc LESS_THAN = "<";
95     public static final String JavaDoc LESS_THAN_OR_EQUAL = "<=";
96     public static final String JavaDoc GREATER_THAN = ">";
97     public static final String JavaDoc GREATER_THAN_OR_EQUAL = ">=";
98     public static final String JavaDoc IS_NULL = " IS NULL ";
99     public static final String JavaDoc IS_NOT_NULL = " IS NOT NULL ";
100     public static final String JavaDoc OPEN_IN = " IN ( ";
101     public static final String JavaDoc OPEN_NOT_IN = " NOT IN ( ";
102     public static final String JavaDoc OPEN_EXISTS = " EXISTS ( ";
103     public static final String JavaDoc OPEN_NOT_EXISTS = " NOT EXISTS ( ";
104     public static final String JavaDoc CLOSE_IN = " ) ";
105     public static final String JavaDoc CASE_SENSITIVE_CONTAINS = "%X%";
106     public static final String JavaDoc CASE_INSENSITIVE_CONTAINS = "%x%";
107     public static final String JavaDoc CASE_SENSITIVE_STARTS_WITH = "X%";
108     public static final String JavaDoc CASE_INSENSITIVE_STARTS_WITH = "x%";
109     public static final String JavaDoc CASE_SENSITIVE_ENDS_WITH = "%X";
110     public static final String JavaDoc CASE_INSENSITIVE_ENDS_WITH = "%x";
111     public static final String JavaDoc CASE_INSENSITIVE_EQUAL = "%xxxx";
112     // WebDocWf extension for extended wildcard support
113
// The following lines have been added:
114
public static final String JavaDoc CASE_SENSITIVE_MATCH = "X";
115     public static final String JavaDoc CASE_INSENSITIVE_MATCH = "x";
116     public static final String JavaDoc USER_CASE_SENSITIVE_MATCH = "U";
117     public static final String JavaDoc USER_CASE_INSENSITIVE_MATCH = "u";
118     // end ofWebDocWf extension for extended wildcard support
119
/**
120      * Null-acceptability indicator passed as 3rd arg to addWhereClause( String )
121      * @deprecated Use addWhere() methods instead of addWhereClause() methods.
122      */

123     public static final boolean NULL_OK = true;
124
125     /**
126      * Null-acceptability indicator passed as 3rd arg to addWhereClause( String )
127      * @deprecated Use addWhere() methods instead of addWhereClause() methods.
128      */

129     public static final boolean NOT_NULL = false;
130
131     /**
132      * Wild-card indicator passed as 4th arg to addWhereClause( String )
133      * @deprecated Use addWhere() methods instead of addWhereClause() methods.
134      */

135     public static final boolean EXACT_MATCH = true;
136
137     /**
138      * Wild-card indicator passed as 4th arg to addWhereClause( String )
139      * @deprecated Use addWhere() methods instead of addWhereClause() methods.
140      */

141     public static final boolean NOT_EXACT = false;
142     // Default inexact string match keyword (e.g. can be MATCHES or LIKE)
143
public static final String JavaDoc DEFAULT_MATCHES_KEYWORD = "MATCHES";
144     private String JavaDoc likeKeyword = DEFAULT_MATCHES_KEYWORD;
145     // Default inexact string wildcard (e.g. can be * or %)
146
public static final String JavaDoc DEFAULT_WILDCARD = "*";
147     private String JavaDoc wildcard = DEFAULT_WILDCARD;
148     // WebDocWf extension for extended wildcard support
149
// The following lines have been added:
150
// Do NOT use "\" or "\\" or "\\\\" ... as wildcard/escape characters
151
// this would lead to runtime errrors because of multiple string parsing in the DODS code
152
public static final String JavaDoc DEFAULT_SINGLE_WILDCARD = "_";
153     public static final String JavaDoc DEFAULT_SINGLE_WILDCARD_ESCAPE = "?";
154     public static final String JavaDoc DEFAULT_WILDCARD_ESCAPE = "?";
155     public static final String JavaDoc DEFAULT_WILDCARD_ESCAPE_CLAUSE = "ESCAPE '?'";
156     public static final String JavaDoc DEFAULT_USER_WILDCARD = "*";
157     public static final String JavaDoc DEFAULT_USER_SINGLE_WILDCARD = "?";
158     public static final String JavaDoc DEFAULT_USER_SINGLE_WILDCARD_ESCAPE = "?";
159     public static final String JavaDoc DEFAULT_USER_WILDCARD_ESCAPE = "?";
160     public static final boolean DEFAULT_USER_APPEND_WILDCARD = false;
161     public static final boolean DEFAULT_USER_TRIM_STRING = false;
162     public String JavaDoc userConfigWildcard = DEFAULT_USER_WILDCARD;
163     public String JavaDoc userConfigSingleWildcard = DEFAULT_USER_SINGLE_WILDCARD;
164     public String JavaDoc userConfigSingleWildcardEscape = DEFAULT_USER_SINGLE_WILDCARD_ESCAPE;
165     public String JavaDoc userConfigWildcardEscape = DEFAULT_USER_WILDCARD_ESCAPE;
166     // end of first part WebDocWf extension for extended wildcard support
167
// See debug() method.
168
static private boolean debugAllSQL = false;
169     private boolean debugSQL = false;
170     // true if it is used at least one method that provides possibility of join between tables
171
private boolean multiTableJoin = false;
172     private boolean unionTableJoin = false;
173     // true if select <table>.primaryKey can be performed
174
private boolean preventPrimaryKeySelect = false;
175     // WebDocWf extension cursor-handling
176
// Value -1 means not defined
177
private int iCurrentFetchSize = -1;
178     private static int iDefaultFetchSize = -1;
179     private int iCurrentQueryTimeout = CacheConstants.DEFAULT_QUERY_TIMEOUT;
180     private static int iDefaultQueryTimeout = CacheConstants.DEFAULT_QUERY_TIMEOUT;
181     // WebDocWf extension cursor-handling end
182
private String JavaDoc databaseName = null;
183
184     private int DEFAULT_RS_TYPE = -100;
185     private int DEFAULT_RS_CONCURRENCY = -100;
186     private int iResultSetConcurrency = DEFAULT_RS_CONCURRENCY;
187     private int iResultSetType = DEFAULT_RS_TYPE;
188     
189     private String JavaDoc customNotEqualSqlOperator = null;
190     
191     private boolean caseInsensitiveDatabase = CommonConstants.DEFAULT_CASE_INSENSITIVE_DATABASE;
192     
193     /*
194      The DODS (Data Object Design Studio) development tool
195      generates data-layer source code which uses QueryBuilder objects
196      to perform database queries.
197      This is the original (1st, old) purpose of QueryBuilder.
198      QueryBuilder can also be used by application developers
199      to perform straight SQL queries. Certain static final data members
200      of the DO classes generated by DODS are used to specify the tables and columns
201      for the query. This allows developers to write straight SQL queries
202      but still enjoy the compile-time checking.
203      This is the 2nd (new) purpose of QueryBuilder.
204      ================= Usage 1: DODS generated code =================================
205      NOTE! Application developers, please see "Usage 2" section below.
206      1st, old, String-based style (used by DODS-generated Query classes):
207      Query creation:
208      The ctor takes a String tablename
209      (and optional String list of comma-separated column names).
210      E.g.:
211      // In PersonQuery class:
212      QueryBuilder qb = new QueryBuilder( "person", "person.LastName" );
213      addWhereClause() methods:
214      A where-clause is added by calling one of the addWhereClause() methods
215      which takes a String column name a String value for comparison.
216      Because table and column names are Strings, the application code
217      can become out-of-sync with a changing database schema,
218      and the developer gets no warning from the compiler.
219      This scheme is ok for use by DODS since the application code
220      (DO, Query classes) are (re)generated every time the
221      schema (the DODS project file) is changed.
222      However, this scheme is non-ideal for manual coding.
223      E.g.:
224      // In PersonQuery class:
225      qb.addWhereClause( "FirstName", "Bob", QueryBuilder.EQUAL );
226      Obtaining results:
227      The results of the query are returned as a JDBC ResultSet.
228      Column values are retrieved by their postion within each returned row,
229      or by the String name of the column in the returned row.
230      Again, no hope for compile-time checking.
231      E.g.:
232      // PersonQuery class creates a DBQuery object to run the query:
233      DBQuery dbQuery = DODS.getDatabaseManager().createQuery();
234      dbQuery.query( this ); // invokes PersonQuery.executeQuery();
235      // PersonQuery class extends Query and implements executeQuery():
236      ResultSet rs = qb.executeQuery( connection );
237      while ( rs.next() ) {
238      String lastname = rs.getString( 1 );
239      }
240      ================= Usage 2: Application Developers =============================
241      2nd, new, Object Oriented style (used by application developers):
242      Query creation:
243      The ctor takes a Vector of RDBColumn objects.
244      Each RDBColumn object knows which RDBTable it belongs to.
245      In each DO class generated by DODS, there is a static RDBColumn object
246      for each column in database table for the DO.
247      E.g.:
248      Vector fields = new Vector();
249      fields.addElement( PersonDO.LastName );
250      QueryBuilder qb = new QueryBuilder( fields );
251      Or:
252      QueryBuilder qb = new QueryBuilder();
253      qb.select( PersonDO.LastName );
254      addWhere() methods:
255      A where-clause is added by passing an RDBColumn object and a value.
256      Because objects (not Strings) are used to specify columns in the query,
257      errors in hand-written application code can be caught by the compiler.
258      E.g.:
259      qb.addWhere( PersonDO.FirstName, "Bob" );
260      Obtaining results:
261      The results of the query are returned as a series of RDBRow objects.
262      Each RDBRow contains an RDBColumnValue object for each returned column.
263      An RDBColumnValue object is retrieved from the RDBRow using
264      a one of the RDBColumn objects passed to the QueryBuilder ctor.
265      The value is extracted from an RDBColumnValue object via its
266      getString or getInteger (...) method.
267      These methods throw an exception if the application attempts to
268      extract an incorrect type for the RDBColumnValue.
269      E.g.:
270      RDBRow row;
271      while ( null != ( row = qb.getNextRow() ) ) {
272      String lastname = row.get( PersonDO.LastName ).getString();
273      }
274      qb.close(); // always release the resources
275      Note:
276      The templates used by the DODS sourceGenerator_Query class
277      could be converted to use this 2nd style.
278      */

279
280     /**
281      * Construct a QueryBuilder object that will return specified fields of a table.
282      * Style 2 (see above.)
283      *
284      * @param fields Vector of RDBColumn objects,
285      * one for each column to be returned. Fields can refer to different tables.
286      */

287     public QueryBuilder(Vector JavaDoc fields) {
288         init();
289         reset();
290         if (null != fields) {
291             selectedFields = (Vector JavaDoc) fields.clone();
292         }
293     }
294
295     private void init(){
296         try {
297             String JavaDoc value;
298
299             value=((StandardDatabaseManager)DODS.getDatabaseManager())
300                 .getDatabaseManagerConfiguration().getUserConfigWildcard();
301             if (value!= null) {
302                 userConfigWildcard = value;
303             }
304
305             value=((StandardDatabaseManager)DODS.getDatabaseManager())
306                 .getDatabaseManagerConfiguration().getUserConfigSingleWildcard();
307             if (value!= null) {
308                 userConfigSingleWildcard = value;
309             }
310
311             value=((StandardDatabaseManager)DODS.getDatabaseManager())
312                 .getDatabaseManagerConfiguration().getUserConfigSingleWildcardEscape();
313             if (value!= null) {
314                 userConfigSingleWildcardEscape = value;
315             }
316         } catch (Exception JavaDoc except) {}
317         initDefaultWildCards();
318         
319         try {
320             caseInsensitiveDatabase=((StandardLogicalDatabase)DODS.getDatabaseManager()
321                      .findLogicalDatabase(getDatabaseName())).getDatabaseConfiguration().isCaseInsensitiveDatabase();
322         } catch (Exception JavaDoc e) {
323             caseInsensitiveDatabase = CommonConstants.DEFAULT_CASE_INSENSITIVE_DATABASE;
324         }
325         
326         customNotEqualSqlOperator = null;
327         try {
328             String JavaDoc customNotEqualSqlOperatorStr = ((StandardLogicalDatabase)DODS.getDatabaseManager()
329                      .findLogicalDatabase(getDatabaseName())).getDriverProperty(DriverSpecificConstants.PARAMNAME_CUSTOM_NOT_EQUAL_SQL_OPERATOR);
330             if(customNotEqualSqlOperatorStr!=null) {
331                     customNotEqualSqlOperator=customNotEqualSqlOperatorStr;
332             }else {
333                 customNotEqualSqlOperator = DriverSpecificConstants.DEFAULT_CUSTOM_NOT_EQUAL_SQL_OPERATOR;
334             }
335         }catch(Exception JavaDoc e) {}
336         if(customNotEqualSqlOperator!=null) NOT_EQUAL=customNotEqualSqlOperator;
337     }
338
339     /**
340      * Construct a QueryBuilder object that will return specified fields of a table.
341      * Style 2 (see above.)
342      *
343      * @param fields array of RDBColumn objects,
344      * one for each column to be returned. Fields can refer to different tables.
345      */

346     public QueryBuilder(RDBColumn[] fields) {
347         init();
348         reset();
349         for (int i = 0; i < fields.length; i++) {
350             select(fields[i]);
351         }
352     }
353
354     /**
355      * Construct a QueryBuilder object.
356      * When no fields are specified in the constructor,
357      * you must use calls to select() to specify the RDBColumns
358      * that will be returned.
359      * This can be more convenient than constructing the Vector before
360      * calling the QueryBuilder(Vector) constructor.
361      * Style 2 (see above.)
362      */

363     public QueryBuilder() {
364         init();
365         reset();
366     }
367
368     /**
369      * Add a field to be returned by this QueryBuilder.
370      * Style 2 (see above.)
371      *
372      * @param field RDBColumn object to be returned.
373      * Fields can refer to different tables.
374      */

375     public void select(RDBColumn field) {
376         if (null == field) {
377             return;
378         }
379         for (int i = 0; i < selectedFields.size(); i++) {
380             if (field.equals((RDBColumn) selectedFields.elementAt(i))) {
381                 return;
382             }
383         }
384         selectedFields.addElement(field);
385     }
386
387     /**
388      * Returns an array of RDBRow objects.
389      *
390      * @return array of RDBRow objects.
391      * @exception ATException If the data is not accessible
392      * @exception BusinessRuleException If x is invalid.
393      * @see #getNextRow
394      * author Jay Gunter
395      */

396     public RDBRow[] getRows()
397         throws QueryException {
398         Vector JavaDoc v = new Vector JavaDoc();
399         RDBRow row;
400
401         while (null != (row = getNextRow())) {
402             v.addElement(row);
403         }
404         RDBRow[] ret = new RDBRow[ v.size() ];
405
406         v.copyInto(ret);
407         return ret;
408     }
409
410     /**
411      * Returns an RDBRow object containing the fields specified in the ctor.
412      * On first call, executes the query.
413      * NOTE: to use this method, the QueryBuilder object must be created
414      * using the
415      * QueryBuilder( RDBColumn[] )
416      * constructor.
417      *
418      * @return row the RDBRow representing 1 row from the ResultSet.
419      * @exception ATException If the data is not accessible
420      * @exception BusinessRuleException If x is invalid.
421      * author Jay Gunter
422      */

423     private DBQuery dbQuery = null;
424     private ResultSet JavaDoc rs = null;
425     private Boolean JavaDoc rsClosed = null;
426     private boolean done = false;
427     public RDBRow getNextRow() throws QueryException {
428         if (done) {
429             return null;
430         }
431         if (null == rs) {
432             try {
433                 if (null == dbQuery) {
434                     // May not be null if I later implement
435
// a ctor that takes a DBQuery.
436
dbQuery = DODS.getDatabaseManager().createQuery();
437                 }
438             } catch (Exception JavaDoc e) {
439                 throw new QueryException("SQL=[" + sql
440                                              + "]: Unable to create query",
441                                          e);
442             }
443             try {
444                 // invokes executeQuery which sets ResultSet rs
445
dbQuery.query(this);
446             } catch (Exception JavaDoc e) {
447                 throw new QueryException("SQL=[" + sql
448                                              + "]: Unable to run query",
449                                          e);
450             }
451             if (null == rs) {
452                 throw new QueryException("No ResultSet for Query.");
453             }
454         }
455         try {
456             if (!rs.next()) {
457                 // ResultSet.next() only returns false once.
458
// After that, drivers typically throw "result set empty" exception.
459
// That isn't very friendly or useful to an application programmer.
460
// Setting done=true allows us to just keep returning nulls.
461
done = true;
462                 rsClosed=new Boolean JavaDoc(true);
463                 rs.close();
464                 dbQuery.release();
465                 return null;
466             }
467         } catch (Exception JavaDoc e) {
468             throw new QueryException("SQL=[" + sql
469                                          + "]: Unable to get query results",
470                                      e);
471         }
472         RDBColumnValue[] vals = new RDBColumnValue[ selectedFields.size() ];
473         RDBColumn field = null;
474
475         for (int i = 0; i < selectedFields.size(); i++) {
476             try {
477                 field = (RDBColumn) selectedFields.elementAt(i);
478                 vals[i] = new RDBColumnValue(field, rs.getObject(i + 1));
479             } catch (Exception JavaDoc e) {
480                 throw new QueryException("SQL=[" + sql
481                                              + "]: Unable to get query result for column " + field,
482                                          e);
483             }
484         }
485         return new RDBRow(vals);
486     }
487
488     /**
489      * WARNING:
490      * This method is disabled and should never be called.
491      * It's implementation is forced by the Query interface.
492      * Use getNextRow instead().
493      */

494     public Object JavaDoc next(ResultSet JavaDoc rs)
495         throws SQLException JavaDoc, ObjectIdException {
496         return null;
497     }
498
499     // /////////////////////////////////////////////////////////////////////////////
500
// / Constructors used by DODS-generated Query classes. ////////////////////////
501
// /////////////////////////////////////////////////////////////////////////////
502
/**
503      * Construct a QueryBuilder object that will return all fields of a table.
504      * Style 1 (see above.)
505      * WARNING: QueryBuilder objects created with this constructor
506      * cannot be used with the getNextRow() method.
507      * @see #getNextRow
508      *
509      * @param tableName Name of the table on which to perform the SQL 'select'.
510      */

511     public QueryBuilder(String JavaDoc tableName) {
512         this(tableName, tableName + ".*");
513     }
514
515     /**
516      * Construct a QueryBuilder object that will return specified fields of a table.
517      * Style 1 (see above.)
518      *
519      * @param tableName Name of the table on which to perform the SQL 'select'.
520      * @param fieldList Comma-separated string of field names to retrieve.
521      */

522     public QueryBuilder(String JavaDoc tableName, String JavaDoc fieldList) {
523         reset();
524         init();
525         /* mainTableName = tableName.toLowerCase(); */
526         mainTableName = tableName;
527         storeTableName(mainTableName);
528         selectClause = fieldList;
529     }
530
531     /**
532      * Determine table name of column.
533      * For example, we return 'tableX' from the following column specification:
534      * UPPER(tableX.columnY)
535      * WARNING: trickier column specifications will cause this method to fail.
536      *
537      * @param column A column (field) name, possibly with a leading table name.
538      */

539     private String JavaDoc getTableName(String JavaDoc column) {
540         int offset = 0;
541         int end = 0;
542         String JavaDoc str = column;
543         int index = str.lastIndexOf("(");
544
545         if (-1 != index) {
546             str = str.substring(index + 1);
547         }
548         index = str.indexOf(")");
549         if (-1 != index) {
550             str = str.substring(0, index);
551         }
552         index = str.indexOf(".");
553         if (-1 == index) {
554             return null;
555         }
556         return str.substring(0, index);
557     }
558
559     /**
560      * Returnes multiTableJoin attribute.
561      *
562      * @return multiTableJoin attribute.
563      */

564     public boolean isMultiTableJoin() {
565         return multiTableJoin;
566     }
567     
568     /**
569      * Returnes unionTableJoin attribute.
570      *
571      * @return unionTableJoin attribute.
572      */

573     public boolean isUnionTableJoin() {
574         return unionTableJoin;
575     }
576     /**
577      * Returnes preventPrimaryKeySelect attribute.
578      *
579      * @return preventPrimaryKeySelect attribute.
580      */

581     public boolean getPreventPrimaryKeySelect() {
582         return preventPrimaryKeySelect;
583     }
584
585     /**
586      * Resets selected fields.
587      */

588     public void resetSelectedFields() {
589         selectedFields = new Vector JavaDoc();
590         selectClause = "";
591     }
592
593     /**
594      * Store all table names that occur as prefix of column specifications.
595      * All table names must appear in the "from" clause.
596      *
597      * @param column A column (field) name, possibly with a leading table name.
598      */

599     private void storeTableNameForColumn(String JavaDoc column) {
600         String JavaDoc table = getTableName(column);
601
602         storeTableName(table);
603     }
604
605     /**
606      * Store all table names that occur as prefix of column specifications.
607      * All table names must appear in the "from" clause.
608      *
609      * @param column RDBColumn containing table name.
610      */

611     private void storeTableNameForColumn(RDBColumn column) {
612         storeTableName(column.getTableName());
613     }
614
615     /**
616      * Store a table name.
617      * All table names must appear in the "from" clause.
618      *
619      * @param table name.
620      */

621     private void storeTableName(String JavaDoc table) {
622         if (null != table) {
623             tableNames.put(table, "");
624         }
625     }
626
627     /**
628      * <PRE>
629      * Specify that the next conditional expression (where-clause)
630      * should be preceded by OR instead of AND. (AND is the default).
631      * For example:
632      * addWhereClause( "person.fname", "Bob", EQUAL );
633      * addWhereClause( "person.lname", "Smith", EQUAL );
634      * produces
635      * person.fname = 'Bob' AND person.lname = 'Smith'
636      * But:
637      * addWhereClause( "person.fname", "Bob", EQUAL );
638      * addWhereOr();
639      * addWhereClause( "person.lname", "Smith", EQUAL );
640      * produces
641      * person.fname = 'Bob' OR person.lname = 'Smith'
642      * Disallows 'OR OR'.
643      * Trailing ORs are removed by prepareStatement().
644      *
645      * </PRE>
646      *
647      * author Jay Gunter
648      */

649     public void addWhereOr() {
650         int n = whereClauses.size();
651
652         if (0 == n) {
653             return;
654         }
655         String JavaDoc prev = (String JavaDoc) whereClauses.lastElement();
656
657         if (!OR.equals(prev)) {
658             whereClauses.addElement(OR);
659         }
660     }
661
662     /**
663      * Specify that the next conditional expression (where-clause)
664      * should be preceded by '('.
665      * Trailing OPEN_PARENs are removed by prepareStatement().
666      *
667      * author Jay Gunter
668      */

669     public void addWhereOpenParen() {
670         whereClauses.addElement(OPEN_PAREN);
671
672         /*
673          for ( int i = 0; i < whereClauses.size(); i++ ) {
674          System.err.println("whereClauses.elementAt("+i+")="+whereClauses.elementAt(i));
675          }
676          */

677     }
678
679     /**
680      * Close a previous addWhereOpenParen.
681      * Automatically disallows bad sequences like 'OR )' and '( )'.
682      *
683      * author Jay Gunter
684      */

685     public void addWhereCloseParen() {
686         int n = whereClauses.size();
687
688         if (0 == n) {
689             return;
690         }
691         String JavaDoc prev = (String JavaDoc) whereClauses.lastElement();
692
693         if (!(OR.equals(prev) || OPEN_PAREN.equals(prev))) {
694             whereClauses.addElement(CLOSE_PAREN);
695         }
696     }
697
698     /**
699      * Add a where-clause that compares a column against a String.
700      * @param column A column (field) name to use as a search constraint.
701      * @param value int value to compare against.
702      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
703      *
704      * author Jay Gunter
705      */

706     public void addWhere(RDBColumn column, GenericDO value, String JavaDoc cmp_op) {
707         BigDecimal JavaDoc id = null;
708
709         if (null != value) {
710             id = value.get_OId().toBigDecimal();
711         }
712         _addWhereClause(column, id, cmp_op);
713     }
714
715     /**
716      * Add a where-clause that compares a column against a byte array.
717      * @param column A column (field) name to use as a search constraint.
718      * @param value byte array to compare against.
719      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
720      *
721      * author Jay Gunter
722      */

723     public void addWhere(RDBColumn column, byte[] value, String JavaDoc cmp_op) {
724         String JavaDoc v = null;
725
726         if (null != value) {
727             v = new String JavaDoc(value);
728         }
729         _addWhereClause(column, v, cmp_op);
730     }
731
732     /**
733      * Add a where-clause that compares a column against a String.
734      * @param column A column (field) name to use as a search constraint.
735      * @param value int value to compare against.
736      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
737      *
738      * author Jay Gunter
739      */

740     public void addWhere(RDBColumn column, java.sql.Time JavaDoc value, String JavaDoc cmp_op) {
741         _addWhereClause(column, value, cmp_op);
742     }
743
744     /**
745      * Add a where-clause that compares a column against a String.
746      * @param column A column (field) name to use as a search constraint.
747      * @param value int value to compare against.
748      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
749      *
750      * author Jay Gunter
751      */

752     public void addWhere(RDBColumn column, java.sql.Timestamp JavaDoc value, String JavaDoc cmp_op) {
753         _addWhereClause(column, value, cmp_op);
754     }
755
756     /**
757      * Add a where-clause that compares a column against a String.
758      * @param column A column (field) name to use as a search constraint.
759      * @param value long value to compare against.
760      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
761      *
762      * author Jay Gunter
763      */

764     public void addWhere(RDBColumn column, long value, String JavaDoc cmp_op) {
765         _addWhereClause(column, new Long JavaDoc(value), cmp_op);
766     }
767
768     /**
769      * Add a where-clause that compares a column against a String.
770      * @param column A column (field) name to use as a search constraint.
771      * @param value double value to compare against.
772      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
773      *
774      * author Jay Gunter
775      */

776     public void addWhere(RDBColumn column, double value, String JavaDoc cmp_op) {
777         _addWhereClause(column, new Double JavaDoc(value), cmp_op);
778     }
779
780     /**
781      * Add a where-clause that compares a column against a String.
782      * @param column A column (field) name to use as a search constraint.
783      * @param value float value to compare against.
784      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
785      *
786      * author Jay Gunter
787      */

788     public void addWhere(RDBColumn column, float value, String JavaDoc cmp_op) {
789         _addWhereClause(column, new Float JavaDoc(value), cmp_op);
790     }
791
792     /**
793      * Add a where-clause that compares a column against a String.
794      * @param column A column (field) name to use as a search constraint.
795      * @param value BigDecimal value to compare against.
796      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
797      *
798      * author Jay Gunter
799      */

800     public void addWhere(RDBColumn column, BigDecimal JavaDoc value, String JavaDoc cmp_op) {
801         _addWhereClause(column, value, cmp_op);
802     }
803
804     /**
805      * Add a where-clause that compares a column against a String.
806      * @param column A column (field) name to use as a search constraint.
807      * @param value int value to compare against.
808      * @param cmp_op The comparison operator to use: QueryBuilder.EQUAL, ...
809      *
810      * author Jay Gunter
811      */

812     public void addWhere(RDBColumn column, int value, String JavaDoc cmp_op) {
813