View Javadoc

1   package org.apache.torque.util;
2   
3   /*
4    * Copyright 2001-2004 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License")
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *     http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import java.io.Serializable;
20  import java.lang.reflect.Array;
21  import java.math.BigDecimal;
22  import java.util.ArrayList;
23  import java.util.Arrays;
24  import java.util.GregorianCalendar;
25  import java.util.HashMap;
26  import java.util.Hashtable;
27  import java.util.Iterator;
28  import java.util.List;
29  import java.util.Map;
30  
31  import org.apache.commons.collections.OrderedMap;
32  import org.apache.commons.collections.map.ListOrderedMap;
33  import org.apache.commons.lang.StringUtils;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.apache.torque.Torque;
37  import org.apache.torque.adapter.DB;
38  import org.apache.torque.om.DateKey;
39  import org.apache.torque.om.ObjectKey;
40  
41  /***
42   * This is a utility class that is used for retrieving different types
43   * of values from a hashtable based on a simple name string.  This
44   * class is meant to minimize the amount of casting that needs to be
45   * done when working with Hashtables.
46   *
47   * NOTE: other methods will be added as needed and as time permits.
48   *
49   * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
50   * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
51   * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
52   * @author <a href="mailto:eric@dobbse.net">Eric Dobbs</a>
53   * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
54   * @author <a href="mailto:sam@neurogrid.com">Sam Joseph</a>
55   * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
56   * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
57   * @version $Id: Criteria.java,v 1.47 2005/07/02 15:22:32 tfischer Exp $
58   */
59  public class Criteria extends Hashtable
60  {
61  
62      /*** Comparison type. */
63      public static final SqlEnum EQUAL = SqlEnum.EQUAL;
64  
65      /*** Comparison type. */
66      public static final SqlEnum NOT_EQUAL = SqlEnum.NOT_EQUAL;
67  
68      /*** Comparison type. */
69      public static final SqlEnum ALT_NOT_EQUAL = SqlEnum.ALT_NOT_EQUAL;
70  
71      /*** Comparison type. */
72      public static final SqlEnum GREATER_THAN = SqlEnum.GREATER_THAN;
73  
74      /*** Comparison type. */
75      public static final SqlEnum LESS_THAN = SqlEnum.LESS_THAN;
76  
77      /*** Comparison type. */
78      public static final SqlEnum GREATER_EQUAL = SqlEnum.GREATER_EQUAL;
79  
80      /*** Comparison type. */
81      public static final SqlEnum LESS_EQUAL = SqlEnum.LESS_EQUAL;
82  
83      /*** Comparison type. */
84      public static final SqlEnum LIKE = SqlEnum.LIKE;
85  
86      /*** Comparison type. */
87      public static final SqlEnum NOT_LIKE = SqlEnum.NOT_LIKE;
88  
89      /*** Comparison type. */
90      public static final SqlEnum ILIKE = SqlEnum.ILIKE;
91  
92      /*** Comparison type. */
93      public static final SqlEnum NOT_ILIKE = SqlEnum.NOT_ILIKE;
94  
95      /*** Comparison type. */
96      public static final SqlEnum CUSTOM = SqlEnum.CUSTOM;
97  
98      /*** Comparison type. */
99      public static final SqlEnum DISTINCT = SqlEnum.DISTINCT;
100 
101     /*** Comparison type. */
102     public static final SqlEnum IN = SqlEnum.IN;
103 
104     /*** Comparison type. */
105     public static final SqlEnum NOT_IN = SqlEnum.NOT_IN;
106 
107     /*** Comparison type. */
108     public static final SqlEnum ALL = SqlEnum.ALL;
109 
110     /*** Comparison type. */
111     public static final SqlEnum JOIN = SqlEnum.JOIN;
112 
113     /*** &quot;Order by&quot; qualifier - ascending */
114     private static final SqlEnum ASC = SqlEnum.ASC;
115 
116     /*** &quot;Order by&quot; qualifier - descending */
117     private static final SqlEnum DESC = SqlEnum.DESC;
118 
119     /*** &quot;IS NULL&quot; null comparison */
120     public static final SqlEnum ISNULL = SqlEnum.ISNULL;
121 
122     /*** &quot;IS NOT NULL&quot; null comparison */
123     public static final SqlEnum ISNOTNULL = SqlEnum.ISNOTNULL;
124 
125     /*** &quot;CURRENT_DATE&quot; ANSI SQL function */
126     public static final SqlEnum CURRENT_DATE = SqlEnum.CURRENT_DATE;
127 
128     /*** &quot;CURRENT_TIME&quot; ANSI SQL function */
129     public static final SqlEnum CURRENT_TIME = SqlEnum.CURRENT_TIME;
130 
131     /*** &quot;LEFT JOIN&quot; SQL statement */
132     public static final SqlEnum LEFT_JOIN = SqlEnum.LEFT_JOIN;
133 
134     /*** &quot;RIGHT JOIN&quot; SQL statement */
135     public static final SqlEnum RIGHT_JOIN = SqlEnum.RIGHT_JOIN;
136   
137     /*** &quot;INNER JOIN&quot; SQL statement */
138     public static final SqlEnum INNER_JOIN = SqlEnum.INNER_JOIN;
139     
140     private static final int DEFAULT_CAPACITY = 10;
141 
142     private boolean ignoreCase = false;
143     private boolean singleRecord = false;
144     private boolean cascade = false;
145     private UniqueList selectModifiers = new UniqueList();
146     private UniqueList selectColumns = new UniqueList();
147     private UniqueList orderByColumns = new UniqueList();
148     private UniqueList groupByColumns = new UniqueList();
149     private Criterion having = null;
150     private OrderedMap asColumns = ListOrderedMap.decorate(new HashMap());
151     private List joins = null;
152 
153     /*** The name of the database. */
154     private String dbName;
155 
156     /*** The name of the database as given in the contructor. */
157     private String originalDbName;
158 
159     /***
160      * To limit the number of rows to return.  <code>-1</code> means return all
161      * rows.
162      */
163     private int limit = -1;
164 
165     /*** To start the results at a row other than the first one. */
166     private int offset = 0;
167 
168     private HashMap aliases = null;
169 
170     private boolean useTransaction = false;
171 
172     /*** the log. */
173     private static Log log = LogFactory.getLog(Criteria.class);
174 
175     /***
176      * Creates a new instance with the default capacity.
177      */
178     public Criteria()
179     {
180         this(DEFAULT_CAPACITY);
181     }
182 
183     /***
184      * Creates a new instance with the specified capacity.
185      *
186      * @param initialCapacity An int.
187      */
188     public Criteria(int initialCapacity)
189     {
190         this(Torque.getDefaultDB(), initialCapacity);
191     }
192 
193     /***
194      * Creates a new instance with the default capacity which corresponds to
195      * the specified database.
196      *
197      * @param dbName The dabase name.
198      */
199     public Criteria(String dbName)
200     {
201         this(dbName, DEFAULT_CAPACITY);
202     }
203 
204     /***
205      * Creates a new instance with the specified capacity which corresponds to
206      * the specified database.
207      *
208      * @param dbName          The dabase name.
209      * @param initialCapacity The initial capacity.
210      */
211     public Criteria(String dbName, int initialCapacity)
212     {
213         super(initialCapacity);
214         this.dbName = dbName;
215         this.originalDbName = dbName;
216     }
217 
218     /***
219      * Brings this criteria back to its initial state, so that it
220      * can be reused as if it was new. Except if the criteria has grown in
221      * capacity, it is left at the current capacity.
222      */
223     public void clear()
224     {
225         super.clear();
226         ignoreCase = false;
227         singleRecord = false;
228         cascade = false;
229         selectModifiers.clear();
230         selectColumns.clear();
231         orderByColumns.clear();
232         groupByColumns.clear();
233         having = null;
234         asColumns.clear();
235         joins = null;
236         dbName = originalDbName;
237         offset = 0;
238         limit = -1;
239         aliases = null;
240         useTransaction = false;
241     }
242 
243     /***
244      * Add an AS clause to the select columns. Usage:
245      * <p>
246      * <code>
247      *
248      * Criteria myCrit = new Criteria();
249      * myCrit.addAsColumn(&quot;alias&quot;, &quot;ALIAS(&quot;+MyPeer.ID+&quot;)&quot;);
250      *
251      * </code>
252      *
253      * @param name  wanted Name of the column
254      * @param clause SQL clause to select from the table
255      *
256      * If the name already exists, it is replaced by the new clause.
257      *
258      * @return A modified Criteria object.
259      */
260     public Criteria addAsColumn(String name, String clause)
261     {
262         asColumns.put(name, clause);
263         return this;
264     }
265 
266     /***
267      * Get the column aliases.
268      *
269      * @return A Map which map the column alias names
270      * to the alias clauses.
271      */
272     public Map getAsColumns()
273     {
274         return asColumns;
275     }
276 
277     /***
278      * Allows one to specify an alias for a table that can
279      * be used in various parts of the SQL.
280      *
281      * @param alias a <code>String</code> value
282      * @param table a <code>String</code> value
283      */
284     public void addAlias(String alias, String table)
285     {
286         if (aliases == null)
287         {
288             aliases = new HashMap(8);
289         }
290         aliases.put(alias, table);
291     }
292 
293     /***
294      * Returns the table name associated with an alias.
295      *
296      * @param alias a <code>String</code> value
297      * @return a <code>String</code> value
298      */
299     public String getTableForAlias(String alias)
300     {
301         if (aliases == null)
302         {
303             return null;
304         }
305         return (String) aliases.get(alias);
306     }
307 
308     /***
309      * Does this Criteria Object contain the specified key?
310      *
311      * @param table The name of the table.
312      * @param column The name of the column.
313      * @return True if this Criteria Object contain the specified key.
314      */
315     public boolean containsKey(String table, String column)
316     {
317         return containsKey(table + '.' + column);
318     }
319 
320     /***
321      * Convenience method to return value as a boolean.
322      *
323      * @param column String name of column.
324      * @return A boolean.
325      */
326     public boolean getBoolean(String column)
327     {
328         return ((Boolean) getCriterion(column).getValue()).booleanValue();
329     }
330 
331     /***
332      * Convenience method to return value as a boolean.
333      *
334      * @param table String name of table.
335      * @param column String name of column.
336      * @return A boolean.
337      */
338     public boolean getBoolean(String table, String column)
339     {
340         return getBoolean(new StringBuffer(table.length() + column.length() + 1)
341                 .append(table).append('.').append(column)
342                 .toString());
343     }
344 
345     /***
346      * Will force the sql represented by this criteria to be executed within
347      * a transaction.  This is here primarily to support the oid type in
348      * postgresql.  Though it can be used to require any single sql statement
349      * to use a transaction.
350      */
351     public void setUseTransaction(boolean v)
352     {
353         useTransaction = v;
354     }
355 
356     /***
357      * called by BasePeer to determine whether the sql command specified by
358      * this criteria must be wrapped in a transaction.
359      *
360      * @return a <code>boolean</code> value
361      */
362     protected boolean isUseTransaction()
363     {
364         return useTransaction;
365     }
366 
367     /***
368      * Method to return criteria related to columns in a table.
369      *
370      * @param column String name of column.
371      * @return A Criterion.
372      */
373     public Criterion getCriterion(String column)
374     {
375         return (Criterion) super.get(column);
376     }
377 
378     /***
379      * Method to return criteria related to a column in a table.
380      *
381      * @param table String name of table.
382      * @param column String name of column.
383      * @return A Criterion.
384      */
385     public Criterion getCriterion(String table, String column)
386     {
387         return getCriterion(
388                 new StringBuffer(table.length() + column.length() + 1)
389                 .append(table).append('.').append(column)
390                 .toString());
391     }
392 
393     /***
394      * Method to return criterion that is not added automatically
395      * to this Criteria.  This can be used to chain the
396      * Criterions to form a more complex where clause.
397      *
398      * @param column String full name of column (for example TABLE.COLUMN).
399      * @return A Criterion.
400      */
401     public Criterion getNewCriterion(String column, Object value,
402             SqlEnum comparison)
403     {
404         return new Criterion(column, value, comparison);
405     }
406 
407     /***
408      * Method to return criterion that is not added automatically
409      * to this Criteria.  This can be used to chain the
410      * Criterions to form a more complex where clause.
411      *
412      * @param table String name of table.
413      * @param column String name of column.
414      * @return A Criterion.
415      */
416     public Criterion getNewCriterion(String table, String column,
417             Object value, SqlEnum comparison)
418     {
419         return new Criterion(table, column, value, comparison);
420     }
421 
422     /***
423      * This method adds a prepared Criterion object to the Criteria.
424      * You can get a new, empty Criterion object with the
425      * getNewCriterion() method. If a criterion for the requested column
426      * already exists, it is replaced. This is used as follows:
427      *
428      * <p>
429      * <code>
430      * Criteria crit = new Criteria();
431      * Criteria.Criterion c = crit
432      * .getNewCriterion(BasePeer.ID, new Integer(5), Criteria.LESS_THAN);
433      * crit.add(c);
434      * </code>
435      *
436      * @param c A Criterion object
437      *
438      * @return A modified Criteria object.
439      */
440     public Criteria add(Criterion c)
441     {
442         StringBuffer sb = new StringBuffer(c.getTable().length()
443                 + c.getColumn().length() + 1);
444         sb.append(c.getTable());
445         sb.append('.');
446         sb.append(c.getColumn());
447         super.put(sb.toString(), c);
448         return this;
449     }
450 
451     /***
452      * Method to return a String table name.
453      *
454      * @param name A String with the name of the key.
455      * @return A String with the value of the object at key.
456      */
457     public String getColumnName(String name)
458     {
459         return getCriterion(name).getColumn();
460     }
461 
462     /***
463      * Method to return a comparison String.
464      *
465      * @param key String name of the key.
466      * @return A String with the value of the object at key.
467      */
468     public SqlEnum getComparison(String key)
469     {
470         return getCriterion(key).getComparison();
471     }
472 
473     /***
474      * Method to return a comparison String.
475      *
476      * @param table String name of table.
477      * @param column String name of column.
478      * @return A String with the value of the object at key.
479      */
480     public SqlEnum getComparison(String table, String column)
481     {
482         return getComparison(
483                 new StringBuffer(table.length() + column.length() + 1)
484                 .append(table).append('.').append(column)
485                 .toString());
486     }
487 
488     /***
489      * Convenience method to return a Date.
490      *
491      * @param name column name (TABLE.COLUMN)
492      * @return A java.util.Date with the value of object at key.
493      */
494     public java.util.Date getDate(String name)
495     {
496         return (java.util.Date) getCriterion(name).getValue();
497     }
498 
499     /***
500      * Convenience method to return a Date.
501      *
502      * @param table String name of table.
503      * @param column String name of column.
504      * @return A java.util.Date with the value of object at key.
505      */
506     public java.util.Date getDate(String table, String column)
507     {
508         return getDate(
509                 new StringBuffer(table.length() + column.length() + 1)
510                 .append(table).append('.').append(column)
511                 .toString());
512     }
513 
514     /***
515      * Get the Database(Map) name.
516      *
517      * @return A String with the Database(Map) name.  By default, this
518      * is PoolBrokerService.DEFAULT.
519      */
520     public String getDbName()
521     {
522         return dbName;
523     }
524 
525     /***
526      * Set the DatabaseMap name.  If <code>null</code> is supplied, uses value
527      * provided by <code>Torque.getDefaultDB()</code>.
528      *
529      * @param dbName A String with the Database(Map) name.
530      */
531     public void setDbName(String dbName)
532     {
533         this.dbName = (dbName == null ? Torque.getDefaultDB() : dbName.trim());
534     }
535 
536     /***
537      * Convenience method to return a double.
538      *
539      * @param name A String with the name of the key.
540      * @return A double with the value of object at key.
541      */
542     public double getDouble(String name)
543     {
544         Object obj = getCriterion(name).getValue();
545         if (obj instanceof String)
546         {
547             return new Double((String) obj).doubleValue();
548         }
549         return ((Double) obj).doubleValue();
550     }
551 
552     /***
553      * Convenience method to return a double.
554      *
555      * @param table String name of table.
556      * @param column String name of column.
557      * @return A double with the value of object at key.
558      */
559     public double getDouble(String table, String column)
560     {
561         return getDouble(new StringBuffer(table.length() + column.length() + 1)
562                 .append(table).append('.').append(column)
563                 .toString());
564     }
565 
566     /***
567      * Convenience method to return a float.
568      *
569      * @param name A String with the name of the key.
570      * @return A float with the value of object at key.
571      */
572     public float getFloat(String name)
573     {
574         Object obj = getCriterion(name).getValue();
575         if (obj instanceof String)
576         {
577             return new Float((String) obj).floatValue();
578         }
579         return ((Float) obj).floatValue();
580     }
581 
582     /***
583      * Convenience method to return a float.
584      *
585      * @param table String name of table.
586      * @param column String name of column.
587      * @return A float with the value of object at key.
588      */
589     public float getFloat(String table, String column)
590     {
591         return getFloat(new StringBuffer(table.length() + column.length() + 1)
592                 .append(table).append('.').append(column)
593                 .toString());
594     }
595 
596     /***
597      * Convenience method to return an Integer.
598      *
599      * @param name A String with the name of the key.
600      * @return An Integer with the value of object at key.
601      */
602     public Integer getInteger(String name)
603     {
604         Object obj = getCriterion(name).getValue();
605         if (obj instanceof String)
606         {
607             return new Integer((String) obj);
608         }
609         return ((Integer) obj);
610     }
611 
612     /***
613      * Convenience method to return an Integer.
614      *
615      * @param table String name of table.
616      * @param column String name of column.
617      * @return An Integer with the value of object at key.
618      */
619     public Integer getInteger(String table, String column)
620     {
621         return getInteger(
622                 new StringBuffer(table.length() + column.length() + 1)
623                 .append(table).append('.').append(column)
624                 .toString());
625     }
626 
627     /***
628      * Convenience method to return an int.
629      *
630      * @param name A String with the name of the key.
631      * @return An int with the value of object at key.
632      */
633     public int getInt(String name)
634     {
635         Object obj = getCriterion(name).getValue();
636         if (obj instanceof String)
637         {
638             return new Integer((String) obj).intValue();
639         }
640         return ((Integer) obj).intValue();
641     }
642 
643     /***
644      * Convenience method to return an int.
645      *
646      * @param table String name of table.
647      * @param column String name of column.
648      * @return An int with the value of object at key.
649      */
650     public int getInt(String table, String column)
651     {
652         return getInt(
653                 new StringBuffer(table.length() + column.length() + 1)
654                 .append(table).append('.').append(column)
655                 .toString());
656     }
657 
658     /***
659      * Convenience method to return a BigDecimal.
660      *
661      * @param name A String with the name of the key.
662      * @return A BigDecimal with the value of object at key.
663      */
664     public BigDecimal getBigDecimal(String name)
665     {
666         Object obj = getCriterion(name).getValue();
667         if (obj instanceof String)
668         {
669             return new BigDecimal((String) obj);
670         }
671         return (BigDecimal) obj;
672     }
673 
674     /***
675      * Convenience method to return a BigDecimal.
676      *
677      * @param table String name of table.
678      * @param column String name of column.
679      * @return A BigDecimal with the value of object at key.
680      */
681     public BigDecimal getBigDecimal(String table, String column)
682     {
683         return getBigDecimal(
684                 new StringBuffer(table.length() + column.length() + 1)
685                 .append(table).append('.').append(column)
686                 .toString());
687     }
688 
689     /***
690      * Convenience method to return a long.
691      *
692      * @param name A String with the name of the key.
693      * @return A long with the value of object at key.
694      */
695     public long getLong(String name)
696     {
697         Object obj = getCriterion(name).getValue();
698         if (obj instanceof String)
699         {
700             return new Long((String) obj).longValue();
701         }
702         return ((Long) obj).longValue();
703     }
704 
705     /***
706      * Convenience method to return a long.
707      *
708      * @param table String name of table.
709      * @param column String name of column.
710      * @return A long with the value of object at key.
711      */
712     public long getLong(String table, String column)
713     {
714         return getLong(
715                 new StringBuffer(table.length() + column.length() + 1)
716                 .append(table).append('.').append(column)
717                 .toString());
718     }
719 
720     /***
721      * Convenience method to return a String.
722      *
723      * @param name A String with the name of the key.
724      * @return A String with the value of object at key.
725      */
726     public String getString(String name)
727     {
728         return (String) getCriterion(name).getValue();
729     }
730 
731     /***
732      * Convenience method to return a String.
733      *
734      * @param table String name of table.
735      * @param column String name of column.
736      * @return A String with the value of object at key.
737      */
738     public String getString(String table, String column)
739     {
740         return getString(
741                 new StringBuffer(table.length() + column.length() + 1)
742                 .append(table).append('.').append(column)
743                 .toString());
744     }
745 
746     /***
747      * Method to return a String table name.
748      *
749      * @param name A String with the name of the key.
750      * @return A String with the value of object at key.
751      */
752     public String getTableName(String name)
753     {
754         return getCriterion(name).getTable();
755     }
756 
757     /***
758      * Convenience method to return a List.
759      *
760      * @param name A String with the name of the key.
761      * @return A List with the value of object at key.
762      */
763     public List getList(String name)
764     {
765         return (List) getCriterion(name).getValue();
766     }
767 
768     /***
769      * Convenience method to return a List.
770      *
771      * @param table String name of table.
772      * @param column String name of column.
773      * @return A List with the value of object at key.
774      */
775     public List getList(String table, String column)
776     {
777         return getList(
778                 new StringBuffer(table.length() + column.length() + 1)
779                 .append(table).append('.').append(column)
780                 .toString());
781     }
782 
783     /***
784      * Method to return the value that was added to Criteria.
785      *
786      * @param name A String with the name of the key.
787      * @return An Object with the value of object at key.
788      */
789     public Object getValue(String name)
790     {
791         return getCriterion(name).getValue();
792     }
793 
794     /***
795      * Method to return the value that was added to Criteria.
796      *
797      * @param table String name of table.
798      * @param column String name of column.
799      * @return An Object with the value of object at key.
800      */
801     public Object getValue(String table, String column)
802     {
803         return getValue(
804                 new StringBuffer(table.length() + column.length() + 1)
805                 .append(table).append('.').append(column)
806                 .toString());
807     }
808 
809     /***
810      * Convenience method to return an ObjectKey.
811      *
812      * @param name A String with the name of the key.
813      * @return An ObjectKey with the value of object at key.
814      */
815     public ObjectKey getObjectKey(String name)
816     {
817         return (ObjectKey) getCriterion(name).getValue();
818     }
819 
820     /***
821      * Convenience method to return an ObjectKey.
822      *
823      * @param table String name of table.
824      * @param column String name of column.
825      * @return A String with the value of object at key.
826      */
827     public ObjectKey getObjectKey(String table, String column)
828     {
829         return getObjectKey(
830                 new StringBuffer(table.length() + column.length() + 1)
831                 .append(table).append('.').append(column)
832                 .toString());
833     }
834 
835     /***
836      * Overrides Hashtable get, so that the value placed in the
837      * Criterion is returned instead of the Criterion.
838      *
839      * @param key An Object.
840      * @return An Object.
841      */
842     public Object get(Object key)
843     {
844         return getValue((String) key);
845     }
846 
847     /***
848      * Overrides Hashtable put, so that this object is returned
849      * instead of the value previously in the Criteria object.
850      * The reason is so that it more closely matches the behavior
851      * of the add() methods. If you want to get the previous value
852      * then you should first Criteria.get() it yourself. Note, if
853      * you attempt to pass in an Object that is not a String, it will
854      * throw a NPE. The reason for this is that none of the add()
855      * methods support adding anything other than a String as a key.
856      *
857      * @param key An Object. Must be instanceof String!
858      * @param value An Object.
859      * @throws NullPointerException if key != String or key/value is null.
860      * @return Instance of self.
861      */
862     public Object put(Object key, Object value)
863     {
864         if (!(key instanceof String))
865         {
866             throw new NullPointerException(
867                     "Criteria: Key must be a String object.");
868         }
869         return add((String) key, value);
870     }
871 
872     /***
873      * Copies all of the mappings from the specified Map to this Criteria
874      * These mappings will replace any mappings that this Criteria had for any
875      * of the keys currently in the specified Map.
876      *
877      * if the map was another Criteria, its attributes are copied to this
878      * Criteria, overwriting previous settings.
879      *
880      * @param t Mappings to be stored in this map.
881      */
882     public synchronized void putAll(Map t)
883     {
884         Iterator i = t.entrySet().iterator();
885         while (i.hasNext())
886         {
887             Map.Entry e = (Map.Entry) i.next();
888             Object val = e.getValue();
889             if (val instanceof Criteria.Criterion)
890             {
891                 super.put(e.getKey(), val);
892             }
893             else
894             {
895                 put(e.getKey(), val);
896             }
897         }
898         if (t instanceof Criteria)
899         {
900             Criteria c = (Criteria) t;
901             this.joins = c.joins;
902         }
903         /* this would make a copy, not included
904            but might want to use some of it.
905            if (t instanceof Criteria)
906            {
907            Criteria c = (Criteria)t;
908            this.ignoreCase = c.ignoreCase;
909            this.singleRecord = c.singleRecord;
910            this.cascade = c.cascade;
911            this.selectModifiers = c.selectModifiers;
912            this.selectColumns = c.selectColumns;
913            this.orderByColumns = c.orderByColumns;
914            this.dbName = c.dbName;
915            this.limit = c.limit;
916            this.offset = c.offset;
917            this.aliases = c.aliases;
918            }
919         */
920     }
921 
922     /***
923      * This method adds a new criterion to the list of criterias. If a
924      * criterion for the requested column already exists, it is
925      * replaced. This is used as follows:
926      *
927      * <p>
928      * <code>
929      * Criteria crit = new Criteria().add(&quot;column&quot;,
930      *                                      &quot;value&quot;);
931      * </code>
932      *
933      * An EQUAL comparison is used for column and value.
934      *
935      * The name of the table must be used implicitly in the column name,
936      * so the Column name must be something like 'TABLE.id'. If you
937      * don't like this, you can use the add(table, column, value) method.
938      *
939      * @param column The column to run the comparison on
940      * @param value An Object.
941      *
942      * @return A modified Criteria object.
943      */
944     public Criteria add (String column, Object value)
945     {
946         add(column, value, EQUAL);
947         return this;
948     }
949 
950     /***
951      * This method adds a new criterion to the list of criterias.
952      * If a criterion for the requested column already exists, it is
953      * replaced. If is used as follow:
954      *
955      * <p>
956      * <code>
957      * Criteria crit = new Criteria().add(&quot;column&quot;,
958      *                                      &quot;value&quot;
959      *                                      &quot;Criterion.GREATER_THAN&quot;);
960      * </code>
961      *
962      * Any comparison can be used.
963      *
964      * The name of the table must be used implicitly in the column name,
965      * so the Column name must be something like 'TABLE.id'. If you
966      * don't like this, you can use the add(table, column, value) method.
967      *
968      * @param column The column to run the comparison on
969      * @param value An Object.
970      * @param comparison A String.
971      *
972      * @return A modified Criteria object.
973      */
974     public Criteria add(String column, Object value, SqlEnum comparison)
975     {
976         super.put(column, new Criterion(column, value, comparison));
977         return this;
978     }
979 
980     /***
981      * This method adds a new criterion to the list of criterias.
982      * If a criterion for the requested column already exists, it is
983      * replaced. If is used as follows:
984      *
985      * <p>
986      * <code>
987      * Criteria crit = new Criteria().add(&quot;table&quot;,
988      *                                      &quot;column&quot;,
989      *                                      &quot;value&quot;);
990      * </code>
991      *
992      * An EQUAL comparison is used for column and value.
993      *
994      * @param table Name of the table which contains the column
995      * @param column The column to run the comparison on
996      * @param value An Object.
997      *
998      * @return A modified Criteria object.
999      */
1000     public Criteria add(String table, String column, Object value)
1001     {
1002         add(table, column, value, EQUAL);
1003         return this;
1004     }
1005 
1006     /***
1007      * This method adds a new criterion to the list of criterias.
1008      * If a criterion for the requested column already exists, it is
1009      * replaced. If is used as follows:
1010      *
1011      * <p>
1012      * <code>
1013      * Criteria crit = new Criteria().add(&quot;table&quot;,
1014      *                                      &quot;column&quot;,
1015      *                                      &quot;value&quot;,
1016      *                                      &quot;Criterion.GREATER_THAN&quot;);
1017      * </code>
1018      *
1019      * Any comparison can be used.
1020      *
1021      * @param table Name of table which contains the column
1022      * @param column The column to run the comparison on
1023      * @param value An Object.
1024      * @param comparison String describing how to compare the column with
1025      *        the value
1026      * @return A modified Criteria object.
1027      */
1028     public Criteria add(String table,
1029             String column,
1030             Object value,
1031             SqlEnum comparison)
1032     {
1033         StringBuffer sb = new StringBuffer(table.length()
1034                 + column.length() + 1);
1035         sb.append(table);
1036         sb.append('.');
1037         sb.append(column);
1038         super.put(sb.toString(),
1039                 new Criterion(table, column, value, comparison));
1040         return this;
1041     }
1042 
1043     /***
1044      * Convenience method to add a boolean to Criteria.
1045      * Equal to
1046      *
1047      * <p>
1048      * <code>
1049      * add(column, new Boolean(value), EQUAL);
1050      * </code>
1051      *
1052      * @param column The column to run the comparison on
1053      * @param value A Boolean.
1054      *
1055      * @return A modified Criteria object.
1056      */
1057     public Criteria add(String column, boolean value)
1058     {
1059         add(column, (value ? Boolean.TRUE : Boolean.FALSE));
1060         return this;
1061     }
1062 
1063     /***
1064      * Convenience method to add a boolean to Criteria.
1065      * Equal to
1066      *
1067      * <p>
1068      * <code>
1069      * add(column, new Boolean(value), comparison);
1070      * </code>
1071      *
1072      * @param column The column to run the comparison on
1073      * @param value A Boolean.
1074      * @param comparison String describing how to compare the column with
1075      *        the value
1076      * @return A modified Criteria object.
1077      */
1078     public Criteria add(String column, boolean value, SqlEnum comparison)
1079     {
1080         add(column, new Boolean(value), comparison);
1081         return this;
1082     }
1083 
1084     /***
1085      * Convenience method to add an int to Criteria.
1086      * Equal to
1087      *
1088      * <p>
1089      * <code>
1090      * add(column, new Integer(value), EQUAL);
1091      * </code>
1092      *
1093      * @param column The column to run the comparison on
1094      * @param value An int.
1095      * @return A modified Criteria object.
1096      */
1097     public Criteria add(String column, int value)
1098     {
1099         add(column, new Integer(value));
1100         return this;
1101     }
1102 
1103     /***
1104      * Convenience method to add an int to Criteria.
1105      * Equal to
1106      *
1107      * <p>
1108      * <code>
1109      * add(column, new Integer(value), comparison);
1110      * </code>
1111      *
1112      * @param column The column to run the comparison on
1113      * @param value An int.
1114      * @param comparison String describing how to compare the column with
1115      *        the value
1116      * @return A modified Criteria object.
1117      */
1118     public Criteria add(String column, int value, SqlEnum comparison)
1119     {
1120         add(column, new Integer(value), comparison);
1121         return this;
1122     }
1123 
1124     /***
1125      * Convenience method to add a long to Criteria.
1126      * Equal to
1127      *
1128      * <p>
1129      * <code>
1130      * add(column, new Long(value), EQUAL);
1131      * </code>
1132      *
1133      * @param column The column to run the comparison on
1134      * @param value A long.
1135      * @return A modified Criteria object.
1136      */
1137     public Criteria add(String column, long value)
1138     {
1139         add(column, new Long(value));
1140         return this;
1141     }
1142 
1143     /***
1144      * Convenience method to add a long to Criteria.
1145      * Equal to
1146      *
1147      * <p>
1148      * <code>
1149      * add(column, new Long(value), comparison);
1150      * </code>
1151      *
1152      * @param column The column to run the comparison on
1153      * @param value A long.
1154      * @param comparison String describing how to compare the column with
1155      *        the value
1156      * @return A modified Criteria object.
1157      */
1158     public Criteria add(String column, long value, SqlEnum comparison)
1159     {
1160         add(column, new Long(value), comparison);
1161         return this;
1162     }
1163 
1164     /***
1165      * Convenience method to add a float to Criteria.
1166      * Equal to
1167      *
1168      * <p>
1169      * <code>
1170      * add(column, new Float(value), EQUAL);
1171      * </code>
1172      *
1173      * @param column The column to run the comparison on
1174      * @param value A float.
1175      * @return A modified Criteria object.
1176      */
1177     public Criteria add(String column, float value)
1178     {
1179         add(column, new Float(value));
1180         return this;
1181     }
1182 
1183     /***
1184      * Convenience method to add a float to Criteria.
1185      * Equal to
1186      *
1187      * <p>
1188      * <code>
1189      * add(column, new Float(value), comparison);
1190      * </code>
1191      *
1192      * @param column The column to run the comparison on
1193      * @param value A float.
1194      * @param comparison String describing how to compare the column with
1195      *        the value
1196      * @return A modified Criteria object.
1197      */
1198     public Criteria add(String column, float value, SqlEnum comparison)
1199     {
1200         add(column, new Float(value), comparison);
1201         return this;
1202     }
1203 
1204     /***
1205      * Convenience method to add a double to Criteria.
1206      * Equal to
1207      *
1208      * <p>
1209      * <code>
1210      * add(column, new Double(value), EQUAL);
1211      * </code>
1212      *
1213      * @param column The column to run the comparison on
1214      * @param value A double.
1215      * @return A modified Criteria object.
1216      */
1217     public Criteria add(String column, double value)
1218     {
1219         add(column, new Double(value));
1220         return this;
1221     }
1222 
1223     /***
1224      * Convenience method to add a double to Criteria.
1225      * Equal to
1226      *
1227      * <p>
1228      * <code>
1229      * add(column, new Double(value), comparison);
1230      * </code>
1231      *
1232      * @param column The column to run the comparison on
1233      * @param value A double.
1234      * @param comparison String describing how to compare the column with
1235      *        the value
1236      * @return A modified Criteria object.
1237      */
1238     public Criteria add(String column, double value, SqlEnum comparison)
1239     {
1240         add(column, new Double(value), comparison);
1241         return this;
1242     }
1243 
1244     /***
1245      * Convenience method to add a Date object specified by
1246      * year, month, and date into the Criteria.
1247      * Equal to
1248      *
1249      * <p>
1250      * <code>
1251      * add(column, new GregorianCalendar(year, month,date), EQUAL);
1252      * </code>
1253      *
1254      * @param column A String value to use as column.
1255      * @param year An int with the year.
1256      * @param month An int with the month. Month value is 0-based.
1257      *        e.g., 0 for January
1258      * @param date An int with the date.
1259      * @return A modified Criteria object.
1260      */
1261     public Criteria addDate(String column, int year, int month, int date)
1262     {
1263         add(column, new GregorianCalendar(year, month, date).getTime());
1264         return this;
1265     }
1266 
1267     /***
1268      * Convenience method to add a Date object specified by
1269      * year, month, and date into the Criteria.
1270      * Equal to
1271      *
1272      * <p>
1273      * <code>
1274      * add(column, new GregorianCalendar(year, month,date), comparison);
1275      * </code>
1276      *
1277      * @param column The column to run the comparison on
1278      * @param year An int with the year.
1279      * @param month An int with the month. Month value is 0-based.
1280      *        e.g., 0 for January
1281      * @param date An int with the date.
1282      * @param comparison String describing how to compare the column with
1283      *        the value
1284      * @return A modified Criteria object.
1285      */
1286     public Criteria addDate(String column, int year, int month, int date,
1287             SqlEnum comparison)
1288     {
1289         add(column, new GregorianCalendar(year, month, date).getTime(),
1290                 comparison);
1291         return this;
1292     }
1293 
1294     /***
1295      * This is the way that you should add a join of two tables.  For
1296      * example:
1297      *
1298      * <p>
1299      * AND PROJECT.PROJECT_ID=FOO.PROJECT_ID
1300      * <p>
1301      *
1302      * left = PROJECT.PROJECT_ID
1303      * right = FOO.PROJECT_ID
1304      *
1305      * @param left A String with the left side of the join.
1306      * @param right A String with the right side of the join.
1307      * @return A modified Criteria object.
1308      */
1309     public Criteria addJoin(String left, String right)
1310     {
1311         return addJoin(left, right, null);
1312     }
1313 
1314     /***
1315      * This is the way that you should add a join of two tables.  For
1316      * example:
1317      *
1318      * <p>
1319      * PROJECT LEFT JOIN FOO ON PROJECT.PROJECT_ID=FOO.PROJECT_ID
1320      * <p>
1321      *
1322      * left = &quot;PROJECT.PROJECT_ID&quot;
1323      * right = &quot;FOO.PROJECT_ID&quot;
1324      * operator = Criteria.LEFT_JOIN
1325      *
1326      * @param left A String with the left side of the join.
1327      * @param right A String with the right side of the join.
1328      * @param operator The operator used for the join: must be one of null,
1329      *        Criteria.LEFT_JOIN, Criteria.RIGHT_JOIN, Criteria.INNER_JOIN
1330      * @return A modified Criteria object.
1331      */
1332     public Criteria addJoin(String left, String right, SqlEnum operator)
1333     {
1334         if (joins == null)
1335         {
1336             joins = new ArrayList(3);
1337         }
1338         joins.add(new Join(left,right, operator));
1339   
1340         return this;
1341     }
1342 
1343     /***
1344      * get the List of Joins.  This method is meant to
1345      * be called by BasePeer.
1346      * @return a List which contains objects of type Join,
1347      *         or null if the criteria dies not contains any joins
1348      */
1349     public List getJoins()
1350     {
1351         return joins;
1352     }
1353 
1354     /***
1355      * get one side of the set of possible joins.  This method is meant to
1356      * be called by BasePeer.
1357      *
1358      * @deprecated This method is no longer used by BasePeer.
1359      */
1360     public List getJoinL()
1361     {
1362         throw new RuntimeException("getJoinL() in Criteria is no longer supported!");
1363     }
1364 
1365     /***
1366      * get one side of the set of possible joins.  This method is meant to
1367      * be called by BasePeer.
1368      *
1369      * @deprecated This method is no longer used by BasePeer.
1370      */
1371     public List getJoinR()
1372     {
1373         throw new RuntimeException("getJoinL() in Criteria is no longer supported!");
1374     }
1375 
1376     /***
1377      * Adds an 'IN' clause with the criteria supplied as an Object
1378      * array.  For example:
1379      *
1380      * <p>
1381      * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
1382      * <p>
1383      *
1384      * where 'values' contains three objects that evaluate to the
1385      * respective strings above when .toString() is called.
1386      *
1387      * If a criterion for the requested column already exists, it is
1388      * replaced.
1389      *
1390      * @param column The column to run the comparison on
1391      * @param values An Object[] with the allowed values.
1392      * @return A modified Criteria object.
1393      */
1394     public Criteria addIn(String column, Object[] values)
1395     {
1396         add(column, (Object) values, Criteria.IN);
1397         return this;
1398     }
1399 
1400     /***
1401      * Adds an 'IN' clause with the criteria supplied as an int array.
1402      * For example:
1403      *
1404      * <p>
1405      * FOO.ID IN ('2', '3', '7')
1406      * <p>
1407      *
1408      * where 'values' contains those three integers.
1409      *
1410      * If a criterion for the requested column already exists, it is
1411      * replaced.
1412      *
1413      * @param column The column to run the comparison on
1414      * @param values An int[] with the allowed values.
1415      * @return A modified Criteria object.
1416      */
1417     public Criteria addIn(String column, int[] values)
1418     {
1419         add(column, (Object) values, Criteria.IN);
1420         return this;
1421     }
1422 
1423     /***
1424      * Adds an 'IN' clause with the criteria supplied as a List.
1425      * For example:
1426      *
1427      * <p>
1428      * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
1429      * <p>
1430      *
1431      * where 'values' contains three objects that evaluate to the
1432      * respective strings above when .toString() is called.
1433      *
1434      * If a criterion for the requested column already exists, it is
1435      * replaced.
1436      *
1437      * @param column The column to run the comparison on
1438      * @param values A List with the allowed values.
1439      * @return A modified Criteria object.
1440      */
1441     public Criteria addIn(String column, List values)
1442     {
1443         add(column, (Object) values, Criteria.IN);
1444         return this;
1445     }
1446 
1447     /***
1448      * Adds a 'NOT IN' clause with the criteria supplied as an Object
1449      * array.  For example:
1450      *
1451      * <p>
1452      * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
1453      * <p>
1454      *
1455      * where 'values' contains three objects that evaluate to the
1456      * respective strings above when .toString() is called.
1457      *
1458      * If a criterion for the requested column already exists, it is
1459      * replaced.
1460      *
1461      * @param column The column to run the comparison on
1462      * @param values An Object[] with the disallowed values.
1463      * @return A modified Criteria object.
1464      */
1465     public Criteria addNotIn(String column, Object[] values)
1466     {
1467         add(column, (Object) values, Criteria.NOT_IN);
1468         return this;
1469     }
1470 
1471     /***
1472      * Adds a 'NOT IN' clause with the criteria supplied as an int
1473      * array.  For example:
1474      *
1475      * <p>
1476      * FOO.ID NOT IN ('2', '3', '7')
1477      * <p>
1478      *
1479      * where 'values' contains those three integers.
1480      *
1481      * If a criterion for the requested column already exists, it is
1482      * replaced.
1483      *
1484      * @param column The column to run the comparison on
1485      * @param values An int[] with the disallowed values.
1486      * @return A modified Criteria object.
1487      */
1488     public Criteria addNotIn(String column, int[] values)
1489     {
1490         add(column, (Object) values, Criteria.NOT_IN);
1491         return this;
1492     }
1493 
1494     /***
1495      * Adds a 'NOT IN' clause with the criteria supplied as a List.
1496      * For example:
1497      *
1498      * <p>
1499      * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
1500      * <p>
1501      *
1502      * where 'values' contains three objects that evaluate to the
1503      * respective strings above when .toString() is called.
1504      *
1505      * If a criterion for the requested column already exists, it is
1506      * replaced.
1507      *
1508      * @param column The column to run the comparison on
1509      * @param values A List with the disallowed values.
1510      * @return A modified Criteria object.
1511      */
1512     public Criteria addNotIn(String column, List values)
1513     {
1514         add(column, (Object) values, Criteria.NOT_IN);
1515         return this;
1516     }
1517 
1518     /***
1519      * Adds &quot;ALL &quot; to the SQL statement.
1520      */
1521     public void setAll()
1522     {
1523         selectModifiers.add(ALL.toString());
1524     }
1525 
1526     /***
1527      * Adds &quot;DISTINCT &quot; to the SQL statement.
1528      */
1529     public void setDistinct()
1530     {
1531         selectModifiers.add(DISTINCT.toString());
1532     }
1533 
1534     /***
1535      * Sets ignore case.
1536      *
1537      * @param b True if case should be ignored.
1538      * @return A modified Criteria object.
1539      */
1540     public Criteria setIgnoreCase(boolean b)
1541     {
1542         ignoreCase = b;
1543         return this;
1544     }
1545 
1546     /***
1547      * Is ignore case on or off?
1548      *
1549      * @return True if case is ignored.
1550      */
1551     public boolean isIgnoreCase()
1552     {
1553         return ignoreCase;
1554     }
1555 
1556     /***
1557      * Set single record?  Set this to <code>true</code> if you expect the query
1558      * to result in only a single result record (the default behaviour is to
1559      * throw a TorqueException if multiple records are returned when the query
1560      * is executed).  This should be used in situations where returning multiple
1561      * rows would indicate an error of some sort.  If your query might return
1562      * multiple records but you are only interested in the first one then you
1563      * should be using setLimit(1).
1564      *
1565      * @param b set to <code>true</code> if you expect the query to select just
1566      * one record.
1567      * @return A modified Criteria object.
1568      */
1569     public Criteria setSingleRecord(boolean b)
1570     {
1571         singleRecord = b;
1572         return this;
1573     }
1574 
1575     /***
1576      * Is single record?
1577      *
1578      * @return True if a single record is being returned.
1579      */
1580     public boolean isSingleRecord()
1581     {
1582         return singleRecord;
1583     }
1584 
1585     /***
1586      * Set cascade.
1587      *
1588      * @param b True if cascade is set.
1589      * @return A modified Criteria object.
1590      */
1591     public Criteria setCascade(boolean b)
1592     {
1593         cascade = b;
1594         return this;
1595     }
1596 
1597     /***
1598      * Is cascade set?
1599      *
1600      * @return True if cascade is set.
1601      */
1602     public boolean isCascade()
1603     {
1604         return cascade;
1605     }
1606 
1607     /***
1608      * Set limit.
1609      *
1610      * @param limit An int with the value for limit.
1611      * @return A modified Criteria object.
1612      */
1613     public Criteria setLimit(int limit)
1614     {
1615         this.limit = limit;
1616         return this;
1617     }
1618 
1619     /***
1620      * Get limit.
1621      *
1622      * @return An int with the value for limit.
1623      */
1624     public int getLimit()
1625     {
1626         return limit;
1627     }
1628 
1629     /***
1630      * Set offset.
1631      *
1632      * @param offset An int with the value for offset.
1633      * @return A modified Criteria object.
1634      */
1635     public Criteria setOffset(int offset)
1636     {
1637         this.offset = offset;
1638         return this;
1639     }
1640 
1641     /***
1642      * Get offset.
1643      *
1644      * @return An int with the value for offset.
1645      */
1646     public int getOffset()
1647     {
1648         return offset;
1649     }
1650 
1651     /***
1652      * Add select column.
1653      *
1654      * @param name A String with the name of the select column.
1655      * @return A modified Criteria object.
1656      */
1657     public Criteria addSelectColumn(String name)
1658     {
1659         selectColumns.add(name);
1660         return this;
1661     }
1662 
1663     /***
1664      * Get select columns.
1665      *
1666      * @return An StringStack with the name of the select
1667      * columns.
1668      */
1669     public UniqueList getSelectColumns()
1670     {
1671         return selectColumns;
1672     }
1673 
1674     /***
1675      * Get select modifiers.
1676      *
1677      * @return An UniqueList with the select modifiers.
1678      */
1679     public UniqueList getSelectModifiers()
1680     {
1681         return selectModifiers;
1682     }
1683 
1684     /***
1685      * Add group by column name.
1686      *
1687      * @param groupBy The name of the column to group by.
1688      * @return A modified Criteria object.
1689      */
1690     public Criteria addGroupByColumn(String groupBy)
1691     {
1692         groupByColumns.add(groupBy);
1693         return this;
1694     }
1695 
1696     /***
1697      * Add order by column name, explicitly specifying ascending.
1698      *
1699      * @param name The name of the column to order by.
1700      * @return A modified Criteria object.
1701      */
1702     public Criteria addAscendingOrderByColumn(String name)
1703     {
1704         orderByColumns.add(name + ' ' + ASC);
1705         return this;
1706     }
1707 
1708     /***
1709      * Add order by column name, explicitly specifying descending.
1710      *
1711      * @param name The name of the column to order by.
1712      * @return A modified Criteria object.
1713      */
1714     public Criteria addDescendingOrderByColumn(String name)
1715     {
1716         orderByColumns.add(name + ' ' + DESC);
1717         return this;
1718     }
1719 
1720     /***
1721      * Get order by columns.
1722      *
1723      * @return An UniqueList with the name of the order columns.
1724      */
1725     public UniqueList getOrderByColumns()
1726     {
1727         return orderByColumns;
1728     }
1729 
1730     /***
1731      * Get group by columns.
1732      *
1733      * @return An UniqueList with the name of the groupBy clause.
1734      */
1735     public UniqueList getGroupByColumns()
1736     {
1737         return groupByColumns;
1738     }
1739 
1740     /***
1741      * Get Having Criterion.
1742      *
1743      * @return A Criterion that is the having clause.
1744      */
1745     public Criterion getHaving()
1746     {
1747         return having;
1748     }
1749 
1750     /***
1751      * Remove an object from the criteria.
1752      *
1753      * @param key A String with the key to be removed.
1754      * @return The removed object.
1755      */
1756     public Object remove(String key)
1757     {
1758         Object foo = super.remove(key);
1759         if (foo instanceof Criterion)
1760         {
1761             return ((Criterion) foo).getValue();
1762         }
1763         return foo;
1764     }
1765 
1766     /***
1767      * Build a string representation of the Criteria.
1768      *
1769      * @return A String with the representation of the Criteria.
1770      */
1771     public String toString()
1772     {
1773         StringBuffer sb = new StringBuffer("Criteria:: ");
1774         Iterator it = keySet().iterator();
1775         while (it.hasNext())
1776         {
1777             String key = (String) it.next();
1778             sb.append(key).append("<=>")
1779                     .append(super.get(key).toString()).append(":  ");
1780         }
1781 
1782         try
1783         {
1784             sb.append("\nCurrent Query SQL (may not be complete or applicable): ")
1785                     .append(BasePeer.createQueryDisplayString(this));
1786         }
1787         catch (Exception exc)
1788         {
1789         }
1790 
1791         return sb.toString();
1792     }
1793 
1794     /***
1795      * This method checks another Criteria to see if they contain
1796      * the same attributes and hashtable entries.
1797      */
1798     public boolean equals(Object crit)
1799     {
1800         boolean isEquiv = false;
1801         if (crit == null || !(crit instanceof Criteria))
1802         {
1803             isEquiv = false;
1804         }
1805         else if (this == crit)
1806         {
1807             isEquiv = true;
1808         }
1809         else if (this.size() == ((Criteria) crit).size())
1810         {
1811             Criteria criteria = (Criteria) crit;
1812             if (this.offset == criteria.getOffset()
1813                     && this.limit == criteria.getLimit()
1814                     && ignoreCase == criteria.isIgnoreCase()
1815                     && singleRecord == criteria.isSingleRecord()
1816                     && cascade == criteria.isCascade()
1817                     && dbName.equals(criteria.getDbName())
1818                     && selectModifiers.equals(criteria.getSelectModifiers())
1819                     && selectColumns.equals(criteria.getSelectColumns())
1820                     && orderByColumns.equals(criteria.getOrderByColumns())
1821                 )
1822             {
1823                 isEquiv = true;
1824                 for (Iterator it = criteria.keySet().iterator(); it.hasNext();)
1825                 {
1826                     String key = (String) it.next();
1827                     if (this.containsKey(key))
1828                     {
1829                         Criterion a = this.getCriterion(key);
1830                         Criterion b = criteria.getCriterion(key);
1831                         if (!a.equals(b))
1832                         {
1833                             isEquiv = false;
1834                             break;
1835                         }
1836                     }
1837                     else
1838                     {
1839                         isEquiv = false;
1840                         break;
1841                     }
1842                 }
1843             }
1844         }
1845         return isEquiv;
1846     }
1847 
1848     /*
1849      *------------------------------------------------------------------------
1850      *
1851      * Start of the "and" methods
1852      *
1853      *------------------------------------------------------------------------
1854      */
1855 
1856     /***
1857      * This method adds a prepared Criterion object to the Criteria as a having
1858      * clause. You can get a new, empty Criterion object with the
1859      * getNewCriterion() method.
1860      *
1861      * <p>
1862      * <code>
1863      * Criteria crit = new Criteria();
1864      * Criteria.Criterion c = crit.getNewCriterion(BasePeer.ID, new Integer(5),
1865      *         Criteria.LESS_THAN);
1866      * crit.addHaving(c);
1867      * </code>
1868      *
1869      * @param having A Criterion object
1870      * @return A modified Criteria object.
1871      */
1872     public Criteria addHaving(Criterion having)
1873     {
1874         this.having = having;
1875         return this;
1876     }
1877 
1878     /***
1879      * This method adds a prepared Criterion object to the Criteria.
1880      * You can get a new, empty Criterion object with the
1881      * getNewCriterion() method. If a criterion for the requested column
1882      * already exists, it is &quot;AND&quot;ed to the existing criterion.
1883      * This is used as follows:
1884      *
1885      * <p>
1886      * <code>
1887      * Criteria crit = new Criteria();
1888      * Criteria.Criterion c = crit.getNewCriterion(BasePeer.ID, new Integer(5),
1889      *         Criteria.LESS_THAN);
1890      * crit.and(c);
1891      * </code>
1892      *
1893      * @param c A Criterion object
1894      * @return A modified Criteria object.
1895      */
1896     public Criteria and(Criterion c)
1897     {
1898         Criterion oc = getCriterion(c.getTable() + '.' + c.getColumn());
1899 
1900         if (oc == null)
1901         {
1902             add(c);
1903         }
1904         else
1905         {
1906             oc.and(c);
1907         }
1908         return this;
1909     }
1910 
1911     /***
1912      * This method adds a new criterion to the list of criterias. If a
1913      * criterion for the requested column already exists, it is
1914      * &quot;AND&quot;ed to the existing criterion. This is used as follows:
1915      *
1916      * <p>
1917      * <code>
1918      * Criteria crit = new Criteria().and(&quot;column&quot;,
1919      *                                      &quot;value&quot;);
1920      * </code>
1921      *
1922      * An EQUAL comparison is used for column and value.
1923      *
1924      * The name of the table must be used implicitly in the column name,
1925      * so the Column name must be something like 'TABLE.id'. If you
1926      * don't like this, you can use the and(table, column, value) method.
1927      *
1928      * @param column The column to run the comparison on
1929      * @param value An Object.
1930      *
1931      * @return A modified Criteria object.
1932      */
1933     public Criteria and(String column, Object value)
1934     {
1935         and(column, value, EQUAL);
1936         return this;
1937     }
1938 
1939     /***
1940      * This method adds a new criterion to the list of criterias.
1941      * If a criterion for the requested column already exists, it is
1942      * &quot;AND&quot;ed to the existing criterion. If is used as follow:
1943      *
1944      * <p>
1945      * <code>
1946      * Criteria crit = new Criteria().and(&quot;column&quot;,
1947      *                                      &quot;value&quot;
1948      *                                      &quot;Criterion.GREATER_THAN&quot;);
1949      * </code>
1950      *
1951      * Any comparison can be used.
1952      *
1953      * The name of the table must be used implicitly in the column name,
1954      * so the Column name must be something like 'TABLE.id'. If you
1955      * don't like this, you can use the and(table, column, value) method.
1956      *
1957      * @param column The column to run the comparison on
1958      * @param value An Object.
1959      * @param comparison A String.
1960      *
1961      * @return A modified Criteria object.
1962      */
1963     public Criteria and(String column, Object value, SqlEnum comparison)
1964     {
1965         Criterion oc = getCriterion(column);
1966         Criterion nc = new Criterion(column, value, comparison);
1967 
1968         if (oc == null)
1969         {
1970             super.put(column, nc);
1971         }
1972         else
1973         {
1974             oc.and(nc);
1975         }
1976         return this;
1977     }
1978 
1979     /***
1980      * This method adds a new criterion to the list of criterias.
1981      * If a criterion for the requested column already exists, it is
1982      * &quot;AND&quot;ed to the existing criterion. If is used as follows:
1983      *
1984      * <p>
1985      * <code>
1986      * Criteria crit = new Criteria().and(&quot;table&quot;,
1987      *                                      &quot;column&quot;,
1988      *                                      &quot;value&quot;);
1989      * </code>
1990      *
1991      * An EQUAL comparison is used for column and value.
1992      *
1993      * @param table Name of the table which contains the column
1994      * @param column The column to run the comparison on
1995      * @param value An Object.
1996      * @return A modified Criteria object.
1997      */
1998     public Criteria and(String table, String column, Object value)
1999     {
2000         and(table, column, value, EQUAL);
2001         return this;
2002     }
2003 
2004     /***
2005      * This method adds a new criterion to the list of criterias.
2006      * If a criterion for the requested column already exists, it is
2007      * &quot;AND&quot;ed to the existing criterion. If is used as follows:
2008      *
2009      * <p>
2010      * <code>
2011      * Criteria crit = new Criteria().and(&quot;table&quot;,
2012      *                                      &quot;column&quot;,
2013      *                                      &quot;value&quot;,
2014      *                                      &quot;Criterion.GREATER_THAN&quot;);
2015      * </code>
2016      *
2017      * Any comparison can be used.
2018      *
2019      * @param table Name of table which contains the column
2020      * @param column The column to run the comparison on
2021      * @param value An Object.
2022      * @param comparison String describing how to compare the column with
2023      *        the value
2024      * @return A modified Criteria object.
2025      */
2026     public Criteria and(String table, String column, Object value,
2027             SqlEnum comparison)
2028     {
2029         StringBuffer sb = new StringBuffer(table.length()
2030                 + column.length() + 1);
2031         sb.append(table);
2032         sb.append('.');
2033         sb.append(column);
2034 
2035         Criterion oc = getCriterion(table, column);
2036         Criterion nc = new Criterion(table, column, value, comparison);
2037 
2038         if (oc == null)
2039         {
2040             super.put(sb.toString(), nc);
2041         }
2042         else
2043         {
2044             oc.and(nc);
2045         }
2046         return this;
2047     }
2048 
2049     /***
2050      * Convenience method to add a boolean to Criteria.
2051      * Equal to
2052      *
2053      * <p>
2054      * <code>
2055      * and(column, new Boolean(value), EQUAL);
2056      * </code>
2057      *
2058      * @param column The column to run the comparison on
2059      * @param value A Boolean.
2060      * @return A modified Criteria object.
2061      */
2062     public Criteria and(String column, boolean value)
2063     {
2064         and(column, new Boolean(value));
2065         return this;
2066     }
2067 
2068     /***
2069      * Convenience method to add a boolean to Criteria.
2070      * Equal to
2071      *
2072      * <p>
2073      * <code>
2074      * and(column, new Boolean(value), comparison);
2075      * </code>
2076      *
2077      * @param column The column to run the comparison on
2078      * @param value A Boolean.
2079      * @param comparison String describing how to compare the column
2080      * with the value
2081      * @return A modified Criteria object.
2082      */
2083     public Criteria and(String column, boolean value, SqlEnum comparison)
2084     {
2085         and(column, new Boolean(value), comparison);
2086         return this;
2087     }
2088 
2089     /***
2090      * Convenience method to add an int to Criteria.
2091      * Equal to
2092      *
2093      * <p>
2094      * <code>
2095      * and(column, new Integer(value), EQUAL);
2096      * </code>
2097      *
2098      * @param column The column to run the comparison on
2099      * @param value An int.
2100      * @return A modified Criteria object.
2101      */
2102     public Criteria and(String column, int value)
2103     {
2104         and(column, new Integer(value));
2105         return this;
2106     }
2107 
2108     /***
2109      * Convenience method to add an int to Criteria.
2110      * Equal to
2111      *
2112      * <p>
2113      * <code>
2114      * and(column, new Integer(value), comparison);
2115      * </code>
2116      *
2117      * @param column The column to run the comparison on
2118      * @param value An int.
2119      * @param comparison String describing how to compare the column with the value
2120      * @return A modified Criteria object.
2121      */
2122     public Criteria and(String column, int value, SqlEnum comparison)
2123     {
2124         and(column, new Integer(value), comparison);
2125         return this;
2126     }
2127 
2128     /***
2129      * Convenience method to add a long to Criteria.
2130      * Equal to
2131      *
2132      * <p>
2133      * <code>
2134      * and(column, new Long(value), EQUAL);
2135      * </code>
2136      *
2137      * @param column The column to run the comparison on
2138      * @param value A long.
2139      * @return A modified Criteria object.
2140      */
2141     public Criteria and(String column, long value)
2142     {
2143         and(column, new Long(value));
2144         return this;
2145     }
2146 
2147     /***
2148      * Convenience method to add a long to Criteria.
2149      * Equal to
2150      *
2151      * <p>
2152      * <code>
2153      * and(column, new Long(value), comparison);
2154      * </code>
2155      *
2156      * @param column The column to run the comparison on
2157      * @param value A long.
2158      * @param comparison String describing how to compare the column with
2159      *        the value
2160      * @return A modified Criteria object.
2161      */
2162     public Criteria and(String column, long value, SqlEnum comparison)
2163     {
2164         and(column, new Long(value), comparison);
2165         return this;
2166     }
2167 
2168     /***
2169      * Convenience method to add a float to Criteria.
2170      * Equal to
2171      *
2172      * <p>
2173      * <code>
2174      * and(column, new Float(value), EQUAL);
2175      * </code>
2176      *
2177      * @param column The column to run the comparison on
2178      * @param value A float.
2179      * @return A modified Criteria object.
2180      */
2181     public Criteria and(String column, float value)
2182     {
2183         and(column, new Float(value));
2184         return this;
2185     }
2186 
2187     /***
2188      * Convenience method to add a float to Criteria.
2189      * Equal to
2190      *
2191      * <p>
2192      * <code>
2193      * and(column, new Float(value), comparison);
2194      * </code>
2195      *
2196      * @param column The column to run the comparison on
2197      * @param value A float.
2198      * @param comparison String describing how to compare the column with
2199      *        the value
2200      * @return A modified Criteria object.
2201      */
2202     public Criteria and(String column, float value, SqlEnum comparison)
2203     {
2204         and(column, new Float(value), comparison);
2205         return this;
2206     }
2207 
2208     /***
2209      * Convenience method to add a double to Criteria.
2210      * Equal to
2211      *
2212      * <p>
2213      * <code>
2214      * and(column, new Double(value), EQUAL);
2215      * </code>
2216      *
2217      * @param column The column to run the comparison on
2218      * @param value A double.
2219      * @return A modified Criteria object.
2220      */
2221     public Criteria and(String column, double value)
2222     {
2223         and(column, new Double(value));
2224         return this;
2225     }
2226 
2227     /***
2228      * Convenience method to add a double to Criteria.
2229      * Equal to
2230      *
2231      * <p>
2232      * <code>
2233      * and(column, new Double(value), comparison);
2234      * </code>
2235      *
2236      * @param column The column to run the comparison on
2237      * @param value A double.
2238      * @param comparison String describing how to compare the column with
2239      *        the value
2240      * @return A modified Criteria object.
2241      */
2242     public Criteria and(String column, double value, SqlEnum comparison)
2243     {
2244         and(column, new Double(value), comparison);
2245         return this;
2246     }
2247 
2248     /***
2249      * Convenience method to add a Date object specified by
2250      * year, month, and date into the Criteria.
2251      * Equal to
2252      *
2253      * <p>
2254      * <code>
2255      * and(column, new GregorianCalendar(year, month,date), EQUAL);
2256      * </code>
2257      *
2258      * @param column A String value to use as column.
2259      * @param year An int with the year.
2260      * @param month An int with the month.
2261      * @param date An int with the date.
2262      * @return A modified Criteria object.
2263      */
2264     public Criteria andDate(String column, int year, int month, int date)
2265     {
2266         and(column, new GregorianCalendar(year, month, date));
2267         return this;
2268     }
2269 
2270     /***
2271      * Convenience method to add a Date object specified by
2272      * year, month, and date into the Criteria.
2273      * Equal to
2274      *
2275      * <p>
2276      * <code>
2277      * and(column, new GregorianCalendar(year, month,date), comparison);
2278      * </code>
2279      *
2280      * @param column The column to run the comparison on
2281      * @param year An int with the year.
2282      * @param month An int with the month.
2283      * @param date An int with the date.
2284      * @param comparison String describing how to compare the column with
2285      *        the value
2286      * @return A modified Criteria object.
2287      */
2288     public Criteria andDate(String column, int year, int month, int date,
2289             SqlEnum comparison)
2290     {
2291         and(column, new GregorianCalendar(year, month, date), comparison);
2292         return this;
2293     }
2294 
2295     /***
2296      * Adds an 'IN' clause with the criteria supplied as an Object array.
2297      * For example:
2298      *
2299      * <p>
2300      * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
2301      * <p>
2302      *
2303      * where 'values' contains three objects that evaluate to the
2304      * respective strings above when .toString() is called.
2305      *
2306      * If a criterion for the requested column already exists, it is
2307      * &quot;AND&quot;ed to the existing criterion.
2308      *
2309      * @param column The column to run the comparison on
2310      * @param values An Object[] with the allowed values.
2311      * @return A modified Criteria object.
2312      */
2313     public Criteria andIn(String column, Object[] values)
2314     {
2315         and(column, (Object) values, Criteria.IN);
2316         return this;
2317     }
2318 
2319     /***
2320      * Adds an 'IN' clause with the criteria supplied as an int array.
2321      * For example:
2322      *
2323      * <p>
2324      * FOO.ID IN ('2', '3', '7')
2325      * <p>
2326      *
2327      * where 'values' contains those three integers.
2328      *
2329      * If a criterion for the requested column already exists, it is
2330      * &quot;AND&quot;ed to the existing criterion.
2331      *
2332      * @param column The column to run the comparison on
2333      * @param values An int[] with the allowed values.
2334      * @return A modified Criteria object.
2335      */
2336     public Criteria andIn(String column, int[] values)
2337     {
2338         and(column, (Object) values, Criteria.IN);
2339         return this;
2340     }
2341 
2342     /***
2343      * Adds an 'IN' clause with the criteria supplied as a List.
2344      * For example:
2345      *
2346      * <p>
2347      * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
2348      * <p>
2349      *
2350      * where 'values' contains three objects that evaluate to the
2351      * respective strings above when .toString() is called.
2352      *
2353      * If a criterion for the requested column already exists, it is
2354      * &quot;AND&quot;ed to the existing criterion.
2355      *
2356      * @param column The column to run the comparison on
2357      * @param values A List with the allowed values.
2358      * @return A modified Criteria object.
2359      */
2360     public Criteria andIn(String column, List values)
2361     {
2362         and(column, (Object) values, Criteria.IN);
2363         return this;
2364     }
2365 
2366     /***
2367      * Adds a 'NOT IN' clause with the criteria supplied as an Object
2368      * array.  For example:
2369      *
2370      * <p>
2371      * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
2372      * <p>
2373      *
2374      * where 'values' contains three objects that evaluate to the
2375      * respective strings above when .toString() is called.
2376      *
2377      * If a criterion for the requested column already exists, it is
2378      * &quot;AND&quot;ed to the existing criterion.
2379      *
2380      * @param column The column to run the comparison on
2381      * @param values An Object[] with the disallowed values.
2382      * @return A modified Criteria object.
2383      */
2384     public Criteria andNotIn(String column, Object[] values)
2385     {
2386         and(column, (Object) values, Criteria.NOT_IN);
2387         return this;
2388     }
2389 
2390     /***
2391      * Adds a 'NOT IN' clause with the criteria supplied as an int
2392      * array.  For example:
2393      *
2394      * <p>
2395      * FOO.ID NOT IN ('2', '3', '7')
2396      * <p>
2397      *
2398      * where 'values' contains those three integers.
2399      *
2400      * If a criterion for the requested column already exists, it is
2401      * &quot;AND&quot;ed to the existing criterion.
2402      *
2403      * @param column The column to run the comparison on
2404      * @param values An int[] with the disallowed values.
2405      * @return A modified Criteria object.
2406      */
2407     public Criteria andNotIn(String column, int[] values)
2408     {
2409         and(column, (Object) values, Criteria.NOT_IN);
2410         return this;
2411     }
2412 
2413     /***
2414      * Adds a 'NOT IN' clause with the criteria supplied as a List.
2415      * For example:
2416      *
2417      * <p>
2418      * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
2419      * <p>
2420      *
2421      * where 'values' contains three objects that evaluate to the
2422      * respective strings above when .toString() is called.
2423      *
2424      * If a criterion for the requested column already exists, it is
2425      * &quot;AND&quot;ed to the existing criterion.
2426      *
2427      * @param column The column to run the comparison on
2428      * @param values A List with the disallowed values.
2429      * @return A modified Criteria object.
2430      */
2431     public Criteria andNotIn(String column, List values)
2432     {
2433         and(column, (Object) values, Criteria.NOT_IN);
2434         return this;
2435     }
2436 
2437     /*
2438      *------------------------------------------------------------------------
2439      *
2440      * Start of the "or" methods
2441      *
2442      *------------------------------------------------------------------------
2443      */
2444 
2445     /***
2446      * This method adds a prepared Criterion object to the Criteria.
2447      * You can get a new, empty Criterion object with the
2448      * getNewCriterion() method. If a criterion for the requested column
2449      * already exists, it is &quot;OR&quot;ed to the existing criterion.
2450      * This is used as follows:
2451      *
2452      * <p>
2453      * <code>
2454      * Criteria crit = new Criteria();
2455      * Criteria.Criterion c = crit.getNewCriterion(BasePeer.ID, new Integer(5), Criteria.LESS_THAN);
2456      * crit.or(c);
2457      * </code>
2458      *
2459      * @param c A Criterion object
2460      * @return A modified Criteria object.
2461      */
2462     public Criteria or(Criterion c)
2463     {
2464         Criterion oc = getCriterion(c.getTable() + '.' + c.getColumn());
2465 
2466         if (oc == null)
2467         {
2468             add(c);
2469         }
2470         else
2471         {
2472             oc.or(c);
2473         }
2474         return this;
2475     }
2476 
2477     /***
2478      * This method adds a new criterion to the list of criterias. If a
2479      * criterion for the requested column already exists, it is
2480      * &quot;OR&quot;ed to the existing criterion. This is used as follows:
2481      *
2482      * <p>
2483      * <code>
2484      * Criteria crit = new Criteria().or(&quot;column&quot;,
2485      *                                      &quot;value&quot;);
2486      * </code>
2487      *
2488      * An EQUAL comparison is used for column and value.
2489      *
2490      * The name of the table must be used implicitly in the column name,
2491      * so the Column name must be something like 'TABLE.id'. If you
2492      * don't like this, you can use the or(table, column, value) method.
2493      *
2494      * @param column The column to run the comparison on
2495      * @param value An Object.
2496      *
2497      * @return A modified Criteria object.
2498      */
2499     public Criteria or(String column, Object value)
2500     {
2501         or(column, value, EQUAL);
2502         return this;
2503     }
2504 
2505     /***
2506      * This method adds a new criterion to the list of criterias.
2507      * If a criterion for the requested column already exists, it is
2508      * &quot;OR&quot;ed to the existing criterion. If is used as follow:
2509      *
2510      * <p>
2511      * <code>
2512      * Criteria crit = new Criteria().or(&quot;column&quot;,
2513      *                                      &quot;value&quot;
2514      *                                      &quot;Criterion.GREATER_THAN&quot;);
2515      * </code>
2516      *
2517      * Any comparison can be used.
2518      *
2519      * The name of the table must be used implicitly in the column name,
2520      * so the Column name must be something like 'TABLE.id'. If you
2521      * don't like this, you can use the or(table, column, value) method.
2522      *
2523      * @param column The column to run the comparison on
2524      * @param value An Object.
2525      * @param comparison A String.
2526      * @return A modified Criteria object.
2527      */
2528     public Criteria or(String column, Object value, SqlEnum comparison)
2529     {
2530         Criterion oc = getCriterion(column);
2531         Criterion nc = new Criterion(column, value, comparison);
2532 
2533         if (oc == null)
2534         {
2535             super.put(column, nc);
2536         }
2537         else
2538         {
2539             oc.or(nc);
2540         }
2541         return this;
2542     }
2543 
2544     /***
2545      * This method adds a new criterion to the list of criterias.
2546      * If a criterion for the requested column already exists, it is
2547      * &quot;OR&quot;ed to the existing criterion. If is used as follows:
2548      *
2549      * <p>
2550      * <code>
2551      * Criteria crit = new Criteria().or(&quot;table&quot;,
2552      *                                      &quot;column&quot;,
2553      *                                      &quot;value&quot;);
2554      * </code>
2555      *
2556      * An EQUAL comparison is used for column and value.
2557      *
2558      * @param table Name of the table which contains the column
2559      * @param column The column to run the comparison on
2560      * @param value An Object.
2561      * @return A modified Criteria object.
2562      */
2563     public Criteria or(String table, String column, Object value)
2564     {
2565         or(table, column, value, EQUAL);
2566         return this;
2567     }
2568 
2569     /***
2570      * This method adds a new criterion to the list of criterias.
2571      * If a criterion for the requested column already exists, it is
2572      * &quot;OR&quot;ed to the existing criterion. If is used as follows:
2573      *
2574      * <p>
2575      * <code>
2576      * Criteria crit = new Criteria().or(&quot;table&quot;,
2577      *                                      &quot;column&quot;,
2578      *                                      &quot;value&quot;,
2579      *                                      &quot;Criterion.GREATER_THAN&quot;);
2580      * </code>
2581      *
2582      * Any comparison can be used.
2583      *
2584      * @param table Name of table which contains the column
2585      * @param column The column to run the comparison on
2586      * @param value An Object.
2587      * @param comparison String describing how to compare the column with the value
2588      * @return A modified Criteria object.
2589      */
2590     public Criteria or(String table, String column, Object value,
2591             SqlEnum comparison)
2592     {
2593         StringBuffer sb = new StringBuffer(table.length() + column.length() + 1);
2594         sb.append(table);
2595         sb.append('.');
2596         sb.append(column);
2597 
2598         Criterion oc = getCriterion(table, column);
2599         Criterion nc = new Criterion(table, column, value, comparison);
2600         if (oc == null)
2601         {
2602             super.put(sb.toString(), nc);
2603         }
2604         else
2605         {
2606             oc.or(nc);
2607         }
2608         return this;
2609     }
2610 
2611     /***
2612      * Convenience method to add a boolean to Criteria.
2613      * Equal to
2614      *
2615      * <p>
2616      * <code>
2617      * or(column, new Boolean(value), EQUAL);
2618      * </code>
2619      *
2620      * @param column The column to run the comparison on
2621      * @param value A Boolean.
2622      * @return A modified Criteria object.
2623      */
2624     public Criteria or(String column, boolean value)
2625     {
2626         or(column, new Boolean(value));
2627         return this;
2628     }
2629 
2630     /***
2631      * Convenience method to add a boolean to Criteria.
2632      * Equal to
2633      *
2634      * <p>
2635      * <code>
2636      * or(column, new Boolean(value), comparison);
2637      * </code>
2638      *
2639      * @param column The column to run the comparison on
2640      * @param value A Boolean.
2641      * @param comparison String describing how to compare the column
2642      * with the value
2643      * @return A modified Criteria object.
2644      */
2645     public Criteria or(String column, boolean value, SqlEnum comparison)
2646     {
2647         or(column, new Boolean(value), comparison);
2648         return this;
2649     }
2650 
2651     /***
2652      * Convenience method to add an int to Criteria.
2653      * Equal to
2654      *
2655      * <p>
2656      * <code>
2657      * or(column, new Integer(value), EQUAL);
2658      * </code>
2659      *
2660      *
2661      * @param column The column to run the comparison on
2662      * @param value An int.
2663      * @return A modified Criteria object.
2664      */
2665     public Criteria or(String column, int value)
2666     {
2667         or(column, new Integer(value));
2668         return this;
2669     }
2670 
2671     /***
2672      * Convenience method to add an int to Criteria.
2673      * Equal to
2674      *
2675      * <p>
2676      * <code>
2677      * or(column, new Integer(value), comparison);
2678      * </code>
2679      *
2680      *
2681      * @param column The column to run the comparison on
2682      * @param value An int.
2683      * @param comparison String describing how to compare the column
2684      * with the value
2685      * @return A modified Criteria object.
2686      */
2687     public Criteria or(String column, int value, SqlEnum comparison)
2688     {
2689         or(column, new Integer(value), comparison);
2690         return this;
2691     }
2692 
2693     /***
2694      * Convenience method to add a long to Criteria.
2695      * Equal to
2696      *
2697      * <p>
2698      * <code>
2699      * or(column, new Long(value), EQUAL);
2700      * </code>
2701      *
2702      * @param column The column to run the comparison on
2703      * @param value A long.
2704      * @return A modified Criteria object.
2705      */
2706     public Criteria or(String column, long value)
2707     {
2708         or(column, new Long(value));
2709         return this;
2710     }
2711 
2712     /***
2713      * Convenience method to add a long to Criteria.
2714      * Equal to
2715      *
2716      * <p>
2717      * <code>
2718      * or(column, new Long(value), comparison);
2719      * </code>
2720      *
2721      * @param column The column to run the comparison on
2722      * @param value A long.
2723      * @param comparison String describing how to compare the column
2724      * with the value
2725      * @return A modified Criteria object.
2726      */
2727     public Criteria or(String column, long value, SqlEnum comparison)
2728     {
2729         or(column, new Long(value), comparison);
2730         return this;
2731     }
2732 
2733     /***
2734      * Convenience method to add a float to Criteria.
2735      * Equal to
2736      *
2737      * <p>
2738      * <code>
2739      * or(column, new Float(value), EQUAL);
2740      * </code>
2741      *
2742      * @param column The column to run the comparison on
2743      * @param value A float.
2744      * @return A modified Criteria object.
2745      */
2746     public Criteria or(String column, float value)
2747     {
2748         or(column, new Float(value));
2749         return this;
2750     }
2751 
2752     /***
2753      * Convenience method to add a float to Criteria.
2754      * Equal to
2755      *
2756      * <p>
2757      * <code>
2758      * or(column, new Float(value), comparison);
2759      * </code>
2760      *
2761      * @param column The column to run the comparison on
2762      * @param value A float.
2763      * @param comparison String describing how to compare the column
2764      * with the value
2765      * @return A modified Criteria object.
2766      */
2767     public Criteria or(String column, float value, SqlEnum comparison)
2768     {
2769         or(column, new Float(value), comparison);
2770         return this;
2771     }
2772 
2773     /***
2774      * Convenience method to add a double to Criteria.
2775      * Equal to
2776      *
2777      * <p>
2778      * <code>
2779      * or(column, new Double(value), EQUAL);
2780      * </code>
2781      *
2782      * @param column The column to run the comparison on
2783      * @param value A double.
2784      * @return A modified Criteria object.
2785      */
2786     public Criteria or(String column, double value)
2787     {
2788         or(column, new Double(value));
2789         return this;
2790     }
2791 
2792     /***
2793      * Convenience method to add a double to Criteria.
2794      * Equal to
2795      *
2796      * <p>
2797      * <code>
2798      * or(column, new Double(value), comparison);
2799      * </code>
2800      *
2801      * @param column The column to run the comparison on
2802      * @param value A double.
2803      * @param comparison String describing how to compare the column
2804      * with the value
2805      * @return A modified Criteria object.
2806      */
2807     public Criteria or(String column, double value, SqlEnum comparison)
2808     {
2809         or(column, new Double(value), comparison);
2810         return this;
2811     }
2812 
2813     /***
2814      * Convenience method to add a Date object specified by
2815      * year, month, and date into the Criteria.
2816      * Equal to
2817      *
2818      * <p>
2819      * <code>
2820      * or(column, new GregorianCalendar(year, month,date), EQUAL);
2821      * </code>
2822      *
2823      * @param column A String value to use as column.
2824      * @param year An int with the year.
2825      * @param month An int with the month.
2826      * @param date An int with the date.
2827      * @return A modified Criteria object.
2828      */
2829     public Criteria orDate(String column, int year, int month, int date)
2830     {
2831         or(column, new GregorianCalendar(year, month, date));
2832         return this;
2833     }
2834 
2835     /***
2836      * Convenience method to add a Date object specified by
2837      * year, month, and date into the Criteria.
2838      * Equal to
2839      *
2840      * <p>
2841      * <code>
2842      * or(column, new GregorianCalendar(year, month,date), comparison);
2843      * </code>
2844      *
2845      * @param column The column to run the comparison on
2846      * @param year An int with the year.
2847      * @param month An int with the month.
2848      * @param date An int with the date.
2849      * @param comparison String describing how to compare the column
2850      * with the value
2851      * @return A modified Criteria object.
2852      */
2853     public Criteria orDate(String column, int year, int month, int date,
2854             SqlEnum comparison)
2855     {
2856         or(column, new GregorianCalendar(year, month, date), comparison);
2857         return this;
2858     }
2859 
2860     /***
2861      * Adds an 'IN' clause with the criteria supplied as an Object
2862      * array.  For example:
2863      *
2864      * <p>
2865      * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
2866      * <p>
2867      *
2868      * where 'values' contains three objects that evaluate to the
2869      * respective strings above when .toString() is called.
2870      *
2871      * If a criterion for the requested column already exists, it is
2872      * &quot;OR&quot;ed to the existing criterion.
2873      *
2874      * @param column The column to run the comparison on
2875      * @param values An Object[] with the allowed values.
2876      * @return A modified Criteria object.
2877      */
2878     public Criteria orIn(String column, Object[] values)
2879     {
2880         or(column, (Object) values, Criteria.IN);
2881         return this;
2882     }
2883 
2884     /***
2885      * Adds an 'IN' clause with the criteria supplied as an int array.
2886      * For example:
2887      *
2888      * <p>
2889      * FOO.ID IN ('2', '3', '7')
2890      * <p>
2891      *
2892      * where 'values' contains those three integers.
2893      *
2894      * If a criterion for the requested column already exists, it is
2895      * &quot;OR&quot;ed to the existing criterion.
2896      *
2897      * @param column The column to run the comparison on
2898      * @param values An int[] with the allowed values.
2899      * @return A modified Criteria object.
2900      */
2901     public Criteria orIn(String column, int[] values)
2902     {
2903         or(column, (Object) values, Criteria.IN);
2904         return this;
2905     }
2906 
2907     /***
2908      * Adds an 'IN' clause with the criteria supplied as a List.
2909      * For example:
2910      *
2911      * <p>
2912      * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
2913      * <p>
2914      *
2915      * where 'values' contains three objects that evaluate to the
2916      * respective strings above when .toString() is called.
2917      *
2918      * If a criterion for the requested column already exists, it is
2919      * &quot;OR&quot;ed to the existing criterion.
2920      *
2921      * @param column The column to run the comparison on
2922      * @param values A List with the allowed values.
2923      * @return A modified Criteria object.
2924      */
2925     public Criteria orIn(String column, List values)
2926     {
2927         or(column, (Object) values, Criteria.IN);
2928         return this;
2929     }
2930 
2931     /***
2932      * Adds a 'NOT IN' clause with the criteria supplied as an Object
2933      * array.  For example:
2934      *
2935      * <p>
2936      * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
2937      * <p>
2938      *
2939      * where 'values' contains three objects that evaluate to the
2940      * respective strings above when .toString() is called.
2941      *
2942      * If a criterion for the requested column already exists, it is
2943      * &quot;OR&quot;ed to the existing criterion.
2944      *
2945      * @param column The column to run the comparison on
2946      * @param values An Object[] with the disallowed values.
2947      * @return A modified Criteria object.
2948      */
2949     public Criteria orNotIn(String column, Object[] values)
2950     {
2951         or(column, (Object) values, Criteria.NOT_IN);
2952         return this;
2953     }
2954 
2955     /***
2956      * Adds a 'NOT IN' clause with the criteria supplied as an int
2957      * array.  For example:
2958      *
2959      * <p>
2960      * FOO.ID NOT IN ('2', '3', '7')
2961      * <p>
2962      *
2963      * where 'values' contains those three integers.
2964      *
2965      * If a criterion for the requested column already exists, it is
2966      * &quot;OR&quot;ed to the existing criterion.
2967      *
2968      * @param column The column to run the comparison on
2969      * @param values An int[] with the disallowed values.
2970      * @return A modified Criteria object.
2971      */
2972     public Criteria orNotIn(String column, int[] values)
2973     {
2974         or(column, (Object) values, Criteria.NOT_IN);
2975         return this;
2976     }
2977 
2978     /***
2979      * Adds a 'NOT IN' clause with the criteria supplied as a List.
2980      * For example:
2981      *
2982      * <p>
2983      * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
2984      * <p>
2985      *
2986      * where 'values' contains three objects that evaluate to the
2987      * respective strings above when .toString() is called.
2988      *
2989      * If a criterion for the requested column already exists, it is
2990      * &quot;OR&quot;ed to the existing criterion.
2991      *
2992      * @param column The column to run the comparison on
2993      * @param values A List with the disallowed values.
2994      * @return A modified Criteria object.
2995      */
2996     public Criteria orNotIn(String column, List values)
2997     {
2998         or(column, (Object) values, Criteria.NOT_IN);
2999         return this;
3000     }
3001 
3002     /***
3003      * This is an inner class that describes an object in the
3004      * criteria.
3005      */
3006     public final class Criterion implements Serializable
3007     {
3008         public static final String AND = " AND ";
3009         public static final String OR = " OR ";
3010 
3011         /*** Value of the CO. */
3012         private Object value;
3013 
3014         /*** Comparison value. */
3015         private SqlEnum comparison;
3016 
3017         /*** Table name. */
3018         private String table;
3019 
3020         /*** Column name. */
3021         private String column;
3022 
3023         /*** flag to ignore case in comparision */
3024         private boolean ignoreStringCase = false;
3025 
3026         /***
3027          * The DB adaptor which might be used to get db specific
3028          * variations of sql.
3029          */
3030         private DB db;
3031 
3032         /***
3033          * other connected criteria and their conjunctions.
3034          */
3035         private List clauses = new ArrayList();
3036         private List conjunctions = new ArrayList();
3037 
3038         /***
3039          * Creates a new instance, initializing a couple members.
3040          */
3041         private Criterion(Object val, SqlEnum comp)
3042         {
3043             this.value = val;
3044             this.comparison = comp;
3045         }
3046 
3047         /***
3048          * Create a new instance.
3049          *
3050          * @param table A String with the name of the table.
3051          * @param column A String with the name of the column.
3052          * @param val An Object with the value for the Criteria.
3053          * @param comp A String with the comparison value.
3054          */
3055         Criterion(String table, String column, Object val, SqlEnum comp)
3056         {
3057             this(val, comp);
3058             this.table = (table == null ? "" : table);
3059             this.column = (column == null ? "" : column);
3060         }
3061 
3062         /***
3063          * Create a new instance.
3064          *
3065          * @param tableColumn A String with the full name of the
3066          * column.
3067          * @param val An Object with the value for the Criteria.
3068          * @param comp A String with the comparison value.
3069          */
3070         Criterion(String tableColumn, Object val, SqlEnum comp)
3071         {
3072             this(val, comp);
3073             int dot = tableColumn.lastIndexOf('.');
3074             if (dot == -1)
3075             {
3076                 table = "";
3077                 column = tableColumn;
3078             }
3079             else
3080             {
3081                 table = tableColumn.substring(0, dot);
3082                 column = tableColumn.substring(dot + 1);
3083             }
3084         }
3085 
3086         /***
3087          * Create a new instance.
3088          *
3089          * @param table A String with the name of the table.
3090          * @param column A String with the name of the column.
3091          * @param val An Object with the value for the Criteria.
3092          */
3093         Criterion(String table, String column, Object val)
3094         {
3095             this(table, column, val, EQUAL);
3096         }
3097 
3098         /***
3099          * Create a new instance.
3100          *
3101          * @param tableColumn A String with the full name of the
3102          * column.
3103          * @param val An Object with the value for the Criteria.
3104          */
3105         Criterion(String tableColumn, Object val)
3106         {
3107             this(tableColumn, val, EQUAL);
3108         }
3109 
3110         /***
3111          * Get the column name.
3112          *
3113          * @return A String with the column name.
3114          */
3115         public String getColumn()
3116         {
3117             return this.column;
3118         }
3119 
3120         /***
3121          * Set the table name.
3122          *
3123          * @param name A String with the table name.
3124          */
3125         public void setTable(String name)
3126         {
3127             this.table = name;
3128         }
3129 
3130         /***
3131          * Get the table name.
3132          *
3133          * @return A String with the table name.
3134          */
3135         public String getTable()
3136         {
3137             return this.table;
3138         }
3139 
3140         /***
3141          * Get the comparison.
3142          *
3143          * @return A String with the comparison.
3144          */
3145         public SqlEnum getComparison()
3146         {
3147             return this.comparison;
3148         }
3149 
3150         /***
3151          * Get the value.
3152          *
3153          * @return An Object with the value.
3154          */
3155         public Object getValue()
3156         {
3157             return this.value;
3158         }
3159 
3160         /***
3161          * Get the value of db.
3162          * The DB adaptor which might be used to get db specific
3163          * variations of sql.
3164          * @return value of db.
3165          */
3166         public DB getDb()
3167         {
3168             DB db = null;
3169             if (this.db == null)
3170             {
3171                 // db may not be set if generating preliminary sql for
3172                 // debugging.
3173                 try
3174                 {
3175                     db = Torque.getDB(getDbName());
3176                 }
3177                 catch (Exception e)
3178                 {
3179                     // we are only doing this to allow easier debugging, so
3180                     // no need to throw up the exception, just make note of it.
3181                     log.error(
3182                             "Could not get a DB adapter, so sql may be wrong");
3183                 }
3184             }
3185             else
3186             {
3187                 db = this.db;
3188             }
3189 
3190             return db;
3191         }
3192 
3193         /***
3194          * Set the value of db.
3195          * The DB adaptor might be used to get db specific
3196          * variations of sql.
3197          * @param v  Value to assign to db.
3198          */
3199         public void setDB(DB v)
3200         {
3201             this.db = v;
3202 
3203             for (int i = 0; i < this.clauses.size(); i++)
3204             {
3205                 ((Criterion) (clauses.get(i))).setDB(v);
3206             }
3207         }
3208 
3209         /***
3210          * Sets ignore case.
3211          *
3212          * @param b True if case should be ignored.
3213          * @return A modified Criteria object.
3214          */
3215         public Criterion setIgnoreCase(boolean b)
3216         {
3217             ignoreStringCase = b;
3218             return this;
3219         }
3220 
3221         /***
3222          * Is ignore case on or off?
3223          *
3224          * @return True if case is ignored.
3225          */
3226         public boolean isIgnoreCase()
3227         {
3228             return ignoreStringCase;
3229         }
3230 
3231         /***
3232          *  get the list of clauses in this Criterion
3233          */
3234         private List getClauses()
3235         {
3236             return clauses;
3237         }
3238 
3239         /***
3240          *  get the list of conjunctions in this Criterion
3241          */
3242         private List getConjunctions()
3243         {
3244             return conjunctions;
3245         }
3246 
3247         /***
3248          * Append an AND Criterion onto this Criterion's list.
3249          */
3250         public Criterion and(Criterion criterion)
3251         {
3252             this.clauses.add(criterion);
3253             this.conjunctions.add(AND);
3254             return this;
3255         }
3256 
3257         /***
3258          * Append an OR Criterion onto this Criterion's list.
3259          */
3260         public Criterion or(Criterion criterion)
3261         {
3262             this.clauses.add(criterion);
3263             this.conjunctions.add(OR);
3264             return this;
3265         }
3266 
3267         /***
3268          * Appends a representation of the Criterion onto the buffer.
3269          */
3270         public void appendTo(StringBuffer sb)
3271         {
3272             //
3273             // it is alright if value == null
3274             //
3275 
3276             if (column == null)
3277             {
3278                 return;
3279             }
3280 
3281             Criterion clause = null;
3282             for (int j = 0; j < this.clauses.size(); j++)
3283             {
3284                 sb.append('(');
3285             }
3286             if (CUSTOM == comparison)
3287             {
3288                 if (value != null && !"".equals(value))
3289                 {
3290                     sb.append((String) value);
3291                 }
3292             }
3293             else
3294             {
3295                 String field = null;
3296                 if  (table == null)
3297                 {
3298                     field = column;
3299                 }
3300                 else
3301                 {
3302                     field = new StringBuffer(
3303                             table.length() + 1 + column.length())
3304                             .append(table).append('.').append(column)
3305                             .toString();
3306                 }
3307                 SqlExpression.build(field, value, comparison,
3308                         ignoreStringCase, getDb(), sb);
3309             }
3310 
3311             for (int i = 0; i < this.clauses.size(); i++)
3312             {
3313                 sb.append(this.conjunctions.get(i));
3314                 clause = (Criterion) (this.clauses.get(i));
3315                 clause.appendTo(sb);
3316                 sb.append(')');
3317             }
3318         }
3319 
3320         /***
3321          * Appends a Prepared Statement representation of the Criterion
3322          * onto the buffer.
3323          *
3324          * @param sb The stringbuffer that will receive the Prepared Statement
3325          * @param params A list to which Prepared Statement parameters
3326          * will be appended
3327          */
3328         public void appendPsTo(StringBuffer sb, List params)
3329         {
3330             if (column == null || value == null)
3331             {
3332                 return;
3333             }
3334 
3335             DB db = getDb();
3336 
3337             for (int j = 0; j < this.clauses.size(); j++)
3338             {
3339                 sb.append('(');
3340             }
3341             if (CUSTOM == comparison)
3342             {
3343                 if (!"".equals(value))
3344                 {
3345                     sb.append((String) value);
3346                 }
3347             }
3348             else
3349             {
3350                 String field = null;
3351                 if (table == null)
3352                 {
3353                     field = column;
3354                 }
3355                 else
3356                 {
3357                     field = new StringBuffer(
3358                             table.length() + 1 + column.length())
3359                             .append(table).append('.').append(column)
3360                             .toString();
3361                 }
3362 
3363                 if (comparison.equals(Criteria.IN)
3364                         || comparison.equals(Criteria.NOT_IN))
3365                 {
3366                     sb.append(field)
3367                             .append(comparison);
3368 
3369                     UniqueList inClause = new UniqueList();
3370 
3371                     if (value instanceof List)
3372                     {
3373                         value = ((List) value).toArray (new Object[0]);
3374                     }
3375 
3376                     for (int i = 0; i < Array.getLength(value); i++)
3377                     {
3378                         Object item = Array.get(value, i);
3379 
3380                         inClause.add(SqlExpression.processInValue(item,
3381                                              ignoreCase,
3382                                              db));
3383                     }
3384 
3385                     StringBuffer inString = new StringBuffer();
3386                     inString.append('(').append(StringUtils.join(
3387                                                         inClause.iterator(), (","))).append(')');
3388                     sb.append(inString.toString());
3389                 }
3390                 else
3391                 {
3392                     if (ignoreCase)
3393                     {
3394                         sb.append(db.ignoreCase(field))
3395                                 .append(comparison)
3396                                 .append(db.ignoreCase("?"));
3397                     }
3398                     else
3399                     {
3400                         sb.append(field)
3401                                 .append(comparison)
3402                                 .append(" ? ");
3403                     }
3404 
3405                     if (value instanceof java.util.Date)
3406                     {
3407                         params.add(new java.sql.Date(
3408                                            ((java.util.Date) value).getTime()));
3409                     }
3410                     else if (value instanceof DateKey)
3411                     {
3412                         params.add(new java.sql.Date(
3413                                            ((DateKey) value).getDate().getTime()));
3414                     }
3415                     else
3416                     {
3417                         params.add(value.toString());
3418                     }
3419                 }
3420             }
3421 
3422             for (int i = 0; i < this.clauses.size(); i++)
3423             {
3424                 sb.append(this.conjunctions.get(i));
3425                 Criterion clause = (Criterion) (this.clauses.get(i));
3426                 clause.appendPsTo(sb, params);
3427                 sb.append(')');
3428             }
3429         }
3430 
3431         /***
3432          * Build a string representation of the Criterion.
3433          *
3434          * @return A String with the representation of the Criterion.
3435          */
3436         public String toString()
3437         {
3438             //
3439             // it is alright if value == null
3440             //
3441             if (column == null)
3442             {
3443                 return "";
3444             }
3445 
3446             StringBuffer expr = new StringBuffer(25);
3447             appendTo(expr);
3448             return expr.toString();
3449         }
3450 
3451         /***
3452          * This method checks another Criteria to see if they contain
3453          * the same attributes and hashtable entries.
3454          */
3455         public boolean equals(Object obj)
3456         {
3457             if (this == obj)
3458             {
3459                 return true;
3460             }
3461 
3462             if ((obj == null) || !(obj instanceof Criterion))
3463             {
3464                 return false;
3465             }
3466 
3467             Criterion crit = (Criterion) obj;
3468 
3469             boolean isEquiv = ((table == null && crit.getTable() == null)
3470                     || (table != null && table.equals(crit.getTable()))
3471                                )
3472                     && column.equals(crit.getColumn())
3473                     && comparison.equals(crit.getComparison());
3474 
3475             // we need to check for value equality
3476             if (isEquiv)
3477             {
3478                 Object b = crit.getValue();
3479                 if (value instanceof Object[] && b instanceof Object[])
3480                 {
3481                     isEquiv &= Arrays.equals((Object[]) value, (Object[]) b);
3482                 }
3483                 else if (value instanceof int[] && b instanceof int[])
3484                 {
3485                     isEquiv &= Arrays.equals((int[]) value, (int[]) b);
3486                 }
3487                 else
3488                 {
3489                     isEquiv &= value.equals(b);
3490                 }
3491             }
3492 
3493             // check chained criterion
3494 
3495             isEquiv &= this.clauses.size() == crit.getClauses().size();
3496             for (int i = 0; i < this.clauses.size(); i++)
3497             {
3498                 isEquiv &=  ((String) (conjunctions.get(i)))
3499                         .equals((String) (crit.getConjunctions().get(i)));
3500                 isEquiv &=  ((Criterion) (clauses.get(i)))
3501                         .equals((Criterion) (crit.getClauses().get(i)));
3502             }
3503 
3504             return isEquiv;
3505         }
3506 
3507         /***
3508          * Returns a hash code value for the object.
3509          */
3510         public int hashCode()
3511         {
3512             int h = value.hashCode() ^ comparison.hashCode();
3513 
3514             if (table != null)
3515             {
3516                 h ^= table.hashCode();
3517             }
3518 
3519             if (column != null)
3520             {
3521                 h ^= column.hashCode();
3522             }
3523 
3524             for (int i = 0; i < this.clauses.size(); i++)
3525             {
3526                 h ^= ((Criterion) (clauses.get(i))).hashCode();
3527             }
3528 
3529             return h;
3530         }
3531 
3532         /***
3533          * get all tables from nested criterion objects
3534          *
3535          * @return the list of tables
3536          */
3537         public List getAllTables()
3538         {
3539             UniqueList tables = new UniqueList();
3540             addCriterionTable(this, tables);
3541             return tables;
3542         }
3543 
3544         /***
3545          * method supporting recursion through all criterions to give
3546          * us a StringStack of tables from each criterion
3547          */
3548         private void addCriterionTable(Criterion c, UniqueList s)
3549         {
3550             if (c != null)
3551             {
3552                 s.add(c.getTable());
3553                 for (int i = 0; i < c.getClauses().size(); i++)
3554                 {
3555                     addCriterionTable((Criterion) (c.getClauses().get(i)), s);
3556                 }
3557             }
3558         }
3559 
3560         /***
3561          * get an array of all criterion attached to this
3562          * recursing through all sub criterion
3563          */
3564         public Criterion[] getAttachedCriterion()
3565         {
3566             ArrayList crits = new ArrayList();
3567             traverseCriterion(this, crits);
3568             Criterion[] crita = new Criterion[crits.size()];
3569             for (int i = 0; i < crits.size(); i++)
3570             {
3571                 crita[i] = (Criterion) crits.get(i);
3572             }
3573 
3574             return crita;
3575         }
3576 
3577         /***
3578          * method supporting recursion through all criterions to give
3579          * us an ArrayList of them
3580          */
3581         private void traverseCriterion(Criterion c, ArrayList a)
3582         {
3583             if (c != null)
3584             {
3585                 a.add(c);
3586                 for (int i = 0; i < c.getClauses().size(); i++)
3587                 {
3588                     traverseCriterion((Criterion) (c.getClauses().get(i)), a);
3589                 }
3590             }
3591         }
3592     }
3593     
3594     /***
3595      * Data object to describe a join between two tables, for example
3596      * <pre>
3597      * table_a LEFT JOIN table_b ON table_a.id = table_b.a_id
3598      * </pre>
3599      * The class is immutable. Because the class is also used by 
3600      * {@link org.apache.torque.util.BasePeer}, it is visible from the package.
3601      */
3602     public static class Join
3603     {
3604         /*** the left column of the join condition */
3605         private String leftColumn = null;
3606       
3607         /*** the right column of the join condition */
3608         private String rightColumn = null;
3609       
3610         /*** the type of the join (LEFT JOIN, ...), or null */
3611         private SqlEnum joinType = null;
3612       
3613         /***
3614          * Constructor
3615          * @param leftColumn the left column of the join condition; 
3616          *        might contain an alias name
3617          * @param rightColumn the right column of the join condition
3618          *        might contain an alias name
3619          * @param joinType the type of the join. Valid join types are 
3620          *        null (adding the join condition to the where clause),
3621          *        SqlEnum.LEFT_JOIN, SqlEnum.RIGHT_JOIN, and SqlEnum.INNER_JOIN
3622          */
3623         public Join(
3624                 final String leftColumn, 
3625                 final String rightColumn, 
3626                 final SqlEnum joinType)
3627         {
3628             this.leftColumn = leftColumn;
3629             this.rightColumn = rightColumn;
3630             this.joinType = joinType;
3631         }
3632       
3633         /***
3634          * @return the type of the join, i.e. SqlEnum.LEFT_JOIN, ..., 
3635          *         or null for adding the join condition to the where Clause
3636          */
3637         public final SqlEnum getJoinType() 
3638         {
3639             return joinType;
3640         }
3641   
3642         /***
3643          * @return the left column of the join condition
3644          */
3645         public final String getLeftColumn() 
3646         {
3647             return leftColumn;
3648         }
3649   
3650         /***
3651          * @return the right column of the join condition
3652          */
3653         public final String getRightColumn() 
3654         {
3655             return rightColumn;
3656         }
3657         
3658         /***
3659          * returns a String representation of the class,
3660          * mainly for debuggung purposes
3661          * @return a String representation of the class
3662          */
3663         public String toString() 
3664         {
3665             StringBuffer result = new StringBuffer();
3666             if (joinType != null)
3667             {
3668                 result.append(joinType)
3669                         .append(" : ");
3670             }
3671             result.append(leftColumn)
3672                     .append("=")
3673                     .append(rightColumn)
3674                     .append(" (ignoreCase not considered)");
3675 
3676             return result.toString();
3677         }
3678     } // end of inner class Join
3679 }