/*
 * Copyright (c) 1998, 2021 Oracle and/or its affiliates. All rights reserved.
 * Copyright (c) 2021 IBM Corporation. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0 which is available at
 * http://www.eclipse.org/legal/epl-2.0,
 * or the Eclipse Distribution License v. 1.0 which is available at
 * http://www.eclipse.org/org/documents/edl-v10.php.
 *
 * SPDX-License-Identifier: EPL-2.0 OR BSD-3-Clause
 */

// Contributors:
//     Oracle - initial API and implementation from Oracle TopLink
//     05/24/2011-2.3 Guy Pelletier
//       - 345962: Join fetch query when using tenant discriminator column fails.
package org.eclipse.persistence.expressions;

import java.util.*;
import java.io.*;

import org.eclipse.persistence.mappings.DatabaseMapping;
import org.eclipse.persistence.queries.*;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.exceptions.*;
import org.eclipse.persistence.history.*;
import org.eclipse.persistence.internal.helper.*;
import org.eclipse.persistence.internal.expressions.*;
import org.eclipse.persistence.internal.localization.*;
import org.eclipse.persistence.internal.sessions.AbstractRecord;
import org.eclipse.persistence.internal.sessions.AbstractSession;

/**
 * <p>
 * <b>Purpose</b>: Define an object-level representation of a database query where clause.</p>
 * <p>
 * <b>Description</b>: An expression is a tree-like structure that defines the selection
 * criteria for a query against objects in the database.  The expression has the advantage
 * over SQL by being at the object-level, i.e. the object model attributes and relationships
 * can be used to be query on instead of the database field names.
 * Because it is an object, not a string the expression has the advantage that is can be
 * easily manipulated through code to easily build complex selection criterias.</p>
 * <p>
 * <b>Responsibilities</b>:
 * <ul>
 * <li> Store the selection criteria in a tree-like structure.
 * <li> Support public manipulation protocols for all comparison and function operators.
 * <li> Use operator overloading to support all primitive types as well as objects.
 * </ul>
 */
public abstract class Expression implements Serializable, Cloneable {

    /** Required for serialization compatibility. */
    static final long serialVersionUID = -5979150600092006081L;

    /** Temporary values for table aliasing */
    protected transient DatabaseTable lastTable;
    protected transient DatabaseTable currentAlias;
    protected boolean selectIfOrderedBy = true;
    /** PERF: Cache the hashCode. */
    protected int hashCode = 0;

    /** Use the upper() function for case insensitive expression operations (default).
        Seting this flag to false will use the lower() function instead. */
    public static boolean shouldUseUpperCaseForIgnoreCase = true;

    /**
     * Base Expression Constructor.  Not generally used by Developers
     */
    public Expression() {
        super();
    }

    /**
     * PUBLIC:
     * Function, return an expression that adds to a date based on
     * the specified datePart.  This is equivalent to the Sybase DATEADD function.
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").addDate("year", 2)
     * Java: NA
     * SQL: DATEADD(date, 2, year)
     * </pre></blockquote>
     */
    public Expression addDate(String datePart, int numberToAdd) {
        return addDate(datePart, Integer.valueOf(numberToAdd));
    }

