org.apache.torque.util.Criteria.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.torque.util.Criteria.java

Source

package org.apache.torque.util;

/* ====================================================================
 * The Apache Software License, Version 1.1
 *
 * Copyright (c) 2001-2002 The Apache Software Foundation.  All rights
 * reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in
 *    the documentation and/or other materials provided with the
 *    distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgment:
 *       "This product includes software developed by the
 *        Apache Software Foundation (http://www.apache.org/)."
 *    Alternately, this acknowledgment may appear in the software itself,
 *    if and wherever such third-party acknowledgments normally appear.
 *
 * 4. The names "Apache" and "Apache Software Foundation" and
 *    "Apache Turbine" must not be used to endorse or promote products
 *    derived from this software without prior written permission. For
 *    written permission, please contact apache@apache.org.
 *
 * 5. Products derived from this software may not be called "Apache",
 *    "Apache Turbine", nor may "Apache" appear in their name, without
 *    prior written permission of the Apache Software Foundation.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
 * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 * ====================================================================
 *
 * This software consists of voluntary contributions made by many
 * individuals on behalf of the Apache Software Foundation.  For more
 * information on the Apache Software Foundation, please see
 * <http://www.apache.org/>.
 */

import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.GregorianCalendar;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.apache.torque.Torque;
import org.apache.torque.TorqueException;
import org.apache.torque.adapter.DB;
import org.apache.torque.map.DatabaseMap;
import org.apache.torque.om.DateKey;
import org.apache.torque.om.ObjectKey;
import org.apache.commons.collections.StringStack;
import org.apache.log4j.Category;

/**
 * This is a utility class that is used for retrieving different types
 * of values from a hashtable based on a simple name string.  This
 * class is meant to minimize the amount of casting that needs to be
 * done when working with Hashtables.
 *
 * NOTE: other methods will be added as needed and as time permits.
 *
 * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
 * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
 * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
 * @author <a href="mailto:eric@dobbse.net">Eric Dobbs</a>
 * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 * @author <a href="mailto:sam@neurogrid.com">Sam Joseph</a>
 * @version $Id: Criteria.java,v 1.1 2003/03/27 21:08:24 wolfj Exp $
 */
public class Criteria extends Hashtable {

    /** Comparison type. */
    public static final SqlEnum EQUAL = SqlEnum.EQUAL;

    /** Comparison type. */
    public static final SqlEnum NOT_EQUAL = SqlEnum.NOT_EQUAL;

    /** Comparison type. */
    public static final SqlEnum ALT_NOT_EQUAL = SqlEnum.ALT_NOT_EQUAL;

    /** Comparison type. */
    public static final SqlEnum GREATER_THAN = SqlEnum.GREATER_THAN;

    /** Comparison type. */
    public static final SqlEnum LESS_THAN = SqlEnum.LESS_THAN;

    /** Comparison type. */
    public static final SqlEnum GREATER_EQUAL = SqlEnum.GREATER_EQUAL;

    /** Comparison type. */
    public static final SqlEnum LESS_EQUAL = SqlEnum.LESS_EQUAL;

    /** Comparison type. */
    public static final SqlEnum LIKE = SqlEnum.LIKE;

    /** Comparison type. */
    public static final SqlEnum NOT_LIKE = SqlEnum.NOT_LIKE;

    /** Comparison type. */
    public static final SqlEnum CUSTOM = SqlEnum.CUSTOM;

    /** Comparison type. */
    public static final SqlEnum DISTINCT = SqlEnum.DISTINCT;

    /** Comparison type. */
    public static final SqlEnum IN = SqlEnum.IN;

    /** Comparison type. */
    public static final SqlEnum NOT_IN = SqlEnum.NOT_IN;

    /** Comparison type. */
    public static final SqlEnum ALL = SqlEnum.ALL;

    /** Comparison type. */
    public static final SqlEnum JOIN = SqlEnum.JOIN;

    /** "Order by" qualifier - ascending */
    private static final SqlEnum ASC = SqlEnum.ASC;

    /** "Order by" qualifier - descending */
    private static final SqlEnum DESC = SqlEnum.DESC;

    /** "IS NULL" null comparison */
    public static final SqlEnum ISNULL = SqlEnum.ISNULL;

    /** "IS NOT NULL" null comparison */
    public static final SqlEnum ISNOTNULL = SqlEnum.ISNOTNULL;

    /** "CURRENT_DATE" ANSI SQL function */
    public static final SqlEnum CURRENT_DATE = SqlEnum.CURRENT_DATE;

    /** "CURRENT_TIME" ANSI SQL function */
    public static final SqlEnum CURRENT_TIME = SqlEnum.CURRENT_TIME;

    private static final int DEFAULT_CAPACITY = 10;

    private boolean ignoreCase = false;
    private boolean singleRecord = false;
    private boolean cascade = false;
    private StringStack selectModifiers = new StringStack();
    private StringStack selectColumns = new StringStack();
    private StringStack orderByColumns = new StringStack();
    private StringStack groupByColumns = new StringStack();
    private Criterion having = null;
    private Hashtable asColumns = new Hashtable(8);
    private ArrayList joinL = null;
    private ArrayList joinR = null;

    /** The name of the database. */
    private String dbName;

    /** The name of the database as given in the contructor. */
    private String originalDbName;

    /**
     * To limit the number of rows to return.  <code>-1</code> means return all
     * rows.
     */
    private int limit = -1;

    /** To start the results at a row other than the first one. */
    private int offset = 0;

    // flag to note that the criteria involves a blob.
    private Boolean blobFlag = null;

    private HashMap aliases = null;

    private boolean useTransaction = false;

    /** Log4j category used for logging. */
    private static Category category = Category.getInstance(Criteria.class.getName());

    /**
     * Creates a new instance with the default capacity.
     */
    public Criteria() {
        this(DEFAULT_CAPACITY);
    }

    /**
     * Creates a new instance with the specified capacity.
     *
     * @param initialCapacity An int.
     */
    public Criteria(int initialCapacity) {
        this(Torque.getDefaultDB(), initialCapacity);
    }

    /**
     * Creates a new instance with the default capacity which corresponds to
     * the specified database.
     *
     * @param dbName The dabase name.
     */
    public Criteria(String dbName) {
        this(dbName, DEFAULT_CAPACITY);
    }

    /**
     * Creates a new instance with the specified capacity which corresponds to
     * the specified database.
     *
     * @param dbName          The dabase name.
     * @param initialCapacity The initial capacity.
     */
    public Criteria(String dbName, int initialCapacity) {
        super(initialCapacity);
        this.dbName = dbName;
        this.originalDbName = dbName;
    }

    /**
     * Brings this criteria back to its initial state, so that it
     * can be reused as if it was new. Except if the criteria has grown in
     * capacity, it is left at the current capacity.
     */
    public void clear() {
        super.clear();
        ignoreCase = false;
        singleRecord = false;
        cascade = false;
        selectModifiers.clear();
        selectColumns.clear();
        orderByColumns.clear();
        groupByColumns.clear();
        having = null;
        asColumns.clear();
        joinL = null;
        joinR = null;
        dbName = originalDbName;
        offset = 0;
        limit = -1;
        blobFlag = null;
        aliases = null;
        useTransaction = false;
    }

    /**
     * Add an AS clause to the select columns. Usage:
     * <p>
     * <code>
     *
     * Criteria myCrit = new Criteria();
     * myCrit.addAsColumn("alias", "ALIAS("+MyPeer.ID+")");
     *
     * </code>
     *
     * @param name  wanted Name of the column
     * @param clause SQL clause to select from the table
     *
     * If the name already exists, it is replaced by the new clause.
     *
     * @return A modified Criteria object.
     */
    public Criteria addAsColumn(String name, String clause) {
        asColumns.put(name, clause);
        return this;
    }

    /**
     * Get the column aliases.
     *
     * @return A Hashtable which map the column alias names
     * to the alias clauses.
     */
    public Hashtable getAsColumns() {
        return asColumns;
    }

