Package Express.services

Source Code of Express.services.BusinessQuery

/*
Copyright (c) 2003-2009 ITerative Consulting Pty Ltd. All Rights Reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted
provided that the following conditions are met:

o Redistributions of source code must retain the above copyright notice, this list of conditions and
the following disclaimer.
 
o Redistributions in binary form must reproduce the above copyright notice, this list of conditions
and the following disclaimer in the documentation and/or other materials provided with the distribution.
   
o This jcTOOL Helper Class software, whether in binary or source form may not be used within,
or to derive, any other product without the specific prior written permission of the copyright holder

 
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.


*/
package Express.services;

import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
import java.io.Serializable;
import java.util.Iterator;

import DisplayProject.binding.beans.ExtendedPropertyChangeSupport;
import DisplayProject.binding.beans.Observable;
import Framework.Array_Of_IntegerData;
import Framework.Array_Of_Object;
import Framework.Array_Of_TextData;
import Framework.CloneHelper;
import Framework.DataValue;
import Framework.DateFormat;
import Framework.DateTimeData;
import Framework.DecimalData;
import Framework.DoubleData;
import Framework.IntegerData;
import Framework.NumericData;
import Framework.NumericFormat;
import Framework.ParameterHolder_TextData;
import Framework.ParameterHolder_integer;
import Framework.RuntimeProperties;
import Framework.TextData;
import Framework.TextFormat;
import Framework.TextFormat.qq_Resolver;
import GenericDBMS.DBConnectionManager;
import GenericDBMS.DBDataSet;