    /**
     * PUBLIC:
     * Function, return an expression that adds to a date based on
     * the specified datePart.  This is equivalent to the Sybase DATEADD function.
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").addDate("year", 2)
     * Java: NA
     * SQL: DATEADD(date, 2, year)
     * </pre></blockquote>
     */
    public Expression addDate(String datePart, Object numberToAdd) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.AddDate);
        List args = new ArrayList(2);
        args.add(Expression.fromLiteral(datePart, this));
        args.add(numberToAdd);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, to add months to a date.
     */
    public Expression addMonths(int months) {
        return addMonths(Integer.valueOf(months));
    }

    /**
     * PUBLIC:
     * Function, to add months to a date.
     */
    public Expression addMonths(Object months) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.AddMonths);
        return anOperator.expressionFor(this, months);
    }

    /**
     * INTERNAL:
     * Find the alias for a given table
     */
    public DatabaseTable aliasForTable(DatabaseTable table) {
        return null;
    }

    /**
     * PUBLIC: Returns an expression equivalent to all of <code>attributeName</code>
     * holding true for <code>criteria</code>.
     * <p>
     * For every expression with an anyOf, its negation has either an allOf or a
     * noneOf.  The following two examples will illustrate as the second is the
     * negation of the first:
     * <p>
     * AnyOf Example: Employees with a non '613' area code phone number.
     * <blockquote><pre>
     * ReadAllQuery query = new ReadAllQuery(Employee.class);
     * ExpressionBuilder employee = new ExpressionBuilder();
     * Expression exp = employee.anyOf("phoneNumbers").get("areaCode").notEqual("613");
     * </pre></blockquote>
     * <p>
     * AllOf Example: Employees with all '613' area code phone numbers.
     * <blockquote><pre>
     * ExpressionBuilder employee = new ExpressionBuilder();
     * ExpressionBuilder phones = new ExpressionBuilder();
     * Expression exp = employee.allOf("phoneNumbers", phones.get("areaCode").equal("613"));
     * SQL:
     * SELECT ... EMPLOYEE t0 WHERE NOT EXISTS (SELECT ... PHONE t1 WHERE
     *                     (t0.EMP_ID = t1.EMP_ID) AND NOT (t1.AREACODE = '613'))
     * </pre></blockquote>
     * <p>
     * allOf is the universal counterpart to the existential anyOf.  To have the
     * condition evaluated for each instance it must be put inside of a subquery,
     * which can be expressed as not exists (any of attributeName some condition).
     * (All x such that y = !Exist x such that !y).
     * <p>Likewise the syntax employee.allOf("phoneNumbers").get("areaCode").equal("613")
     * is not supported for the <pre>equal</pre> must go inside a subQuery.
     * <p>
     * This method saves you from writing the sub query yourself.  The above is
     * equivalent to the following expression:
     * <blockquote><pre>
     * ExpressionBuilder employee = new ExpressionBuilder();
     * ExpressionBuilder phone = new ExpressionBuilder();
     * ReportQuery subQuery = new ReportQuery(Phone.class, phone);
     * subQuery.retreivePrimaryKeys();
     * subQuery.setSelectionCriteria(phone.equal(employee.anyOf("phoneNumbers").and(
     *         phone.get("areaCode").notEqual("613")));
     * Expression exp = employee.notExists(subQuery);
     * </pre></blockquote>
     * <p>
     * Note if employee has no phone numbers allOf ~ noneOf.
     * @param criteria must have its own builder, as it will become the
     * separate selection criteria of a subQuery.
     * @return a notExists subQuery expression
     */
    public Expression allOf(String attributeName, Expression criteria) {
        ReportQuery subQuery = new ReportQuery();
        subQuery.setShouldRetrieveFirstPrimaryKey(true);
        Expression builder = criteria.getBuilder();
        criteria = builder.equal(anyOf(attributeName)).and(criteria.not());
        subQuery.setSelectionCriteria(criteria);
        return notExists(subQuery);
    }

    /**
     * PUBLIC:
     * Return an expression that is the boolean logical combination of both expressions.
     * This is equivalent to the SQL "AND" operator and the Java {@literal "&&"} operator.
     * <p>Example:
     * <blockquote><pre>
     *  EclipseLink: employee.get("firstName").equal("Bob").and(employee.get("lastName").equal("Smith"))
     *  Java: (employee.getFirstName().equals("Bob")) {@literal &&} (employee.getLastName().equals("Smith"))
     *  SQL: F_NAME = 'Bob' AND L_NAME = 'Smith'
     * </pre></blockquote>
     */
    public Expression and(Expression theExpression) {
        // Allow ands with null.
        if (theExpression == null) {
            return this;
        }

        ExpressionBuilder base = getBuilder();
        Expression expressionToUse = theExpression;

        // Ensure the same builder, unless a parralel query is used.
        // For flashback added an extra condition: if left side is a 'NullExpression'
        // then rebuild on it regardless.
        if ((theExpression.getBuilder() != base) && ((base == this) || (theExpression.getBuilder().getQueryClass() == null))) {
            expressionToUse = theExpression.rebuildOn(base);
        }

        if (base == this) {// Allow and to be sent to the builder.
            return expressionToUse;
        }

        ExpressionOperator anOperator = getOperator(ExpressionOperator.And);
        return anOperator.expressionFor(this, expressionToUse);
    }

    /**
     * PUBLIC:
     * Return an expression representing traversal of a 1:many or many:many relationship.
     * This allows you to query whether any of the "many" side of the relationship satisfies the remaining criteria.
     * <p>Example:
     * </p>
     * <table border=0 summary="This table compares an example EclipseLink anyOf Expression to Java and SQL">
     * <tr>
     * <th id="c1">Format</th>
     * <th id="c2">Equivalent</th>
     * </tr>
     * <tr>
     * <td headers="c1">EclipseLink</td>
     * <td headers="c2">
     * <pre>
     * ReadAllQuery query = new ReadAllQuery(Employee.class);<br>
     * ExpressionBuilder builder = new ExpressionBuilder();<br>
     * Expression exp = builder.get("id").equal("14858");<br>
     * exp = exp.or(builder.anyOf("managedEmployees").get("firstName").equal("Bob"));<br>
     * </pre>
     * </td>
     * </tr>
     * <tr>
     * <td headers="c1">Java</td>
     * <td headers="c2">No direct equivalent</td>
     * </tr>
     * <tr>
     * <td headers="c1">SQL</td>
     * <td headers="c2">SELECT DISTINCT ... WHERE (t2.MGR_ID (+) = t1.ID) AND (t2.F_NAME = 'Bob')</td>
     * </tr>
     * </table>
     */
    public Expression anyOf(String attributeName) {
        return anyOf(attributeName, true);
    }

    /**
     * ADVANCED:
     * Return an expression representing traversal of a 1:many or many:many relationship.
     * This allows you to query whether any of the "many" side of the relationship satisfies the remaining criteria.
     * <p>Example:
     * </p>
     * <table border=0 summary="This table compares an example EclipseLink anyOf Expression to Java and SQL">
     * <tr>
     * <th id="c3">Format</th>
     * <th id="c4">Equivalent</th>
     * </tr>
     * <tr>
     * <td headers="c3">EclipseLink</td>
     * <td headers="c4">
     * <pre>
     * ReadAllQuery query = new ReadAllQuery(Employee.class);<br>
     * ExpressionBuilder builder = new ExpressionBuilder();<br>
     * Expression exp = builder.get("id").equal("14858");<br>
     * exp = exp.or(builder.anyOf("managedEmployees").get("firstName").equal("Bob"));<br>
     * </pre>
     * </td>
     * </tr>
     * <tr>
     * <td headers="c3">Java</td>
     * <td headers="c4">No direct equivalent</td>
     * </tr>
     * <tr>
     * <td headers="c3">SQL</td>
     * <td headers="c4">SELECT DISTINCT ... WHERE (t2.MGR_ID (+) = t1.ID) AND (t2.F_NAME = 'Bob')</td>
     * </tr>
     * </table>
     * @param shouldJoinBeIndependent indicates whether a new expression should be created.
     */
    public Expression anyOf(String attributeName, boolean shouldJoinBeIndependent) {
        throw new UnsupportedOperationException("anyOf");
    }

    /**
     * ADVANCED:
     * Return an expression representing traversal of a 1:many or many:many relationship.
     * This allows you to query whether any of the "many" side of the relationship satisfies the remaining criteria.
     * This version of the anyOf operation performs an outer join.
     * Outer joins allow the join to performed even if the target of the relationship is empty.
     * NOTE: outer joins are not supported on all database and have differing semantics.
     * <p>Example:
     * </p>
     * <table border=0 summary="This table compares an example EclipseLink anyOfAllowingNone Expression to Java and SQL">
     * <tr>
     * <th id="c5">Format</th>
     * <th id="c6">Equivalent</th>
     * </tr>
     * <tr>
     * <td headers="c5">EclipseLink</td>
     * <td headers="c6">
     * <pre>
     * ReadAllQuery query = new ReadAllQuery(Employee.class);<br>
     * ExpressionBuilder builder = new ExpressionBuilder();<br>
     * Expression exp = builder.get("id").equal("14858");<br>
     * exp = exp.or(builder.anyOfAllowingNone("managedEmployees").get("firstName").equal("Bob"));<br>
     * </pre>
     * </td>
     * </tr>
     * <tr>
     * <td headers="c5">Java</td>
     * <td headers="c6">No direct equivalent</td>
     * </tr>
     * <tr>
     * <td headers="c5">SQL</td>
     * <td headers="c6">SELECT DISTINCT ... WHERE (t2.MGR_ID (+) = t1.ID) AND (t2.F_NAME = 'Bob')</td>
     * </tr>
     * </table>
     */
    public Expression anyOfAllowingNone(String attributeName) {
        return anyOfAllowingNone(attributeName, true);
    }

    /**
     * ADVANCED:
     * Return an expression representing traversal of a 1:many or many:many relationship.
     * This allows you to query whether any of the "many" side of the relationship satisfies the remaining criteria.
     * This version of the anyOf operation performs an outer join.
     * Outer joins allow the join to performed even if the target of the relationship is empty.
     * NOTE: outer joins are not supported on all database and have differing semantics.
     * <p>Example:
     * </p>
     * <table border=0 summary="This table compares an example EclipseLink anyOfAllowingNone Expression to Java and SQL">
     * <tr>
     * <th id="c7">Format</th>
     * <th id="c8">Equivalent</th>
     * </tr>
     * <tr>
     * <td headers="c7">EclipseLink</td>
     * <td headers="c8">
     * <pre>
     * ReadAllQuery query = new ReadAllQuery(Employee.class);<br>
     * ExpressionBuilder builder = new ExpressionBuilder();<br>
     * Expression exp = builder.get("id").equal("14858");<br>
     * exp = exp.or(builder.anyOfAllowingNone("managedEmployees").get("firstName").equal("Bob"));<br>
     * </pre>
     * </td>
     * </tr>
     * <tr>
     * <td headers="c7">Java</td>
     * <td headers="c8">No direct equivalent</td>
     * </tr>
     * <tr>
     * <td headers="c7">SQL</td>
     * <td headers="c8">SELECT DISTINCT ... WHERE (t2.MGR_ID (+) = t1.ID) AND (t2.F_NAME = 'Bob')</td>
     * </tr>
     * </table>
     * @param shouldJoinBeIndependent indicates whether a new expression should be created.
     */
    public Expression anyOfAllowingNone(String attributeName, boolean shouldJoinBeIndependent) {
        throw new UnsupportedOperationException("anyOfAllowingNone");
    }

    /**
     * ADVANCED:
     * Return an expression that allows you to treat its base as if it were a subclass of the class returned by the base.
     * @deprecated replaced by {@link #treat(Class)}
     */
    @Deprecated
    public Expression as(Class castClass) {
        return treat(castClass);
    }

    /**
     * ADVANCED:
     * Assign an alias to the expression in the select clause.
     */
    public Expression as(String alias) {
        ExpressionOperator operator = getOperator(ExpressionOperator.As);
        return operator.expressionFor(this, literal(alias));
    }

    /**
     * ADVANCED:
     * Return an expression that allows you to treat its base as if it were a subclass of the class returned by the base
     * This can only be called on an ExpressionBuilder, the result of expression.get(String), expression.getAllowingNull(String),
     * the result of expression.anyOf("String") or the result of expression.anyOfAllowingNull("String")
     *
     *  downcast uses Expression.type() internally to guarantee the results are of the specified class.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("project").treat(LargeProject.class).get("budget").equal(1000)
     *     Java: ((LargeProject)employee.getProjects().get(0)).getBudget() == 1000
     *     SQL: LPROJ.PROJ_ID (+)= PROJ.PROJ_ID AND L_PROJ.BUDGET = 1000 AND PROJ.TYPE = "L"
     * </pre></blockquote>
     */
    public Expression treat(Class castClass) {
        return this;
    }

    /**
     * PUBLIC:
     * This can only be used within an ordering expression.
     * It will order the result ascending.
     * Example:
     * <blockquote><pre>
     *  readAllQuery.addOrderBy(expBuilder.get("address").get("city").ascending())
     * </pre></blockquote>
     */
    public Expression ascending() {
        return getFunction(ExpressionOperator.Ascending);
    }

    /**
     * PUBLIC:
     * This can only be used within an ordering expression.
     * Null results will be ordered first.
     * Example:
     * <blockquote><pre>
     *  readAllQuery.addOrderBy(expBuilder.get("address").get("city").ascending().nullsFirst())
     * </pre></blockquote>
     */
    public Expression nullsFirst() {
        return getFunction(ExpressionOperator.NullsFirst);
    }

    /**
     * PUBLIC:
     * This can only be used within an ordering expression.
     * Null results will be ordered last.
     * Example:
     * <blockquote><pre>
     *  readAllQuery.addOrderBy(expBuilder.get("address").get("city").ascending().nullsLast())
     * </pre></blockquote>
     */
    public Expression nullsLast() {
        return getFunction(ExpressionOperator.NullsLast);
    }

    /**
     * PUBLIC:
     * Function, returns the single character strings ascii value.
     */
    public Expression asciiValue() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Ascii);
        return anOperator.expressionFor(this);
    }

    /**
     * Sets all tables represented by this expression to be queried as of a past
     * time.
     * <p>
     * Example:
     * </p>
     * <pre>
     *  EclipseLink: employee.asOf(new AsOfClause(pastTime))
     *  Java: None
     *  SQL (Flashback): SELECT ... FROM EMPLOYEE AS OF TIMESTAMP (pastTime) t0 ...
     *  SQL (Generic): .. WHERE (t1.START {@literal <=} pastTime) AND ((t1.END IS NULL) OR t1.END {@literal >} pastTime)
     * </pre>
     * <p>
     * Set an as of clause at the expression level to still query for current objects
     * while expressing selection criteria like:
     * <ul>
     * <li>query objects as of one time that met some condition at another time.
     * <li>query objects that changed a certain way over a certain interval (querying for change).
     * </ul>
     * <p>
     * Simultaneously querying on two versions of the same object (one past
     * one present) lets you express these advanced selection criteria.
     * <p>
     * Example: Querying on past attributes using parallel expressions.
     * </p>
     * <blockquote><pre>
     *   // Finds all employees who lived in Ottawa as of a past time.
     *   ExpressionBuilder employee = new ExpressionBuilder();
     *   ExpressionBuilder pastEmployee = new ExpressionBuilder(Employee.class);
     *   pastEmployee.asOf(pastTime);
     *   Expression pastAddress = pastEmployee.get("address"); // by default address will also be as of past time.
     *   Expression selectionCriteria = pastAddress.get("city").equal("Ottawa").and(
     *       employee.equal(pastEmployee));
     * </pre></blockquote>
     * <p>
     * The advantage of the parallel expression is that you can still read current
     * objects, the as of clause will affect only the where clause / selection criteria.
     * <p>
     * You may be tempted to rewrite the above as employee.get("address").asOf(pastTime).
     * That is allowed but see below for the finer points involved in this.
     * <p>
     * Example: Querying on object changes using parallel expressions.
     * </p>
     * <blockquote><pre>
     *   // Finds all employees who recently received a raise.  Note that current
     *   // objects are returned, so can be cached normally.
     *   ExpressionBuilder employee = new ExpressionBuilder();
     *   Expression pastEmployee = new ExpressionBuilder(Employee.class);
     *   pastEmployee.asOf(yesterday);
     *   Expression parallelJoin = employee.equal(pastEmployee);
     *   Expression selectionCriteria = parallelJoin.and(
     *       employee.get("salary").greaterThan(pastEmployee.get("salary")));
     * </pre></blockquote>
     * <p>
     * Example: Querying on object changes using custom query keys
     * </p><blockquote><pre>
     *   // First define the custom query key and add it to your descriptor.
     *   ExpressionBuilder builder = new ExpressionBuilder(Employee.class);
     *   Expression joinCriteria = builder.getField("EMPLOYEE.EMP_ID").equal(builder.getParameter("EMPLOYEE.EMP_ID"));
     *   OneToOneQueryKey selfReferential = new OneToOneQueryKey();
     *   selfReferential.setName("this");
     *   selfReferential.setJoinCriteria(joinCriteria);
     *   selfReferential.setReferenceClass(Employee.class);
     *   getSession().getDescriptor(Employee.class).addQueryKey(selfReferential);
     *
     *   // Now build query as before.
     *   Expression employee = new ExpessionBuilder();
     *   Expression pastEmployee = employee.get("this").asOf(yesterday);
     *   Expression selectionCriteria = employee.get("salary").greaterThan(pastEmployee.get("salary"));
     * </pre></blockquote>
     * <p>
     * Note in general that any parallel expression can be rewritten using a custom query key.
     * EclipseLink will even automatically interpret x.get("this") for you so you do
     * not need to define the above query key first.
     * <p>
     * <b>Full Reference:</b>
     * <p>
     * If an object is mapped to multiple tables, then each table will be as of
     * the same time.  Two objects mapped to the same table can not have different
     * as of times.  Conversely only expressions which have associated tables can have an as
     * of clause.
     * <p>
     * If an as of clause is not explicitly set an expression will use the clause
     * of its base expression, and so on recursively until one is found or an
     * ExpressionBuilder is reached.  Some usage scenarios follow:
     * <ul>
     * <li>employee.asOf(pastTime).anyOf("projects"): projects as of past time.
     * <li>expressionBuilder.asOf(pastTime): entire expression as of past time.
     * <li>employee.asOf(pastTime).anyOf("projects").asOf(null): projects as of current time.
     * <li>employee.anyOf("projects").asOf(pastTime): projects only as of past time.
     * </ul>
     * <p>
     * Watch out for x.asOf(oneTime).get("y").asOf(anotherTime).
     * <ul>
     * <li>emp.anyOf("phoneNumbers").asOf(yesterday) = emp.asOf(yesterday).anyOf("phoneNumbers") but:
     * <li>emp.get("address").asOf(yesterday) != emp.asOf(yesterday).get("address").
     * </ul>
     * Whether the join is also as of yesterday depends on which table the foreign
     * key field resides on.  In an anyOf the foreign key is always on the right, but
     * in a get (1-1) it could be on either side.  For this
     * reason employee.get("address").asOf(yesterday) is undefined as it can mean
     * either 'my address as of yesterday', or 'my address, as of yesterday.'
     * @param pastTime A read only data object used to represent a past time.
     * @return <code>this</code>
     * @since OracleAS EclipseLink 10<i>g</i> (10.0.3)
     * @see org.eclipse.persistence.history.AsOfClause
     * @see #hasAsOfClause
     * @see org.eclipse.persistence.sessions.Session#acquireHistoricalSession(org.eclipse.persistence.history.AsOfClause)
     * @see org.eclipse.persistence.queries.ObjectLevelReadQuery#setAsOfClause(org.eclipse.persistence.history.AsOfClause)
     */
    public Expression asOf(AsOfClause pastTime) {
        throw new UnsupportedOperationException("anyOfAllowingNone");
    }

    /**
     * INTERNAL:
     * Alias a particular table within this node
     */
    protected void assignAlias(String name, DatabaseTable tableOrExpression) {
        // By default, do nothing.
    }

    /**
     * INTERNAL:
     * Assign aliases to any tables which I own. Start with t(initialValue),
     * and return the new value of  the counter , i.e. if initialValue is one
     * and I have tables ADDRESS and EMPLOYEE I will assign them t1 and t2 respectively, and return 3.
     */
    public int assignTableAliasesStartingAt(int initialValue) {
        if (hasBeenAliased()) {
            return initialValue;
        }
        int counter = initialValue;
        List<DatabaseTable> ownedTables = getOwnedTables();
        if (ownedTables != null) {
            for (DatabaseTable table : ownedTables) {
                assignAlias("t" + counter, table);
                counter++;
            }
        }
        return counter;
    }

    /**
     * PUBLIC:
     * Function, This represents the aggregate function Average. Can be used only within Report Queries.
     */
    public Expression average() {
        return getFunction(ExpressionOperator.Average);
    }

    /**
     * PUBLIC:
     * Function, between two bytes
     */
    public Expression between(byte leftValue, byte rightValue) {
        return between(Byte.valueOf(leftValue), Byte.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Function, between two chars
     */
    public Expression between(char leftChar, char rightChar) {
        return between(Character.valueOf(leftChar), Character.valueOf(rightChar));
    }

    /**
     * PUBLIC:
     * Function, between two doubles
     */
    public Expression between(double leftValue, double rightValue) {
        return between(Double.valueOf(leftValue), Double.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Function, between two floats
     */
    public Expression between(float leftValue, float rightValue) {
        return between(Float.valueOf(leftValue), Float.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Function, between two ints
     */
    public Expression between(int leftValue, int rightValue) {
        return between(Integer.valueOf(leftValue), Integer.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Function, between two longs
     */
    public Expression between(long leftValue, long rightValue) {
        return between(Long.valueOf(leftValue), Long.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receiver's value is between two other values.
     * This means the receiver's value is greater than or equal to the leftValue argument and less than or equal to the
     * rightValue argument.
     * <p>
     * This is equivalent to the SQL "BETWEEN AND" operator and Java {@literal ">=", "<=;"} operators.
     * <p>Example:
     * <pre>
     *     EclipseLink: employee.get("age").between(19,50)
     *     Java: (employee.getAge() {@literal >=} 19) {@literal &&} (employee.getAge() {@literal <=} 50)
     *     SQL: AGE BETWEEN 19 AND 50
     * </pre>
     */
    public Expression between(Object leftValue, Object rightValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Between);
        List args = new ArrayList(2);
        args.add(leftValue);
        args.add(rightValue);
        return anOperator.expressionForArguments(this, args);
    }

    public Expression between(Expression leftExpression, Expression rightExpression) {
        return between((Object)leftExpression, (Object)rightExpression);

    }

    /**
     * PUBLIC:
     * Function, between two shorts
     */
    public Expression between(short leftValue, short rightValue) {
        return between(Short.valueOf(leftValue), Short.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Function Convert values returned by the query to values
     * given in the caseItems Map.  The equivalent of
     * the Oracle CASE function
     * <p>Example:
     * <blockquote><pre>
     * Map caseTable = new HashMap();
     * caseTable.put("Robert", "Bob");
     * caseTable.put("Susan", "Sue");
     *
     * EclipseLink: employee.get("name").caseStatement(caseTable, "No-Nickname")
     * Java: NA
     * SQL: CASE name WHEN "Robert" THEN "Bob"
     *     WHEN "Susan" THEN "Sue"
     *  ELSE "No-Nickname"
     * </pre></blockquote>
     * @param caseItems java.util.Map
     * A Map containing the items to be processed.
     * Keys represent the items to match coming from the query.
     * Values represent what a key will be changed to.
     * @param defaultItem java.lang.String  the default value that will be used if none of the keys in the
     * hashtable match
     */
    public Expression caseStatement(Map caseItems, Object defaultItem) {
        FunctionExpression expression = caseStatement();
        expression.addChild(this);
        Iterator iterator = caseItems.keySet().iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            expression.addChild(Expression.from(key, this));
            expression.addChild(Expression.from(caseItems.get(key), this));
        }
        expression.addChild(Expression.from(defaultItem, this));
        return expression;
    }

    /**
     * INTERNAL:
     * Creates an ArgumentListFunctionExpression that is capable of creating a case statement of the form:
     * <blockquote><pre>
     * SQL: CASE name WHEN "Robert" THEN "Bob"
     *     WHEN "Susan" THEN "Sue"
     *  ELSE "No-Nickname"
     * </pre></blockquote>
     *
     * This expression must be manipulated to successfully build a case statement by adding appropriate
     * children to it.
     *
     * A child must be added for the "case expression" (name above), a pair of children must be added for
     * each "when then" expression and a child must be added for the else.
     *
     * @see ArgumentListFunctionExpression
     */
    public ArgumentListFunctionExpression caseStatement() {

        ListExpressionOperator caseOperator = (ListExpressionOperator)getOperator(ExpressionOperator.Case);
        ListExpressionOperator clonedCaseOperator = new ListExpressionOperator();
        caseOperator.copyTo(clonedCaseOperator);

        ArgumentListFunctionExpression expression = new ArgumentListFunctionExpression();
        expression.setBaseExpression(this);

        expression.setOperator(clonedCaseOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * Function Convert values returned by the query to values
     * given in the caseConditions Map.  The equivalent of
     * the SQL CASE function
     * <p>Example:
     * <blockquote><pre>
     * Map caseTable = new HashMap();
     * caseTable.put(employee.get("name").equals("Robert"), "Bob");
     * caseTable.put(employee.get("name").equals("Susan"), "Sue");
     *
     * EclipseLink: expressionBuilder.caseConditionStatement(caseTable, "No-Nickname")
     * Java: NA
     * SQL: CASE WHEN name = "Robert" THEN "Bob"
     *     WHEN name = "Susan" THEN "Sue"
     *  ELSE "No-Nickname"
     * </pre></blockquote>
     * @param caseConditions java.util.Map
     * A Map containing the items to be processed.
     * Keys represent the items to match coming from the query.
     * Values represent what a key will be changed to.
     * @param defaultItem java.lang.Object  the default value that will be used if none of the keys in the
     * Map match
     */
    public Expression caseConditionStatement(Map<Expression, Object> caseConditions, Object defaultItem) {
        FunctionExpression expression = caseConditionStatement();
        Iterator<Expression> iterator = caseConditions.keySet().iterator();
        if (iterator.hasNext()){
            Expression key = iterator.next();
            expression.addChild(key);
            expression.setBaseExpression(key);//base needs to be the same as the first child for reportQuery items.
            expression.addChild(Expression.from(caseConditions.get(key), this));

            while (iterator.hasNext()) {
                key = iterator.next();
                expression.addChild(key);
                expression.addChild(Expression.from(caseConditions.get(key), this));
            }
        }
        expression.addChild(Expression.from(defaultItem, this));
        return expression;
    }

    /**
     * INTERNAL:
     * Creates an ArgumentListFunctionExpression that is capable of creating a case statement of the form:
     * <blockquote><pre>
     * SQL: CASE WHEN name = "Robert" THEN "Bob"
     *     WHEN name = "Susan" THEN "Sue"
     *  ELSE "No-Nickname"
     * </pre></blockquote>
     *
     * This expression must be manipulated to successfully build a case statement by adding appropriate
     * children to it.
     *
     * A pair of children must be added for  each "when then" expression and a child must be added for the else.
     *
     * @see ArgumentListFunctionExpression
     */
    public ArgumentListFunctionExpression caseConditionStatement() {
        ListExpressionOperator caseOperator = (ListExpressionOperator)getOperator(ExpressionOperator.CaseCondition);
        ListExpressionOperator clonedCaseOperator = new ListExpressionOperator();
        caseOperator.copyTo(clonedCaseOperator);

        ArgumentListFunctionExpression expression = new ArgumentListFunctionExpression();
        expression.setBaseExpression(this);

        expression.setOperator(clonedCaseOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * Function Test if arguments are equal, returning null if they are and the value of the
     * first expression otherwise.
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: builder.get("name").nullIf( "Bobby")
     * Java: NA
     * SQL: NULLIF(name, "Bobby")
     * </pre></blockquote>
     * @param object java.lang.Object the value/expression that will be compared to the base expression
     */
    public Expression nullIf(Object object) {
            ExpressionOperator anOperator = getOperator(ExpressionOperator.NullIf);
            List args = new ArrayList(1);
            args.add(Expression.from(object, this));
            return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function Return null if all arguments are null and the first non-null argument otherwise
     * The equivalent of the COALESCE SQL function
     * <p>Example:
     * <blockquote><pre>
     * List list = new ArrayList(3);
     * list.add(builder.get("firstName"));
     * list.add(builder.get("lastName"));
     * list.add(builder.get("nickname"));
     *
     * EclipseLink: expressionBuilder.coalesce(caseTable)
     * Java: NA
     * SQL: COALESCE(firstname, lastname, nickname)
     * </pre></blockquote>
     * @param expressions java.util.Collection
     * A Collection containing the items to check if null
     */
    public ArgumentListFunctionExpression coalesce(Collection expressions) {
        ArgumentListFunctionExpression expression = coalesce();
        Iterator iterator = expressions.iterator();
        if (iterator.hasNext()){
            Expression base = Expression.from(iterator.next(), this);
            expression.addChild(base);
            expression.setBaseExpression(base);//base needs to be the same as the first child for reportQuery items.
            while (iterator.hasNext()) {
                expression.addChild(Expression.from(iterator.next(), this));
            }
        }
        return expression;
    }

    public ArgumentListFunctionExpression coalesce() {
        ListExpressionOperator coalesceOperator = (ListExpressionOperator)getOperator(ExpressionOperator.Coalesce);
        ListExpressionOperator clonedCoalesceOperator = new ListExpressionOperator();
        coalesceOperator.copyTo(clonedCoalesceOperator);

        ArgumentListFunctionExpression expression = new ArgumentListFunctionExpression();
        expression.setBaseExpression(this);

        expression.setOperator(clonedCoalesceOperator);
        return expression;
    }

    /**
     * INTERNAL:
     * Clone the expression maintaining clone identity in the inter-connected expression graph.
     */
    public Object clone() {
        // 2612538 - the default size of Map (32) is appropriate
        Map alreadyDone = new IdentityHashMap();
        return copiedVersionFrom(alreadyDone);
    }

    /**
     * INTERNAL:
     * This expression is built on a different base than the one we want. Rebuild it and
     * return the root of the new tree.
     * This method will rebuildOn the receiver even it is a parallel select or a
     * sub select: it will not replace every base with newBase.
     * Also it will rebuild using anyOf as appropriate not get.
     * @see org.eclipse.persistence.mappings.ForeignReferenceMapping#batchedValueFromRow
     * @see #rebuildOn(Expression)
     * @bug 2637484 INVALID QUERY KEY EXCEPTION THROWN USING BATCH READS AND PARALLEL EXPRESSIONS
     * @bug 2612567 CR4298- NULLPOINTEREXCEPTION WHEN USING SUBQUERY AND BATCH READING IN 4.6
     * @bug 2612140 CR2973- BATCHATTRIBUTE QUERIES WILL FAIL WHEN THE INITIAL QUERY HAS A SUBQUERY
     * @bug 2720149 INVALID SQL WHEN USING BATCH READS AND MULTIPLE ANYOFS
     */
    public Expression cloneUsing(Expression newBase) {
        // 2612538 - the default size of Map (32) is appropriate
        Map alreadyDone = new IdentityHashMap();

        // cloneUsing is identical to cloning save that the primary builder
        // will be replaced not with its clone but with newBase.
        // ExpressionBuilder.registerIn() will check for this newBase with
        // alreadyDone.get(alreadyDone);
        // copiedVersionFrom() must be called on the primary builder before
        // other builders.
        alreadyDone.put(alreadyDone, newBase);
        return copiedVersionFrom(alreadyDone);
    }

    /**
     * PUBLIC:
     * Function, returns the concatenation of the two string values.
     */
    public Expression concat(Object left) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Concat);
        return anOperator.expressionFor(this, left);
    }

    /**
     * PUBLIC:
     * Return an expression that performs a key word search.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: project.get("description").containsAllKeyWords("EclipseLink rdbms java")
     * </pre></blockquote>
     */
    public Expression containsAllKeyWords(String spaceSeparatedKeyWords) {
        StringTokenizer tokenizer = new StringTokenizer(spaceSeparatedKeyWords);
        Expression expression = null;
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            if (expression == null) {
                expression = containsSubstringIgnoringCase(token);
            } else {
                expression = expression.and(containsSubstringIgnoringCase(token));
            }
        }

        if (expression == null) {
            return like("%");
        } else {
            return expression;
        }
    }

    /**
     * PUBLIC:
     * Return an expression that performs a key word search.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: project.get("description").containsAllKeyWords("EclipseLink rdbms java")
     * </pre></blockquote>
     */
    public Expression containsAnyKeyWords(String spaceSeparatedKeyWords) {
        StringTokenizer tokenizer = new StringTokenizer(spaceSeparatedKeyWords);
        Expression expression = null;
        while (tokenizer.hasMoreTokens()) {
            String token = tokenizer.nextToken();
            if (expression == null) {
                expression = containsSubstringIgnoringCase(token);
            } else {
                expression = expression.or(containsSubstringIgnoringCase(token));
            }
        }

        if (expression == null) {
            return like("%");
        } else {
            return expression;
        }
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value contains the substring.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").containsSubstring("Bob")
     *     Java: employee.getFirstName().indexOf("Bob") != -1
     *     SQL: F_NAME LIKE '%BOB%'
     * </pre></blockquote>
     */
    public Expression containsSubstring(String theValue) {
        return like("%" + theValue + "%");
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value contains the substring.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").containsSubstring("Bob")
     *     Java: employee.getFirstName().indexOf("Bob") != -1
     *     SQL: F_NAME LIKE '%BOB%'
     * </pre></blockquote>
     */
    public Expression containsSubstring(Expression expression) {
        return like((value("%").concat(expression)).concat("%"));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value contains the substring, ignoring case.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").containsSubstringIgnoringCase("Bob")
     *     Java: employee.getFirstName().toUpperCase().indexOf("BOB") != -1
     *     SQL: UPPER(F_NAME) LIKE '%BOB%'
     * </pre></blockquote>
     */
    public Expression containsSubstringIgnoringCase(String theValue) {
        if (shouldUseUpperCaseForIgnoreCase) {
            return toUpperCase().containsSubstring(theValue.toUpperCase());
        } else {
            return toLowerCase().containsSubstring(theValue.toLowerCase());
        }
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value contains the substring, ignoring case.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").containsSubstringIgnoringCase("Bob")
     *     Java: employee.getFirstName().toUpperCase().indexOf("BOB") != -1
     *     SQL: UPPER(F_NAME) LIKE '%BOB%'
     * </pre></blockquote>
     */
    public Expression containsSubstringIgnoringCase(Expression expression) {
        if (shouldUseUpperCaseForIgnoreCase) {
            return toUpperCase().containsSubstring(expression.toUpperCase());
        } else {
            return toLowerCase().containsSubstring(expression.toLowerCase());
        }
    }

    /*
     * Modify this individual expression node to use outer joins wherever there are
     * equality operations between two field nodes.
     */
    protected void convertNodeToUseOuterJoin() {
    }

    /**
     * INTERNAL:
     * Modify this expression to use outer joins wherever there are
     * equality operations between two field nodes.
     */
    public Expression convertToUseOuterJoin() {
        ExpressionIterator iterator = new ExpressionIterator() {
            public void iterate(Expression each) {
                each.convertNodeToUseOuterJoin();
            }
        };
        iterator.iterateOn(this);
        return this;
    }

    /**
     * INTERNAL:
     */
    public Expression copiedVersionFrom(Map alreadyDone) {
        if (alreadyDone == null) {
            // For sub-selects no cloning is done.
            return this;
        }
        Expression existing = (Expression)alreadyDone.get(this);
        if (existing == null) {
            return registerIn(alreadyDone);
        } else {
            return existing;
        }
    }

    /**
     * PUBLIC:
     * This represents the aggregate function Average. Can be used only within Report Queries.
     */
    public Expression count() {
        return getFunction(ExpressionOperator.Count);
    }

    /**
     * INTERNAL:
     */
    public Expression create(Expression base, Object singleArgument, ExpressionOperator anOperator) {
        // This is a replacement for real class methods in Java. Instead of returning a new instance we create it, then
        // mutate it using this method.
        return this;
    }

    /**
     * INTERNAL:
     */
    public Expression createWithBaseLast(Expression base, Object singleArgument, ExpressionOperator anOperator) {
        // This is a replacement for real class methods in Java. Instead of returning a new instance we create it, then
        // mutate it using this method.
        return this;
    }

    /**
     * INTERNAL:
     */
    public Expression create(Expression base, List arguments, ExpressionOperator anOperator) {
        // This is a replacement for real class methods in Java. Instead of returning a new instance we create it, then
        // mutate it using this method.
        return this;
    }

    /**
     * PUBLIC:
     * This gives access to the current timestamp on the database through expression.
     * Please note, this method is added for consistency and returns the same
     * result as currentDate.
     */
    public Expression currentTimeStamp() {
        return currentDate();
    }

    /**
     * PUBLIC:
     * This gives access to the current date on the database through expression.
     */
    public Expression currentDate() {
        return getFunction(ExpressionOperator.Today);
    }

   /**
    * PUBLIC:
    * This gives access to the current date only on the database through expression.
    * Note the difference between currentDate() and this method. This method does
    * not return the time portion of current date where as currentDate() does.
    */
   public Expression currentDateDate() {
       return getFunction(ExpressionOperator.CurrentDate);
   }

   /**
    * PUBLIC:
    * This gives access to the current time only on the database through expression.
    * Note the difference between currentDate() and this method. This method does
    * not return the date portion where as currentDate() does.
    */
   public Expression currentTime() {
       return getFunction(ExpressionOperator.CurrentTime);
   }

    /**
     * PUBLIC:
     * Function, Return the difference between the queried part of a date(i.e. years, days etc.)
     * and same part of the given date. The equivalent of the Sybase function DateDiff
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").dateDifference("year", new Date(System.currentTimeMillis()))
     * Java: NA
     * SQL: DATEADD(date, 2, GETDATE)
     * </pre></blockquote>
     */
    public Expression dateDifference(String datePart, java.util.Date date) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.DateDifference);
        FunctionExpression expression = new FunctionExpression();
        expression.setBaseExpression(this);
        expression.addChild(Expression.fromLiteral(datePart, this));
        expression.addChild(Expression.from(date, this));
        expression.addChild(this);
        expression.setOperator(anOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * Function, Return the difference between the queried part of a date(i.e. years, days etc.)
     * and same part of the given date. The equivalent of the Sybase function DateDiff
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").dateDifference("year", new Date(System.currentTimeMillis()))
     * Java: NA
     * SQL: DATEADD(date, 2, GETDATE)
     * </pre></blockquote>
     */
    public Expression dateDifference(String datePart, Expression comparisonExpression) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.DateDifference);
        FunctionExpression expression = new FunctionExpression();
        expression.setBaseExpression(this);
        expression.addChild(Expression.fromLiteral(datePart, this));
        expression.addChild(comparisonExpression);
        expression.addChild(this);
        expression.setOperator(anOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * return a string that represents the given part of a date. The equivalent
     * of the Sybase DATENAME function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").dateName("year")
     * Java: new String(date.getYear())
     * SQL: DATENAME(date, year)
     * </pre></blockquote>
     */
    public Expression dateName(String datePart) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.DateName);
        FunctionExpression expression = new FunctionExpression();
        expression.setBaseExpression(this);
        expression.addChild(Expression.fromLiteral(datePart, this));
        expression.addChild(this);
        expression.setOperator(anOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * Function return an integer which represents the requested
     * part of the date.  Equivalent of the Sybase function DATEPART
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").datePart("year")
     * Java: date.getYear()
     * SQL: DATEPART(date, year)
     * </pre></blockquote>
     */
    public Expression datePart(String datePart) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.DatePart);
        FunctionExpression expression = new FunctionExpression();
        expression.setBaseExpression(this);
        expression.addChild(Expression.fromLiteral(datePart, this));
        expression.addChild(this);
        expression.setOperator(anOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * Function, returns the date converted to the string value in the default database format.
     */
    public Expression dateToString() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.DateToString);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function Convert values returned by the query to values given in the decodeableItems Map.
     * The equivalent of the Oracle DECODE function.
     * Note: This will only work on databases that support Decode with the syntax below.
     * <p>Example:
     * <blockquote><pre>
     * Map decodeTable = new HashMap();
     * decodeTable.put("Robert", "Bob");
     * decodeTable.put("Susan", "Sue");
     *
     * EclipseLink: employee.get("name").Decode(decodeTable, "No-Nickname")
     * Java: NA
     * SQL: DECODE(name, "Robert", "Bob", "Susan", "Sue", "No-Nickname")
     * </pre></blockquote>
     * @param decodeableItems java.util.Map
     *   a Map containing the items to be decoded.  Keys represent
     * the items to match coming from the query.  Values represent what
     * a key will be changed to.
     * @param defaultItem
     *  the default value that will be used if none of the keys in the
     * Map match
     **/
    public Expression decode(Map decodeableItems, String defaultItem) {

        /**
         * decode works differently than most of the functionality in the expression framework.
         * It takes a variable number of arguments and as a result, the printed strings for
         * a decode call have to be built when the number of arguments are known.
         * As a result, we do not look up decode in the ExpressionOperator.  Instead we build
         * the whole operator here.  The side effect of this is that decode will not thrown
         * an invalid operator exception for any platform.  (Even the ones that do not support
         * decode)
         */
        ExpressionOperator anOperator = new ExpressionOperator();
        anOperator.setSelector(ExpressionOperator.Decode);
        anOperator.setName("DECODE");
        anOperator.setNodeClass(ClassConstants.FunctionExpression_Class);
        anOperator.setType(ExpressionOperator.FunctionOperator);
        anOperator.bePrefix();

        Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(decodeableItems.size() + 1);
        v.add("DECODE(");
        for (int i = 0; i < ((decodeableItems.size() * 2) + 1); i++) {
            v.add(", ");
        }
        v.add(")");
        anOperator.printsAs(v);

        FunctionExpression expression = new FunctionExpression();
        expression.setBaseExpression(this);
        expression.addChild(this);
        Iterator iterator = decodeableItems.keySet().iterator();
        while (iterator.hasNext()) {
            Object key = iterator.next();
            expression.addChild(Expression.from(key, this));
            expression.addChild(Expression.from(decodeableItems.get(key), this));
        }
        expression.addChild(Expression.from(defaultItem, this));
        expression.setOperator(anOperator);
        return expression;
    }

    /**
     * PUBLIC:
     * This can only be used within an ordering expression.
     * It will order the result descending.
     * <p>Example:
     * <blockquote><pre>
     * readAllQuery.addOrderBy(expBuilder.get("address").get("city").descending())
     * </pre></blockquote>
     */
    public Expression descending() {
        return getFunction(ExpressionOperator.Descending);
    }

    /**
     * INTERNAL:
     * Used in debug printing of this node.
     */
    public String descriptionOfNodeType() {
        return "Expression";
    }

    /**
     * PUBLIC:
     * Function return a value which indicates how much difference there is
     * between two expressions.  Equivalent of the Sybase DIFFERENCE function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").difference("Frank")
     * SQL: DIFFERENCE(name, 'Frank')
     * </pre></blockquote>
     */
    public Expression difference(String expression) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Difference);
        return anOperator.expressionFor(this, expression);
    }

    /**
     * PUBLIC:
     * Function, This represents the distinct option inside an aggregate function. Can be used only within Report Queries.
     */
    public Expression distinct() {
        return getFunction(ExpressionOperator.Distinct);
    }

    /**
     * INTERNAL:
     * Check if the object conforms to the expression in memory.
     * This is used for in-memory querying.
     * By default throw an exception as all valid root expressions must override.
     * If the expression in not able to determine if the object conform throw a not supported exception.
     */
    public boolean doesConform(Object object, AbstractSession session, AbstractRecord translationRow, int valueHolderPolicy) throws QueryException {
        return doesConform(object, session, translationRow, valueHolderPolicy, false);
    }

    /**
     * INTERNAL:
     * New parameter added to doesConform for feature 2612601
     * @param objectIsUnregistered true if object possibly not a clone, but is being
     * conformed against the unit of work cache; if object is not in the UOW cache
     * but some of its attributes are, use the registered versions of
     * object's attributes for the purposes of this method.
     */
    public boolean doesConform(Object object, AbstractSession session, AbstractRecord translationRow, int valueHolderPolicy, boolean objectIsUnregistered) throws QueryException {
        throw QueryException.cannotConformExpression();
    }

    /**
     * INTERNAL:
     * Return if the expression is equal to the other.
     * This is used to allow dynamic expression's SQL to be cached.
     * Two expressions should be considered equal if they have the same "parameterized" SQL.
     * This must be over written by each subclass.
     */
    public boolean equals(Object expression) {
        return (this == expression) || ((expression != null) && getClass().equals(expression.getClass()) && (hashCode() == expression.hashCode()));
    }

    /**
     * INTERNAL:
     * Return a consistent hash-code for the expression.
     * This is used to allow dynamic expression's SQL to be cached.
     * Two expressions should have the same hashCode if they have the same "parameterized" SQL.
     * This should be over written by each subclass to provide a consistent value.
     */
    public int hashCode() {
        if (this.hashCode == 0) {
            this.hashCode = computeHashCode();
        }
        return this.hashCode;
    }

    /**
     * INTERNAL:
     * Compute a consistent hash-code for the expression.
     * This is used to allow dynamic expression's SQL to be cached.
     * Two expressions should have the same hashCode if they have the same "parameterized" SQL.
     * This should be over written by each subclass to provide a consistent value.
     */
    public int computeHashCode() {
        return 32;
    }

    public Expression equal(byte theValue) {
        return equal(Byte.valueOf(theValue));
    }

    public Expression equal(char theChar) {
        return equal(Character.valueOf(theChar));
    }

    public Expression equal(double theValue) {
        return equal(Double.valueOf(theValue));
    }

    public Expression equal(float theValue) {
        return equal(Float.valueOf(theValue));
    }

    public Expression equal(int theValue) {
        return equal(Integer.valueOf(theValue));
    }

    public Expression equal(long theValue) {
        return equal(Long.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receiver's value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").equal("Bob")
     *     Java: employee.getFirstName().equals("Bob")
     *     SQL: F_NAME = 'Bob'
     * </pre></blockquote>
     */
    public Expression equal(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Equal);
        return anOperator.expressionFor(this, theValue);
    }

    /**
     * Returns an expression that compares if the receiver's value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     * <p>Since OracleAS EclipseLink 10<i>g</i> (9.0.4) if <code>this</code> is an <code>ExpressionBuilder</code> and <code>theValue</code>
     * is not used elsewhere, both will be translated to the same table.  This can
     * generate SQL with one less join for most exists subqueries.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("manager").equal(employee)
     *     Java: employee.getManager().equals(employee)
     *     SQL (optimized): EMP_ID = MANAGER_ID
     *     SQL (unoptimized): t0.MANAGER_ID = t1.EMP_ID AND t0.EMP_ID = t1.EMP_ID
     * </pre></blockquote>
     * @see #equal(Object)
     */
    public Expression equal(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Equal);
        return anOperator.expressionFor(this, theValue);

    }

    public Expression equal(short theValue) {
        return equal(Short.valueOf(theValue));
    }

    public Expression equal(boolean theBoolean) {
        return equal(Boolean.valueOf(theBoolean));
    }

    /**
     * INTERNAL:
     * Return an expression representing an outer join comparison
     */

    // cr3546
    public Expression equalOuterJoin(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.EqualOuterJoin);
        return anOperator.expressionFor(this, theValue);
    }

    /**
     * INTERNAL:
     * Return an expression representing an outer join comparison
     */
    public Expression equalOuterJoin(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.EqualOuterJoin);
        return anOperator.expressionFor(this, theValue);

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receiver's value is equal to the other value, ignoring case.
     * This is equivalent to the Java "equalsIgnoreCase" method.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").equalsIgnoreCase("Bob")
     *     Java: employee.getFirstName().equalsIgnoreCase("Bob")
     *     SQL: UPPER(F_NAME) = 'BOB'
     * </pre></blockquote>
     */
    public Expression equalsIgnoreCase(String theValue) {
        if (shouldUseUpperCaseForIgnoreCase) {
            return toUpperCase().equal(theValue.toUpperCase());
        } else {
            return toLowerCase().equal(theValue.toLowerCase());
        }
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receiver's value is equal to the other value, ignoring case.
     * This is equivalent to the Java "equalsIgnoreCase" method.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").equalsIgnoreCase("Bob")
     *     Java: employee.getFirstName().equalsIgnoreCase("Bob")
     *     SQL: UPPER(F_NAME) = 'BOB'
     * </pre></blockquote>
     */
    public Expression equalsIgnoreCase(Expression theValue) {
        if (shouldUseUpperCaseForIgnoreCase) {
            return toUpperCase().equal(theValue.toUpperCase());
        } else {
            return toLowerCase().equal(theValue.toLowerCase());
        }
    }

    /**
     * PUBLIC:
     * Return a sub query expression.
     * A sub query using a report query to define a subselect within another queries expression or select's where clause.
     * The sub query (the report query) will use its own expression builder be can reference expressions from the base expression builder.
     * <p>Example:
     * <blockquote><pre>
     * ExpressionBuilder builder = new ExpressionBuilder();
     * ReportQuery subQuery = new ReportQuery(Employee.class, new ExpressionBuilder());
     * subQuery.setSelectionCriteria(subQuery.getExpressionBuilder().get("name").equal(builder.get("name")));
     * builder.exists(subQuery);
     * </pre></blockquote>
     */
    public Expression exists(ReportQuery subQuery) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Exists);
        return anOperator.expressionFor(subQuery(subQuery));
    }

    /**
     * INTERNAL:
     * Extract the primary key from the expression into the row.
     * Ensure that the query is querying the exact primary key.
     * Return false if not on the primary key.
     */
    public boolean extractPrimaryKeyValues(boolean requireExactMatch, ClassDescriptor descriptor, AbstractRecord primaryKeyRow, AbstractRecord translationRow) {
        return extractValues(true, requireExactMatch, descriptor, primaryKeyRow, translationRow);
    }

    /**
     * INTERNAL:
     * Extract the primary key from the expression into the row.
     * Ensure that the query is querying the exact primary key.
     * Return false if not on the primary key.
     */
    public boolean extractValues(boolean primaryKeyOnly, boolean requireExactMatch, ClassDescriptor descriptor, AbstractRecord primaryKeyRow, AbstractRecord translationRow) {
        return false;
    }

    /**
     * INTERNAL:
     * Return if the expression is not a valid primary key expression and add all primary key fields to the set.
     */
    public boolean extractFields(boolean requireExactMatch, boolean primaryKey, ClassDescriptor descriptor, List<DatabaseField> searchFields, Set<DatabaseField> foundFields) {
        return false;
    }

    /**
     * INTERNAL:
     * Create an expression node.
     */
    public static Expression from(Object value, Expression base) {
        //CR#... null value used to return null, must build a null constant expression.
        if (value instanceof Expression) {
            Expression exp = (Expression)value;
            if (exp.isValueExpression() || base.isExpressionBuilder()) {
                exp.setLocalBase(base);
            } else {
                // We don't know which side of the relationship cares about the other one, so notify both
                // However for 3107049 value.equal(value) would cause infinite loop if did that.
                base.setLocalBase(exp);
            }
            return exp;
        }
        if (value instanceof ReportQuery) {
            Expression exp = base.subQuery((ReportQuery)value);
            exp.setLocalBase(base);// We don't know which side of the relationship cares about the other one, so notify both
            base.setLocalBase(exp);
            return exp;
        }
        return fromConstant(value, base);

    }

    /**
     * INTERNAL:
     * Create an expression node.
     */
    public static Expression fromConstant(Object value, Expression base) {
        return new ConstantExpression(value, base);
    }

    /**
     * INTERNAL:
     * Create an expression node.
     */
    public static Expression fromLiteral(String value, Expression base) {
        return new LiteralExpression(value, base);
    }

    /**
     * PUBLIC:
     * Return an expression that wraps the attribute or query key name.
     * This method is used to construct user-defined queries containing joins.
     * <p>Example:
     * <blockquote><pre>
     *  builder.get("address").get("city").equal("Ottawa");
     * </pre></blockquote>
     */
    public Expression get(String attributeName) {
        return get(attributeName, true);
    }

    /**
     * PUBLIC:
     * Return an expression that wraps the attribute or query key name.
     * This method is used to construct user-defined queries containing joins.
     * <p>Example:
     * <blockquote><pre>
     *  builder.get("address", false).get("city").equal("Ottawa");
     * </pre></blockquote>
     * @param forceInnerJoin - allows the get to not force an inner-join (if getAllowingNull was used elsewhere).
     */
    public Expression get(String attributeName, boolean forceInnerJoin) {
        throw new UnsupportedOperationException("get");
    }

    /**
     * ADVANCED:
     * Return an expression that wraps the attribute or query key name.
     * This is only applicable to 1:1 relationships, and allows the target of
     * the relationship to be null if there is no corresponding relationship in the database.
     * Implemented via an outer join in the database.
     * <p>Example:
     * <blockquote><pre>
     *  builder.getAllowingNull("address").get("city").equal("Ottawa");
     * </pre></blockquote>
     */
    public Expression getAllowingNull(String attributeName) {
        throw new UnsupportedOperationException("getAllowingNull");
    }

    /**
     * Answers the past time the expression is explicitly as of.
     * @return An immutable object representation of the past time.
     * <code>null</code> if no clause set, <code>AsOfClause.NO_CLAUSE</code> if
     * clause explicitly set to <code>null</code>.
     * @see #asOf(org.eclipse.persistence.history.AsOfClause)
     * @see #hasAsOfClause()
     */
    public AsOfClause getAsOfClause() {
        return null;
    }

    /**
     * INTERNAL:
     * For Flashback: If this expression is not already as of some timestamp
     * gets the clause from the base expression.  Allows a clause to be set
     * only on the builder and then propogated during normalize.
     */
    public AsOfClause getAsOfClauseRecursively() {
        return null;
    }

    /**
     * INTERNAL:
     * Return the expression builder which is the ultimate base of this expression, or
     * null if there isn't one (shouldn't happen if we start from a root)
     */
    public abstract ExpressionBuilder getBuilder();

    /**
     * INTERNAL:
     * If there are any fields associated with this expression, return them
     */
    public DatabaseField getClonedField() {
        return null;
    }

    /**
     * ADVANCED:
     * Return an expression representing a field in a data-level query.
     * This is used internally in EclipseLink, or to construct queries involving
     * fields and/or tables that are not mapped.
     * <p> Example:
     * <blockquote><pre>
     *  builder.getField("ADDR_ID").greaterThan(100);
     *  builder.getTable("PROJ_EMP").getField("TYPE").equal("S");
     * </pre></blockquote>
     */
    public Expression getField(String fieldName) {
        throw QueryException.illegalUseOfGetField(fieldName);
    }

    /**
     * ADVANCED: Return an expression representing a field in a data-level query.
     * This is used internally in EclipseLink, or to construct queries involving
     * fields and/or tables that are not mapped.
     * <p> Example:
     * <blockquote><pre>
     *  builder.getField(aField).greaterThan(100);
     * </pre></blockquote>
     */
    public Expression getField(DatabaseField field) {
        throw QueryException.illegalUseOfGetField(field);
    }

    /**
     * INTERNAL:
     */
    public Vector getFields() {
        return org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
    }

    /**
     * INTERNAL:
     */
    public List<DatabaseField> getSelectionFields() {
        return getSelectionFields(null);
    }
    public List<DatabaseField> getSelectionFields(ReadQuery query) {
        return getFields();
    }

    /**
     * INTERNAL:
     * Transform the object-level value into a database-level value
     */
    public Object getFieldValue(Object objectValue, AbstractSession session) {
        // Enums default to their ordinal
        if (objectValue instanceof Enum){
            return ((Enum)objectValue).ordinal();
        }
        return objectValue;

    }

    /**
     * ADVANCED:
     * Defines a join between the two objects based on the specified ON clause.
     * This can be used to define a join condition on two unrelated objects,
     * or to qualify a relationship join with additional criteria.
     * <p> Example:
     * <blockquote><pre>
     *  Expression address = employee.getAllowingNull("address");
     *  employee.join(address, address.get("city").equal("Ottawa"));
     *  query.addNonFetchJoin(address);
     * </pre></blockquote>
     */
    public Expression join(Expression target, Expression onClause) {
        throw new UnsupportedOperationException("join");
    }

    /**
     * ADVANCED:
     * Defines an outer join between the two objects based on the specified ON clause.
     * This can be used to define a join condition on two unrelated objects,
     * or to qualify a relationship join with additional criteria.
     * <p> Example:
     * <blockquote><pre>
     *  Expression address = employee.getAllowingNull("address");
     *  employee.leftJoin(address, address.get("city").equal("Ottawa"));
     *  query.addNonFetchJoin(address);
     * </pre></blockquote>
     */
    public Expression leftJoin(Expression target, Expression onClause) {
        throw new UnsupportedOperationException("leftJoin");
    }

    /**
     * ADVANCED:
     * This can be used for accessing user defined functions.
     * The operator must be defined in ExpressionOperator to be able to reference it.
     * @see ExpressionOperator
     * <p> Example:
     * <blockquote><pre>
     *  builder.get("name").getFunction(MyFunctions.FOO_BAR).greaterThan(100);
     * </pre></blockquote>
     */
    public Expression getFunction(int selector) {
        ExpressionOperator anOperator = getOperator(selector);
        return anOperator.expressionFor(this);
    }

    /**
     * ADVANCED:
     * This can be used for accessing user defined functions that have arguments.
     * The operator must be defined in ExpressionOperator to be able to reference it.
     * @see ExpressionOperator
     * <p> Example:
     * <blockquote><pre>
     *    List arguments = new ArrayList();
     *    arguments.add("blee");
     *  builder.get("name").getFunction(MyFunctions.FOO_BAR, arguments).greaterThan(100);
     * </pre></blockquote>
     */
    public Expression getFunction(int selector, List arguments) {
        ExpressionOperator anOperator = getOperator(selector);
        return anOperator.expressionForArguments(this, arguments);
    }

    /**
     * ADVANCED:
     * This can be used for accessing user defined operators that have arguments.
     * The operator must be defined in ExpressionOperator to be able to reference it.
     * @see ExpressionOperator
     * <p> Example:
     * <blockquote><pre>
     *  List arguments = new ArrayList();
     *  arguments.add("blee");
     *  builder.get("name").operator("FOO_BAR", arguments).greaterThan(100);
     * </pre></blockquote>
     */
    public Expression operator(String name, List arguments) {
        Integer selector = ExpressionOperator.getPlatformOperatorSelectors().get(name);
        if (selector == null) {
            return getFunctionWithArguments(name, arguments);
        }
        return getFunction(selector, arguments);
    }

    /**
     * ADVANCED:
     * This can be used for accessing user defined functions that have arguments.
     * The operator must be defined in ExpressionOperator to be able to reference it.
     * @see ExpressionOperator
     * <p> Example:
     * <blockquote><pre>
     *    List arguments = new ArrayList();
     *    arguments.add("blee");
     *  builder.get("name").getFunction(MyFunctions.FOO_BAR, arguments).greaterThan(100);
     * </pre></blockquote>
     */
    @Deprecated
    public Expression getFunction(int selector, Vector arguments) {
        return getFunction(selector, (List)arguments);
    }

    /**
     * ADVANCED:
     * Return a user defined function accepting the argument.
     * The function is assumed to be a normal prefix function and will print like, UPPER(base).
     * <p> Example:
     * <blockquote><pre>
     *  builder.get("firstName").getFunction("UPPER");
     * </pre></blockquote>
     */
    public Expression getFunction(String functionName) {
        ExpressionOperator anOperator = ExpressionOperator.simpleFunction(0, functionName);
        return anOperator.expressionFor(this);
    }

    /**
     * ADVANCED:
     * Return a user defined function accepting the argument.
     * The function is assumed to be a normal prefix function and will print like, CONCAT(base, argument).
     */
    public Expression getFunction(String functionName, Object argument) {
        ExpressionOperator anOperator = ExpressionOperator.simpleTwoArgumentFunction(0, functionName);
        return anOperator.expressionFor(this, argument);
    }

    /**
     * ADVANCED:
     * Return a user defined function accepting all of the arguments.
     * The function is assumed to be a normal prefix function like, CONCAT(base, value1, value2, value3, ...).
     */
    @Deprecated
    public Expression getFunctionWithArguments(String functionName, Vector arguments) {
        return getFunctionWithArguments(functionName, (List)arguments);
    }

    /**
     * ADVANCED:
     * Return a user defined function accepting all of the arguments.
     * The function is assumed to be a normal prefix function like, CONCAT(base, value1, value2, value3, ...).
     */
    public Expression getFunctionWithArguments(String functionName, List arguments) {
        ExpressionOperator anOperator = new ExpressionOperator();
        anOperator.setType(ExpressionOperator.FunctionOperator);
        Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(arguments.size());
        v.add(functionName + "(");
        for (int index = 0; index < arguments.size(); index++) {
            v.add(", ");
        }
        v.add(")");
        anOperator.printsAs(v);
        anOperator.bePrefix();
        anOperator.setNodeClass(ClassConstants.FunctionExpression_Class);

        return anOperator.expressionForArguments(this, arguments);
    }

    /**
     * ADVANCED:
     * Parse the SQL for parameter and return a custom function expression
     * using a custom operator that will print itself as the SQL.
     * Arguments are passed using '?', and must match the number of arguments.
     */
    public Expression sql(String sql, List arguments) {
        ExpressionOperator anOperator = new ExpressionOperator();
        anOperator.setType(ExpressionOperator.FunctionOperator);
        Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(arguments.size());
        int start = 0;
        int index = sql.indexOf('?');
        while (index != -1) {
            v.add(sql.substring(start, index));
            start = index + 1;
            index = sql.indexOf('?', start);
        }
        if (start <= sql.length()) {
            v.add(sql.substring(start, sql.length()));
        }
        anOperator.printsAs(v);
        anOperator.bePrefix();
        anOperator.setNodeClass(ClassConstants.FunctionExpression_Class);

        return anOperator.expressionForArguments(this, arguments);
    }

    /**
     * PUBLIC:
     * Return an expression that wraps the inheritance type field in an expression.
     * <p>Example:
     * <blockquote><pre>
     *  builder.getClassForInheritance().equal(SmallProject.class);
     *  builder.anyOf("projects").getClassForInheritance().equal(builder.getParameter("projectClass"));
     * </pre></blockquote>
     */
    public Expression type() {
        //Only valid on an ObjectExpression
        return null;
    }

    /**
     * INTERNAL:
     */
    public String getName() {
        return "";
    }

    /**
     * INTERNAL:
     * Most expression have operators, so this is just a convenience method.
     */
    public ExpressionOperator getOperator() {
        return null;
    }

    /**
     * INTERNAL:
     * Create a new expression tree with the named operator. Part of the implementation of user-level "get"
     */
    public ExpressionOperator getOperator(int selector) {
        ExpressionOperator result = ExpressionOperator.getOperator(Integer.valueOf(selector));
        if (result != null) {
            return result;
        }

        // Make a temporary operator which we expect the platform
        // to supply later.
        result = new ExpressionOperator();
        result.setSelector(selector);
        result.setNodeClass(ClassConstants.FunctionExpression_Class);
        return result;
    }

    /**
     * INTERNAL:
     * Return the tables that this node owns for purposes of table aliasing.
     */
    public List<DatabaseTable> getOwnedTables() {
        return null;
    }

    /**
     * INTERNAL:
     * Return an expression representing a parameter with the given name and type
     */
    public Expression getParameter(String parameterName, Object type) {
        return new ParameterExpression(parameterName, getBuilder(), type);

    }

    /**
     * ADVANCED:
     * Return an expression representing a parameter with the given name.
     */
    public Expression getParameter(String parameterName) {
        return new ParameterExpression(parameterName, getBuilder(), null);

    }

    /**
     * ADVANCED:
     * Return an expression representing a parameter with the given name.
     */
    public Expression getParameter(DatabaseField field) {
        return new ParameterExpression(field, getBuilder());

    }

    /**
     * ADVANCED:
     * Return an expression representing a property with the given name.
     */
    public Expression getProperty(DatabaseField field) {
        ParameterExpression paramExpression = new ParameterExpression(field, this);
        paramExpression.setIsProperty(true);
        return paramExpression;
    }

    /**
     * INTERNAL:
     */
    public AbstractSession getSession() {
        return getBuilder().getSession();
    }

    /**
     * ADVANCED: Return an expression representing a table in a data-level query.
     * This is used internally in EclipseLink, or to construct queries involving
     * fields and/or tables that are not mapped.
     * <p> Example:
     * <blockquote><pre>
     *  builder.getTable("PROJ_EMP").getField("TYPE").equal("S");
     * </pre></blockquote>
     */
    public Expression getTable(String tableName) {
        DatabaseTable table = new DatabaseTable(tableName);
        return getTable(table);
    }

    /**
     * ADVANCED: Return an expression representing a table in a data-level query.
     * This is used internally in EclipseLink, or to construct queries involving
     * fields and/or tables that are not mapped.
     * <p> Example:
     * <blockquote><pre>
     *  builder.getTable(linkTable).getField("TYPE").equal("S");
     * </pre></blockquote>
     */
    public Expression getTable(DatabaseTable table) {
        throw QueryException.illegalUseOfGetTable(table);
    }

    /**
     * ADVANCED: Return an expression representing a sub-select in the from clause.
     * <p> Example:
     * <blockquote><pre>
     *  builder.getAlias(builder.subQuery(reportQuery)).get("type").equal("S");
     * </pre></blockquote>
     */
    public Expression getAlias(Expression subSelect) {
        throw QueryException.illegalUseOfGetTable(subSelect);
    }

    /**
     * INTERNAL:
     * Return the aliases used. By default, return null, since we don't have tables.
     */
    public TableAliasLookup getTableAliases() {
        return null;

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(byte theValue) {
        return greaterThan(Byte.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(char theChar) {
        return greaterThan(Character.valueOf(theChar));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(double theValue) {
        return greaterThan(Double.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(float theValue) {
        return greaterThan(Float.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(int theValue) {
        return greaterThan(Integer.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(long theValue) {
        return greaterThan(Long.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receiver's value is greater than the other value.
     * This is equivalent to the SQL {@literal ">"} operator.
     */
    public Expression greaterThan(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.GreaterThan);
        return anOperator.expressionFor(this, theValue);
    }

    public Expression greaterThan(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.GreaterThan);
        return anOperator.expressionFor(this, theValue);

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(short theValue) {
        return greaterThan(Short.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is equal to the other value.
     * This is equivalent to the SQL "=" operator and Java "equals" method.
     */
    public Expression greaterThan(boolean theBoolean) {
        return greaterThan(Boolean.valueOf(theBoolean));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(byte theValue) {
        return greaterThanEqual(Byte.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(char theChar) {
        return greaterThanEqual(Character.valueOf(theChar));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(double theValue) {
        return greaterThanEqual(Double.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(float theValue) {
        return greaterThanEqual(Float.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(int theValue) {
        return greaterThanEqual(Integer.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(long theValue) {
        return greaterThanEqual(Long.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.GreaterThanEqual);
        return anOperator.expressionFor(this, theValue);

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.GreaterThanEqual);
        return anOperator.expressionFor(this, theValue);

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(short theValue) {
        return greaterThanEqual(Short.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is greater and equal to the other value.
     * This is equivalent to the SQL {@literal ">="} operator.
     */
    public Expression greaterThanEqual(boolean theBoolean) {
        return greaterThanEqual(Boolean.valueOf(theBoolean));
    }

    /**
     * ADVANCED:
     * Answers true if <code>this</code> is to be queried as of a past time.
     * @return false from <code>asOf(null); hasAsOfClause()</code>.
     * @see #getAsOfClause
     */
    public boolean hasAsOfClause() {
        return false;
    }

    /**
     * INTERNAL:
     * Answers if the database tables associated with this expression have been
     * aliased.  This insures the same tables are not aliased twice.
     */
    public boolean hasBeenAliased() {
        return false;
    }

    /**
     * PUBLIC:
     * Function, returns binary array value for the hex string.
     */
    public Expression hexToRaw() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.HexToRaw);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function  return a specific value if item returned from the
     * query is null.  Equivalent of the oracle NVL function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").ifNull("no-name")
     * Java: NA
     * SQL: NVL(name, 'no-name')
     * </pre></blockquote>
     */
    public Expression ifNull(Object nullValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Nvl);
        return anOperator.expressionFor(this, nullValue);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(byte[] theBytes) {
        List values = new ArrayList(theBytes.length);

        for (int index = 0; index < theBytes.length; index++) {
            values.add(Byte.valueOf(theBytes[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(char[] theChars) {
        List values = new ArrayList(theChars.length);

        for (int index = 0; index < theChars.length; index++) {
            values.add(Character.valueOf(theChars[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(double[] theDoubles) {
        List values = new ArrayList(theDoubles.length);

        for (int index = 0; index < theDoubles.length; index++) {
            values.add(Double.valueOf(theDoubles[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(float[] theFloats) {
        List values = new ArrayList(theFloats.length);

        for (int index = 0; index < theFloats.length; index++) {
            values.add(Float.valueOf(theFloats[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(int[] theInts) {
        List values = new ArrayList(theInts.length);

        for (int index = 0; index < theInts.length; index++) {
            values.add(Integer.valueOf(theInts[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(long[] theLongs) {
        List values = new ArrayList(theLongs.length);

        for (int index = 0; index < theLongs.length; index++) {
            values.add(Long.valueOf(theLongs[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(Object[] theObjects) {
        List values = new ArrayList(theObjects.length);

        for (int index = 0; index < theObjects.length; index++) {
            values.add(theObjects[index]);
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(short[] theShorts) {
        List values = new ArrayList(theShorts.length);

        for (int index = 0; index < theShorts.length; index++) {
            values.add(Short.valueOf(theShorts[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression in(boolean[] theBooleans) {
        List values = new ArrayList(theBooleans.length);

        for (int index = 0; index < theBooleans.length; index++) {
            values.add(Boolean.valueOf(theBooleans[index]));
        }

        return in(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     */
    public Expression in(Collection theObjects) {
        return in(new CollectionExpression(theObjects, this));
    }

    public Expression in(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.In);
        return anOperator.expressionFor(this, arguments);
    }

    public Expression in(ReportQuery subQuery) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.InSubQuery);
        return anOperator.expressionFor(this, subQuery);
    }

    /*
     * PUBLIC:
     * Index method could be applied to QueryKeyExpression corresponding to CollectionMapping
     * that has non-null listOrderField (the field holding the index values).
     * <p>Example:
     * <blockquote><pre>
     *    ReportQuery query = new ReportQuery();
     *    query.setReferenceClass(Employee.class);
     *    ExpressionBuilder builder = query.getExpressionBuilder();
     *    Expression firstNameJohn = builder.get("firstName").equal("John");
     *    Expression anyOfProjects = builder.anyOf("projects");
     *    Expression exp = firstNameJohn.and(anyOfProjects.index().between(2, 4));
     *    query.setSelectionCriteria(exp);
     *    query.addAttribute("projects", anyOfProjects);
     *
     *    SELECT DISTINCT t0.PROJ_ID, t0.PROJ_TYPE, t0.DESCRIP, t0.PROJ_NAME, t0.LEADER_ID, t0.VERSION, t1.PROJ_ID, t1.BUDGET, t1.MILESTONE
     *    FROM OL_PROJ_EMP t4, OL_SALARY t3, OL_EMPLOYEE t2, OL_LPROJECT t1, OL_PROJECT t0
     *    WHERE ((((t2.F_NAME = 'John') AND (t4.PROJ_ORDER BETWEEN 2 AND 4)) AND (t3.OWNER_EMP_ID = t2.EMP_ID)) AND
     *    (((t4.EMP_ID = t2.EMP_ID) AND (t0.PROJ_ID = t4.PROJ_ID)) AND (t1.PROJ_ID (+) = t0.PROJ_ID)))
     * </pre></blockquote>
     */
    public Expression index() {
        throw QueryException.indexRequiresQueryKeyExpression(this);
    }

    /**
     * PUBLIC:
     * Function, returns the integer index of the substring within the source string.
     */
    public Expression indexOf(Object substring) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Instring);
        return anOperator.expressionFor(this, substring);
    }

    /**
     * INTERNAL:
     */
    public boolean isClassTypeExpression(){
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isCompoundExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isConstantExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isDataExpression() {
        return false;
    }

    /**
     * PUBLIC: A logical expression for the collection <code>attributeName</code>
     * being empty.
     * Equivalent to <code>size(attributeName).equal(0)</code>
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.isEmpty("phoneNumbers")
     *     Java: employee.getPhoneNumbers().size() == 0
     *     SQL: SELECT ... FROM EMP t0 WHERE (
     *      (SELECT COUNT(*) FROM PHONE t1 WHERE (t0.EMP_ID = t1.EMP_ID)) = 0)
     * </pre></blockquote>
     * This is a case where a fast operation in java does not translate to an
     * equally fast operation in SQL, requiring a correlated subselect.
     * @see #size(java.lang.String)
     */
    public Expression isEmpty(String attributeName) {
        return size(attributeName).equal(0);
    }

    /**
     * INTERNAL:
     */
    public boolean isExpressionBuilder() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isFieldExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isFunctionExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isLiteralExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isLogicalExpression() {
        return false;
    }

    /**
     * PUBLIC:
     * Compare to null.
     */
    public Expression isNull() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.IsNull);
        return anOperator.expressionFor(this);
    }

    /**
     * INTERNAL:
     */
    public boolean isObjectExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isParameterExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isQueryKeyExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isRelationExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isSubSelectExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isTableExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isTreatExpression() {
        return false;
    }

    /**
     * INTERNAL:
     */
    public boolean isMapEntryExpression(){
        return false;
    }

    /**
     * INTERNAL:
     * Subclasses implement (isParameterExpression() || isConstantExpression())
     */
    public boolean isValueExpression() {
        return false;
    }

    /**
     * INTERNAL:
     * For iterating using an inner class
     */
    public void iterateOn(ExpressionIterator iterator) {
        iterator.iterate(this);
    }

    /**
     * PUBLIC:
     * Function, returns the date with the last date in the months of this source date.
     */
    public Expression lastDay() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LastDay);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the string padded with the substring to the size.
     */
    public Expression leftPad(int size, Object substring) {
        return leftPad(Integer.valueOf(size), substring);
    }

    /**
     * PUBLIC:
     * Function, returns the string padded with the substring to the size.
     */
    public Expression leftPad(Object size, Object substring) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LeftPad);
        List args = new ArrayList(2);
        args.add(size);
        args.add(substring);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, returns the string left trimmed for white space.
     */
    public Expression leftTrim() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LeftTrim);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the string with the substring trimed from the left.
     */
    public Expression leftTrim(Object substring) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LeftTrim2);
        return anOperator.expressionFor(this, substring);
    }

    /**
     * PUBLIC:
     * Function, returns the size of the string.
     */
    public Expression length() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Length);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(byte theValue) {
        return lessThan(Byte.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(char theChar) {
        return lessThan(Character.valueOf(theChar));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(double theValue) {
        return lessThan(Double.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(float theValue) {
        return lessThan(Float.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(int theValue) {
        return lessThan(Integer.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(long theValue) {
        return lessThan(Long.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LessThan);
        return anOperator.expressionFor(this, theValue);
    }

    public Expression lessThan(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LessThan);
        return anOperator.expressionFor(this, theValue);

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(short theValue) {
        return lessThan(Short.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than the other value.
     * This is equivalent to the SQL {@literal "<"} operator.
     */
    public Expression lessThan(boolean theBoolean) {
        return lessThan(Boolean.valueOf(theBoolean));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(byte theValue) {
        return lessThanEqual(Byte.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(char theChar) {
        return lessThanEqual(Character.valueOf(theChar));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(double theValue) {
        return lessThanEqual(Double.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(float theValue) {
        return lessThanEqual(Float.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(int theValue) {
        return lessThanEqual(Integer.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(long theValue) {
        return lessThanEqual(Long.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LessThanEqual);
        return anOperator.expressionFor(this, theValue);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LessThanEqual);
        return anOperator.expressionFor(this, theValue);

    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(short theValue) {
        return lessThanEqual(Short.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is less than and equal to the other value.
     * This is equivalent to the SQL {@literal "<="} operator.
     */
    public Expression lessThanEqual(boolean theBoolean) {
        return lessThanEqual(Boolean.valueOf(theBoolean));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is like other value.
     * This is equivalent to the SQL "LIKE" operator that except wildcards.
     * The character "%" means any sequence of characters and the character "_" mean any character.
     * i.e. "B%" == "Bob", "B_B" == "BOB"
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").like("B%")
     *     Java: NA
     *     SQL: F_NAME LIKE 'B%'
     * </pre></blockquote>
     */
    public Expression like(String value) {
        return like(new ConstantExpression(value, this));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is like other value.
     * This is equivalent to the SQL "LIKE ESCAPE" operator that except wildcards.
     * The character "%" means any sequence of characters and the character "_" mean any character.
     * i.e. "B%" == "Bob", "B_B" == "BOB"
     * The escape sequence specifies a set of characters the may be used to indicate that
     * an one of the wildcard characters should be interpreted literally.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").like("B\_SMITH", "\")
     *     Java: NA
     *     SQL: F_NAME LIKE 'B\_SMITH ESCAPE '\''
     * </pre></blockquote>
     */
    public Expression like(String value, String escapeSequence) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LikeEscape);
        List args = new ArrayList(2);
        args.add(value);
        args.add(escapeSequence);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is like other value.
     * This is equivalent to the SQL "LIKE" operator that except wildcards.
     * The character "%" means any sequence of characters and the character "_" mean any character.
     * i.e. "B%" == "Bob", "B_B" == "BOB"
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").like("B%")
     *     Java: NA
     *     SQL: F_NAME LIKE 'B%'
     * </pre></blockquote>
     */
    public Expression like(Expression argument) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Like);
        return anOperator.expressionFor(this, argument);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value matches the regular expression.
     * This uses the databases support for regular expression.
     * Regular expressions are similar to LIKE except support a much larger scope of comparisons.
     * i.e. "^B.*" == "Bob", "^B.B$" == "BOB"
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").regexp("^B.*")
     *     Java: Pattern.compile("^B.*").matcher(employee.getFirstName()).matches()
     *     SQL: F_NAME REGEXP '^B.*'
     * </pre></blockquote>
     */
    public Expression regexp(String regexp) {
        return regexp(new ConstantExpression(regexp, this));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value matches the regular expression.
     * This uses the databases support for regular expression.
     * Regular expressions are similar to LIKE except support a much larger scope of comparisons.
     * i.e. "^B.*" == "Bob", "^B.B$" == "BOB"
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").regexp("^B.*")
     *     Java: Pattern.compile("^B.*").matcher(employee.getFirstName()).matches()
     *     SQL: F_NAME REGEXP '^B.*'
     * </pre></blockquote>
     */
    public Expression regexp(Expression regexp) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Regexp);
        return anOperator.expressionFor(this, regexp);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is like other value.
     * This is equivalent to the SQL "LIKE ESCAPE" operator that except wildcards.
     * The character "%" means any sequence of characters and the character "_" mean any character.
     * i.e. "B%" == "Bob", "B_B" == "BOB"
     * The escape sequence specifies a set of characters the may be used to indicate that
     * an one of the wildcard characters should be interpreted literally.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").like("B\_SMITH", "\")
     *     Java: NA
     *     SQL: F_NAME LIKE 'B\_SMITH ESCAPE '\''
     * </pre></blockquote>
     */
    public Expression like(Expression value, Expression escapeSequence) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.LikeEscape);
        List args = new ArrayList(2);
        args.add(value);
        args.add(escapeSequence);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is like the other value, ignoring case.
     * This is a case in-sensitive like.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").likeIgnoreCase("%Bob%")
     *     Java: none
     *     SQL: UPPER(F_NAME) LIKE 'BOB'
     * </pre></blockquote>
     */
    public Expression likeIgnoreCase(String theValue) {
        if (shouldUseUpperCaseForIgnoreCase) {
            return toUpperCase().like(theValue.toUpperCase());
        } else {
            return toLowerCase().like(theValue.toLowerCase());
        }
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is like the other value, ignoring case.
     * This is a case in-sensitive like.
     */
    public Expression likeIgnoreCase(Expression theValue) {
        if (shouldUseUpperCaseForIgnoreCase) {
            return toUpperCase().like(theValue.toUpperCase());
        } else {
            return toLowerCase().like(theValue.toLowerCase());
        }
    }

    /**
     * PUBLIC:
     * Function, returns the position of <code>str</code> in <code>this</code>
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("firstName").locate("ob")
     * Java: employee.getFirstName().indexOf("ob") + 1
     * SQL: LOCATE('ob', t0.F_NAME)
     * </pre></blockquote>
     * <p>
     * Note that while in String.locate(str) -1 is returned if not found, and the
     * index starting at 0 if found, in SQL it is 0 if not found, and the index
     * starting at 1 if found.
     */
    public Expression locate(Object str) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Locate);
        List args = new ArrayList(1);
        args.add(str);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, returns the position of <code>str</code> in <code>this</code>,
     * starting the search at <code>fromIndex</code>.
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("firstName").locate("ob", 1)
     * Java: employee.getFirstName().indexOf("ob", 1) + 1
     * SQL: LOCATE('ob', t0.F_NAME, 1)
     * </pre></blockquote>
     * <p>
     * Note that while in String.locate(str) -1 is returned if not found, and the
     * index starting at 0 if found, in SQL it is 0 if not found, and the index
     * starting at 1 if found.
     */
    public Expression locate(String str, int fromIndex) {
        return locate(str, Integer.valueOf(fromIndex));
    }

    /**
     * PUBLIC:
     * Function, returns the position of <code>str</code> in <code>this</code>,
     * starting the search at <code>fromIndex</code>.
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("firstName").locate("ob", 1)
     * Java: employee.getFirstName().indexOf("ob", 1) + 1
     * SQL: LOCATE('ob', t0.F_NAME, 1)
     * </pre></blockquote>
     * <p>
     * Note that while in String.locate(str) -1 is returned if not found, and the
     * index starting at 0 if found, in SQL it is 0 if not found, and the index
     * starting at 1 if found.
     */
    public Expression locate(Object str, Object fromIndex) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Locate2);
        List args = new ArrayList(2);
        args.add(str);
        args.add(fromIndex);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * This represents the aggregate function Maximum. Can be used only within Report Queries.
     */
    public Expression maximum() {
        return getFunction(ExpressionOperator.Maximum);
    }

    /**
     * PUBLIC:
     * This represents the aggregate function Minimum. Can be used only within Report Queries.
     */
    public Expression minimum() {
        return getFunction(ExpressionOperator.Minimum);
    }

    /**
     * PUBLIC:
     * Function, returns the decimal number of months between the two dates.
     */
    public Expression monthsBetween(Object otherDate) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.MonthsBetween);
        return anOperator.expressionFor(this, otherDate);
    }

    /**
     * PUBLIC:
     * Return a Map.Entry containing the key and the value from a mapping that maps to a java.util.Map
     * This expression can only be used as a return value in a ReportQuery and cannot be used as part of
     * the WHERE clause in any query
     *
     * EclipseLink: eb.get("mapAttribute").mapEntry()
     * @return
     */
    public Expression mapEntry(){
        MapEntryExpression expression = new MapEntryExpression(this);
        expression.returnMapEntry();
        return expression;
    }

    /**
     * PUBLIC:
     * Return the key from a mapping that maps to a java.util.Map
     * This expression can be used either in as a return value in a ReportQuery or in the WHERE clause in a query
     *
     * EclipseLink: eb.get("mapAttribute").mapKey()
     * @return
     */
    public Expression mapKey(){
        return new MapEntryExpression(this);
    }

    /**
     * PUBLIC:
     * funcation return a date converted to a new timezone. Equivalent of the Oracle NEW_TIME function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").newTime("EST", "PST")
     * Java: NA
     * SQL: NEW_TIME(date, 'EST', 'PST')
     * </pre></blockquote>
     */
    public Expression newTime(String timeZoneFrom, String timeZoneTo) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NewTime);
        List args = new ArrayList(2);
        args.add(timeZoneFrom);
        args.add(timeZoneTo);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, returns the date with the next day from the source date as the day name given.
     */
    public Expression nextDay(Object dayName) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NextDay);
        return anOperator.expressionFor(this, dayName);
    }

    /**
     * PUBLIC: Returns an expression equivalent to none of <code>attributeName</code>
     * holding true for <code>criteria</code>.
     * <p>
     * For every expression with an anyOf, its negation has either an allOf or a
     * noneOf.  The following two examples will illustrate as the second is the
     * negation of the first:
     * <p>
     * AnyOf Example: Employees with a '613' area code phone number.
     * <blockquote><pre>
     * ReadAllQuery query = new ReadAllQuery(Employee.class);
     * ExpressionBuilder employee = new ExpressionBuilder();
     * Expression exp = employee.anyOf("phoneNumbers").get("areaCode").equal("613");
     * </pre></blockquote>
     * <p>
     * NoneOf Example: Employees with no '613' area code phone numbers.
     * <blockquote><pre>
     * ExpressionBuilder employee = new ExpressionBuilder();
     * ExpressionBuilder phones = new ExpressionBuilder();
     * Expression exp = employee.noneOf("phoneNumbers", phones.get("areaCode").equal("613"));
     * SQL:
     * SELECT ... EMPLOYEE t0 WHERE NOT EXISTS (SELECT ... PHONE t1 WHERE
     *                         (t0.EMP_ID = t1.EMP_ID) AND (t1.AREACODE = '613'))
     * </pre></blockquote>
     * <p>
     * noneOf is the universal counterpart to the existential anyOf.  To have the
     * condition evaluated for each instance it must be put inside of a subquery,
     * which can be expressed as not exists (any of attributeName some condition).
     * (All x such that !y = !Exist x such that y).
     * <p>Likewise the syntax employee.noneOf("phoneNumbers").get("areaCode").equal("613")
     * is not supported for the <code>equal</code> must go inside a subQuery.
     * <p>
     * This method saves you from writing the sub query yourself.  The above is
     * equivalent to the following expression:
     * <blockquote><pre>
     * ExpressionBuilder employee = new ExpressionBuilder();
     * ExpressionBuilder phone = new ExpressionBuilder();
     * ReportQuery subQuery = new ReportQuery(Phone.class, phone);
     * subQuery.retreivePrimaryKeys();
     * subQuery.setSelectionCriteria(phone.equal(employee.anyOf("phoneNumbers").and(
     *         phone.get("areaCode").equal("613")));
     * Expression exp = employee.notExists(subQuery);
     * </pre></blockquote>
     * @param criteria must have its own builder, as it will become the
     * separate selection criteria of a subQuery.
     * @return a notExists subQuery expression
     */
    public Expression noneOf(String attributeName, Expression criteria) {
        ReportQuery subQuery = new ReportQuery();
        subQuery.setShouldRetrieveFirstPrimaryKey(true);
        Expression builder = criteria.getBuilder();
        criteria = builder.equal(anyOf(attributeName)).and(criteria);
        subQuery.setSelectionCriteria(criteria);
        return notExists(subQuery);
    }

    /**
     * INTERNAL:
     * Normalize into a structure that is printable.
     * Also compute printing information such as outer joins.
     */
    public Expression normalize(ExpressionNormalizer normalizer) {
        //This class has no validation but we should still make the method call for consistency
        //bug # 2956674
        //validation is moved into normalize to ensure that expressions are valid before we attempt to work with them
        validateNode();
        return this;
    }

    /**
     * PUBLIC:
     * Return an expression that is the boolean logical negation of the expression.
     * This is equivalent to the SQL "NOT" operator and the Java "!" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").equal(24).not()
     *     Java: (! (employee.getAge() == 24))
     *     SQL: NOT (AGE = 24)
     * </pre></blockquote>
     */
    public Expression not() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Not);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(byte leftValue, byte rightValue) {
        return notBetween(Byte.valueOf(leftValue), Byte.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(char leftChar, char rightChar) {
        return notBetween(Character.valueOf(leftChar), Character.valueOf(rightChar));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(double leftValue, double rightValue) {
        return notBetween(Double.valueOf(leftValue), Double.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(float leftValue, float rightValue) {
        return notBetween(Float.valueOf(leftValue), Float.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(int leftValue, int rightValue) {
        return notBetween(Integer.valueOf(leftValue), Integer.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(long leftValue, long rightValue) {
        return notBetween(Long.valueOf(leftValue), Long.valueOf(rightValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(Object leftValue, Object rightValue) {
        return between(leftValue, rightValue).not();
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(Expression leftExpression, Expression rightExpression) {
        return between(leftExpression, rightExpression).not();
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not between two other values.
     * Equivalent to between negated.
     * @see #between(Object, Object)
     */
    public Expression notBetween(short leftValue, short rightValue) {
        return notBetween(Short.valueOf(leftValue), Short.valueOf(rightValue));
    }

    /**
     * PUBLIC: A logical expression for the collection <code>attributeName</code>
     * not being empty.
     * Equivalent to <code>size(attributeName).greaterThan(0)</code>
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.notEmpty("phoneNumbers")
     *     Java: employee.getPhoneNumbers().size() {@literal >} 0
     *     SQL: SELECT ... FROM EMP t0 WHERE (
     *      (SELECT COUNT(*) FROM PHONE t1 WHERE (t0.EMP_ID = t1.EMP_ID)) {@literal >} 0)
     * </pre></blockquote>
     * This is a case where a fast operation in java does not translate to an
     * equally fast operation in SQL, requiring a correlated subselect.
     * @see #size(java.lang.String)
     */
    public Expression notEmpty(String attributeName) {
        return size(attributeName).greaterThan(0);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(byte theValue) {
        return notEqual(Byte.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(char theChar) {
        return notEqual(Character.valueOf(theChar));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(double theValue) {
        return notEqual(Double.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(float theValue) {
        return notEqual(Float.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(int theValue) {
        return notEqual(Integer.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(long theValue) {
        return notEqual(Long.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotEqual);
        return anOperator.expressionFor(this, theValue);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(Expression theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotEqual);
        return anOperator.expressionFor(this, theValue);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(short theValue) {
        return notEqual(Short.valueOf(theValue));
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not equal to the other value.
     * This is equivalent to the SQL {@literal "<>"} operator
     *
     * @see #equal(Object)
     */
    public Expression notEqual(boolean theBoolean) {
        return notEqual(Boolean.valueOf(theBoolean));
    }

    /**
     * PUBLIC:
     * Return a sub query expression.
     * A sub query using a report query to define a subselect within another queries expression or select's where clause.
     * The sub query (the report query) will use its own expression builder be can reference expressions from the base expression builder.
     * <p>Example:
     * <blockquote><pre>
     * ExpressionBuilder builder = new ExpressionBuilder();
     * ReportQuery subQuery = new ReportQuery(Employee.class, new ExpressionBuilder());
     * subQuery.setSelectionCriteria(subQuery.getExpressionBuilder().get("name").equal(builder.get("name")));
     * builder.notExists(subQuery);
     * </pre></blockquote>
     */
    public Expression notExists(ReportQuery subQuery) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotExists);
        return anOperator.expressionFor(subQuery(subQuery));
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(byte[] theBytes) {
        List values = new ArrayList(theBytes.length);

        for (int index = 0; index < theBytes.length; index++) {
            values.add(Byte.valueOf(theBytes[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(char[] theChars) {
        List values = new ArrayList(theChars.length);

        for (int index = 0; index < theChars.length; index++) {
            values.add(Character.valueOf(theChars[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(double[] theDoubles) {
        List values = new ArrayList(theDoubles.length);

        for (int index = 0; index < theDoubles.length; index++) {
            values.add(Double.valueOf(theDoubles[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(float[] theFloats) {
        List values = new ArrayList(theFloats.length);

        for (int index = 0; index < theFloats.length; index++) {
            values.add(Float.valueOf(theFloats[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(int[] theInts) {
        List values = new ArrayList(theInts.length);

        for (int index = 0; index < theInts.length; index++) {
            values.add(Integer.valueOf(theInts[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(long[] theLongs) {
        List values = new ArrayList(theLongs.length);

        for (int index = 0; index < theLongs.length; index++) {
            values.add(Long.valueOf(theLongs[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(Object[] theObjects) {
        List values = new ArrayList(theObjects.length);

        for (int index = 0; index < theObjects.length; index++) {
            values.add(theObjects[index]);
        }

        return notIn(values);
    }

    public Expression notIn(ReportQuery subQuery) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotInSubQuery);
        return anOperator.expressionFor(this, subQuery);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(short[] theShorts) {
        List values = new ArrayList(theShorts.length);

        for (int index = 0; index < theShorts.length; index++) {
            values.add(Short.valueOf(theShorts[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression notIn(boolean[] theBooleans) {
        List values = new ArrayList(theBooleans.length);

        for (int index = 0; index < theBooleans.length; index++) {
            values.add(Boolean.valueOf(theBooleans[index]));
        }

        return notIn(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * The collection can be a collection of constants or expressions.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     */
    public Expression notIn(Collection theObjects) {
        return notIn(new CollectionExpression(theObjects, this));
    }

    public Expression notIn(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotIn);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not like the other value.
     * Equivalent to like negated.
     * @see #like(String)
     */
    public Expression notLike(String aString) {
        return notLike(new ConstantExpression(aString, this));
    }


    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not like the other value.
     * Equivalent to like negated.
     * @see #like(String)
     */
    public Expression notLike(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotLike);
        return anOperator.expressionFor(this, arguments);
    }
    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not like the other value.
     * Equivalent to like negated.
     * @param value string to compare
     * @param escapeSequence the escape character to use
     * @see #like(String)
     */
    public Expression notLike(String value, String escapeSequence) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotLikeEscape);
        List args = new ArrayList(2);
        args.add(value);
        args.add(escapeSequence);
        return anOperator.expressionForArguments(this, args);
    }
    /**
     * PUBLIC:
     * Return an expression that compares if the receivers value is not like the other value.
     * Equivalent to like negated.
     * @param value string to compare
     * @param escapeSequence the escape character to use
     * @see #like(String)
     */
    public Expression notLike(Expression value, Expression escapeSequence) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotLikeEscape);
        List args = new ArrayList(2);
        args.add(value);
        args.add(escapeSequence);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Return an expression representing a comparison to null
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").notNull()
     *     Java: employee.getAge() != null
     *     SQL: AGE IS NOT NULL
     * </pre></blockquote>
     */
    public Expression notNull() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.NotNull);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Return an expression that is the boolean logical combination of both expressions.
     * This is equivalent to the SQL "OR" operator and the Java "||" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").equal("Bob").OR(employee.get("lastName").equal("Smith"))
     *     Java: (employee.getFirstName().equals("Bob")) || (employee.getLastName().equals("Smith"))
     *     SQL: F_NAME = 'Bob' OR L_NAME = 'Smith'
     * </pre></blockquote>
     */
    public Expression or(Expression theExpression) {
        // Allow ands with null.
        if (theExpression == null) {
            return this;
        }

        ExpressionBuilder base = getBuilder();
        Expression expressionToUse = theExpression;

        // Ensure the same builder, unless a parralel query is used.
        if ((theExpression.getBuilder() != base) && (theExpression.getBuilder().getQueryClass() == null)) {
            expressionToUse = theExpression.rebuildOn(base);
        }

        if (base == this) {// Allow and to be sent to the builder.
            return expressionToUse;
        }

        ExpressionOperator anOperator = getOperator(ExpressionOperator.Or);
        return anOperator.expressionFor(this, expressionToUse);
    }

    /**
     * INTERNAL:
     */
    public Expression performOperator(ExpressionOperator anOperator, List args) {
        return anOperator.expressionForArguments(this, args);
    }

    protected void postCopyIn(Map alreadyDone) {
    }

    /**
     * ADVANCED:
     * Inserts the SQL as is directly into the expression.
     * The sql will be printed immediately after (postfixed to) the sql for
     * <b>this</b>.
     * Warning: Allowing an unverified SQL string to be passed into this
     * method makes your application vulnerable to SQL injection attacks.
     */
    public Expression postfixSQL(String sqlString) {
        ExpressionOperator anOperator = new ExpressionOperator();
        anOperator.setType(ExpressionOperator.FunctionOperator);
        Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
        v.add(sqlString);
        anOperator.printsAs(v);
        anOperator.bePostfix();
        anOperator.setNodeClass(ClassConstants.FunctionExpression_Class);

        return anOperator.expressionFor(this);
    }

    /**
     * ADVANCED:
     * Insert the SQL as is directly into the expression.
     * The sql will be printed immediately before (prefixed to) the sql for
     * <b>this</b>.
      * Warning: Allowing an unverified SQL string to be passed into this
     * method makes your application vulnerable to SQL injection attacks.
     */
    public Expression prefixSQL(String sqlString) {
        ExpressionOperator anOperator = new ExpressionOperator();
        anOperator.setType(ExpressionOperator.FunctionOperator);
        Vector v = org.eclipse.persistence.internal.helper.NonSynchronizedVector.newInstance(1);
        v.add(sqlString);
        anOperator.printsAs(v);
        anOperator.bePrefix();
        anOperator.setNodeClass(ClassConstants.FunctionExpression_Class);

        return anOperator.expressionFor(this);
    }

    /**
     * INTERNAL:
     * Print SQL
     */
    public abstract void printSQL(ExpressionSQLPrinter printer);

    /**
     * INTERNAL:
     * Print java for project class generation
     */
    public void printJava(ExpressionJavaPrinter printer) {
        //do nothing
    }

    /**
     * INTERNAL:
     * This expression is built on a different base than the one we want. Rebuild it and
     * return the root of the new tree
     * If receiver is a complex expression, use cloneUsing(newBase) instead.
     * @see #cloneUsing(Expression newBase)
     */
    public abstract Expression rebuildOn(Expression newBase);

    /**
     * INTERNAL:
     * Search the tree for any expressions (like SubSelectExpressions) that have been
     * built using a builder that is not attached to the query.  This happens in case of an Exists
     * call using a new ExpressionBuilder().  This builder needs to be replaced with one from the query.
     */
    public abstract void resetPlaceHolderBuilder(ExpressionBuilder queryBuilder);

    /**
     * ADVANCED:
     * For Object-relational support.
     */
    public Expression ref() {
        return getFunction(ExpressionOperator.Ref);
    }

    protected Expression registerIn(Map alreadyDone) {
        Expression copy = shallowClone();
        alreadyDone.put(this, copy);
        copy.postCopyIn(alreadyDone);
        return copy;

    }

    /**
     * PUBLIC:
     * Function, returns the string with occurances of the first substring replaced with the second substring.
     */
    public Expression replace(Object stringToReplace, Object stringToReplaceWith) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Replace);
        List args = new ArrayList(2);
        args.add(stringToReplace);
        args.add(stringToReplaceWith);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * return the result of this query repeated a given number of times.
     * Equivalent of the Sybase REPLICATE function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").replicate(2)
     * Java: NA
     * SQL: REPLICATE(name, 2)
     * </pre></blockquote>
     */
    public Expression replicate(int constant) {
        return replicate(Integer.valueOf(constant));
    }

    /**
     * PUBLIC:
     * return the result of this query repeated a given number of times.
     * Equivalent of the Sybase REPLICATE function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").replicate(2)
     * Java: NA
     * SQL: REPLICATE(name, 2)
     * </pre></blockquote>
     */
    public Expression replicate(Object theValue) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Replicate);
        return anOperator.expressionFor(this, theValue);
    }

    /**
     * Reset cached information here so that we can be sure we're accurate.
     */
    protected void resetCache() {
    }

    /**
     * PUBLIC:
     * Function return the reverse of the query result. Equivalent of the
     * Sybase REVERSE function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").reverse()
     * Java: NA
     * SQL: REVERSE(name)
     * </pre></blockquote>
     */
    public Expression reverse() {
        return getFunction(ExpressionOperator.Reverse);
    }

    /**
     * PUBLIC:
     * Function return a given number of characters starting at the
     * right of a string. Equivalent to the Sybase RIGHT function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").right(2)
     * Java: NA
     * SQL: RIGHT(name, 2)
     * </pre></blockquote>
     */
    public Expression right(int characters) {
        return right(Integer.valueOf(characters));
    }

    /**
     * PUBLIC:
     * Function return a given number of characters starting at the
     * right of a string. Equivalent to the Sybase RIGHT function
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("name").right(2)
     * Java: NA
     * SQL: RIGHT(name, 2)
     * </pre></blockquote>
     */
    public Expression right(Object characters) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Right);
        return anOperator.expressionFor(this, characters);
    }

    /**
     * PUBLIC:
     * Function, returns the string padded with the substring to the size.
     */
    public Expression rightPad(int size, Object substring) {
        return rightPad(Integer.valueOf(size), substring);
    }

    /**
     * PUBLIC:
     * Function, returns the string padded with the substring to the size.
     */
    public Expression rightPad(Object size, Object substring) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.RightPad);
        List args = new ArrayList(2);
        args.add(size);
        args.add(substring);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, returns the string right trimmed for white space.
     */
    public Expression rightTrim() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.RightTrim);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the string with the substring trimed from the right.
     */
    public Expression rightTrim(Object substring) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.RightTrim2);
        return anOperator.expressionFor(this, substring);
    }

    /**
     * PUBLIC:
     * Function, returns the date rounded to the year, month or day.
     */
    public Expression roundDate(Object yearOrMonthOrDayRoundToken) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.RoundDate);
        return anOperator.expressionFor(this, yearOrMonthOrDayRoundToken);
    }

    /**
     * PUBLIC:
     * Return whether this expression should be included in the SELECT clause if it is used
     * in an ORDER BY clause
     */
    public boolean selectIfOrderedBy() {
        return selectIfOrderedBy;
    }

    /**
     * INTERNAL:
     * Set the local base expression, ie the one on the other side of the operator
     * Most types will ignore this, since they don't need it.
     */
    public void setLocalBase(Expression exp) {
    }

    /**
     * PUBLIC:
     * Set whether this expression should be included in the SELECT clause of a query
     * that uses it in the ORDER BY clause.
     *
     * @param selectIfOrderedBy
     */
    public void setSelectIfOrderedBy(boolean selectIfOrderedBy) {
        this.selectIfOrderedBy = selectIfOrderedBy;
    }

    /**
     * INTERNAL:
     */
    public Expression shallowClone() {
        Expression result = null;
        try {
            result = (Expression)super.clone();
        } catch (CloneNotSupportedException exception) {
            throw new InternalError(exception.toString());
        }
        return result;
    }

    /**
     * PUBLIC: A logical expression for the size of collection <code>attributeName</code>.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.size("phoneNumbers")
     *     Java: employee.getPhoneNumbers().size()
     *     SQL: SELECT ... FROM EMP t0 WHERE  ...
     *      (SELECT COUNT(*) FROM PHONE t1 WHERE (t0.EMP_ID = t1.EMP_ID))
     * </pre></blockquote>
     * This is a case where a fast operation in java does not translate to an
     * equally fast operation in SQL, requiring a correlated subselect.
     */
    public Expression size(String attributeName) {
        return SubSelectExpression.createSubSelectExpressionForCount(this, this, attributeName, null);
    }

    /**
     * PUBLIC: A logical expression for the size of collection expression.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.size(Class returnType)
     *     Java: employee.getPhoneNumbers().size()
     *     SQL: SELECT ... FROM EMP t0 WHERE  ...
     *      (SELECT COUNT(*) FROM PHONE t1 WHERE (t0.EMP_ID = t1.EMP_ID))
     * </pre></blockquote>
     * This is a case where a fast operation in java does not translate to an
     * equally fast operation in SQL, requiring a correlated subselect.
     */
    public Expression size(Class returnType) {
        if (((BaseExpression)this).getBaseExpression() == null){
            return SubSelectExpression.createSubSelectExpressionForCount(this, this, null, returnType);
        }
        return SubSelectExpression.createSubSelectExpressionForCount(((BaseExpression)this).getBaseExpression(), this, null, returnType);
    }

    /**
     * PUBLIC:
     * This represents the aggregate function StandardDeviation. Can be used only within Report Queries.
     */
    public Expression standardDeviation() {
        return getFunction(ExpressionOperator.StandardDeviation);
    }

    /**
     * PUBLIC:
     * Return a sub query expression.
     * A sub query using a report query to define a subselect within another queries expression or select's where clause.
     * The sub query (the report query) will use its own expression builder be can reference expressions from the base expression builder.
     * <p>Example:
     * <blockquote><pre>
     * ExpressionBuilder builder = new ExpressionBuilder();
     * ReportQuery subQuery = new ReportQuery(Employee.class, new ExpressionBuilder());
     * subQuery.addMaximum("salary");
     * builder.get("salary").equal(builder.subQuery(subQuery));
     * </pre></blockquote>
     */
    public Expression subQuery(ReportQuery subQuery) {
        return new SubSelectExpression(subQuery, this);
    }

    /**
     * PUBLIC:
     * Function, returns the substring from the source string.
     * EclipseLink: employee.get("firstName").substring(1, 2)
     * Java: NA
     * SQL: SUBSTR(FIRST_NAME, 1, 2)
     */
    public Expression substring(int startPosition, int size) {
        return substring(Integer.valueOf(startPosition), Integer.valueOf(size));
    }

    /**
     * PUBLIC:
     * Function, returns the substring from the source string.
     * EclipseLink: employee.get("firstName").substring(1, 2)
     * Java: NA
     * SQL: SUBSTR(FIRST_NAME, 1, 2)
     */
    public Expression substring(Object startPosition, Object size) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Substring);
        List args = new ArrayList(2);
        args.add(startPosition);
        args.add(size);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, returns the substring from the source string.
     * EclipseLink: employee.get("firstName").substring(1)
     * Java: NA
     * SQL: SUBSTR(FIRST_NAME, 1)
     */
    public Expression substring(int startPosition) {
        return substring(Integer.valueOf(startPosition));
    }

    /**
     * PUBLIC:
     * Function, returns the substring from the source string.
     * EclipseLink: employee.get("firstName").substring(1)
     * Java: NA
     * SQL: SUBSTR(FIRST_NAME, 1)
     */
    public Expression substring(Object startPosition) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.SubstringSingleArg);
        List args = new ArrayList(1);
        args.add(startPosition);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * This represents the aggregate function Sum. Can be used only within Report Queries.
     */
    public Expression sum() {
        return getFunction(ExpressionOperator.Sum);
    }

    /**
     * PUBLIC:
     * Function, returns the single character string with the ascii or character set value.
     */
    public Expression toCharacter() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Chr);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns date from the string using the default format.
     */
    public Expression toDate() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ToDate);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Return an expression that represents the receiver value converted to a character string.
     * This is equivalent to the SQL "TO_CHAR" operator and Java "toString" method.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("salary").toChar().equal("100000")
     *     Java: employee.getSalary().toString().equals("100000")
     *     SQL: TO_CHAR(SALARY) = '100000'
     * </pre></blockquote>
     */
    public Expression toChar() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ToChar);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Return an expression that represents the receiver value converted to a character string,
     * with the database formating options (i.e. 'year', 'yyyy', 'day', etc.).
     * This is equivalent to the SQL "TO_CHAR" operator and Java Date API.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("startDate").toChar("day").equal("monday")
     *     Java: employee.getStartDate().getDay().equals("monday")
     *     SQL: TO_CHAR(START_DATE, 'day') = 'monday'
     * </pre></blockquote>
     */
    public Expression toChar(String format) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ToCharWithFormat);
        return anOperator.expressionFor(this, format);
    }

    /**
     * PUBLIC:
     * Return an expression that represents the receiver value converted to lower case.
     * This is equivalent to the SQL "LOWER" operator and Java "toLowerCase" method.
     * This is only allowed for String attribute values.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").toLowerCase().equal("bob")
     *     Java: employee.getFirstName().toLowerCase().equals("bob")
     *     SQL: LOWER(F_NAME) = 'bob'
     * </pre></blockquote>
     */
    public Expression toLowerCase() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ToLowerCase);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the number converted from the string.
     */
    public Expression toNumber() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ToNumber);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Print a debug form of the expression tree.
     */
    public String toString() {
        try {
            StringWriter innerWriter = new StringWriter();
            BufferedWriter outerWriter = new BufferedWriter(innerWriter);
            toString(outerWriter, 0);
            outerWriter.flush();
            return innerWriter.toString();
        } catch (IOException e) {
            return ToStringLocalization.buildMessage("error_printing_expression", (Object[])null);
        }
    }

    /**
     * INTERNAL:
     * Print a debug form of the expression tree.
     */
    public void toString(BufferedWriter writer, int indent) throws IOException {
        writer.newLine();
        for (int i = 0; i < indent; i++) {
            writer.write("   ");
        }
        writer.write(descriptionOfNodeType());
        writer.write(" ");
        writeDescriptionOn(writer);
        writeSubexpressionsTo(writer, indent + 1);
    }

    /**
     * PUBLIC:
     * Return an expression that represents the receiver value converted to upper case.
     * This is equivalent to the SQL "UPPER" operator and Java "toUpperCase" method.
     * This is only allowed for String attribute values.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("firstName").toUpperCase().equal("BOB")
     *     Java: employee.getFirstName().toUpperCase().equals("BOB")
     *     SQL: UPPER(F_NAME) = 'BOB'
     * </pre></blockquote>
     */
    public Expression toUpperCase() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ToUpperCase);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the string with the first letter of each word capitalized.
     */
    public Expression toUppercaseCasedWords() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Initcap);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the string with each char from the from string converted to the char in the to string.
     */
    public Expression translate(Object fromString, Object toString) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Translate);
        List args = new ArrayList(2);
        args.add(fromString);
        args.add(toString);
        return anOperator.expressionForArguments(this, args);
    }

    /**
     * PUBLIC:
     * Function, returns the string trimmed for white space.
     */
    public Expression trim() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Trim);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Function, returns the string right and left trimmed for the substring.
     */
    public Expression trim(Object substring) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Trim2);
        return anOperator.expressionFor(this, substring);
    }

    /**
     * PUBLIC:
     * XMLType Function, extracts a secton of XML from a larget XML document
     * @param xpath XPath expression representing the node to be returned
     */
    public Expression extractXml(String xpath) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ExtractXml);
        return anOperator.expressionFor(this, xpath);
    }

    /**
     * PUBLIC:
     * Extract the date part from the date/time value.
     * EXTRACT is part of the SQL standard, so should be supported by most databases.
     * @param part is the date part to extract, "YEAR", "MONTH", "DAY", "HOUR", "MINUTE", "SECOND", "TIMEZONE_HOUR", "TIMEZONE_MINUTE".
     */
    public Expression extract(String part) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Extract);
        return anOperator.expressionFor(this, literal(part));
    }

    /**
     * PUBLIC:
     * Cast the value to the database type.
     * CAST is part of the SQL standard, so should be supported by most databases.
     * @param type is the database type name, this is database specific but should include, "CHAR", "VARCHAR", "NUMERIC", "INTEGER", "DATE", "TIME", "TIMESTAMP",
     * the type may include a size and scale.
     */
    public Expression cast(String type) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Cast);
        return anOperator.expressionFor(this, literal(type));
    }

    /**
     * PUBLIC:
     * XMLType Function, extracts a value from an XMLType field
     * @param xpath XPath expression
     */
    public Expression extractValue(String xpath) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ExtractValue);
        return anOperator.expressionFor(this, xpath);
    }

    /**
     * PUBLIC:
     * XMLType Function, gets the number of nodes returned by the given xpath expression
     * returns 0 if there are none
     * @param xpath Xpath expression
     */
    public Expression existsNode(String xpath) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ExistsNode);
        return anOperator.expressionFor(this, xpath);
    }

    /**
     * PUBLIC:
     * XMLType Function - evaluates to 0 if the xml is a well formed document and 1 if the document
     * is a fragment
     */
    public Expression isFragment() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.IsFragment);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * XMLType Function - gets a string value from an XMLType
     */
    public Expression getStringVal() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.GetStringVal);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * XMLType Function - gets a number value from an XMLType
     */
    public Expression getNumberVal() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.GetNumberVal);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * return the date truncated to the indicated datePart. Equivalent
     * to the Sybase TRUNC function for dates
     * <p>Example:
     * <blockquote><pre>
     * EclipseLink: employee.get("date").truncDate(year)
     * Java: NA
     * SQL: TRUNC(date, year)
     * </pre></blockquote>
     */
    public Expression truncateDate(String datePart) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.TruncateDate);
        return anOperator.expressionFor(this, datePart);

    }

    /**
     * INTERNAL:
     * We are given an expression that comes from a different context than the one in which this was built,
     * e.g. it is the selection criteria of a mapping, or the criteria on which multiple tables are joined in a descriptor.
     * We need to transform it so it refers to the objects we are dealing with, and AND it into the rest of our expression.
     *
     * We want to replace the original base expression with (newBase), and any parameters will be given values based
     * on the context which (this) provides.
     *
     * For example, suppose that the main expression is
     *      emp.address.streetName = 'something'
     * and we are trying to twist the selection criteria for the mapping 'address' in Employee. Because that mapping
     * selects addresses, we will use the 'address' node as the base. Values for any parameters will come from the 'emp' node,
     * which was the base of the original expression. Note that the values need not be constants, they can be fields.
     *
     * We do this by taking the tree we're trying to merge and traverse it more or less re-executing it
     * it with the appropriate initial receiver and context.
     * Return the root of the new expression tree. This will probably need to be AND'ed with the root of the old tree.
     */
    public Expression twist(Expression expression, Expression newBase) {
        if (expression == null) {
            return null;
        }
        return expression.twistedForBaseAndContext(newBase, this, null);

    }

    /**
     * INTERNAL:
     * Rebuild myself against the base, with the values of parameters supplied by the context
     * expression. This is used for transforming a standalone expression (e.g. the join criteria of a mapping)
     * into part of some larger expression. You normally would not call this directly, instead calling twist
     * See the comment there for more details"
     */
    public Expression twistedForBaseAndContext(Expression newBase, Expression context, Expression oldBase) {
        // Will be overridden by subclasses
        return this;
    }

    /**
     * INTERNAL:
     * Do any required validation for this node. Throw an exception for any incorrect constructs.
     */
    public void validateNode() {
    }

    /**
     * PUBLIC:
     * Function, this represents the value function, used in nestedtable
     */
    public Expression value() {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Value);
        return anOperator.expressionFor(this);
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(byte constant) {
        return value(Byte.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(char constant) {
        return value(Character.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(double constant) {
        return value(Double.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(float constant) {
        return value(Float.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(int constant) {
        return value(Integer.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(long constant) {
        return value(Long.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(Object constant) {
        return new ConstantExpression(constant, this);
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(short constant) {
        return value(Short.valueOf(constant));
    }

    /**
     * PUBLIC:
     * Return an expression on the constant.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("a constant", builder.value("a constant"));
     * </pre></blockquote>
     */
    public Expression value(boolean constant) {
        return value(Boolean.valueOf(constant));
    }

    /**
     * ADVANCED:
     * Return an expression on the literal.
     * A literal is a specific SQL syntax string that will be printed as is without quotes in the SQL.
     * It can be useful for printing database key words or global variables.
     * <p>Example:
     * <blockquote><pre>
     * reportQuery.addItem("currentTime", builder.literal("SYSDATE"));
     * </pre></blockquote>
     */
    public Expression literal(String literal) {
        return new LiteralExpression(literal, this);
    }

    /**
     * ADVANCED:
     * Return an expression for the alias.
     * This allows an alias used in the select clause to be used in other clauses.
     */
    public Expression alias(String alias) {
        return literal(alias);
    }

    /**
     * INTERNAL:
     * Return the value for in memory comparison.
     * This is only valid for valueable expressions.
     * New parameter added for feature 2612601
     * @param isObjectUnregistered true if object possibly not a clone, but is being
     * conformed against the unit of work cache.
     */
    public Object valueFromObject(Object object, AbstractSession session, AbstractRecord translationRow, int valueHolderPolicy, boolean isObjectUnregistered) {
        throw QueryException.cannotConformExpression();
    }

    /**
     * INTERNAL:
     * Return the value for in memory comparison.
     * This is only valid for valueable expressions.
     */
    public Object valueFromObject(Object object, AbstractSession session, AbstractRecord translationRow, int valueHolderPolicy) {
        return valueFromObject(object, session, translationRow, valueHolderPolicy, false);
    }

    /**
     * PUBLIC:
     * Function, this represents the aggregate function Variance. Can be used only within Report Queries.
     */
    public Expression variance() {
        return getFunction(ExpressionOperator.Variance);
    }

    /**
     * INTERNAL:
     * Used to print a debug form of the expression tree.
     */
    public void writeDescriptionOn(BufferedWriter writer) throws IOException {
        writer.write("some expression");
    }

    /**
     * INTERNAL:
     * Append the field name to the writer. Should be overridden for special operators such as functions.
     */
    protected void writeField(ExpressionSQLPrinter printer, DatabaseField field, SQLSelectStatement statement) {
        //print ", " before each selected field except the first one
        if (printer.isFirstElementPrinted()) {
            printer.printString(", ");
        } else {
            printer.setIsFirstElementPrinted(true);
        }

        if (statement.requiresAliases()) {
            if (field.getTable() != lastTable) {
                lastTable = field.getTable();
                currentAlias = aliasForTable(lastTable);
            }
            printer.printString(currentAlias.getQualifiedNameDelimited(printer.getPlatform()));
            printer.printString(".");
        }
        printer.printString(field.getNameDelimited(printer.getPlatform()));

        //bug6070214: unique field aliases need to be generated when required.
        if (statement.getUseUniqueFieldAliases()){
            printer.printString(" AS " + statement.generatedAlias(field.getNameDelimited(printer.getPlatform())));
        }
    }

    /**
     * INTERNAL:
     * Append the field's alias to the writer.
     * This is used for pessimistic locking.
     */
    protected void writeAlias(ExpressionSQLPrinter printer, DatabaseField field, SQLSelectStatement statement) {
        //print ", " before each selected field except the first one
        if (printer.isFirstElementPrinted()) {
            printer.printString(", ");
        } else {
            printer.setIsFirstElementPrinted(true);
        }

        if (statement.requiresAliases()) {
            if (field.getTable() != this.lastTable) {
                this.lastTable = field.getTable();
                this.currentAlias = aliasForTable(this.lastTable);
            }
            printer.printString(this.currentAlias.getQualifiedNameDelimited(printer.getPlatform()));
        } else {
            printer.printString(field.getTable().getQualifiedNameDelimited(printer.getPlatform()));
        }
    }

    /**
     * INTERNAL:
     * called from SQLSelectStatement.writeFieldsFromExpression(...)
     */
    public void writeFields(ExpressionSQLPrinter printer, Vector newFields, SQLSelectStatement statement) {
        for (DatabaseField field : getSelectionFields(statement.getQuery())) {
            newFields.add(field);
            writeField(printer, field, statement);
        }
    }

    /**
     * INTERNAL:
     * Used in SQL printing.
     */
    public void writeSubexpressionsTo(BufferedWriter writer, int indent) throws IOException {
        // In general, there are no sub-expressions
    }

    /**
     *
     * PUBLIC:
     * Return an expression that is used with a comparison expression.
     * The ANY keyword denotes that the search condition is TRUE if the comparison is TRUE
     * for at least one of the values that is returned. If the subquery returns no value,
     * the search condition is FALSE
     */
    public Expression any(byte[] theBytes) {
        List values = new ArrayList(theBytes.length);

        for (int index = 0; index < theBytes.length; index++) {
            values.add(Byte.valueOf(theBytes[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(char[] theChars) {
        List values = new ArrayList(theChars.length);

        for (int index = 0; index < theChars.length; index++) {
            values.add(Character.valueOf(theChars[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(double[] theDoubles) {
        List values = new ArrayList(theDoubles.length);

        for (int index = 0; index < theDoubles.length; index++) {
            values.add(Double.valueOf(theDoubles[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(float[] theFloats) {
        List values = new ArrayList(theFloats.length);

        for (int index = 0; index < theFloats.length; index++) {
            values.add(Float.valueOf(theFloats[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(int[] theInts) {
        List values = new ArrayList(theInts.length);

        for (int index = 0; index < theInts.length; index++) {
            values.add(Integer.valueOf(theInts[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(long[] theLongs) {
        List values = new ArrayList(theLongs.length);

        for (int index = 0; index < theLongs.length; index++) {
            values.add(Long.valueOf(theLongs[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(Object[] theObjects) {
        List values = new ArrayList(theObjects.length);

        for (int index = 0; index < theObjects.length; index++) {
            values.add(theObjects[index]);
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(short[] theShorts) {
        List values = new ArrayList(theShorts.length);

        for (int index = 0; index < theShorts.length; index++) {
            values.add(Short.valueOf(theShorts[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression any(boolean[] theBooleans) {
        List values = new ArrayList(theBooleans.length);

        for (int index = 0; index < theBooleans.length; index++) {
            values.add(Boolean.valueOf(theBooleans[index]));
        }

        return any(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     * @deprecated since 2.4 replaced by any(List)
     * @see #any(List)
     */
    @Deprecated
    public Expression any(Vector theObjects) {
        return any((List)theObjects);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     */
    public Expression any(List theObjects) {
        return any(new ConstantExpression(theObjects, this));
    }

    public Expression any(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Any);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return a union expression with the subquery.
     */
    public Expression union(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Union);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return a intersect expression with the subquery.
     */
    public Expression intersect(ReportQuery query) {
        return intersect(subQuery(query));
    }

    /**
     * PUBLIC:
     * Return a intersect all expression with the subquery.
     */
    public Expression intersectAll(ReportQuery query) {
        return intersectAll(subQuery(query));
    }

    /**
     * PUBLIC:
     * Return a intersect expression with the subquery.
     */
    public Expression intersect(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Intersect);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return a except expression with the subquery.
     */
    public Expression except(ReportQuery query) {
        return except(subQuery(query));
    }

    /**
     * PUBLIC:
     * Return a except all expression with the subquery.
     */
    public Expression exceptAll(ReportQuery query) {
        return exceptAll(subQuery(query));
    }

    /**
     * PUBLIC:
     * Return a except expression with the subquery.
     */
    public Expression except(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Except);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return a union expression with the subquery.
     */
    public Expression union(ReportQuery query) {
        return union(subQuery(query));
    }

    /**
     * PUBLIC:
     * Return a union all expression with the subquery.
     */
    public Expression unionAll(ReportQuery query) {
        return unionAll(subQuery(query));
    }

    /**
     * PUBLIC:
     * Return a union all expression with the subquery.
     */
    public Expression unionAll(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.UnionAll);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return a intersect all expression with the subquery.
     */
    public Expression intersectAll(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.IntersectAll);
        return anOperator.expressionFor(this, arguments);
    }

    /**
     * PUBLIC:
     * Return a except all expression with the subquery.
     */
    public Expression exceptAll(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.ExceptAll);
        return anOperator.expressionFor(this, arguments);
    }

    public Expression any(ReportQuery subQuery) {
        return any(subQuery(subQuery));
    }

    /**
     * PUBLIC:
     * Return an expression that is used with a comparison expression.
     * The SOME keyword denotes that the search condition is TRUE if the comparison is TRUE
     * for at least one of the values that is returned. If the subquery returns no value,
     * the search condition is FALSE
     */
    public Expression some(byte[] theBytes) {
        List values = new ArrayList(theBytes.length);

        for (int index = 0; index < theBytes.length; index++) {
            values.add(Byte.valueOf(theBytes[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(char[] theChars) {
        List values = new ArrayList(theChars.length);

        for (int index = 0; index < theChars.length; index++) {
            values.add(Character.valueOf(theChars[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(double[] theDoubles) {
        List values = new ArrayList(theDoubles.length);

        for (int index = 0; index < theDoubles.length; index++) {
            values.add(Double.valueOf(theDoubles[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(float[] theFloats) {
        List values = new ArrayList(theFloats.length);

        for (int index = 0; index < theFloats.length; index++) {
            values.add(Float.valueOf(theFloats[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(int[] theInts) {
        List values = new ArrayList(theInts.length);

        for (int index = 0; index < theInts.length; index++) {
            values.add(Integer.valueOf(theInts[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(long[] theLongs) {
        List values = new ArrayList(theLongs.length);

        for (int index = 0; index < theLongs.length; index++) {
            values.add(Long.valueOf(theLongs[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(Object[] theObjects) {
        List values = new ArrayList(theObjects.length);

        for (int index = 0; index < theObjects.length; index++) {
            values.add(theObjects[index]);
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(short[] theShorts) {
        List values = new ArrayList(theShorts.length);

        for (int index = 0; index < theShorts.length; index++) {
            values.add(Short.valueOf(theShorts[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression some(boolean[] theBooleans) {
        List values = new ArrayList(theBooleans.length);

        for (int index = 0; index < theBooleans.length; index++) {
            values.add(Boolean.valueOf(theBooleans[index]));
        }

        return some(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     * @deprecated since 2.4 replaced by some(List)
     * @see #some(List)
     */
    @Deprecated
    public Expression some(Vector theObjects) {
        return some(new ConstantExpression(theObjects, this));
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     */
    public Expression some(List theObjects) {
        return some(new ConstantExpression(theObjects, this));
    }

    public Expression some(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.Some);
        return anOperator.expressionFor(this, arguments);
    }

    public Expression some(ReportQuery subQuery) {
        return some(subQuery(subQuery));
    }

    /**
     *
     * PUBLIC:
     * Return an expression that is used with a comparison expression.
     * The SOME keyword denotes that the search condition is TRUE if the comparison is TRUE
     * for at least one of the values that is returned. If the subquery returns no value,
     * the search condition is FALSE
     */
    public Expression all(byte[] theBytes) {
        List values = new ArrayList(theBytes.length);

        for (int index = 0; index < theBytes.length; index++) {
            values.add(Byte.valueOf(theBytes[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(char[] theChars) {
        List values = new ArrayList(theChars.length);

        for (int index = 0; index < theChars.length; index++) {
            values.add(Character.valueOf(theChars[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(double[] theDoubles) {
        List values = new ArrayList(theDoubles.length);

        for (int index = 0; index < theDoubles.length; index++) {
            values.add(Double.valueOf(theDoubles[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(float[] theFloats) {
        List values = new ArrayList(theFloats.length);

        for (int index = 0; index < theFloats.length; index++) {
            values.add(Float.valueOf(theFloats[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(int[] theInts) {
        List values = new ArrayList(theInts.length);

        for (int index = 0; index < theInts.length; index++) {
            values.add(Integer.valueOf(theInts[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(long[] theLongs) {
        List values = new ArrayList(theLongs.length);

        for (int index = 0; index < theLongs.length; index++) {
            values.add(Long.valueOf(theLongs[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(Object[] theObjects) {
        List values = new ArrayList(theObjects.length);

        for (int index = 0; index < theObjects.length; index++) {
            values.add(theObjects[index]);
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(short[] theShorts) {
        List values = new ArrayList(theShorts.length);

        for (int index = 0; index < theShorts.length; index++) {
            values.add(Short.valueOf(theShorts[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     */
    public Expression all(boolean[] theBooleans) {
        List values = new ArrayList(theBooleans.length);

        for (int index = 0; index < theBooleans.length; index++) {
            values.add(Boolean.valueOf(theBooleans[index]));
        }

        return all(values);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     * @deprecated since 2.4 replaced by all(List)
     * @see #all(List)
     */
    @Deprecated
    public Expression all(Vector theObjects) {
        return all((List)theObjects);
    }

    /**
     * PUBLIC:
     * Return an expression that checks if the receivers value is contained in the collection.
     * This is equivalent to the SQL "IN" operator and Java "contains" operator.
     * <p>Example:
     * <blockquote><pre>
     *     EclipseLink: employee.get("age").in(ages)
     *     Java: ages.contains(employee.getAge())
     *     SQL: AGE IN (55, 18, 30)
     * </pre></blockquote>
     */
    public Expression all(List theObjects) {
        return all(new ConstantExpression(theObjects, this));
    }

    public Expression all(Expression arguments) {
        ExpressionOperator anOperator = getOperator(ExpressionOperator.All);
        return anOperator.expressionFor(this, arguments);
    }

    public Expression all(ReportQuery subQuery) {
        return all(subQuery(subQuery));
    }

    /**
     * INTERNAL:
     * Lookup the descriptor for this item by traversing its expression recursively.
     */
    public ClassDescriptor getLeafDescriptor(DatabaseQuery query, ClassDescriptor rootDescriptor, AbstractSession session) {
        return null;
    }

    /**
     * INTERNAL:
     * Lookup the mapping for this item by traversing its expression recursively.
     * If an aggregate of foreign mapping is found it is traversed.
     */
    public DatabaseMapping getLeafMapping(DatabaseQuery query, ClassDescriptor rootDescriptor, AbstractSession session) {
        return null;
    }

}