    /**
     * Allows one to specify an alias for a table that can
     * be used in various parts of the SQL.
     *
     * @param alias a <code>String</code> value
     * @param table a <code>String</code> value
     */
    public void addAlias(String alias, String table) {
        if (aliases == null) {
            aliases = new HashMap(8);
        }
        aliases.put(alias, table);
    }

    /**
     * Returns the table name associated with an alias.
     *
     * @param alias a <code>String</code> value
     * @return a <code>String</code> value
     */
    public String getTableForAlias(String alias) {
        if (aliases == null) {
            return null;
        }
        return (String) aliases.get(alias);
    }

    /**
     * Does this Criteria Object contain the specified key?
     *
     * @param table The name of the table.
     * @param column The name of the column.
     * @return True if this Criteria Object contain the specified key.
     */
    public boolean containsKey(String table, String column) {
        return containsKey(table + '.' + column);
    }

    /**
     * Convenience method to return value as a boolean.
     *
     * @param column String name of column.
     * @return A boolean.
     */
    public boolean getBoolean(String column) {
        return ((Boolean) getCriterion(column).getValue()).booleanValue();
    }

    /**
     * Convenience method to return value as a boolean.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A boolean.
     */
    public boolean getBoolean(String table, String column) {
        return getBoolean(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Returns true if any of the tables in the criteria contain an
     * Object column.
     *
     * @return A boolean.
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     */
    public boolean containsObjectColumn() throws TorqueException {
        return containsObjectColumn(dbName);
    }

    /**
     * Returns true if any of the tables in the criteria contain an
     * Object column.
     *
     * @param databaseMapName A String.
     * @return A boolean.
     * @throws TorqueException Any exceptions caught during processing will be
     *         rethrown wrapped into a TorqueException.
     * @deprecated not sure why anyone would need to use this outside of its
     * use in BasePeer, but it was public, so its now deprecated.
     * It was used to decide whether a transaction should be used, this can
     * be done with the useTransaction() method.
     */
    public boolean containsObjectColumn(String databaseMapName) throws TorqueException {
        // Peer or application may have noted the existence of a blob
        // so we can save the lookup.
        if (blobFlag != null) {
            return blobFlag.booleanValue();
        }

        DatabaseMap map = Torque.getDatabaseMap(databaseMapName);
        StringStack tables = new StringStack();
        for (Iterator it = super.values().iterator(); it.hasNext();) {
            Criterion co = (Criterion) it.next();
            String tableName = co.getTable();
            String tableName2 = getTableForAlias(tableName);
            if (tableName2 != null) {
                tableName = tableName2;
            }

            if (!tables.contains(tableName)) {
                if (map.getTable(tableName).containsObjectColumn()) {
                    return true;
                }
                tables.add(tableName);
            }
        }
        return false;
    }

    /**
     * Will force the sql represented by this criteria to be executed within
     * a transaction.  This is here primarily to support the oid type in
     * postgresql.  Though it can be used to require any single sql statement
     * to use a transaction.
     */
    public void setUseTransaction(boolean v) {
        useTransaction = v;
    }

    /**
     * called by BasePeer to determine whether the sql command specified by
     * this criteria must be wrapped in a transaction.
     *
     * @return a <code>boolean</code> value
     */
    protected boolean isUseTransaction() {
        return useTransaction;
    }

    /**
     * Method to return criteria related to columns in a table.
     *
     * @param column String name of column.
     * @return A Criterion.
     */
    public Criterion getCriterion(String column) {
        return (Criterion) super.get(column);
    }

    /**
     * Method to return criteria related to a column in a table.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A Criterion.
     */
    public Criterion getCriterion(String table, String column) {
        return getCriterion(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Method to return criterion that is not added automatically
     * to this Criteria.  This can be used to chain the
     * Criterions to form a more complex where clause.
     *
     * @param column String full name of column (for example TABLE.COLUMN).
     * @return A Criterion.
     */
    public Criterion getNewCriterion(String column, Object value, SqlEnum comparison) {
        return new Criterion(column, value, comparison);
    }

    /**
     * Method to return criterion that is not added automatically
     * to this Criteria.  This can be used to chain the
     * Criterions to form a more complex where clause.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A Criterion.
     */
    public Criterion getNewCriterion(String table, String column, Object value, SqlEnum comparison) {
        return new Criterion(table, column, value, comparison);
    }

    /**
     * This method adds a prepared Criterion object to the Criteria.
     * You can get a new, empty Criterion object with the
     * getNewCriterion() method. If a criterion for the requested column
     * already exists, it is replaced. This is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria();
     * Criteria.Criterion c = crit
     * .getNewCriterion(BasePeer.ID, new Integer(5), Criteria.LESS_THAN);
     * crit.add(c);
     * </code>
     *
     * @param c A Criterion object
     *
     * @return A modified Criteria object.
     */
    public Criteria add(Criterion c) {
        StringBuffer sb = new StringBuffer(c.getTable().length() + c.getColumn().length() + 1);
        sb.append(c.getTable());
        sb.append('.');
        sb.append(c.getColumn());
        super.put(sb.toString(), c);
        return this;
    }

    /**
     * Method to return a String table name.
     *
     * @param name A String with the name of the key.
     * @return A String with the value of the object at key.
     */
    public String getColumnName(String name) {
        return getCriterion(name).getColumn();
    }

    /**
     * Method to return a comparison String.
     *
     * @param key String name of the key.
     * @return A String with the value of the object at key.
     */
    public SqlEnum getComparison(String key) {
        return getCriterion(key).getComparison();
    }

    /**
     * Method to return a comparison String.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A String with the value of the object at key.
     */
    public SqlEnum getComparison(String table, String column) {
        return getComparison(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return a Date.
     *
     * @param name column name (TABLE.COLUMN)
     * @return A java.util.Date with the value of object at key.
     */
    public java.util.Date getDate(String name) {
        return (java.util.Date) getCriterion(name).getValue();
    }

    /**
     * Convenience method to return a Date.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A java.util.Date with the value of object at key.
     */
    public java.util.Date getDate(String table, String column) {
        return getDate(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Get the Database(Map) name.
     *
     * @return A String with the Database(Map) name.  By default, this
     * is PoolBrokerService.DEFAULT.
     */
    public String getDbName() {
        return dbName;
    }

    /**
     * Set the DatabaseMap name.  If <code>null</code> is supplied, uses value
     * provided by <code>Torque.getDefaultDB()</code>.
     *
     * @param dbName A String with the Database(Map) name.
     */
    public void setDbName(String dbName) {
        this.dbName = (dbName == null ? Torque.getDefaultDB() : dbName);
    }

    /**
     * Convenience method to return a double.
     *
     * @param name A String with the name of the key.
     * @return A double with the value of object at key.
     */
    public double getDouble(String name) {
        Object obj = getCriterion(name).getValue();
        if (obj instanceof String) {
            return new Double((String) obj).doubleValue();
        }
        return ((Double) obj).doubleValue();
    }

    /**
     * Convenience method to return a double.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A double with the value of object at key.
     */
    public double getDouble(String table, String column) {
        return getDouble(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return a float.
     *
     * @param name A String with the name of the key.
     * @return A float with the value of object at key.
     */
    public float getFloat(String name) {
        Object obj = getCriterion(name).getValue();
        if (obj instanceof String) {
            return new Float((String) obj).floatValue();
        }
        return ((Float) obj).floatValue();
    }

    /**
     * Convenience method to return a float.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A float with the value of object at key.
     */
    public float getFloat(String table, String column) {
        return getFloat(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return an Integer.
     *
     * @param name A String with the name of the key.
     * @return An Integer with the value of object at key.
     */
    public Integer getInteger(String name) {
        Object obj = getCriterion(name).getValue();
        if (obj instanceof String) {
            return new Integer((String) obj);
        }
        return ((Integer) obj);
    }

    /**
     * Convenience method to return an Integer.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return An Integer with the value of object at key.
     */
    public Integer getInteger(String table, String column) {
        return getInteger(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return an int.
     *
     * @param name A String with the name of the key.
     * @return An int with the value of object at key.
     */
    public int getInt(String name) {
        Object obj = getCriterion(name).getValue();
        if (obj instanceof String) {
            return new Integer((String) obj).intValue();
        }
        return ((Integer) obj).intValue();
    }

    /**
     * Convenience method to return an int.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return An int with the value of object at key.
     */
    public int getInt(String table, String column) {
        return getInt(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return a BigDecimal.
     *
     * @param name A String with the name of the key.
     * @return A BigDecimal with the value of object at key.
     */
    public BigDecimal getBigDecimal(String name) {
        Object obj = getCriterion(name).getValue();
        if (obj instanceof String) {
            return new BigDecimal((String) obj);
        }
        return (BigDecimal) obj;
    }

    /**
     * Convenience method to return a BigDecimal.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A BigDecimal with the value of object at key.
     */
    public BigDecimal getBigDecimal(String table, String column) {
        return getBigDecimal(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return a long.
     *
     * @param name A String with the name of the key.
     * @return A long with the value of object at key.
     */
    public long getLong(String name) {
        Object obj = getCriterion(name).getValue();
        if (obj instanceof String) {
            return new Long((String) obj).longValue();
        }
        return ((Long) obj).longValue();
    }

    /**
     * Convenience method to return a long.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A long with the value of object at key.
     */
    public long getLong(String table, String column) {
        return getLong(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return a String.
     *
     * @param name A String with the name of the key.
     * @return A String with the value of object at key.
     */
    public String getString(String name) {
        return (String) getCriterion(name).getValue();
    }

    /**
     * Convenience method to return a String.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A String with the value of object at key.
     */
    public String getString(String table, String column) {
        return getString(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Method to return a String table name.
     *
     * @param name A String with the name of the key.
     * @return A String with the value of object at key.
     */
    public String getTableName(String name) {
        return getCriterion(name).getTable();
    }

    /**
     * Convenience method to return a List.
     *
     * @param name A String with the name of the key.
     * @return A List with the value of object at key.
     */
    public List getList(String name) {
        return (List) getCriterion(name).getValue();
    }

    /**
     * Convenience method to return a List.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A List with the value of object at key.
     */
    public List getList(String table, String column) {
        return getList(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Method to return the value that was added to Criteria.
     *
     * @param name A String with the name of the key.
     * @return An Object with the value of object at key.
     */
    public Object getValue(String name) {
        return getCriterion(name).getValue();
    }

    /**
     * Method to return the value that was added to Criteria.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return An Object with the value of object at key.
     */
    public Object getValue(String table, String column) {
        return getValue(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Convenience method to return an ObjectKey.
     *
     * @param name A String with the name of the key.
     * @return An ObjectKey with the value of object at key.
     */
    public ObjectKey getObjectKey(String name) {
        return (ObjectKey) getCriterion(name).getValue();
    }

    /**
     * Convenience method to return an ObjectKey.
     *
     * @param table String name of table.
     * @param column String name of column.
     * @return A String with the value of object at key.
     */
    public ObjectKey getObjectKey(String table, String column) {
        return getObjectKey(new StringBuffer(table.length() + column.length() + 1).append(table).append('.')
                .append(column).toString());
    }

    /**
     * Overrides Hashtable get, so that the value placed in the
     * Criterion is returned instead of the Criterion.
     *
     * @param key An Object.
     * @return An Object.
     */
    public Object get(Object key) {
        return getValue((String) key);
    }

    /**
     * Overrides Hashtable put, so that this object is returned
     * instead of the value previously in the Criteria object.
     * The reason is so that it more closely matches the behavior
     * of the add() methods. If you want to get the previous value
     * then you should first Criteria.get() it yourself. Note, if
     * you attempt to pass in an Object that is not a String, it will
     * throw a NPE. The reason for this is that none of the add()
     * methods support adding anything other than a String as a key.
     *
     * @param key An Object. Must be instanceof String!
     * @param value An Object.
     * @throws NullPointerException if key != String or key/value is null.
     * @return Instance of self.
     */
    public Object put(Object key, Object value) {
        if (!(key instanceof String)) {
            throw new NullPointerException("Criteria: Key must be a String object.");
        }
        return add((String) key, value);
    }

    /**
     * Copies all of the mappings from the specified Map to this Criteria
     * These mappings will replace any mappings that this Criteria had for any
     * of the keys currently in the specified Map.
     *
     * if the map was another Criteria, its attributes are copied to this
     * Criteria, overwriting previous settings.
     *
     * @param t Mappings to be stored in this map.
     */
    public synchronized void putAll(Map t) {
        Iterator i = t.entrySet().iterator();
        while (i.hasNext()) {
            Map.Entry e = (Map.Entry) i.next();
            Object val = e.getValue();
            if (val instanceof Criteria.Criterion) {
                super.put(e.getKey(), val);
            } else {
                put(e.getKey(), val);
            }
        }
        if (t instanceof Criteria) {
            Criteria c = (Criteria) t;
            this.joinL = c.joinL;
            this.joinR = c.joinR;
        }
        /* this would make a copy, not included
           but might want to use some of it.
        if (t instanceof Criteria)
        {
        Criteria c = (Criteria)t;
        this.ignoreCase = c.ignoreCase;
        this.singleRecord = c.singleRecord;
        this.cascade = c.cascade;
        this.selectModifiers = c.selectModifiers;
        this.selectColumns = c.selectColumns;
        this.orderByColumns = c.orderByColumns;
        this.dbName = c.dbName;
        this.limit = c.limit;
        this.offset = c.offset;
        this.aliases = c.aliases;
        }
        */
    }

    /**
     * This method adds a new criterion to the list of criterias. If a
     * criterion for the requested column already exists, it is
     * replaced. This is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().add(&quot;column&quot;,
     *                                      &quot;value&quot;);
     * </code>
     *
     * An EQUAL comparison is used for column and value.
     *
     * The name of the table must be used implicitly in the column name,
     * so the Column name must be something like 'TABLE.id'. If you
     * don't like this, you can use the add(table, column, value) method.
     *
     * @param column The column to run the comparison on
     * @param value An Object.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, Object value) {
        add(column, value, EQUAL);
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * replaced. If is used as follow:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().add(&quot;column&quot;,
     *                                      &quot;value&quot;
     *                                      &quot;Criterion.GREATER_THAN&quot;);
     * </code>
     *
     * Any comparison can be used.
     *
     * The name of the table must be used implicitly in the column name,
     * so the Column name must be something like 'TABLE.id'. If you
     * don't like this, you can use the add(table, column, value) method.
     *
     * @param column The column to run the comparison on
     * @param value An Object.
     * @param comparison A String.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, Object value, SqlEnum comparison) {
        super.put(column, new Criterion(column, value, comparison));
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * replaced. If is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().add(&quot;table&quot;,
     *                                      &quot;column&quot;,
     *                                      &quot;value&quot;);
     * </code>
     *
     * An EQUAL comparison is used for column and value.
     *
     * @param table Name of the table which contains the column
     * @param column The column to run the comparison on
     * @param value An Object.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String table, String column, Object value) {
        add(table, column, value, EQUAL);
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * replaced. If is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().add(&quot;table&quot;,
     *                                      &quot;column&quot;,
     *                                      &quot;value&quot;,
     *                                      &quot;Criterion.GREATER_THAN&quot;);
     * </code>
     *
     * Any comparison can be used.
     *
     * @param table Name of table which contains the column
     * @param column The column to run the comparison on
     * @param value An Object.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String table, String column, Object value, SqlEnum comparison) {
        StringBuffer sb = new StringBuffer(table.length() + column.length() + 1);
        sb.append(table);
        sb.append('.');
        sb.append(column);
        super.put(sb.toString(), new Criterion(table, column, value, comparison));
        return this;
    }

    /**
     * Convenience method to add a boolean to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Boolean(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A Boolean.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, boolean value) {
        add(column, (value ? Boolean.TRUE : Boolean.FALSE));
        return this;
    }

    /**
     * Convenience method to add a boolean to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Boolean(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A Boolean.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, boolean value, SqlEnum comparison) {
        add(column, new Boolean(value), comparison);
        return this;
    }

    /**
     * Convenience method to add an int to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Integer(value), EQUAL);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value An int.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, int value) {
        add(column, new Integer(value));
        return this;
    }

    /**
     * Convenience method to add an int to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Integer(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value An int.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, int value, SqlEnum comparison) {
        add(column, new Integer(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a long to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Long(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A long.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, long value) {
        add(column, new Long(value));
        return this;
    }

    /**
     * Convenience method to add a long to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Long(value), comparison);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value A long.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, long value, SqlEnum comparison) {
        add(column, new Long(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a float to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Float(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A float.
     * @return A modified Criteria object.
     */
    public Criteria add(String column, float value) {
        add(column, new Float(value));
        return this;
    }

    /**
     * Convenience method to add a float to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Float(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A float.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, float value, SqlEnum comparison) {
        add(column, new Float(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a double to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Double(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A double.
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, double value) {
        add(column, new Double(value));
        return this;
    }

    /**
     * Convenience method to add a double to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new Double(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A double.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria add(String column, double value, SqlEnum comparison) {
        add(column, new Double(value), comparison);
        return this;
    }

    /**
     * @deprecated These methods were wrongly named and are misleading.
     *             Use addDate() instead.
     */
    public Criteria addTime(String column, int year, int month, int date) {
        return addDate(column, year, month, date);
    }

    /**
     * @deprecated These methods were wrongly named and are misleading.
     *             Use addDate() instead.
     */
    public Criteria addTime(String column, int year, int month, int date, SqlEnum comparison) {
        return addDate(column, year, month, date, comparison);
    }

    /**
     * Convenience method to add a Date object specified by
     * year, month, and date into the Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new GregorianCalendar(year, month,date), EQUAL);
     * </code>
     *
     * @param column A String value to use as column.
     * @param year An int with the year.
     * @param month An int with the month.
     * @param date An int with the date.
     * @return A modified Criteria object.
     */
    public Criteria addDate(String column, int year, int month, int date) {
        add(column, new GregorianCalendar(year, month, date));
        return this;
    }

    /**
     * Convenience method to add a Date object specified by
     * year, month, and date into the Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * add(column, new GregorianCalendar(year, month,date), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param year An int with the year.
     * @param month An int with the month.
     * @param date An int with the date.
     * @param comparison String describing how to compare the column with the value
     * @return A modified Criteria object.
     */
    public Criteria addDate(String column, int year, int month, int date, SqlEnum comparison) {
        add(column, new GregorianCalendar(year, month, date), comparison);
        return this;
    }

    /* *
     * Convenience method to add a Key to Criteria.
     *
     * @param key A String value to use as key.
     * @param value A Key.
     * @return A modified Criteria object.
     * /
    public Criteria add (String key,
                     Key value)
    {
    add(key, value.getInternalObject());
    return this;
    }
    */

    /**
     * This is the way that you should add a join of two tables.  For
     * example:
     *
     * <p>
     * AND PROJECT.PROJECT_ID=FOO.PROJECT_ID
     * <p>
     *
     * left = PROJECT.PROJECT_ID
     * right = FOO.PROJECT_ID
     *
     * @param left A String with the left side of the join.
     * @param right A String with the right side of the join.
     * @return A modified Criteria object.
     */
    public Criteria addJoin(String left, String right) {
        if (joinL == null) {
            joinL = new ArrayList(3);
            joinR = new ArrayList(3);
        }
        joinL.add(left);
        joinR.add(right);

        return this;
    }

    /**
     * get one side of the set of possible joins.  This method is meant to
     * be called by BasePeer.
     */
    public List getJoinL() {
        return joinL;
    }

    /**
     * get one side of the set of possible joins.  This method is meant to
     * be called by BasePeer.
     */
    public List getJoinR() {
        return joinR;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as an Object
     * array.  For example:
     *
     * <p>
     * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * replaced.
     *
     * @param column The column to run the comparison on
     * @param values An Object[] with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria addIn(String column, Object[] values) {
        add(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as an int array.
     * For example:
     *
     * <p>
     * FOO.ID IN ('2', '3', '7')
     * <p>
     *
     * where 'values' contains those three integers.
     *
     * If a criterion for the requested column already exists, it is
     * replaced.
     *
     * @param column The column to run the comparison on
     * @param values An int[] with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria addIn(String column, int[] values) {
        add(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as a List.
     * For example:
     *
     * <p>
     * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * replaced.
     *
     * @param column The column to run the comparison on
     * @param values A List with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria addIn(String column, List values) {
        add(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as an Object
     * array.  For example:
     *
     * <p>
     * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * replaced.
     *
     * @param column The column to run the comparison on
     * @param values An Object[] with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria addNotIn(String column, Object[] values) {
        add(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as an int
     * array.  For example:
     *
     * <p>
     * FOO.ID NOT IN ('2', '3', '7')
     * <p>
     *
     * where 'values' contains those three integers.
     *
     * If a criterion for the requested column already exists, it is
     * replaced.
     *
     * @param column The column to run the comparison on
     * @param values An int[] with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria addNotIn(String column, int[] values) {
        add(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as a List.
     * For example:
     *
     * <p>
     * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * replaced.
     *
     * @param column The column to run the comparison on
     * @param values A List with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria addNotIn(String column, List values) {
        add(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds "ALL " to the SQL statement.
     */
    public void setAll() {
        selectModifiers.add(ALL.toString());
    }

    /**
     * Adds "DISTINCT " to the SQL statement.
     */
    public void setDistinct() {
        selectModifiers.add(DISTINCT.toString());
    }

    /**
     * Sets ignore case.
     *
     * @param b True if case should be ignored.
     * @return A modified Criteria object.
     */
    public Criteria setIgnoreCase(boolean b) {
        ignoreCase = b;
        return this;
    }

    /**
     * Is ignore case on or off?
     *
     * @return True if case is ignored.
     */
    public boolean isIgnoreCase() {
        return ignoreCase;
    }

    /**
     * Set single record?  Set this to <code>true</code> if you expect the query
     * to result in only a single result record (the default behaviour is to
     * throw a TorqueException if multiple records are returned when the query
     * is executed).  This should be used in situations where returning multiple
     * rows would indicate an error of some sort.  If your query might return
     * multiple records but you are only interested in the first one then you
     * should be using setLimit(1).
     *
     * @param b set to <code>true</code> if you expect the query to select just
     * one record.
     * @return A modified Criteria object.
     */
    public Criteria setSingleRecord(boolean b) {
        singleRecord = b;
        return this;
    }

    /**
     * Is single record?
     *
     * @return True if a single record is being returned.
     */
    public boolean isSingleRecord() {
        return singleRecord;
    }

    /**
     * Set cascade.
     *
     * @param b True if cascade is set.
     * @return A modified Criteria object.
     */
    public Criteria setCascade(boolean b) {
        cascade = b;
        return this;
    }

    /**
     * Is cascade set?
     *
     * @return True if cascade is set.
     */
    public boolean isCascade() {
        return cascade;
    }

    /**
     * Set limit.
     *
     * @param limit An int with the value for limit.
     * @return A modified Criteria object.
     */
    public Criteria setLimit(int limit) {
        this.limit = limit;
        return this;
    }

    /**
     * Get limit.
     *
     * @return An int with the value for limit.
     */
    public int getLimit() {
        return limit;
    }

    /**
     * Set offset.
     *
     * @param offset An int with the value for offset.
     * @return A modified Criteria object.
     */
    public Criteria setOffset(int offset) {
        this.offset = offset;
        return this;
    }

    /**
     * Get offset.
     *
     * @return An int with the value for offset.
     */
    public int getOffset() {
        return offset;
    }

    /**
     * Add select column.
     *
     * @param name A String with the name of the select column.
     * @return A modified Criteria object.
     */
    public Criteria addSelectColumn(String name) {
        selectColumns.add(name);
        return this;
    }

    /**
     * Get select columns.
     *
     * @return A StringStack with the name of the select
     * columns.
     */
    public StringStack getSelectColumns() {
        return selectColumns;
    }

    /**
     * Get select modifiers.
     *
     * @return A StringStack with the select modifiers.
     */
    public StringStack getSelectModifiers() {
        return selectModifiers;
    }

    /**
     * @deprecated Use addAscendingOrderByColumn() instead.
     */
    public Criteria addOrderByColumn(String name) {
        orderByColumns.add(name);
        return this;
    }

    /**
     * Add group by column name.
     *
     * @param groupBy The name of the column to group by.
     * @return A modified Criteria object.
     */
    public Criteria addGroupByColumn(String groupBy) {
        groupByColumns.add(groupBy);
        return this;
    }

    /**
     * Add order by column name, explicitly specifying ascending.
     *
     * @param name The name of the column to order by.
     * @return A modified Criteria object.
     */
    public Criteria addAscendingOrderByColumn(String name) {
        orderByColumns.add(name + ' ' + ASC);
        return this;
    }

    /**
     * Add order by column name, explicitly specifying descending.
     *
     * @param name The name of the column to order by.
     * @return A modified Criteria object.
     */
    public Criteria addDescendingOrderByColumn(String name) {
        orderByColumns.add(name + ' ' + DESC);
        return this;
    }

    /**
     * Get order by columns.
     *
     * @return A StringStack with the name of the order columns.
     */
    public StringStack getOrderByColumns() {
        return orderByColumns;
    }

    /**
     * Get group by columns.
     *
     * @return A StringStack with the name of the groupBy clause.
     */
    public StringStack getGroupByColumns() {
        return groupByColumns;
    }

    /**
     * Get Having Criterion.
     *
     * @return A Criterion that is the having clause.
     */
    public Criterion getHaving() {
        return having;
    }

    /**
     * Remove an object from the criteria.
     *
     * @param key A String with the key to be removed.
     * @return The removed object.
     */
    public Object remove(String key) {
        Object foo = super.remove(key);
        if (foo instanceof Criterion) {
            return ((Criterion) foo).getValue();
        }
        return foo;
    }

    /**
     * Build a string representation of the Criteria.
     *
     * @return A String with the representation of the Criteria.
     */
    public String toString() {
        StringBuffer sb = new StringBuffer("Criteria:: ");
        Iterator it = keySet().iterator();
        while (it.hasNext()) {
            String key = (String) it.next();
            sb.append(key).append("<=>").append(super.get(key).toString()).append(":  ");
        }

        try {
            sb.append("\nCurrent Query SQL (may not be complete or applicable): ")
                    .append(BasePeer.createQueryDisplayString(this));
        } catch (Exception exc) {
        }

        return sb.toString();
    }

    /**
     * This method checks another Criteria to see if they contain
     * the same attributes and hashtable entries.
     */
    public boolean equals(Object crit) {
        boolean isEquiv = false;
        if (crit == null || !(crit instanceof Criteria)) {
            isEquiv = false;
        } else if (this == crit) {
            isEquiv = true;
        } else if (this.size() == ((Criteria) crit).size()) {
            Criteria criteria = (Criteria) crit;
            if (this.offset == criteria.getOffset() && this.limit == criteria.getLimit()
                    && ignoreCase == criteria.isIgnoreCase() && singleRecord == criteria.isSingleRecord()
                    && cascade == criteria.isCascade() && dbName.equals(criteria.getDbName())
                    && selectModifiers.equals(criteria.getSelectModifiers())
                    && selectColumns.equals(criteria.getSelectColumns())
                    && orderByColumns.equals(criteria.getOrderByColumns())) {
                isEquiv = true;
                for (Iterator it = criteria.keySet().iterator(); it.hasNext();) {
                    String key = (String) it.next();
                    if (this.containsKey(key)) {
                        Criterion a = this.getCriterion(key);
                        Criterion b = criteria.getCriterion(key);
                        if (!a.equals(b)) {
                            isEquiv = false;
                            break;
                        }
                    } else {
                        isEquiv = false;
                        break;
                    }
                }
            }
        }
        return isEquiv;
    }

    /*
     *------------------------------------------------------------------------
     *
     * Start of the "and" methods
     *
     *------------------------------------------------------------------------
     */

    /**
     * This method adds a prepared Criterion object to the Criteria as a having clause.
     * You can get a new, empty Criterion object with the
     * getNewCriterion() method.
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria();
     * Criteria.Criterion c = crit.getNewCriterion(BasePeer.ID, new Integer(5), Criteria.LESS_THAN);
     * crit.addHaving(c);
     * </code>
     *
     * @param having A Criterion object
     *
     * @return A modified Criteria object.
     */
    public Criteria addHaving(Criterion having) {
        this.having = having;
        return this;
    }

    /**
     * This method adds a prepared Criterion object to the Criteria.
     * You can get a new, empty Criterion object with the
     * getNewCriterion() method. If a criterion for the requested column
     * already exists, it is "AND"ed to the existing criterion.
     * This is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria();
     * Criteria.Criterion c = crit.getNewCriterion(BasePeer.ID, new Integer(5), Criteria.LESS_THAN);
     * crit.and(c);
     * </code>
     *
     * @param c A Criterion object
     *
     * @return A modified Criteria object.
     */
    public Criteria and(Criterion c) {
        Criterion oc = getCriterion(c.getTable() + '.' + c.getColumn());

        if (oc == null) {
            add(c);
        } else {
            oc.and(c);
        }
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias. If a
     * criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion. This is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().and(&quot;column&quot;,
     *                                      &quot;value&quot;);
     * </code>
     *
     * An EQUAL comparison is used for column and value.
     *
     * The name of the table must be used implicitly in the column name,
     * so the Column name must be something like 'TABLE.id'. If you
     * don't like this, you can use the and(table, column, value) method.
     *
     * @param column The column to run the comparison on
     * @param value An Object.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, Object value) {
        and(column, value, EQUAL);
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion. If is used as follow:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().and(&quot;column&quot;,
     *                                      &quot;value&quot;
     *                                      &quot;Criterion.GREATER_THAN&quot;);
     * </code>
     *
     * Any comparison can be used.
     *
     * The name of the table must be used implicitly in the column name,
     * so the Column name must be something like 'TABLE.id'. If you
     * don't like this, you can use the and(table, column, value) method.
     *
     * @param column The column to run the comparison on
     * @param value An Object.
     * @param comparison A String.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, Object value, SqlEnum comparison) {
        Criterion oc = getCriterion(column);
        Criterion nc = new Criterion(column, value, comparison);

        if (oc == null) {
            super.put(column, nc);
        } else {
            oc.and(nc);
        }
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion. If is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().and(&quot;table&quot;,
     *                                      &quot;column&quot;,
     *                                      &quot;value&quot;);
     * </code>
     *
     * An EQUAL comparison is used for column and value.
     *
     * @param table Name of the table which contains the column
     * @param column The column to run the comparison on
     * @param value An Object.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String table, String column, Object value) {
        and(table, column, value, EQUAL);
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion. If is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().and(&quot;table&quot;,
     *                                      &quot;column&quot;,
     *                                      &quot;value&quot;,
     *                                      &quot;Criterion.GREATER_THAN&quot;);
     * </code>
     *
     * Any comparison can be used.
     *
     * @param table Name of table which contains the column
     * @param column The column to run the comparison on
     * @param value An Object.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String table, String column, Object value, SqlEnum comparison) {
        StringBuffer sb = new StringBuffer(table.length() + column.length() + 1);
        sb.append(table);
        sb.append('.');
        sb.append(column);

        Criterion oc = getCriterion(table, column);
        Criterion nc = new Criterion(table, column, value, comparison);

        if (oc == null) {
            super.put(sb.toString(), nc);
        } else {
            oc.and(nc);
        }
        return this;
    }

    /**
     * Convenience method to add a boolean to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Boolean(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A Boolean.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, boolean value) {
        and(column, new Boolean(value));
        return this;
    }

    /**
     * Convenience method to add a boolean to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Boolean(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A Boolean.
     * @param comparison String describing how to compare the column
     * with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, boolean value, SqlEnum comparison) {
        and(column, new Boolean(value), comparison);
        return this;
    }

    /**
     * Convenience method to add an int to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Integer(value), EQUAL);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value An int.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, int value) {
        and(column, new Integer(value));
        return this;
    }

    /**
     * Convenience method to add an int to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Integer(value), comparison);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value An int.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, int value, SqlEnum comparison) {
        and(column, new Integer(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a long to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Long(value), EQUAL);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value A long.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, long value) {
        and(column, new Long(value));
        return this;
    }

    /**
     * Convenience method to add a long to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Long(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A long.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, long value, SqlEnum comparison) {
        and(column, new Long(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a float to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Float(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A float.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, float value) {
        and(column, new Float(value));
        return this;
    }

    /**
     * Convenience method to add a float to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Float(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A float.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, float value, SqlEnum comparison) {
        and(column, new Float(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a double to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Double(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A double.
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, double value) {
        and(column, new Double(value));
        return this;
    }

    /**
     * Convenience method to add a double to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new Double(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A double.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria and(String column, double value, SqlEnum comparison) {
        and(column, new Double(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a Date object specified by
     * year, month, and date into the Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new GregorianCalendar(year, month,date), EQUAL);
     * </code>
     *
     * @param column A String value to use as column.
     * @param year An int with the year.
     * @param month An int with the month.
     * @param date An int with the date.
     * @return A modified Criteria object.
     */
    public Criteria andDate(String column, int year, int month, int date) {
        and(column, new GregorianCalendar(year, month, date));
        return this;
    }

    /**
     * Convenience method to add a Date object specified by
     * year, month, and date into the Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * and(column, new GregorianCalendar(year, month,date), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param year An int with the year.
     * @param month An int with the month.
     * @param date An int with the date.
     * @param comparison String describing how to compare the column with the value
     * @return A modified Criteria object.
     */
    public Criteria andDate(String column, int year, int month, int date, SqlEnum comparison) {
        and(column, new GregorianCalendar(year, month, date), comparison);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as an Object array.
     * For example:
     *
     * <p>
     * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An Object[] with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria andIn(String column, Object[] values) {
        and(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as an int array.
     * For example:
     *
     * <p>
     * FOO.ID IN ('2', '3', '7')
     * <p>
     *
     * where 'values' contains those three integers.
     *
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An int[] with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria andIn(String column, int[] values) {
        and(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as a List.
     * For example:
     *
     * <p>
     * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values A List with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria andIn(String column, List values) {
        and(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as an Object
     * array.  For example:
     *
     * <p>
     * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An Object[] with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria andNotIn(String column, Object[] values) {
        and(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as an int
     * array.  For example:
     *
     * <p>
     * FOO.ID NOT IN ('2', '3', '7')
     * <p>
     *
     * where 'values' contains those three integers.
     *
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An int[] with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria andNotIn(String column, int[] values) {
        and(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as a List.
     * For example:
     *
     * <p>
     * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "AND"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values A List with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria andNotIn(String column, List values) {
        and(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /*
     *------------------------------------------------------------------------
     *
     * Start of the "or" methods
     *
     *------------------------------------------------------------------------
     */

    /**
     * This method adds a prepared Criterion object to the Criteria.
     * You can get a new, empty Criterion object with the
     * getNewCriterion() method. If a criterion for the requested column
     * already exists, it is "OR"ed to the existing criterion.
     * This is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria();
     * Criteria.Criterion c = crit.getNewCriterion(BasePeer.ID, new Integer(5), Criteria.LESS_THAN);
     * crit.or(c);
     * </code>
     *
     * @param c A Criterion object
     *
     * @return A modified Criteria object.
     */
    public Criteria or(Criterion c) {
        Criterion oc = getCriterion(c.getTable() + '.' + c.getColumn());

        if (oc == null) {
            add(c);
        } else {
            oc.or(c);
        }
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias. If a
     * criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion. This is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().or(&quot;column&quot;,
     *                                      &quot;value&quot;);
     * </code>
     *
     * An EQUAL comparison is used for column and value.
     *
     * The name of the table must be used implicitly in the column name,
     * so the Column name must be something like 'TABLE.id'. If you
     * don't like this, you can use the or(table, column, value) method.
     *
     * @param column The column to run the comparison on
     * @param value An Object.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, Object value) {
        or(column, value, EQUAL);
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion. If is used as follow:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().or(&quot;column&quot;,
     *                                      &quot;value&quot;
     *                                      &quot;Criterion.GREATER_THAN&quot;);
     * </code>
     *
     * Any comparison can be used.
     *
     * The name of the table must be used implicitly in the column name,
     * so the Column name must be something like 'TABLE.id'. If you
     * don't like this, you can use the or(table, column, value) method.
     *
     * @param column The column to run the comparison on
     * @param value An Object.
     * @param comparison A String.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, Object value, SqlEnum comparison) {
        Criterion oc = getCriterion(column);
        Criterion nc = new Criterion(column, value, comparison);

        if (oc == null) {
            super.put(column, nc);
        } else {
            oc.or(nc);
        }
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion. If is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().or(&quot;table&quot;,
     *                                      &quot;column&quot;,
     *                                      &quot;value&quot;);
     * </code>
     *
     * An EQUAL comparison is used for column and value.
     *
     * @param table Name of the table which contains the column
     * @param column The column to run the comparison on
     * @param value An Object.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String table, String column, Object value) {
        or(table, column, value, EQUAL);
        return this;
    }

    /**
     * This method adds a new criterion to the list of criterias.
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion. If is used as follows:
     *
     * <p>
     * <code>
     * Criteria crit = new Criteria().or(&quot;table&quot;,
     *                                      &quot;column&quot;,
     *                                      &quot;value&quot;,
     *                                      &quot;Criterion.GREATER_THAN&quot;);
     * </code>
     *
     * Any comparison can be used.
     *
     * @param table Name of table which contains the column
     * @param column The column to run the comparison on
     * @param value An Object.
     * @param comparison String describing how to compare the column with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String table, String column, Object value, SqlEnum comparison) {
        StringBuffer sb = new StringBuffer(table.length() + column.length() + 1);
        sb.append(table);
        sb.append('.');
        sb.append(column);

        Criterion oc = getCriterion(table, column);
        Criterion nc = new Criterion(table, column, value, comparison);
        if (oc == null) {
            super.put(sb.toString(), nc);
        } else {
            oc.or(nc);
        }
        return this;
    }

    /**
     * Convenience method to add a boolean to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Boolean(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A Boolean.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, boolean value) {
        or(column, new Boolean(value));
        return this;
    }

    /**
     * Convenience method to add a boolean to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Boolean(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A Boolean.
     * @param comparison String describing how to compare the column
     * with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, boolean value, SqlEnum comparison) {
        or(column, new Boolean(value), comparison);
        return this;
    }

    /**
     * Convenience method to add an int to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Integer(value), EQUAL);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value An int.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, int value) {
        or(column, new Integer(value));
        return this;
    }

    /**
     * Convenience method to add an int to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Integer(value), comparison);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value An int.
     * @param comparison String describing how to compare the column
     * with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, int value, SqlEnum comparison) {
        or(column, new Integer(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a long to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Long(value), EQUAL);
     * </code>
     *
     *
     * @param column The column to run the comparison on
     * @param value A long.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, long value) {
        or(column, new Long(value));
        return this;
    }

    /**
     * Convenience method to add a long to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Long(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A long.
     * @param comparison String describing how to compare the column
     * with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, long value, SqlEnum comparison) {
        or(column, new Long(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a float to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Float(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A float.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, float value) {
        or(column, new Float(value));
        return this;
    }

    /**
     * Convenience method to add a float to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Float(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A float.
     * @param comparison String describing how to compare the column
     * with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, float value, SqlEnum comparison) {
        or(column, new Float(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a double to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Double(value), EQUAL);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A double.
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, double value) {
        or(column, new Double(value));
        return this;
    }

    /**
     * Convenience method to add a double to Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new Double(value), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param value A double.
     * @param comparison String describing how to compare the column
     * with the value
     *
     * @return A modified Criteria object.
     */
    public Criteria or(String column, double value, SqlEnum comparison) {
        or(column, new Double(value), comparison);
        return this;
    }

    /**
     * Convenience method to add a Date object specified by
     * year, month, and date into the Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new GregorianCalendar(year, month,date), EQUAL);
     * </code>
     *
     * @param column A String value to use as column.
     * @param year An int with the year.
     * @param month An int with the month.
     * @param date An int with the date.
     * @return A modified Criteria object.
     */
    public Criteria orDate(String column, int year, int month, int date) {
        or(column, new GregorianCalendar(year, month, date));
        return this;
    }

    /**
     * Convenience method to add a Date object specified by
     * year, month, and date into the Criteria.
     * Equal to
     *
     * <p>
     * <code>
     * or(column, new GregorianCalendar(year, month,date), comparison);
     * </code>
     *
     * @param column The column to run the comparison on
     * @param year An int with the year.
     * @param month An int with the month.
     * @param date An int with the date.
     * @param comparison String describing how to compare the column
     * with the value
     * @return A modified Criteria object.
     */
    public Criteria orDate(String column, int year, int month, int date, SqlEnum comparison) {
        or(column, new GregorianCalendar(year, month, date), comparison);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as an Object
     * array.  For example:
     *
     * <p>
     * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An Object[] with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria orIn(String column, Object[] values) {
        or(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as an int array.
     * For example:
     *
     * <p>
     * FOO.ID IN ('2', '3', '7')
     * <p>
     *
     * where 'values' contains those three integers.
     *
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An int[] with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria orIn(String column, int[] values) {
        or(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds an 'IN' clause with the criteria supplied as a List.
     * For example:
     *
     * <p>
     * FOO.NAME IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values A List with the allowed values.
     * @return A modified Criteria object.
     */
    public Criteria orIn(String column, List values) {
        or(column, (Object) values, Criteria.IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as an Object
     * array.  For example:
     *
     * <p>
     * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An Object[] with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria orNotIn(String column, Object[] values) {
        or(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as an int
     * array.  For example:
     *
     * <p>
     * FOO.ID NOT IN ('2', '3', '7')
     * <p>
     *
     * where 'values' contains those three integers.
     *
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values An int[] with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria orNotIn(String column, int[] values) {
        or(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Adds a 'NOT IN' clause with the criteria supplied as a List.
     * For example:
     *
     * <p>
     * FOO.NAME NOT IN ('FOO', 'BAR', 'ZOW')
     * <p>
     *
     * where 'values' contains three objects that evaluate to the
     * respective strings above when .toString() is called.
     *
     * If a criterion for the requested column already exists, it is
     * "OR"ed to the existing criterion.
     *
     * @param column The column to run the comparison on
     * @param values A List with the disallowed values.
     * @return A modified Criteria object.
     */
    public Criteria orNotIn(String column, List values) {
        or(column, (Object) values, Criteria.NOT_IN);
        return this;
    }

    /**
     * Peers can set this flag to notify BasePeer that the table(s) involved
     * in the Criteria contain Blobs, so that the operation can be placed
     * in a transaction if the db requires it.
     * This is primarily to support Postgresql.
     * The flag is set to true by this method.
     * @deprecated Use @see #setBlobFlag(boolean)
     */
    public void setBlobFlag() {
        blobFlag = Boolean.TRUE;
    }

    /**
     * Peers can set this flag to notify BasePeer that the table(s) involved
     * in the Criteria contain Blobs, so that the operation can be placed
     * in a transaction if the db requires it.
     * This is primarily to support Postgresql.
     */
    public void setBlobFlag(boolean b) {
        blobFlag = (b ? Boolean.TRUE : Boolean.FALSE);
    }

    /**
     * This is an inner class that describes an object in the
     * criteria.
     */
    public final class Criterion implements Serializable {
        public static final String AND = " AND ";
        public static final String OR = " OR ";

        /** Value of the CO. */
        private Object value;

        /** Comparison value. */
        private SqlEnum comparison;

        /** Table name. */
        private String table;

        /** Column name. */
        private String column;

        /** flag to ignore case in comparision */
        private boolean ignoreStringCase = false;

        /**
         * The DB adaptor which might be used to get db specific
         * variations of sql.
         */
        private DB db;

        /**
         * other connected criteria and their conjunctions.
         */
        private List clauses = new ArrayList();
        private List conjunctions = new ArrayList();

        /**
         * Creates a new instance, initializing a couple members.
         */
        private Criterion(Object val, SqlEnum comp) {
            this.value = val;
            this.comparison = comp;
        }

        /**
         * Create a new instance.
         *
         * @param table A String with the name of the table.
         * @param column A String with the name of the column.
         * @param val An Object with the value for the Criteria.
         * @param comp A String with the comparison value.
         */
        Criterion(String table, String column, Object val, SqlEnum comp) {
            this(val, comp);
            this.table = (table == null ? "" : table);
            this.column = (column == null ? "" : column);
        }

        /**
         * Create a new instance.
         *
         * @param tableColumn A String with the full name of the
         * column.
         * @param val An Object with the value for the Criteria.
         * @param comp A String with the comparison value.
         */
        Criterion(String tableColumn, Object val, SqlEnum comp) {
            this(val, comp);
            int dot = tableColumn.lastIndexOf('.');
            if (dot == -1) {
                table = "";
                column = tableColumn;
            } else {
                table = tableColumn.substring(0, dot);
                column = tableColumn.substring(dot + 1);
            }
        }

        /**
         * Create a new instance.
         *
         * @param table A String with the name of the table.
         * @param column A String with the name of the column.
         * @param val An Object with the value for the Criteria.
         */
        Criterion(String table, String column, Object val) {
            this(table, column, val, EQUAL);
        }

        /**
         * Create a new instance.
         *
         * @param tableColumn A String with the full name of the
         * column.
         * @param val An Object with the value for the Criteria.
         */
        Criterion(String tableColumn, Object val) {
            this(tableColumn, val, EQUAL);
        }

        /**
         * Get the column name.
         *
         * @return A String with the column name.
         */
        public String getColumn() {
            return this.column;
        }

        /**
         * Set the table name.
         *
         * @param name A String with the table name.
         */
        public void setTable(String name) {
            this.table = name;
        }

        /**
         * Get the table name.
         *
         * @return A String with the table name.
         */
        public String getTable() {
            return this.table;
        }

        /**
         * Get the comparison.
         *
         * @return A String with the comparison.
         */
        public SqlEnum getComparison() {
            return this.comparison;
        }

        /**
         * Get the value.
         *
         * @return An Object with the value.
         */
        public Object getValue() {
            return this.value;
        }

        /**
         * Get the value of db.
         * The DB adaptor which might be used to get db specific
         * variations of sql.
         * @return value of db.
         */
        public DB getDb() {
            DB db = null;
            if (this.db == null) {
                // db may not be set if generating preliminary sql for
                // debugging.
                try {
                    db = Torque.getDB(getDbName());
                } catch (Exception e) {
                    // we are only doing this to allow easier debugging, so
                    // no need to throw up the exception, just make note of it.
                    category.error("Could not get a DB adapter, so sql may be wrong");
                }
            } else {
                db = this.db;
            }

            return db;
        }

        /**
         * Set the value of db.
         * The DB adaptor might be used to get db specific
         * variations of sql.
         * @param v  Value to assign to db.
         */
        public void setDB(DB v) {
            this.db = v;

            for (int i = 0; i < this.clauses.size(); i++) {
                ((Criterion) (clauses.get(i))).setDB(v);
            }
        }

        /**
         * Sets ignore case.
         *
         * @param b True if case should be ignored.
         * @return A modified Criteria object.
         */
        public Criterion setIgnoreCase(boolean b) {
            ignoreStringCase = b;
            return this;
        }

        /**
         * Is ignore case on or off?
         *
         * @return True if case is ignored.
         */
        public boolean isIgnoreCase() {
            return ignoreStringCase;
        }

        /**
         *  get the list of clauses in this Criterion
         */
        private List getClauses() {
            return clauses;
        }

        /**
         *  get the list of conjunctions in this Criterion
         */
        private List getConjunctions() {
            return conjunctions;
        }

        /**
         * Append an AND Criterion onto this Criterion's list.
         */
        public Criterion and(Criterion criterion) {
            this.clauses.add(criterion);
            this.conjunctions.add(AND);
            return this;
        }

        /**
         * Append an OR Criterion onto this Criterion's list.
         */
        public Criterion or(Criterion criterion) {
            this.clauses.add(criterion);
            this.conjunctions.add(OR);
            return this;
        }

        /**
         * Appends a representation of the Criterion onto the buffer.
         */
        public void appendTo(StringBuffer sb) {
            //
            // it is alright if value == null
            //

            if (column == null) {
                return;
            }

            Criterion clause = null;
            for (int j = 0; j < this.clauses.size(); j++) {
                sb.append('(');
            }
            if (CUSTOM == comparison) {
                if (value != null && !"".equals(value)) {
                    sb.append((String) value);
                }
            } else {
                String field = null;
                if (table == null) {
                    field = column;
                } else {
                    field = new StringBuffer(table.length() + 1 + column.length()).append(table).append('.')
                            .append(column).toString();
                }
                SqlExpression.build(field, value, comparison, ignoreStringCase, getDb(), sb);
            }

            for (int i = 0; i < this.clauses.size(); i++) {
                sb.append(this.conjunctions.get(i));
                clause = (Criterion) (this.clauses.get(i));
                clause.appendTo(sb);
                sb.append(')');
            }
        }

        /**
         * Appends a Prepared Statement representation of the Criterion
         * onto the buffer.
         *
         * @param sb The stringbuffer that will receive the Prepared Statement
         * @param params A list to which Prepared Statement parameters
         * will be appended
         */
        public void appendPsTo(StringBuffer sb, List params) {
            if (column == null || value == null) {
                return;
            }

            DB db = getDb();

            for (int j = 0; j < this.clauses.size(); j++) {
                sb.append('(');
            }
            if (CUSTOM == comparison) {
                if (!"".equals(value)) {
                    sb.append((String) value);
                }
            } else {
                String field = null;
                if (table == null) {
                    field = column;
                } else {
                    field = new StringBuffer(table.length() + 1 + column.length()).append(table).append('.')
                            .append(column).toString();
                }

                if (comparison.equals(Criteria.IN) || comparison.equals(Criteria.NOT_IN)) {
                    sb.append(field).append(comparison);

                    StringStack inClause = new StringStack();

                    if (value instanceof List) {
                        value = ((List) value).toArray(new Object[0]);
                    }

                    for (int i = 0; i < Array.getLength(value); i++) {
                        Object item = Array.get(value, i);

                        inClause.add(SqlExpression.processInValue(item, ignoreCase, db));
                    }

                    StringBuffer inString = new StringBuffer();
                    inString.append('(').append(inClause.toString(",")).append(')');

                    sb.append(inString.toString());
                } else {
                    if (ignoreCase) {
                        sb.append(db.ignoreCase(field)).append(comparison).append(db.ignoreCase("?"));
                    } else {
                        sb.append(field).append(comparison).append(" ? ");
                    }

                    if (value instanceof java.util.Date) {
                        params.add(new java.sql.Date(((java.util.Date) value).getTime()));
                    } else if (value instanceof DateKey) {
                        params.add(new java.sql.Date(((DateKey) value).getDate().getTime()));
                    } else {
                        params.add(value.toString());
                    }
                }
            }

            for (int i = 0; i < this.clauses.size(); i++) {
                sb.append(this.conjunctions.get(i));
                Criterion clause = (Criterion) (this.clauses.get(i));
                clause.appendPsTo(sb, params);
                sb.append(')');
            }
        }

        /**
         * Build a string representation of the Criterion.
         *
         * @return A String with the representation of the Criterion.
         */
        public String toString() {
            //
            // it is alright if value == null
            //
            if (column == null) {
                return "";
            }

            StringBuffer expr = new StringBuffer(25);
            appendTo(expr);
            return expr.toString();
        }

        /**
         * This method checks another Criteria to see if they contain
         * the same attributes and hashtable entries.
         */
        public boolean equals(Object obj) {
            if (this == obj) {
                return true;
            }

            if ((obj == null) || !(obj instanceof Criterion)) {
                return false;
            }

            Criterion crit = (Criterion) obj;

            boolean isEquiv = ((table == null && crit.getTable() == null)
                    || (table != null && table.equals(crit.getTable()))) && column.equals(crit.getColumn())
                    && comparison.equals(crit.getComparison());

            // we need to check for value equality
            if (isEquiv) {
                Object b = crit.getValue();
                if (value instanceof Object[] && b instanceof Object[]) {
                    isEquiv &= Arrays.equals((Object[]) value, (Object[]) b);
                } else if (value instanceof int[] && b instanceof int[]) {
                    isEquiv &= Arrays.equals((int[]) value, (int[]) b);
                } else {
                    isEquiv &= value.equals(b);
                }
            }

            // check chained criterion

            isEquiv &= this.clauses.size() == crit.getClauses().size();
            for (int i = 0; i < this.clauses.size(); i++) {
                isEquiv &= ((String) (conjunctions.get(i))).equals((String) (crit.getConjunctions().get(i)));
                isEquiv &= ((Criterion) (clauses.get(i))).equals((Criterion) (crit.getClauses().get(i)));
            }

            return isEquiv;
        }

        /**
         * Returns a hash code value for the object.
         */
        public int hashCode() {
            int h = value.hashCode() ^ comparison.hashCode();

            if (table != null) {
                h ^= table.hashCode();
            }

            if (column != null) {
                h ^= column.hashCode();
            }

            for (int i = 0; i < this.clauses.size(); i++) {
                h ^= ((Criterion) (clauses.get(i))).hashCode();
            }

            return h;
        }

        /**
         * get all tables from nested criterion objects
         */
        public String[] getAllTables() {
            StringStack tables = new StringStack();
            addCriterionTable(this, tables);
            return tables.toStringArray();
        }

        /**
         * method supporting recursion through all criterions to give
         * us a StringStack of tables from each criterion
         */
        private void addCriterionTable(Criterion c, StringStack s) {
            if (c != null) {
                s.add(c.getTable());
                for (int i = 0; i < c.getClauses().size(); i++) {
                    addCriterionTable((Criterion) (c.getClauses().get(i)), s);
                }
            }
        }

        /**
         * get an array of all criterion attached to this
         * recursing through all sub criterion
         */
        public Criterion[] getAttachedCriterion() {
            ArrayList crits = new ArrayList();
            traverseCriterion(this, crits);
            Criterion[] crita = new Criterion[crits.size()];
            for (int i = 0; i < crits.size(); i++) {
                crita[i] = (Criterion) crits.get(i);
            }

            return crita;
        }

        /**
         * method supporting recursion through all criterions to give
         * us an ArrayList of them
         */
        private void traverseCriterion(Criterion c, ArrayList a) {
            if (c != null) {
                a.add(c);
                for (int i = 0; i < c.getClauses().size(); i++) {
                    traverseCriterion((Criterion) (c.getClauses().get(i)), a);
                }
            }
        }
    }
}