View Javadoc

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