View Javadoc

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