/**
* BusinessQuery is the base class for all generated and custom query classes. Express generates subclasses of the BusinessQuery class for each business class.
* <p>
* @author ITerative Consulting
* @since  26-Feb-2008
*/
@RuntimeProperties(isDistributed=false, isAnchored=false, isShared=false, isTransactional=false)
@SuppressWarnings("serial")
public class BusinessQuery
        implements Serializable, Observable
{

    // ---------
    // Constants
    // ---------
    public static final int ASSOC_AGGREGATION = 64;
    public static final int ASSOC_MULT_MANY_TO = 2;
    public static final int ASSOC_MULT_ONE_MASK = 20;
    public static final int ASSOC_MULT_ONE_TO = 1;
    public static final int ASSOC_MULT_OPTIONAL = 16;
    public static final int ASSOC_MULT_TO_MANY = 8;
    public static final int ASSOC_MULT_TO_ONE = 4;
    public static final int ATTR_DB = -2;
    public static final int ATTR_FOREIGN = 10000;
    public static final int ATTR_KEY = -1;
    public static final int ATTR_SIMPLE = 0;
    public static final int OP_DELETE = 1;
    public static final int OP_INSERT = 2;
    public static final int OP_NONE = 0;
    public static final int OP_SELECT = 3;
    public static final int OP_UPDATE = 4;
    public static final int QUERY_INFO_BUILT = 1;
    public static final int QUERY_INFO_EXECUTED = 2;
    public static final int QUERY_INFO_JOINED = 4;

    // ----------
    // Attributes
    // ----------
    public PropertyChangeSupport qq_Listeners = new ExtendedPropertyChangeSupport(this, true);
    private QueryConstraint constraint;
    private Array_Of_BusinessQuery<BusinessQuery> foreignClasses;
    private BusinessKey key;
    private int operation;
    private BusinessClass originalClass;
    private int parentAttr;
    private int parentMult;
    private Array_Of_IntegerData<IntegerData> tableAliases;
    private Array_Of_IntegerData<IntegerData> targetAttrs;
    private BusinessClass updatedClass;
    private QueryConstraint values;
    // AD:25/11/2008: Do not pass exectueInfo across VM boundaries. Contains non serializable classes
    private transient QueryExecuteInfo _ExecuteInfo;

    // ------------
    // Constructors
    // ------------
    public BusinessQuery() {
        // Explicitly call the superclass constructor to prevent the implicit call
        super();

        this.operation = BusinessQuery.OP_SELECT;

    }

    // ----------------------
    // Accessors and Mutators
    // ----------------------
    public void setConstraint(QueryConstraint constraint) {
        QueryConstraint oldValue = this.constraint;
        this.constraint = constraint;
        this.qq_Listeners.firePropertyChange("constraint", oldValue, this.constraint);
    }

    public QueryConstraint getConstraint() {
        return this.constraint;
    }

    public void setForeignClasses(Array_Of_BusinessQuery<BusinessQuery> foreignClasses) {
        Array_Of_BusinessQuery<BusinessQuery> oldValue = this.foreignClasses;
        this.foreignClasses = foreignClasses;
        this.qq_Listeners.firePropertyChange("foreignClasses", oldValue, this.foreignClasses);
    }

    public Array_Of_BusinessQuery<BusinessQuery> getForeignClasses() {
        return this.foreignClasses;
    }

    public void setKey(BusinessKey key) {
        BusinessKey oldValue = this.key;
        this.key = key;
        this.qq_Listeners.firePropertyChange("key", oldValue, this.key);
    }

    public BusinessKey getKey() {
        return this.key;
    }

//    private void setOperation(int operation) {
//        int oldValue = this.operation;
//        this.operation = operation;
//        this.qq_Listeners.firePropertyChange("operation", oldValue, this.operation);
//    }

    public int getOperation() {
        return this.operation;
    }

    public void setOriginalClass(BusinessClass originalClass) {
        BusinessClass oldValue = this.originalClass;
        this.originalClass = originalClass;
        this.qq_Listeners.firePropertyChange("originalClass", oldValue, this.originalClass);
    }

    public BusinessClass getOriginalClass() {
        return this.originalClass;
    }

    public void setParentAttr(int parentAttr) {
        int oldValue = this.parentAttr;
        this.parentAttr = parentAttr;
        this.qq_Listeners.firePropertyChange("parentAttr", oldValue, this.parentAttr);
    }

    public int getParentAttr() {
        return this.parentAttr;
    }

    public void setParentMult(int parentMult) {
        int oldValue = this.parentMult;
        this.parentMult = parentMult;
        this.qq_Listeners.firePropertyChange("parentMult", oldValue, this.parentMult);
    }

    public int getParentMult() {
        return this.parentMult;
    }

    public void setTableAliases(Array_Of_IntegerData<IntegerData> tableAliases) {
        Array_Of_IntegerData<IntegerData> oldValue = this.tableAliases;
        this.tableAliases = tableAliases;
        this.qq_Listeners.firePropertyChange("tableAliases", oldValue, this.tableAliases);
    }

    public Array_Of_IntegerData<IntegerData> getTableAliases() {
        return this.tableAliases;
    }

    public void setTargetAttrs(Array_Of_IntegerData<IntegerData> targetAttrs) {
        Array_Of_IntegerData<IntegerData> oldValue = this.targetAttrs;
        this.targetAttrs = targetAttrs;
        this.qq_Listeners.firePropertyChange("targetAttrs", oldValue, this.targetAttrs);
    }

    public Array_Of_IntegerData<IntegerData> getTargetAttrs() {
        return this.targetAttrs;
    }

    public void setUpdatedClass(BusinessClass updatedClass) {
        BusinessClass oldValue = this.updatedClass;
        this.updatedClass = updatedClass;
        this.qq_Listeners.firePropertyChange("updatedClass", oldValue, this.updatedClass);
    }

    public BusinessClass getUpdatedClass() {
        return this.updatedClass;
    }

    public void setValues(QueryConstraint values) {
        QueryConstraint oldValue = this.values;
        this.values = values;
        this.qq_Listeners.firePropertyChange("values", oldValue, this.values);
    }

    public QueryConstraint getValues() {
        return this.values;
    }

    @SuppressWarnings("unused")
  private void set_ExecuteInfo(QueryExecuteInfo _ExecuteInfo) {
        QueryExecuteInfo oldValue = this._ExecuteInfo;
        this._ExecuteInfo = _ExecuteInfo;
        this.qq_Listeners.firePropertyChange("_ExecuteInfo", oldValue, this._ExecuteInfo);
    }

    @SuppressWarnings("unused")
  private QueryExecuteInfo get_ExecuteInfo() {
        return this._ExecuteInfo;
    }

    // ------------------
    // Virtual attributes
    // ------------------
    // -------------------------------------------------
    // (Virtual) Attribute NumAttrs
    // -------------------------------------------------
    public int getNumAttrs() {
        return this.getNumAttrs(0);
    }

    // -------------------------------------------------
    // (Virtual) Attribute NumDBAttrs
    // -------------------------------------------------
    public int getNumDBAttrs() {
        int numDBAttrs = 0;
        numDBAttrs = this.getNumAttrs(BusinessQuery.ATTR_DB);
        return numDBAttrs;
    }

    // -------------------------------------------------
    // (Virtual) Attribute NumForeignAttrs
    // -------------------------------------------------
    public int getNumForeignAttrs() {
        int numForeignAttrs = 0;
        numForeignAttrs = this.getNumAttrs(BusinessQuery.ATTR_FOREIGN);
        return numForeignAttrs;
    }

    // -------------------------------------------------
    // (Virtual) Attribute NumKeyAttrs
    // -------------------------------------------------
    public int getNumKeyAttrs() {
        int numKeyAttrs = 0;
        numKeyAttrs = this.getNumAttrs(BusinessQuery.ATTR_KEY);
        return numKeyAttrs;
    }

    // -------------------------------------------------
    // (Virtual) Attribute NumTables
    // -------------------------------------------------
    public int getNumTables() {
        return this.qq_getNumTables();
    }

    // -------------------------------------------------
    // (Virtual) Attribute ExecuteInfo
    // -------------------------------------------------
    public QueryExecuteInfo getExecuteInfo() {
        return this.qq_getExecuteInfo();
    }

    // -------
    // Methods
    // -------
    public void addPropertyChangeListener(String property, PropertyChangeListener listener) {
        qq_Listeners.addPropertyChangeListener(property, listener);
    }

    public void addPropertyChangeListener(PropertyChangeListener listener) {
        qq_Listeners.addPropertyChangeListener(listener);
    }

    public void removePropertyChangeListener(String property, PropertyChangeListener listener) {
        qq_Listeners.removePropertyChangeListener(property, listener);
    }

    public void removePropertyChangeListener(PropertyChangeListener listener) {
        qq_Listeners.removePropertyChangeListener(listener);
    }

    /**
     * addAttr<p>
     * AddAttr<br>
     *     The AddAttr method is used to specify which attributes should be<br>
     *     returned in a BusinessClass.  The columns in the database corresponding<br>
     *     to these attributes will be selected from the database and their values<br>
     *     used as the values of the attributes requested.  If the attribute<br>
     *     requested is a dependent or foreign entity then a BusinessQuery must<br>
     *     be provided which describes which attributes of the dependent or foreign<br>
     *     entity should be returned and, optionally, constraints on the entity.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index which specifies an<br>
     *       attribute which should be returned.  Attribute indexes common to<br>
     *       all BusinessQueries and BusinessEntities are defined in<br>
     *       BusinessQuery.  These are ATTR_SIMPLE, ATTR_FOREIGN, and<br>
     *       ATTR_KEY.  Attribute indexes particular to a given<br>
     *       BusinessQuery or BusinessClass are defined in that entity's<br>
     *       generated query class and prefixed by ATTR_.<br>
     * <p>
     *     query<br>
     *       The query parameter specifies a BusinessQuery describing attributes<br>
     *       and constraints for a foreign or dependent entity.<br>
     * <p>
     * @param attr Type: int
     * @param query Type: BusinessQuery (Input) (default in Forte: NIL)
     */
    public void addAttr(int attr, BusinessQuery query) {
        if (attr < BusinessQuery.ATTR_FOREIGN) {

            //
            //  It is a simple attribute, just add it to the TargetAttrs array.
            //

            if (this.getTargetAttrs() == null) {
                this.setTargetAttrs(new Array_Of_IntegerData<IntegerData>());
            }

            if (attr != BusinessQuery.ATTR_SIMPLE) {

                if (attr > this.getNumAttrs()) {
                    throw new Error(Error.BQ_ILLEGAL_ATTR, "AddAttr", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                }
                else {
                    int row = (attr-1)/31+1;
                    double bit = (attr-1) % 31;
                    for (int i = this.getTargetAttrs().size()+1; i <= row; i++) {
                        this.getTargetAttrs().set(i-1, new IntegerData(0));
                    }
                    this.getTargetAttrs().get(row-1).setValue(this.getTargetAttrs().get(row-1).getValue()|((int)new DoubleData(2).power(bit).getValue()));
                }

            }
            else {
                //
                //  ATTR_SIMPLE means add all simple attributes
                //
                int attrs = 0;
                int numAtts = this.getNumAttrs();
                // virtual attr.
                while (attrs+31 < numAtts) {
                    attrs = attrs+31;
                    this.getTargetAttrs().set(attrs/31-1, new IntegerData(2147483647));
                }
                this.getTargetAttrs().set(attrs/31+1-1, new IntegerData((int)(new DoubleData(2).power(numAtts-attrs).getValue()-1)));

            }

        }
        else {

            //
            //  It is a foreign attribute.
            //

            if (query == null) {

                throw new Error(Error.BQ_NEED_QUERY, "AddAttr", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

            }
            else if (attr-BusinessQuery.ATTR_FOREIGN > this.getNumForeignAttrs()) {

                throw new Error(Error.BQ_ILLEGAL_ATTR, "AddAttr", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

            }
            else if (this.operation != BusinessQuery.OP_SELECT && query.operation == BusinessQuery.OP_SELECT) {

                throw new Error(Error.BQ_INCONSISTENT_OP, "AddAttr", this, new IntegerData(query.operation), new IntegerData(this.operation)).getException();
            }

            if (this.getForeignClasses() == null) {
                this.setForeignClasses(new Array_Of_BusinessQuery<BusinessQuery>());
            }
            else if ((this.operation == BusinessQuery.OP_SELECT) && (query.getTargetAttrs() != null)) {
                //
                //  Check and see if this foreign attribute is already specified.
                //  We do this for select queries which have TargetAttrs.  Select
                //  queries which don't have TargetAttrs are constraints only and
                //  they shouldn't be merged in as they are treated specially in the
                //  case of 1-to-many associations.  In that case they apply to the
                //  primary and not to the foreign query.
                //
                if (this.getForeignClasses() != null) {
                    for (BusinessQuery q : this.getForeignClasses()) {

                        if (q == query) {
                            //
                            //  It is already on the list, great! we don't need to do
                            //  anything.
                            //
                            return;

                        }
                        else if ((q.getParentAttr() == attr) && (q.getTargetAttrs() != null)) {

                            //
                            //  Bummer it has.  Now we need to merge the target lists and
                            //  constraints.  What fun.  We start with the target list.
                            //
                            int num = q.getTargetAttrs().size();
                            if (num > query.getTargetAttrs().size()) {
                                num = query.getTargetAttrs().size();
                            }
                            for (int i = 1; i <= num; i++) {
                                q.getTargetAttrs().get(i-1).setValue(q.getTargetAttrs().get(i-1).getValue()|query.getTargetAttrs().get(i-1).getValue());
                            }
                            for (int i = q.getTargetAttrs().size()+1; i <= query.getTargetAttrs().size(); i++) {
                                q.getTargetAttrs().add(query.getTargetAttrs().get(i-1));
                            }

                            //
                            //  Is there a constraint on the new query?
                            //
                            if (query.getConstraint() != null) {
                                //
                                //  Yep one of those too.
                                //
                                if (q.getConstraint() == null) {
                                    q.setConstraint(new QueryConstraint());
                                }
                                //
                                //  Now we have to fixup references on query's Constraint
                                //  stack to itself to point to q.
                                //
                                Array_Of_ConstraintNode<ConstraintNode> qq_localVector = query.getConstraint().getStack();
                                if (qq_localVector != null) {
                                    for (ConstraintNode c : qq_localVector) {
                                        if (c instanceof ConstraintAttr && ((ConstraintAttr)c).getEntity() == query) {
                                            ((ConstraintAttr)c).setEntity(q);
                                        }
                                    }
                                }
                                q.getConstraint().addConstraint(query.getConstraint());
                            }

                            //
                            //  Are there any foreign classes on the new query?
                            //
                            if (query.getForeignClasses() != null && query.getForeignClasses().size() > 0) {
                                //
                                //  Yep some of those too.
                                //
                                Array_Of_BusinessQuery<BusinessQuery> qq_localVector = query.getForeignClasses();
                                if (qq_localVector != null) {
                                    for (BusinessQuery fq : qq_localVector) {
                                        q.addAttr(fq.getParentAttr(), fq);
                                    }
                                }
                            }

                            //
                            //  Now that we've merged all the info from the new query into
                            //  the existing one we're done.
                            //
                            return;
                        }
                    }
                }
            }

            //
            //  Cache multiplicity info for the association between self and query
            //
            query.setParentMult(this.getForeignAttrMult(attr));

            //
            //  We attach this query to the ForeignClasses array and point it back
            //  to the proper attribute in this query.
            //
            query.setParentAttr(attr);
            this.getForeignClasses().add(query);

        }
    }
    /**
     * Same as {@link BusinessQuery#addAttr(int, BusinessQuery)} with the BisinessQuery defaulted to null.
     * @param attr
     */
    public void addAttr(int attr) {
      this.addAttr(attr, null);
    }
    /**
     * addConstraint<p>
     * AddConstraint<br>
     *     This form of the AddConstraint method is used for constraints that<br>
     *     affect the whole query and are not specific to a particular attribute.<br>
     *     Examples are "order by" and max rows.<br>
     * <p>
     *     AddConstraint pushes the value (if any) and operation onto the<br>
     *     Constraint stack.<br>
     * <p>
     *     operation<br>
     *       The operation parameter specifies the relationship the attribute<br>
     *       should bear to the value.  Values for operation are defined in<br>
     *       the ConstraintOperation class.<br>
     * <p>
     *     value<br>
     *       The value parameter specifies the value to which the attribute<br>
     *       should be limited.<br>
     * <p>
     * @param operation Type: int
     * @param value Type: DataValue (Input) (default in Forte: NIL)
     */
    public void addConstraint(int operation, DataValue value) {
        if (this.getConstraint() == null) {
            this.setConstraint(new QueryConstraint());
        }

        if (value != null) {
            this.getConstraint().addValue(value);
        }
        else if (operation == ConstraintOperation.OP_MAX_ROWS) {
            throw new Error(Error.BQ_CONS_OP_NEEDS_VALUE, "AddConstraint", this).getException();
        }

        this.getConstraint().addOperation(operation);
    }
    public void addConstraint(int operation) {
      this.addConstraint(operation, null);
    }

    /**
     * addConstraint<p>
     * AddConstraint<br>
     *     The AddConstraint method is used to limit the values of attributes for<br>
     *     BusinessEntities being selected.<br>
     * <p>
     *     AddConstraint pushes a value, attribute, and an operation onto the<br>
     *     Constraint stack.  The value parameter contains a text string with<br>
     *     an operation and a value.  The operation and value are parsed out and<br>
     *     used to build the constraint.  The type parameter determines what type<br>
     *     of operations can be parsed out and the datatype to which the value<br>
     *     parsed out of the value parameter will be cast.<br>
     * <p>
     *     If the type parameter is NIL or the value parameter is not a TextData<br>
     *     then the value parameter is used as the value and the operation '='<br>
     *     is used.<br>
     * <p>
     *     If the type parameter is a TextData then the value parameter is used<br>
     *     as the value and the operation is either '=', 'like', or 'is null'.<br>
     *     'like' is used if the value contains a '%' or '_' character.<br>
     *     The 'is null' operator is used if the value is 'NULL' (ignoring case).<br>
     * <p>
     *     If the type parameter is NumericData or DateTimeData then the value<br>
     *     parameter can be in the following forms:<br>
     * <p>
     *       [[not] <operator>] <value><br>
     *       [not] null<br>
     *       [not] between <value> and <value><br>
     *       [not] in (<value> [<value> ...])<br>
     * <p>
     *     where:<br>
     * <p>
     *       <operator>   ::= >= | <= | = | > | < | <NE><br>
     *       <NE>    ::= <> | != | ^=<br>
     *       <value>    ::= any string of characters not containing the<br>
     *               characters: ' ', '(', ')', '<', '>', '=',<br>
     *               '!', or '^'.<br>
     * <p>
     *     Any other form causes an exception to be raised.<br>
     * <p>
     *     The constraints on the stack are anded together by default.<br>
     *     More complex relationships on the Constraint stack are supported but<br>
     *     no interface is provided on BusinessQuery to construct them.  The<br>
     *     Constraint stack can be manipulated directly if necessary.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying an attribute<br>
     *       whose value should be limited.<br>
     * <p>
     *     value<br>
     *       The value parameter specifies the value to which the attribute<br>
     *       should be limited and depending on the type parameter may also<br>
     *       contain the operation.<br>
     * <p>
     *     type<br>
     *       The type parameter specifies to what datatype the value parameter<br>
     *       should be cast and how the value should be parsed.<br>
     * <p>
     *     templateText<br>
     *       This optional argument is used as the format template to<br>
     *       decode the value in the "value" parameter. Currently only used<br>
     *       for DateTime data.<br>
     * <p>
     * @param attr Type: int
     * @param value Type: DataValue
     * @param type Type: DataValue
     * @param templateText Type: TextData (Input) (default in Forte: NIL)
     */
    public void addConstraint(int attr, DataValue value, DataValue type, TextData templateText) {
        DataValue kind = null;

        if (attr > this.getNumAttrs()) {

            throw new Error(Error.BQ_ILLEGAL_ATTR, "AddConstraint", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else if (type == null || !(value instanceof TextData)) {

            // no need to parse or do SetValue() on "value".
            this.addConstraint(attr, ConstraintOperation.OP_EQ, value);

        }
        else if (type instanceof TextData) {

            TextData v = (TextData)value;
            v.setOffset(0);

            if (v.moveToChar("%_")) {
                this.addConstraint(attr, ConstraintOperation.OP_LIKE, value);
            }
            else if (v.getActualSize() == 4 && v.moveToString("NULL", false, true)) {
                this.addConstraint(attr, ConstraintOperation.OP_NULL, (DataValue)null);
            }
            else {
                this.addConstraint(attr, ConstraintOperation.OP_EQ, value);
            }

        }
        else if (!(type instanceof NumericData) && !(type instanceof DateTimeData)) {

            kind = CloneHelper.clone(type, false);
            kind.setValue(value);
            this.addConstraint(attr, ConstraintOperation.OP_EQ, kind);

        }
        else {

            //
            //  It is numeric or date; do our fancy parse thing
            //

            TextData v = (TextData)CloneHelper.clone(value, true);

            v.toLower();
            v.trimTrailing();
            v.trimLeading();
            v.setOffset(0);

            if (v.isDigit()) {
                //
                //  The first character is numeric -- use the whole value as the
                //  value in a simple equality constraint.
                //
                kind = CloneHelper.clone(type, false);
                this.setValueTemplate(kind, value, templateText);
                this.addConstraint(attr, ConstraintOperation.OP_EQ, kind);

            }
            else {

                Array_Of_TextData<TextData> words = new Array_Of_TextData<TextData>();
                int i = 0;
                int op = 0;
                boolean hasNot = false;

                //
                //  Parse the text into words.  Legal delimiters are <, >, =, !, ^, (,
                //  ), and blank.  Any delimiter except blank becomes a word itself,
                //  blanks disappear.
                //
                while (v.moveToChar("><=!^() ")) {
                    if (i != v.getOffset()) {
                        words.add(v.copyRange(i, v.getOffset()));
                    }
                    if (!(v.isChar(" "))) {
                        i = v.getOffset();
                        if (v.getActualSize() > v.getOffset()+1 && v.isChar("<>!^") && v.copyRange(v.getOffset()+1, v.getOffset()+2).isChar(">=")) {
                            words.add(v.copyRange(v.getOffset(), v.getOffset()+2));
                            v.moveNext();
                        }
                        else {
                            words.add(v.copyRange(v.getOffset(), v.getOffset()+1));
                        }
                        v.moveNext();
                    }
                    v.moveToNotChar(" ");
                    i = v.getOffset();
                }

                if (i < v.totalLength()) {
                    words.add(v.copyRange(i));
                }

                i = 1;

                if (i > words.size()) {
                    throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, v, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                }

                if ("not".equals(words.get(i-1).toString())) {
                    i = i+1;
                    hasNot = true;
                    if (i > words.size()) {
                        throw new Error(Error.BQ_CONS_ONLYNOT, "AddConstraint", this, v, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                    }
                }

                if ("null".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_NULL;
                }
                else if ("between".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_BETWEEN;
                }
                else if ("in".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_IN;
                }
                else if (">".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_GT;
                }
                else if (">=".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_GE;
                }
                else if ("<".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_LT;
                }
                else if ("<=".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_LE;
                }
                else if ("=".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_EQ;
                }
                else if ("<>".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_NE;
                }
                else if ("!=".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_NE;
                }
                else if ("^=".equals(words.get(i-1).toString())) {
                    op = ConstraintOperation.OP_NE;
                }
                else if (templateText != null) {
                    words.add(i-1, new TextData("="));
                    op = ConstraintOperation.OP_EQ;
                }
                else {
                    throw new Error(Error.BQ_CONS_ILLEGAL_OP, "AddConstraint", this, v, words.get(i-1)).getException();
                }

                if (this.getConstraint() == null) {
                    this.setConstraint(new QueryConstraint());
                }

                if (op == ConstraintOperation.OP_NULL) {

                    if (i != words.size()) {
                        throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                    }
                    if (hasNot) {
                        this.addConstraint(attr, ConstraintOperation.OP_NOTNULL, (DataValue)null);
                        hasNot = false;
                    }
                    else {
                        this.addConstraint(attr, ConstraintOperation.OP_NULL, (DataValue)null);
                    }

                }
                else if (op == ConstraintOperation.OP_BETWEEN) {

                    if (type instanceof NumericData) {
                        if (i+3 != words.size()) {
                            throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                        }
                        else if (!("and".equals(words.get(i+2-1).toString()))) {
                            throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                        }
                        kind = CloneHelper.clone(type, false);
                        this.setValueTemplate(kind, words.get(i+3-1), templateText);
                        this.getConstraint().addValue(kind);
                        kind = CloneHelper.clone(type, false);
                        this.setValueTemplate(kind, words.get(i+1-1), templateText);
                        this.addConstraint(attr, op, kind);
                    }
                    else {
                        if (i+3 > words.size()) {
                            throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                        }
                        int andIx = 0;
                        for (int j = i+2; j <= words.size()-1; j++) {
                            if ("and".equals(words.get(j-1).toString())) {
                                andIx = j;
                                continue;
                            }
                        }
                        if (andIx == 0) {
                            throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                        }
                        for (int j = i+2; j <= andIx-1; j++) {
                            words.get(i+1-1).concat(" ");
                            words.get(i+1-1).concat(words.get(j-1));
                        }
                        for (int j = andIx+2; j <= words.size(); j++) {
                            words.get(andIx+1-1).concat(" ");
                            words.get(andIx+1-1).concat(words.get(j-1));
                        }
                        kind = CloneHelper.clone(type, false);
                        this.setValueTemplate(kind, words.get(andIx+1-1), templateText);
                        this.getConstraint().addValue(kind);

                        kind = CloneHelper.clone(type, false);
                        this.setValueTemplate(kind, words.get(i+1-1), templateText);
                        this.addConstraint(attr, op, kind);
                    }

                }
                else if (op == ConstraintOperation.OP_IN) {

                    if (type instanceof DateTimeData) {
                        throw new Error(Error.BQ_CONS_CANT_USE_DATE_WITH_IN, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                    }
                    if (words.size() < i+3) {
                        throw new Error(Error.BQ_CONS_ILLEGAL, "AddConstraint", this, value, Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                    }
                    SqlData sqlData = new SqlData();
                    TextData sqlText = new TextData();
                    for (int j = i+2; j <= words.size()-1; j++) {
                        kind = CloneHelper.clone(type, false);
                        this.setValueTemplate(kind, words.get(j-1), templateText);
                        sqlData.getValues().add(kind);
                        sqlText.concat("?,");
                    }
                    sqlText.cutRange(sqlText.lengthToEnd()-1);
                    this.getConstraint().addSqlData(sqlData);
                    this.getConstraint().addValue(sqlText);
                    this.getConstraint().addAttr(this, attr, 1);
                    this.getConstraint().addOperation(op);

                }
                else {

                    i = i+1;
                    if (i != words.size()) {
                        for (int j = i+1; j <= words.size(); j++) {
                            words.get(i-1).concat(" ");
                            words.get(i-1).concat(words.get(j-1));
                        }
                    }
                    kind = CloneHelper.clone(type, false);
                    this.setValueTemplate(kind, words.get(i-1), templateText);
                    this.addConstraint(attr, op, kind);

                }

                if (hasNot) {
                    this.getConstraint().addOperation(ConstraintOperation.OP_NOT);
                }

            }

        }
    }
    public void addConstraint(int attr, DataValue value, DataValue type) {
      this.addConstraint(attr, value, type, null);
    }

    /**
     * addConstraint<p>
     * AddConstraint<br>
     *     The AddConstraint method is used to limit the values of attributes for<br>
     *     BusinessClasses being selected.<br>
     * <p>
     *     AddConstraint pushes the value, attribute, and operation onto the<br>
     *     Constraint stack.  The constraints are anded together by default.<br>
     *     More complex relationships on the Constraint stack are supported but<br>
     *     no interface is provided on BusinessQuery to construct them.  The<br>
     *     Constraint stack can be manipulated directly if necessary.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying an attribute<br>
     *       whose value should be limited.<br>
     * <p>
     *     operation<br>
     *       The operation parameter specifies the relationship the attribute<br>
     *       should bear to the value.  Values for operation are defined in<br>
     *       the ConstraintOperation class.<br>
     * <p>
     *     value<br>
     *       The value parameter specifies the value to which the attribute<br>
     *       should be limited.<br>
     * <p>
     * @param attr Type: int
     * @param operation Type: int
     * @param value Type: DataValue (Input) (default in Forte: NIL)
     */
    public void addConstraint(int attr, int operation, DataValue value) {
        if (attr > this.getNumAttrs()) {

            throw new Error(Error.BQ_ILLEGAL_ATTR, "AddConstraint", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else if (this.operation == BusinessQuery.OP_INSERT) {

            throw new Error(Error.BQ_ILLEGAL_ACTION_FOR_OP, "AddConstraint", this, new IntegerData(this.operation), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else if (this.getConstraint() == null) {
            this.setConstraint(new QueryConstraint());
        }

        if ((operation&ConstraintOperation.TYPE_MASK) == ConstraintOperation.TYPE_ORDERBY) {

            //
            //  Check that this attr isn't already specified in an "order by" constraint
            //
            for (int i = this.getConstraint().getStack().size(); i >= 2; i--) {
                if (this.getConstraint().getStack().get(i-1) instanceof ConstraintOperation && ((((ConstraintOperation)(this.getConstraint().getStack().get(i-1))).getOperation()&ConstraintOperation.TYPE_MASK) == ConstraintOperation.TYPE_ORDERBY) && ((ConstraintAttr)(this.getConstraint().getStack().get(i-1-1))).getAttr() == attr && ((ConstraintAttr)(this.getConstraint().getStack().get(i-1-1))).getEntity() == this) {
                    throw new Error(Error.BQ_CONS_DUP_ORDERBY_ATTR, "AddConstraint", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
                }
            }

            if (value != null) {
                this.getConstraint().addValue(value);
            }


        }
        else if (operation == ConstraintOperation.OP_NULL || operation == ConstraintOperation.OP_NOTNULL) {
            if (value != null) {
                throw new Error(Error.BQ_CONS_OP_PROHIBITS_VALUE, "AddConstraint", this, new IntegerData(operation), new IntegerData(attr)).getException();
            }

        }
        else if (value == null) {
            throw new Error(Error.BQ_CONS_OP_NEEDS_VALUE, "AddConstraint", this, new IntegerData(operation), new IntegerData(attr)).getException();

        }
        else {
            this.getConstraint().addValue(value);

        }

        this.getConstraint().addAttr(this, attr, 1);
        this.getConstraint().addOperation(operation);
    }
   
    public void addConstraint(int attr, int operation){
      this.addConstraint(attr, operation, null);
    }

    /**
     * addForeignConstraint<p>
     * AddForeignConstraint<br>
     *     The AddForeignConstraint method adds a constraint on a foreign class<br>
     *     which limits this class.  This is as opposed to the constraints on the<br>
     *     foreign class's query as added by AddAttr which are used to limit the<br>
     *     foreign class itself.<br>
     * <p>
     *     When would you want to use a foreign constraint on the independent<br>
     *     class (this case) vs. a constraint on the foreign class?  Glad<br>
     *     you asked.  Assume the model application with orders and line items.<br>
     *     If you wanted to get all the orders which have one or more line<br>
     *     items which are widgets.  You would need this method because you<br>
     *     want to constrain the independent class (orders in this case) by the<br>
     *     foreign class (line items).  If you wanted to get only the line<br>
     *     items which were widgets then you would constrain the line item<br>
     *     query which you used to specify the line items (the one you used in<br>
     *     the AddAttr call).<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying a dependent<br>
     *       attribute which should be used in limiting the independent class.<br>
     * <p>
     *     query<br>
     *       The query parameter specifies a BusinessQuery describing<br>
     *       constraints of the dependent class for which the independent<br>
     *       class should be limited.<br>
     * <p>
     * @param attr Type: int
     * @param query Type: BusinessQuery
     */
    public void addForeignConstraint(int attr, BusinessQuery query) {
        query.clearAttrs(true);

        this.addAttr(attr, query);
    }

    /**
     * addJoinConstraint<p>
     * AddJoinConstraint<br>
     *     The AddJoinConstraint method is used to join one entity to another.<br>
     * <p>
     *     NOTE:  You don't normally need to invoke this directly.  It is done<br>
     *     implicitly whenever you specify a constraint on a foreign entity or<br>
     *     use AddForeignConstraint.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying which attribute<br>
     *       should be joined.<br>
     * <p>
     *     operation<br>
     *       The operation parameter specifies the relationship the attribute<br>
     *       should bear to the value.  Values for operation are defined in<br>
     *       the ConstraintOperation class.  Legal values are:<br>
     *       ConstraintOperation.EQUIJOIN, ConstraintOperation.LEFTJOIN, and<br>
     *       ConstraintOperation.RIGHTJOIN.<br>
     * <p>
     *     foreignClass<br>
     *       The foreignClass parameter specifies the entity which is to be<br>
     *       joined against.<br>
     * <p>
     *     foreignAttr<br>
     *       The foreignAttr parameter specifies the attribute in the<br>
     *       foreign entity which is to be joined to attr.<br>
     * <p>
     * @param operation Type: int
     * @param foreignClass Type: BusinessQuery
     */
    public void addJoinConstraint(int operation, BusinessQuery foreignClass) {
        if (this.getConstraint() == null) {
            this.setConstraint(new QueryConstraint());
        }

        Array_Of_QueryAttrMap<QueryAttrMap> attrMap = this.getForeignAttrMap(foreignClass.getParentAttr());

        if (attrMap != null) {
            for (QueryAttrMap attr : attrMap) {
                this.getConstraint().addAttr(foreignClass, attr.getForeign(), 1);
                this.getConstraint().addAttr(this, attr.getLocal(), 1);
            }
        }

        this.getConstraint().addOperation((operation&ConstraintOperation.OPCODE_MASK)+(attrMap.size()*ConstraintOperation.PCOUNT_INCREMENT));
    }

    /**
     * buildQuery<p>
     * BuildQuery<br>
     *     The BuildQuery method builds an SQL query for ourself.<br>
     * <p>
     *     NOTE:  You don't normally need to invoke this directly.  It is used<br>
     *     by the BusinessMgr to build the query they must execute.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter is used to return the SQLquery built.  If the<br>
     *       sqlQuery parameter is non NIL on input then it represents a partially<br>
     *       built sqlQuery to which we should append our sqlQuery.<br>
     * <p>
     * @param query Type: SqlQuery
     */
    public void buildQuery(ParameterHolder_SqlQuery query) {
        if ((this.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_BUILT) > 0) {
            return;
        }

        int t = 0, t2 = 0;
        // holds a table index
        TextData c = null;
        // holds a column name
        SqlQuery sq = null;
        // holds the current SqlQuery;
        int lNumKeyAttrs = this.getNumKeyAttrs();
        // local copy of virtual attribute
        int lNumTables = this.getNumTables();
        // local copy of virtual attribute

        if (((SqlQuery)query.getObject()) == null) {
            query.setObject(this.getSqlQuery((DBConnectionManager)null));
        }

        sq = (SqlQuery)query.getObject();

        //
        //  Add tables for this BusinessClass to the from clause of the query.
        //
        this.describeTables(sq);

        switch (this.operation) {

            case BusinessQuery.OP_UPDATE: {

                //
                //  Specify updated values.
                // 
                sq.addValue(this.getValues());

                //
                //  Add constraints to specify which entity is to be updated.
                //
                for (int i = 1; i <= lNumKeyAttrs; i++) {
                    for (int t1 = 1; t1 <= lNumTables; t1++) {
                        t2 = t1;
                        // ------------------------------------
                        // Parameters for call to GetColumnName
                        // ------------------------------------
                        ParameterHolder_integer qq_tableIndex = new ParameterHolder_integer(t2);
                        ParameterHolder_TextData qq_columnName = new ParameterHolder_TextData();
                        this.getColumnName(i, qq_tableIndex, qq_columnName);
                        t2 = qq_tableIndex.getInt();
                        c = (TextData)qq_columnName.getObject();
                        sq.addConstraint(t2, c, ConstraintOperation.OP_EQ, this.getKey().getValues().get(i-1));
                    }
                }

                //
                //  Add user specified constraints.
                //
                sq.addConstraint(this.getConstraint());

                break;
            }
            case BusinessQuery.OP_INSERT: {

                //
                //  For inserts the constraints represent the values to be inserted.
                //
                sq.addValue(this.getValues());

                break;
            }
            case BusinessQuery.OP_DELETE: {

                //
                //  For deletes we need only specify the key attributes as constraints.
                //
                for (int i = 1; i <= lNumKeyAttrs; i++) {
                    for (int t1 = 1; t1 <= lNumTables; t1++) {
                        t2 = t1;
                        // ------------------------------------
                        // Parameters for call to GetColumnName
                        // ------------------------------------
                        ParameterHolder_integer qq_tableIndex = new ParameterHolder_integer(t2);
                        ParameterHolder_TextData qq_columnName = new ParameterHolder_TextData();
                        this.getColumnName(i, qq_tableIndex, qq_columnName);
                        t2 = qq_tableIndex.getInt();
                        c = (TextData)qq_columnName.getObject();
                        sq.addConstraint(t2, c, ConstraintOperation.OP_EQ, this.getKey().getValues().get(i-1));
                    }
                }

                //
                //  Add user specified constraints.
                //
                sq.addConstraint(this.getConstraint());

                break;
            }
            case BusinessQuery.OP_SELECT: {

                //
                // Add attributes to the select list.
                //   
                int attrs = 0;
                int index = 0;
                int baseIndex = 1;
                int lNumDBAttrs = this.getNumDBAttrs();
                // cache virtual attribute

                if (this.getTargetAttrs() != null) {
                    for (IntegerData attr : this.getTargetAttrs()) {
                        if (baseIndex+30 <= lNumKeyAttrs) {
                            //
                            //  All attributes are key attributes -- make sure they're all set.
                            //
                            attr.setValue(2147483647);
                        }
                        else if (baseIndex <= lNumKeyAttrs) {
                            //
                            //  Or in key attributes
                            //
                            attr.setValue(attr.getValue()|((int)(new DoubleData().power(2, lNumKeyAttrs-baseIndex+1).getValue()-1)));
                        }
                        index = baseIndex;
                        attrs = attr.getValue();
                        while ((attrs > 0) && (index <= lNumDBAttrs)) {
                            if ((attrs&1) > 0) {
                                t = 1;
                                // ------------------------------------
                                // Parameters for call to GetColumnName
                                // ------------------------------------
                                ParameterHolder_integer qq_tableIndex = new ParameterHolder_integer(t);
                                ParameterHolder_TextData qq_columnName = new ParameterHolder_TextData();
                                this.getColumnName(index, qq_tableIndex, qq_columnName);
                                t = qq_tableIndex.getInt();
                                c = (TextData)qq_columnName.getObject();
                                sq.addColumn(t, c, (DataValue)null);
                                if (index <= lNumKeyAttrs && lNumTables > 1) {
                                    for (int tindex = 2; tindex <= lNumTables; tindex++) {
                                        t2 = tindex;
                                        // ------------------------------------
                                        // Parameters for call to GetColumnName
                                        // ------------------------------------
                                        ParameterHolder_integer qq_tableIndex1 = new ParameterHolder_integer(t2);
                                        ParameterHolder_TextData qq_columnName1 = new ParameterHolder_TextData();
                                        this.getColumnName(index, qq_tableIndex1, qq_columnName1);
                                        t2 = qq_tableIndex1.getInt();
                                        c = (TextData)qq_columnName1.getObject();
                                        if (this.getConstraint() == null) {
                                            this.setConstraint(new QueryConstraint());
                                        }
                                        this.getConstraint().addAttr(this, index, 1);
                                        this.getConstraint().addAttr(this, index, tindex);
                                        this.getConstraint().addOperation(ConstraintOperation.OP_EQ);
                                    }
                                }
                            }
                            attrs = attrs/2;
                            index = index+1;
                        }
                        baseIndex = baseIndex+31;
                    }
                }

                //
                // Finally do foreign entities.
                //
                if (this.getForeignClasses() != null) {
                    for (BusinessQuery fe : this.getForeignClasses()) {

                        if ((fe.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_JOINED) > 0) {
                            //
                            //  Check what kind of join we are going to do
                            //
                            int op = 0;
                            if ((fe.getParentMult()&BusinessQuery.ASSOC_MULT_OPTIONAL) == 0) {
                                op = ConstraintOperation.OP_EQUIJOIN;
                                sq.setOptions(sq.getOptions()|SqlQuery.OPT_INNER_JOIN);
                            }
                            else {
                                op = ConstraintOperation.OP_LEFTJOIN;
                                sq.setOptions(sq.getOptions()|SqlQuery.OPT_OUTER_JOIN);
                            }

                            //
                            //  Put in a join to the foreign table
                            //
                            this.addJoinConstraint(op, fe);

                            //
                            //  Now have the foreign entity describe itself as we just did and
                            //  append this to the sqlQuery we are building up.
                            //
                            // ---------------------------------
                            // Parameters for call to BuildQuery
                            // ---------------------------------
                            ParameterHolder_SqlQuery qq_query = new ParameterHolder_SqlQuery(sq);
                            fe.buildQuery(qq_query);
                            sq = (SqlQuery)qq_query.getObject();

                        }
                        else if (fe.getTargetAttrs() == null) {
                            //
                            //  This is the case where we have a 1-to-many association
                            //  which has a constraint on the foreign class which is
                            //  suppossed to limit the primary.  We need an "in" sql
                            //  condition of the form:
                            //    where (<join-column-list>) in
                            //      (select <join-column-list> from <foreignTable> ...)
                            //       
                            TextData queryText = null;
                            SqlQuery subQuery = null;

                            // ---------------------------------
                            // Parameters for call to BuildQuery
                            // ---------------------------------
                            ParameterHolder_SqlQuery qq_query = new ParameterHolder_SqlQuery(subQuery);
                            fe.buildQuery(qq_query);
                            subQuery = (SqlQuery)qq_query.getObject();
                            //
                            //  Don't really want this query to look like its executed.
                            //
                            fe.getExecuteInfo().setStatus(fe.getExecuteInfo().getStatus()&~QueryExecuteInfo.ST_BUILT);

                            //
                            //  First build the sub-query and get its text.  Note:
                            //  this query really has the wrong column list.  We'll
                            //  fix that up and reset the query text in a minute, but
                            //  need to get the text now as input data isn't
                            //  computed until we do and we need to know that now.
                            //
                            queryText = subQuery.getText().get(0);

                            if (subQuery.getData().get(0).getValues().size() > 0) {
                                //
                                //  Push input data for the sub-query, if any.
                                //
                                this.getConstraint().addSqlData(subQuery.getData().get(0));
                            }

                            //  Next push the suq-query, we'll fix this up at the end.
                            //
                            this.getConstraint().addValue(queryText);

                            subQuery.clearColumnList();
                            //
                            //  Now clear the column list and recompute it.  At the
                            //  same time push on the column list for the outer query.
                            //       
                            Array_Of_QueryAttrMap<QueryAttrMap> qq_localVector = this.getForeignAttrMap(fe.getParentAttr());
                            if (qq_localVector != null) {
                                for (QueryAttrMap attr : qq_localVector) {
                                    t = 1;
                                    // ------------------------------------
                                    // Parameters for call to GetColumnName
                                    // ------------------------------------
                                    ParameterHolder_integer qq_tableIndex = new ParameterHolder_integer(t);
                                    ParameterHolder_TextData qq_columnName = new ParameterHolder_TextData();
                                    fe.getColumnName(attr.getForeign(), qq_tableIndex, qq_columnName);
                                    t = qq_tableIndex.getInt();
                                    c = (TextData)qq_columnName.getObject();
                                    subQuery.addColumn(t, c, (DataValue)null);
                                    this.getConstraint().addAttr(this, attr.getLocal(), 1);
                                }
                            }

                            //  Now we get the real sub-query we want with the correct
                            //  column list.
                            //
                            queryText.setValue( subQuery.getText().get(0) );

                            //  Finally push the IN operator.
                            //
                            this.getConstraint().addOperation(ConstraintOperation.OP_IN);

                        }
                    }
                }

                sq.addConstraint(this.getConstraint());

                break;
            }

            default: {
                throw new Error(Error.BQ_ILLEGAL_OPERATION, "BuildQuery", this).getException();

            }
        }

        this.getExecuteInfo().setStatus(this.getExecuteInfo().getStatus()|QueryExecuteInfo.ST_BUILT);
    }

    /**
     * clearAttrs<p>
     * ClearAttrs<br>
     *     The ClearAttrs method is used to clear the TargetAttrs for a<br>
     *     BusinessQuery.<br>
     * <p>
     *     deep<br>
     *       The deep parameter specifies whether TargetAttrs of Foreign<br>
     *       BusinessQueries should be cleared as well.<br>
     * <p>
     * @param deep Type: boolean (Input) (default in Forte: FALSE)
     */
    public void clearAttrs(boolean deep) {
        this.setTargetAttrs(null);

        if (deep && this.getForeignClasses() != null) {
            if (this.getForeignClasses() != null) {
                for (BusinessQuery f : this.getForeignClasses()) {
                    f.clearAttrs(deep);
                }
            }
        }
    }

    /**
     * clearConstraints<p>
     * ClearConstraints<br>
     *     The ClearConstraints method is used to clear the constraints for a<br>
     *     BusinessQuery which is used for a select.<br>
     * <p>
     *     deep<br>
     *       The deep parameter specifies whether Constraints of Foreign<br>
     *       BusinessQueries should be cleared as well.<br>
     * <p>
     * @param deep Type: boolean (Input) (default in Forte: FALSE)
     */
    public void clearConstraints(boolean deep) {
        if (this.operation != BusinessQuery.OP_SELECT) {
            throw new Error(Error.BQ_CANT_RESET, "ClearConstraints", this).getException();
        }
        else {
            this.setConstraint(null);
        }

        if (deep && this.getForeignClasses() != null) {
            if (this.getForeignClasses() != null) {
                for (BusinessQuery f : this.getForeignClasses()) {
                    f.clearConstraints(deep);
                }
            }
        }
    }
    /**
     * Same as {@link #clearConstraints(boolean) with the boolean value defaulter to false
     */
    public void clearConstraints(){
      this.clearConstraints(false);
    }

    /**
     * clearForeignAttrs<p>
     * ClearForeignAttrs<br>
     *     The ClearForeignAttrs method is used to remove foreign queries from a<br>
     *     BusinessQuery.<br>
     * <p>
     */
    public void clearForeignAttrs() {
        this.setForeignClasses(null);
    }

    /**
     * connectQueries<p>
     * ConnectQueries<br>
     *     The ConnectQueries method adds querries on foreign classes of source to<br>
     *     us as foreign queries.  It also recursively adds foreign queries of<br>
     *     the foreign classes to the foreign class's queries.  ConnectQueries is<br>
     *     used by the class' client's Update method to connect all the<br>
     *     queries for processing by the class' manager's Update method.<br>
     * <p>
     *     source<br>
     *       The source parameter specifies the BusinessClass whose foreign<br>
     *       attributes are to be checked for queries.  It's Query attribute<br>
     *       should be us!<br>
     * <p>
     * @param source Type: BusinessClass
     * @param client Type: BusinessClient
     */
    @SuppressWarnings("unchecked")
  public void connectQueries(BusinessClass source, BusinessClient client) {
        if (source.getUpdateQuery() != this) {
            throw new Error(Error.BQ_WRONG_ENTITY, "ConnectQueries", this).getException();
        }

        Array_Of_BusinessClass<BusinessClass> foreignClasses = null;
        BusinessClass foreignClass = null;
        int mult = 0;

        for (int i = 1; i <= this.getNumForeignAttrs(); i++) {

            mult = this.getForeignAttrMult(BusinessQuery.ATTR_FOREIGN+i);

            if ((mult&BusinessQuery.ASSOC_MULT_ONE_MASK) > 0) {

                // ------------------------------
                // Parameters for call to GetAttr
                // ------------------------------
                ParameterHolder_BusinessClass qq_value = new ParameterHolder_BusinessClass();
                source.getAttr(BusinessQuery.ATTR_FOREIGN+i, qq_value);
                foreignClass = (BusinessClass)qq_value.getObject();

                if (foreignClass != null && foreignClass.getUpdateQuery() != null && ((foreignClass.getInstanceStatus()&(BusinessClass.ST_UPDATE|BusinessClass.ST_DELETE|BusinessClass.ST_INSERT)) > 0)) {
                    //
                    //  Found a foreign class with changes -- validate it and hook the
                    //  foreign class's query up to us.
                    //
                    foreignClass.validateInstance(client);
                    this.addAttr(BusinessQuery.ATTR_FOREIGN+i, foreignClass.getUpdateQuery());

                    //
                    //  Recursively hook up any dependent querries on this
                    //  dependent query to it.
                    //
                    foreignClass.getUpdateQuery().connectQueries(foreignClass, client);

                }

            }
            else {

                // ------------------------------
                // Parameters for call to GetAttr
                // ------------------------------
                ParameterHolder_BusinessClass_Array qq_value = new ParameterHolder_BusinessClass_Array();
                source.getAttr(BusinessQuery.ATTR_FOREIGN+i, qq_value);
                foreignClasses = (Array_Of_BusinessClass<BusinessClass>)qq_value.getObject();

                if (foreignClasses != null) {

                    if (foreignClasses != null) {
                        for (BusinessClass fe : foreignClasses) {

                            if (fe.getUpdateQuery() != null && ((fe.getInstanceStatus()&(BusinessClass.ST_UPDATE|BusinessClass.ST_DELETE|BusinessClass.ST_INSERT)) > 0)) {

                                //
                                //  Found a foreign class with changes -- validate it and hook the
                                //  foreign  class's query up to us.
                                //
                                fe.validateInstance(client);
                                this.addAttr(BusinessQuery.ATTR_FOREIGN+i, fe.getUpdateQuery());

                                //
                                //  Recursively hook up any foreign queries on this
                                //  foreign query to it.
                                //
                                fe.getUpdateQuery().connectQueries(fe, client);

                            }

                        }
                    }

                }

            }

        }
    }

    /**
     * describeTables<p>
     * DescribeTables<br>
     *     The DescribeTables method is used to add the table names for this<br>
     *     BusinessClass to the query.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BuildQuery method uses it internally.<br>
     * <p>
     *     DescribeTables will use SqlQuery.AddTable to add the actual<br>
     *     table name to the query.  AddTable will return a unique table alias<br>
     *     that we need to use when referencing columns in the table either in<br>
     *     the select list or the where clause, which we will remember in the<br>
     *     TableAliases array.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter contains the SqlQuery which is being used<br>
     *       to construct the SQL for this BusinessQuery.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     */
    public void describeTables(SqlQuery sqlQuery) {
        TextData tableName = null;

        if (this.getTableAliases() == null) {
            this.setTableAliases(new Array_Of_IntegerData<IntegerData>());
        }

        for (int i = 1; i <= this.getNumTables(); i++) {
            // -----------------------------------
            // Parameters for call to GetTableName
            // -----------------------------------
            ParameterHolder_TextData qq_tableName = new ParameterHolder_TextData();
            this.getTableName(i, qq_tableName);
            tableName = (TextData)qq_tableName.getObject();
            this.getTableAliases().add(sqlQuery.addTable(tableName));
        }
    }

    /**
     * disconnectQueries<p>
     * DisconnectQueries<br>
     *     The DisconnectQueries method removes.<br>
     * <p>
     */
    public void disconnectQueries() {
        if (this.getForeignClasses() != null) {
            for (BusinessQuery q : this.getForeignClasses()) {
                q.disconnectQueries();
            }
        }

        this.setForeignClasses(null);
    }

    /**
     * getAttrName<p>
     * GetAttrName<br>
     *     The GetAttrName method is used to get the name of the attribute<br>
     *     indicated by the attr parameter.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying for which<br>
     *       attribute the name should be returned.<br>
     * <p>
     * @param attr Type: int
     * @return String
     */
    public String getAttrName(int attr) {
        throw new Error(Error.BQ_ILLEGAL_ATTR, "GetAttrName", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }

    /**
     * getColumnName<p>
     * GetColumnName<br>
     *     The GetColumnName method is used to get the column and table name in<br>
     *     the underlying database which holds the attribute indicated by the<br>
     *     attr parameter.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     SQLquery class uses it to create the text of the query.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying for which<br>
     *       attribute table and column info should be returned.<br>
     * <p>
     *     tableIndex<br>
     *       The tableIndex parameter returns an index which indicates which<br>
     *       of the tables that comprise this BusinessClass holds attr.<br>
     * <p>
     *     columnName<br>
     *       The columnName parameter returns the name of the column in the<br>
     *       table indicated by the tableIndex parameter which holds attr.<br>
     * <p>
     * @param attr Type: int
     * @param tableIndex Type: int
     * @param columnName Type: TextData
     */
    public void getColumnName(int attr, ParameterHolder_integer tableIndex, ParameterHolder_TextData columnName) {
        throw new Error(Error.BQ_ILLEGAL_ATTR, "GetColumnName", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }

    /**
     * qq_getExecuteInfo<p>
     * Method renamed by jcTOOL from GetExecuteInfo to qq_getExecuteInfo
     * because it conflicted with an attribute<p>
     * <p>
     * @return QueryExecuteInfo
     */
    public QueryExecuteInfo qq_getExecuteInfo() {
        if (this._ExecuteInfo == null) {
            this._ExecuteInfo = new QueryExecuteInfo();
        }

        return this._ExecuteInfo;
    }

    /**
     * getForeignAttrMap<p>
     * GetForeignAttrMap<br>
     *     The GetForeignAttrMap method is used to get the mapping between<br>
     *     simple attributes of this entity to the corresponding simple attributes<br>
     *     of the foreign entity indicated by the attr parameter.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BuildQuery method uses it internally.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying for which<br>
     *       foreign attribute a mapping of local to foreign attributes is<br>
     *       needed.<br>
     * <p>
     *     Returns<br>
     *       The return value is an array of mappings between simple attributes<br>
     *       of this entity to simple attributes of the foreign entity.<br>
     * <p>
     * @param attr Type: int
     * @return Array_Of_QueryAttrMap<QueryAttrMap>
     */
    public Array_Of_QueryAttrMap<QueryAttrMap> getForeignAttrMap(int attr) {
        throw new Error(Error.BQ_ILLEGAL_ATTR, "GetForeignAttrMap", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }

    /**
     * getForeignAttrMgr<p>
     * GetForeignAttrMgr<br>
     *     The GetForeignAttrMgr method is used to get the index of the BusinessMgr<br>
     *     associated with the attribute specified by the attr parameter.  The<br>
     *     Index is used by the BusinessQuery's BusinessMgr to index his<br>
     *     DependentMgr array to find the actual BusinessMgr to use for<br>
     *     the attribute specifed by the attr parameter.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BusinessMgr class uses it internally.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying for which<br>
     *       attribute a BusinessMgr index should be returned.<br>
     * <p>
     * @param attr Type: int
     * @return int
     */
    public int getForeignAttrMgr(int attr) {
        throw new Error(Error.BQ_ILLEGAL_ATTR, "GetForeignAttrMgr", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }

    /**
     * getForeignAttrMult<p>
     * GetForeignAttrMult<br>
     *     The GetForeignAttrMult method is used to get information about the<br>
     *     multiplicity of the association between this class and the foreign<br>
     *     class specified by the attr parameter.  Legal values are any<br>
     *     combination of:<br>
     *       ASSOC_MULT_OPTIONAL   (there may be one foreign object)<br>
     *       ASSOC_MULT_TO_ONE    (there is one foreign object)<br>
     *       ASSOC_MULT_TO_MANY    (there may be many foreign objects)<br>
     *       ASSOC_AGGREGATION<br>
     *       ASSOC_MULT_ONE_TO<br>
     *       ASSOC_MULT_MANY_TO<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BusinessQuery class uses it internally.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying for which<br>
     *       foreign attribute information should be returned.<br>
     * <p>
     * @param attr Type: int
     * @return int
     */
    public int getForeignAttrMult(int attr) {
        throw new Error(Error.BQ_ILLEGAL_ATTR, "GetForeignAttrMult", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }

    /**
     * getMgrID<p>
     * GetMgr<br>
     *     The GetMgr method is used to get the ID of the BusinessMgr<br>
     *     associated with the query.  The ID is used by the BusinessServiceMgr<br>
     *     to index his Mgrs array to find the actual BusinessMgr to use for<br>
     *     the query.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BusinessServiceMgr class uses it internally.<br>
     * <p>
     * @return int
     */
    public int getMgrID() {
        throw new Error(Error.GEN_UNIMPLEMENTED, "GetMgrID", this).getException();
    }

    /**
     * getNumAttrs<p>
     * GetNumAttrs<br>
     *     The GetNumAttrs method is used to get the number of attributes of a<br>
     *     given kind.  The kinds which can be requests are simple attributes.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BusinessQuery class uses it internally.<br>
     * <p>
     *     kind<br>
     *       The kind parameter specifies what kind of attributes are of<br>
     *       interest.  Legal values are:<br>
     * <p>
     *       Value      Meaning<br>
     *       -----      -------<br>
     *       ATTR_KEY    Return the number of attributes which comprise the<br>
     *               key.  Note: the key attributes must be the FIRST<br>
     *               ATTR_KEY attributes (i.e. 1 to ATTR_KEY).<br>
     *       ATTR_DB      Return the number of database attributes.<br>
     *       ATTR_SIMPLE    Return the number of simple attributes.<br>
     *       ATTR_FOREIGN  Return the number of foreign attributes.<br>
     *       Anything else  Return 0.<br>
     * <p>
     *     Returns<br>
     *       The return value specifies the number of attributes this entity<br>
     *       has of the kind specified by the kind parameter.<br>
     * <p>
     * @param kind Type: int (Input) (default in Forte: 0)
     * @return int
     */
    public int getNumAttrs(int kind) {
        return 0;
    }
   
    /**
     * qq_getNumTables<p>
     * Method renamed by jcTOOL from GetNumTables to qq_getNumTables
     * because it conflicted with an attribute<p>
     * <p>
     * @return int
     */
    public int qq_getNumTables() {
        return 1;
    }

    // Method GetOperation() : integer skipped because it is replaced by accessor / mutator.
    /**
     * getOrderConstraints<p>
     * GetOrderConstraints<br>
     *     The GetOrderConstraints method gets all the "order by" constraints<br>
     *     from the BusinessQuery and the closure of all foreign BusinessQueries<br>
     *     of multiplicity  one.  The constraints are ordered such that any<br>
     *     "order by" constraint with position N is placed before any "order by"<br>
     *     constraint with position N+m, where m > 0.  Also any "order by"<br>
     *     constraint with no position (i.e. position < 0) are placed immediately<br>
     *     following the previous "order by" constraint with a position.  The<br>
     *     order of the "order by" constraints on the constraint stack is<br>
     *     changed to effect this ordering.<br>
     * <p>
     *     Returns<br>
     *       An ordered array of ConstraintAttr nodes.  The attr attribute is<br>
     *       negated for any "order by ... desc" constraints.<br>
     * <p>
     * @return Array_Of_ConstraintAttr<ConstraintAttr>
     */
    @SuppressWarnings("unchecked")
  public Array_Of_ConstraintAttr<ConstraintAttr> getOrderConstraints() {
        if (this.getExecuteInfo().getOrderBy() == null) {

            Array_Of_Object<Object> orderBy = new Array_Of_Object<Object>();
            // Array of Array of ConstraintAttr;
            Array_Of_BusinessQuery<BusinessQuery> queries = new Array_Of_BusinessQuery<BusinessQuery>();
            BusinessQuery q = null;
            int i = 0, j = 0, pos = 0;
            int insertAt = 1;
            Array_Of_ConstraintAttr<ConstraintAttr> temp = null;

            queries.add(this);

            j = 1;

            while (j <= queries.size()) {
                q = queries.get(j-1);

                //
                //  Add in any joined queries.
                //
                Array_Of_BusinessQuery<BusinessQuery> qq_localVector = q.getForeignClasses();
                if (qq_localVector != null) {
                    for (BusinessQuery fq : qq_localVector) {
                        if ((fq.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_JOINED) > 0) {
                            queries.add(fq);
                        }
                    }
                }

                //
                //  Now pull out all "order by" constraints and insert them into our
                //  ordered "order by" list.
                //
                if (q.getConstraint() != null) {
                    i = 2;
                    while (i <= q.getConstraint().getStack().size()) {
                        if (q.getConstraint().getStack().get(i-1) instanceof ConstraintOperation && ((((ConstraintOperation)(q.getConstraint().getStack().get(i-1))).getOperation()&ConstraintOperation.TYPE_MASK) == ConstraintOperation.TYPE_ORDERBY)) {
                            pos =  -1;
                            if (i > 2 && q.getConstraint().getStack().get(i-2-1) instanceof ConstraintValue) {
                                pos = ((IntegerData)((ConstraintValue)(q.getConstraint().getStack().get(i-2-1))).getValue()).getValue();
                                q.getConstraint().getStack().deleteRow(i-2- 1);
                                i = i-1;
                            }
                            if (pos > 0) {
                                insertAt = pos+1;
                            }
                            if (orderBy.get(insertAt-1) == null) {
                                orderBy.set(insertAt-1, new Array_Of_ConstraintAttr<ConstraintAttr>());
                            }
                            if (((ConstraintOperation)(q.getConstraint().getStack().get(i-1))).getOperation() == ConstraintOperation.OP_ORDERBY_DESC) {
                                ((ConstraintAttr)(q.getConstraint().getStack().get(i-1-1))).setAttr( -((ConstraintAttr)(q.getConstraint().getStack().get(i-1-1))).getAttr());
                            }
                            temp = (Array_Of_ConstraintAttr)(orderBy.get(insertAt-1));
                            temp.add((ConstraintAttr)q.getConstraint().getStack().get(i-1-1));
                            q.getConstraint().getStack().deleteRow(i- 1);
                            q.getConstraint().getStack().deleteRow(i-1- 1);
                            i = i-2+1;
                        }
                        i = i+1;
                    }
                }

                j = j+1;

            }

            //
            //  Now we flatten the 2-level orderby array into a simple 1-level array
            //  and put the constraints back on the constraint stack.
            //
            this.getExecuteInfo().setOrderBy(new Array_Of_ConstraintAttr<ConstraintAttr>());
            if (orderBy != null) {
                for (Object oa : orderBy) {
                    if (this.getConstraint() == null) {
                        this.setConstraint(new QueryConstraint());
                    }
                    temp = (Array_Of_ConstraintAttr)oa;
                    if (temp != null) {
                        for (ConstraintAttr ob : temp) {
                            this.getExecuteInfo().getOrderBy().add(ob);
                            if (ob.getAttr() < 0) {
                                this.getConstraint().addAttr(ob.getEntity(),  -ob.getAttr(), 1);
                                this.getConstraint().addOperation(ConstraintOperation.OP_ORDERBY_DESC);
                            }
                            else {
                                this.getConstraint().addAttr(ob.getEntity(), ob.getAttr(), 1);
                                this.getConstraint().addOperation(ConstraintOperation.OP_ORDERBY);
                            }
                        }
                    }
                }
            }

        }

        return this.getExecuteInfo().getOrderBy();
    }

    /**
     * getQuery<p>
     * GetQuery<br>
     *     The GetQuery method is used to get the BusinessQuery associated with<br>
     *     the foreign or dependent attribute specified by the attr parameter.<br>
     *     This will be the BusinessQuery first passed in the AddAttr method<br>
     *     for this attribute.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, it is<br>
     *     used internally.<br>
     * <p>
     *     attr<br>
     *       The attr parameter specifies for which attribute the associated<br>
     *       BusinessQuery should be returned.  It should be for either a<br>
     *       foreign or dependent entity.<br>
     * <p>
     *     Returns<br>
     *       The return value specifies the BusinessQuery which is associated<br>
     *       with the attribute specified by the attr parameter.<br>
     * <p>
     * @param attr Type: int
     * @return BusinessQuery
     */
    public BusinessQuery getQuery(int attr) {
        if (attr <= BusinessQuery.ATTR_FOREIGN) {

            throw new Error(Error.BQ_ATTR_NOT_FOREIGN, "GetQuery", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else {

            if (this.getForeignClasses() != null) {
                for (BusinessQuery q : this.getForeignClasses()) {
                    if (q.getParentAttr() == attr) {
                        return q;
                    }
                }
            }

        }

        return null;
    }

    /**
     * getSqlQuery<p>
     * <p>
     * @param dBSession Type: DBConnectionManager (Input) (default in Forte: NIL)
     * @return SqlQuery
     */
    public SqlQuery getSqlQuery(DBConnectionManager dBSession) {
        return new SqlQuery().setup(this, this.operation, dBSession);
    }
   
    /**
     * getSqlQuery<p>
     * <p>
     * @return SqlQuery
     */
    public SqlQuery getSqlQuery() {
      return this.getSqlQuery(null);
    }   

    /**
     * getTableName<p>
     * GetTableName<br>
     *     The GetTableName method is used to get the table names in<br>
     *     the underlying database which holds the business class.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     SQLquery class uses it to create the text of the query.<br>
     * <p>
     *     tableIndex<br>
     *       The tableIndex parameter indicates for which of the tables that<br>
     *       comprise this BusinessClass the should be returned.<br>
     * <p>
     *     tableName<br>
     *       The tableName parameter returns the name of the table in the<br>
     *       database indicated by the tableIndex parameter.<br>
     * <p>
     * @param tableIndex Type: int
     * @param tableName Type: TextData
     */
    public void getTableName(int tableIndex, ParameterHolder_TextData tableName) {
        throw new Error(Error.BQ_ILLEGAL_TABLE_INDEX, "GetTableName", this, new IntegerData(tableIndex), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }

    /**
     * getUpdateAttr<p>
     * GetUpdateAttr<br>
     *     Use GetUpdateAttr when you want to retrieve the new value of an<br>
     *     attribute from a BusinessQuery's Values stack based upon the attribute's<br>
     *     attribute index.  For an insert this will be the value being inserted,<br>
     *     for an update this will be the new value to which the attribute will<br>
     *     be set.<br>
     * <p>
     *     attr<br>
     *       An index identifying which attribute to return.  There is a<br>
     *       constant for each attribute of the entity.  If the attribute<br>
     *       requested has not been updated (i.e. no LogAttr has been done)<br>
     *       then a NIL object will be returned.<br>
     * <p>
     * @param attr Type: int
     * @return DataValue
     */
    public DataValue getUpdateAttr(int attr) {
        if (this.getValues() != null) {
            for (int i = this.getValues().getStack().size(); i >= 2; i--) {
                if (this.getValues().getStack().get(i-1) instanceof ConstraintAttr && (((ConstraintAttr)(this.getValues().getStack().get(i-1))).getAttr() == attr) && this.getValues().getStack().get(i-1-1) instanceof ConstraintValue) {
                    return ((ConstraintValue)(this.getValues().getStack().get(i-1-1))).getValue();
                }
            }
        }

        return null;
    }

    /**
     * hasAttr<p>
     * HasAttr<br>
     *     The HasAttr method returns TRUE if the attribute indicated by the attr<br>
     *     parameter has been selected with the AddAttr method and FALSE otherwise.<br>
     *     If the attr parameter is 0 then HasAttr returns TRUE if any attribute<br>
     *     has been selected.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index indicating which attribute<br>
     *       to check.  If attr is 0 then HasAttr checks for any attribute.<br>
     * <p>
     * @param attr Type: int (Input) (default in Forte: 0)
     * @return boolean
     */
    public boolean hasAttr(int attr) {
        if (attr < 0) {

            throw new Error(Error.BQ_ILLEGAL_ATTR, "HasAttr", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else if (attr == 0) {

            if (this.getTargetAttrs() != null) {
                for (IntegerData i : this.getTargetAttrs()) {
                    if (i.getValue() > 0) {
                        return true;
                    }
                }
            }

        }
        else if (attr < BusinessQuery.ATTR_FOREIGN) {

            int wordindex = (attr-1)/31+1;
            int bitmask = (int)new DoubleData().power(2, attr-(wordindex-1)*31-1).getValue();

            if (this.getTargetAttrs() != null) {
                if (wordindex <= this.getTargetAttrs().size()) {
                    if ((this.getTargetAttrs().get(wordindex-1).getValue()&bitmask) > 0) {
                        return true;
                    }
                }
            }

        }
        else {

            if (this.getForeignClasses() != null) {
                for (BusinessQuery f : this.getForeignClasses()) {
                    if (f.getParentAttr() == attr) {
                        return true;
                    }
                }
            }

        }

        return false;
    }

    /**
     * newArray<p>
     * NewArray<br>
     *     The NewArray method is used by the SQLselect method when new<br>
     *     BusinessClass arrays of the custom subclass need to be created.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     Returns<br>
     *       A new BusinessClass array of the custom subclass.<br>
     * <p>
     * @return Array_Of_BusinessClass<BusinessClass>
     */
    public Array_Of_BusinessClass<BusinessClass> newArray() {
        throw new Error(Error.GEN_UNIMPLEMENTED, "NewArray", this).getException();
    }

    /**
     * newClass<p>
     * NewClass<br>
     *     The NewClass method is used by the SQLselect method when new<br>
     *     BusinessClasses of the custom subclass need to be created.<br>
     * <p>
     *     This method will be overridden by the query's generated class.<br>
     * <p>
     *     Returns<br>
     *       A new BusinessClass of the custom subclass.<br>
     * <p>
     * @return BusinessClass
     */
    public BusinessClass newClass() {
        throw new Error(Error.GEN_UNIMPLEMENTED, "NewClass", this).getException();
    }

    /**
     * newQuery<p>
     * NewQuery<br>
     *     The NewQuery method is used to create a BusinessQuery for<br>
     *     the foreign attribute specified by the attr parameter.<br>
     * <p>
     *     attr<br>
     *       The attr parameter specifies which kind of BusinessQuery should be<br>
     *       returned.  It should be for a foreign BusinessClass.<br>
     * <p>
     *     Returns<br>
     *       The return value is the BusinessQuery for the attribute specified<br>
     *       by the attr parameter.<br>
     * <p>
     * @param attr Type: int (Input) (default in Forte: 0)
     * @return BusinessQuery
     */
    public BusinessQuery newQuery(int attr) {
        throw new Error(Error.GEN_UNIMPLEMENTED, "NewQuery", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();
    }
    /**
     * Same as {@link #newQuery(int) with default value.
     * @return
     */
    public BusinessQuery newQuery() {
      return newQuery(0);
    }

    /**
     * processJoins<p>
     * <p>
     */
    public void processJoins() {
        if ((this.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_BUILT) > 0) {
            return;
        }

        //
        //  Check for 1-1 associations
        //
        if (this.getForeignClasses() != null) {
            for (BusinessQuery fe : this.getForeignClasses()) {
                if ((fe.getParentMult()&BusinessQuery.ASSOC_MULT_TO_ONE) > 0) {
                    if (fe.getConstraint() == null || fe.getConstraint().getOperation(ConstraintOperation.OP_NO_JOIN) == 0) {
                        //
                        // Let's join it!
                        //
                        fe.getExecuteInfo().setStatus(fe.getExecuteInfo().getStatus()|QueryExecuteInfo.ST_JOINED);
                        fe.getExecuteInfo().setSqlQuery(this.getExecuteInfo().getSqlQuery());
                        fe.processJoins();
                    }
                }
            }
        }

        //
        //  Check for optional associations
        //
        if ((this.getExecuteInfo().getSqlQuery().getOptions()&SqlQuery.OPT_NO_OUTER_JOIN) == 0) {
            if (this.getForeignClasses() != null) {
                checkOptionalAssoc:
                for (BusinessQuery fe : this.getForeignClasses()) {
                    if ((fe.getParentMult()&BusinessQuery.ASSOC_MULT_OPTIONAL) > 0 && (fe.getConstraint() == null || fe.getConstraint().getOperation(ConstraintOperation.OP_NO_JOIN) == 0)) {
                        // 
                        //  Need to check that the foreign class doesn't do a
                        //  one-to-one association with another class.  If it
                        //  does we don't want to process it now.  We'll wait
                        //  and get the two foreign classes done together when
                        //  SelectForeign is called.
                        //
                        Array_Of_BusinessQuery<BusinessQuery> qq_localVector = fe.getForeignClasses();
                        if (qq_localVector != null) {
                            for (BusinessQuery fefe : qq_localVector) {
                                if ((fefe.getParentMult()&BusinessQuery.ASSOC_MULT_TO_ONE) > 0) {
                                    continue checkOptionalAssoc;
                                }
                            }
                        }
                        //
                        // Let's join it!
                        //
                        fe.getExecuteInfo().setStatus(fe.getExecuteInfo().getStatus()|QueryExecuteInfo.ST_JOINED);
                        fe.getExecuteInfo().setSqlQuery(this.getExecuteInfo().getSqlQuery());
                        //
                        //  If we can handle transitive outer joins (one table outer
                        //  joined to another which is, in turn, outer joined to
                        //  another) then go do those.
                        //
                        if ((this.getExecuteInfo().getSqlQuery().getOptions()&SqlQuery.OPT_NO_TRANSITIVE_OUTER_JOIN) == 0) {
                            fe.processJoins();
                        }
                    }
                }
            }
        }
    }

    /**
     * removeAttr<p>
     * RemoveAttr<br>
     *     The RemoveAttr method is used to remove attributes previously specified<br>
     *     which should no longer be returned in a BusinessClass.  This is the<br>
     *     inverse of AddAttr.  If the attribute requested is a foreign<br>
     *     BusinessClass then the BusinessQuery originally used in the AddAttr<br>
     *     for this attribute must be provided.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index which specifies an<br>
     *       attribute which should be removed.<br>
     * <p>
     * @param attr Type: int
     */
    public void removeAttr(int attr) {
        if (attr < BusinessQuery.ATTR_FOREIGN) {

            //
            //  It is a simple attribute, just add it to the TargetAttrs array.
            //

            if (attr < 0) {

                throw new Error(Error.BQ_ILLEGAL_ATTR, "RemoveAttr", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

            }
            else if (attr == BusinessQuery.ATTR_SIMPLE) {

                this.setTargetAttrs(null);

            }
            else {

                int row = (attr-1)/31+1;
                int mask = (int)new DoubleData(2).power((attr-1) % 31).getValue();
                if (row <= this.getTargetAttrs().size()) {
                    this.getTargetAttrs().get(row-1).setValue(this.getTargetAttrs().get(row-1).getValue()&~mask);
                }

            }

        }
        else {
            //
            //  It is a foreign attribute.
            // 
            if (this.getForeignClasses() != null) {


              for (Iterator<BusinessQuery> iterator = this.getForeignClasses().iterator(); iterator
            .hasNext();) {
                BusinessQuery businessQuery = (BusinessQuery) iterator.next();
                    if (businessQuery.getParentAttr() == attr) {
                        this.getForeignClasses().deleteRow(businessQuery);
                        return;
                    }
        }
            }

        }
    }

    /**
     * reset<p>
     * Reset<br>
     *     The Reset method is used to clear the constraint for a BusinessQuery<br>
     *     which is used for a select.<br>
     * <p>
     */
    public void reset() {
        if (this.operation != BusinessQuery.OP_SELECT) {
            throw new Error(Error.BQ_CANT_RESET, "Reset", this).getException();
        }
        else {
            this.setConstraint(null);
        }
    }

    /**
     * returnSqlQuery<p>
     * <p>
     * @param dBSession Type: DBConnectionManager (Input) (default in Forte: NIL)
     * @return SqlQuery
     */
    public SqlQuery returnSqlQuery(DBConnectionManager dBSession) {
        if (this.getExecuteInfo().getSqlQuery() == null) {
            this.getExecuteInfo().setSqlQuery(this.getSqlQuery(dBSession));
        }

        return this.getExecuteInfo().getSqlQuery();
    }

    /**
     * sendClassOnUpdate<p>
     * SendClassOnUpdate<br>
     *     The SendClassOnUpdate method returns TRUE if the updated BusinessClass<br>
     *     should be sent to the BusinessMgr on an Update request, and FALSE if it<br>
     *     should not.  Normally only a BusinessQuery describing how to change<br>
     *     the underlying database to track the changes made to the BusinessClass<br>
     *     is sent to the BusinessMgr.  If SendClassOnUpdate option was requested<br>
     *     in the business model for this class then this method will be<br>
     *     overridden in the generated class with one which returns TRUE.<br>
     * <p>
     * @return boolean
     */
    public boolean sendClassOnUpdate() {
        return false;
    }

    /**
     * setAttrs<p>
     * SetAttrs<br>
     *     The SetAttrs method is used to set the attributes of a BusinessClass<br>
     *     from the data returned in a dataset by the database.<br>
     * <p>
     *     SetAttrs invokes itself recursively to set attributes in foreign<br>
     *     entities.<br>
     * <p>
     *     NOTE:  You don't normally need to call this method directly, the<br>
     *     BusinessMgr's Select method uses it.<br>
     * <p>
     *     source<br>
     *       The source parameter specifies the BusinessClass whose attributes<br>
     *       should be set.<br>
     * <p>
     *     data<br>
     *       The data paramters contains the data returned from the database.<br>
     * <p>
     *     index<br>
     *       The index parameter specifies which column in the data parameter<br>
     *       was last retrieved.  To retrieve the next value we always increment<br>
     *       the index.<br>
     * <p>
     * @param source Type: BusinessClass
     * @param data Type: DBDataSet
     * @param index Type: int
     */
    public void setAttrs(BusinessClass source, DBDataSet data, ParameterHolder_integer index) {
        int attrs = 0;
        int attrIndex = 0;
        int baseIndex = 1;
        int lNumDBAttrs = this.getNumDBAttrs();
        // local copy of virtual attribute

        if (this.getTargetAttrs() != null) {
            for (IntegerData attr : this.getTargetAttrs()) {
                attrs = attr.getValue();
                attrIndex = baseIndex;
                while ((attrs > 0) && (attrIndex <= lNumDBAttrs)) {
                    if ((attrs&1) > 0) {
                        index.setInt(index.getInt()+1);
                        // TF:Aug 13, 2008:Refactored this to compensate for the case where the string is NULL. This
                        // throws an exception if you set null on a doublenullable for instance, but doesn't seem to
                        // in the Forte DB.setValue() method
                        //source.newAttr(attrIndex).setValue(data.getResultSet().getString(index.getInt()));
                        // AD:12/11/2008: Kintetsu needs to keep the same scale if it is a DecimalData as the source
                        // Added the Below condition to over come the rounding issue if the attribute is of type MoneyDomain. Becuase by default
                        // the values are getting round to the default scale.
                        if(source.newAttr(attrIndex) instanceof DecimalData){
                          ((DecimalData)source.newAttr(attrIndex)).setValue(data.getResultSet().getDataValue(index.getInt()), true);
                        }else{
                          source.newAttr(attrIndex).setValue(data.getResultSet().getDataValue(index.getInt()));
                        }
                        // Mouli - 01, Oct - End
                    }
                    attrs = attrs/2;
                    attrIndex = attrIndex+1;
                }
                baseIndex = baseIndex+31;
            }
        }

        //
        //  Set the Key attribute of the BusinessClass from the attributes
        //  which comprise the key.
        //
        source.setKey(false);

        //
        //  And finally we get all requested foreign entities.
        //
        BusinessClass fe = null;

        if (this.getForeignClasses() != null) {
            for (BusinessQuery q : this.getForeignClasses()) {

                if ((q.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_JOINED) > 0) {

                    //
                    //  First instantiate the foreign attribute, this returns us the foreign
                    //  source which will need to have its values filled in.
                    //
                    // ------------------------------
                    // Parameters for call to NewAttr
                    // ------------------------------
                    ParameterHolder_BusinessClass qq_value = new ParameterHolder_BusinessClass();
                    source.newAttr(q.getParentAttr(), qq_value);
                    fe = (BusinessClass)qq_value.getObject();

                    //
                    //  We are now allowing all associated records to be read/write
                    //
                    fe.setInstanceStatus(BusinessClass.ST_READWRITE);

                    //
                    //  SetAttrs on the foreign source will fill it in from where we left off
                    //  (index) in the dataset.
                    //
                    // -------------------------------
                    // Parameters for call to SetAttrs
                    // -------------------------------
                    ParameterHolder_integer qq_index = new ParameterHolder_integer(index.getInt());
                    q.setAttrs(fe, data, qq_index);
                    index.setInt(qq_index.getInt());

                    //
                    //  If this is an optional foreign attribute then we check that the
                    //  record really existed.  If it didn't we delete the class.  We
                    //  make the existance check by looking for a non-NULL key.
                    //
                    if ((q.getParentMult()&BusinessQuery.ASSOC_MULT_OPTIONAL) > 0) {
                        if (fe.getInstanceKey().getValues().size() == 0) {
                            source.setAttr(q.getParentAttr(), (BusinessClass)(null));
                        }
                    }

                }

            }
        }
    }

    /**
     * setOperation<p>
     * SetOperation<br>
     *     The SetOperation method sets operation which this query is<br>
     *     going to perform.  SetOperation should be called before any other<br>
     *     method and should only be used once.  Thus a BusinessQuery can be used<br>
     *     for one and only one operation.<br>
     * <p>
     *     operation<br>
     *       The operation parameter specifies which operation this query<br>
     *       should perform.  Legal values are:  OP_SELECT, OP_INSERT,<br>
     *       OP_UPDATE, or OP_DELETE.<br>
     * <p>
     *     key<br>
     *       The key parameter specifies the key of the BusinessClass which<br>
     *       you are updating.  The key parameter should be passed for the<br>
     *       operations:  OP_INSERT, OP_UPDATE, or OP_DELETE, but should not<br>
     *       be passed for OP_SELECT operations.<br>
     * <p>
     * @param operation Type: int
     * @param key Type: BusinessKey (Input) (default in Forte: NIL)
     */
    public void setOperation(int operation, BusinessKey key) {
        if (operation == this.operation && (key == null || key == this.getKey())) {
            return;
        }

        if ((this.operation != BusinessQuery.OP_SELECT) && (this.operation != BusinessQuery.OP_NONE) && (this.operation != BusinessQuery.OP_UPDATE || operation != BusinessQuery.OP_DELETE)) {

            throw new Error(Error.BQ_CANT_RESET_OP, "SetOperation", this, new IntegerData(this.operation), new IntegerData(operation)).getException();

        }
        else {
            switch (operation) {

                case BusinessQuery.OP_SELECT: {
                    if (key != null) {
                        throw new Error(Error.BQ_SETOP_NO_KEY_ON_SELECT, "SetOperation", this).getException();
                    }

                    break;
                }
                case BusinessQuery.OP_INSERT: {
                    if (key != null) {
                        throw new Error(Error.BQ_SETOP_NO_KEY_ON_INSERT, "SetOperation", this).getException();
                    }

                    break;
                }
                case BusinessQuery.OP_NONE: {
                    if (key != null) {
                        throw new Error(Error.BQ_SETOP_NO_KEY_ON_INSERT, "SetOperation", this).getException();
                    }

                    break;
                }
                case BusinessQuery.OP_DELETE: {
                    if (key == null) {
                        throw new Error(Error.BQ_SETOP_NEED_KEY_FOR_UPDATE, "SetOperation", this).getException();
                    }

                    break;
                }
                case BusinessQuery.OP_UPDATE: {
                    if (key == null) {
                        throw new Error(Error.BQ_SETOP_NEED_KEY_FOR_UPDATE, "SetOperation", this).getException();
                    }

                    break;
                }

                default: {
                    throw new Error(Error.BQ_ILLEGAL_OPERATION, "SetOperation", this).getException();

                }
            }
        }

        this.operation = operation;
        this.setKey(key);
    }
    /**
     * Same as {@link #setOperation()} with default key of null.
     * @param operation
     */
    public void setOperation(int operation) {
      this.setOperation(operation, null);
    }

    /**
     * setValue<p>
     * SetValue<br>
     *     The SetValue method is used to set the values of attributes for<br>
     *     BusinessClasses being updated or inserted.<br>
     * <p>
     *     SetValue pushes the value, attribute, and operation onto the<br>
     *     Values stack.<br>
     * <p>
     *     attr<br>
     *       The attr parameter is an attribute index specifying an attribute<br>
     *       whose value should be set.<br>
     * <p>
     *     value<br>
     *       The value parameter specifies the value to which the attribute<br>
     *       should be set.<br>
     * <p>
     * @param attr Type: int
     * @param value Type: DataValue
     */
    public void setValue(int attr, DataValue value) {
        if (attr > this.getNumAttrs()) {

            throw new Error(Error.BQ_ILLEGAL_ATTR, "SetValue", this, new IntegerData(attr), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else if ((this.operation != BusinessQuery.OP_UPDATE) && (this.operation != BusinessQuery.OP_INSERT)) {

            throw new Error(Error.BQ_ILLEGAL_ACTION_FOR_OP, "SetValue", this, new IntegerData(this.operation), Error.qq_Resolver.cERROR_METHODNAME_ORIGINATOR_PARAM1).getException();

        }
        else if (this.getValues() == null) {

            this.setValues(new QueryConstraint());

        }

        this.getValues().addValue(value);
        this.getValues().addAttr(this, attr, 1);
        this.getValues().addOperation(ConstraintOperation.OP_EQ);
    }

    /**
     * setValueTemplate<p>
     * SetValueTemplate<br>
     *     Perform a SetValue on "type"; use a template, if one is given.<br>
     * <p>
     * @param type Type: DataValue
     * @param value Type: DataValue
     * @param templateText Type: TextData
     */
    public void setValueTemplate(DataValue type, DataValue value, TextData templateText) {
        if (templateText != null) {
            if (type instanceof DateTimeData) {
                type.decodeValue(value.getTextValue(), new DateFormat(templateText));
            }
            else if (type instanceof NumericData) {
                type.decodeValue(value.getTextValue(), new NumericFormat(templateText));
            }
            else if (type instanceof TextData) {
                type.decodeValue(value.getTextValue(), new TextFormat(templateText, qq_Resolver.cTEMPLATE));
            }
            else {
                type.setValue(value);
            }
        }
        else {
            type.setValue(value);
        }
    }
// end class BusinessQuery
// c Pass 2 Conversion Time: 7016 milliseconds
TOP

Related Classes of Express.services.BusinessQuery

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.