Package Express.services

Source Code of Express.services.BusinessDBMgr

/*
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.io.ObjectStreamException;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Hashtable;

import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator;

import DisplayProject.binding.beans.Observable;
import Express.services.interfaces.IBusinessMgr;
import Framework.Array_Of_DataValue;
import Framework.Array_Of_TextData;
import Framework.CloneHelper;
import Framework.DataValue;
import Framework.DoubleData;
import Framework.ErrorMgr;
import Framework.EventManager;
import Framework.IntegerData;
import Framework.NumericFormat;
import Framework.ParameterHolder;
import Framework.ParameterHolder_TextData;
import Framework.ParameterHolder_integer;
import Framework.RemoteEvent;
import Framework.RemoteEventProxy;
import Framework.RuntimeProperties;
import Framework.ServiceObjectContext;
import Framework.TextData;
import Framework.UsageException;
import Framework.anchored.Anchorable;
import Framework.anchored.AnchoredProxy;
import Framework.anchored.ServiceInvoker;
import Framework.remoting.parameters.Input;
import GenericDBMS.Constants;
import GenericDBMS.DBConnectionManager;
import GenericDBMS.DBDataSet;

/**
* The BusinessDBMgr class defines methods for retrieving and updating data through the DBSession object. The commands accepted by the BusinessDBMgr are BusinessQuery objects. The data returned by the BusinessDBMgr are BusinessClass objects.
* <p>
* @author ITerative Consulting
* @since  26-Feb-2008
*/
@RuntimeProperties(isDistributed=true, isAnchored=true, isShared=false, isTransactional=false)
public class BusinessDBMgr
        extends BusinessMgr
        implements Serializable, Observable, Anchorable
{

    // ----------
    // Attributes
    // ----------
    private DBConnectionManager dB;
    private Array_Of_IBusinessMgr<IBusinessMgr> foreignMgrs;
    private SqlStatementCache statementCache;
    /**
     * The flag to use for "isAnchored" and the listener for remote requests
     */
    protected ServiceInvoker invoker = null;

    // ------------
    // Constructors
    // ------------
    public BusinessDBMgr() {
        this(true);

    }

    public BusinessDBMgr(ServiceObjectContext pContext) {
    }

    public BusinessDBMgr(boolean pIsAnchored) {
        this.setIsAnchored(pIsAnchored);
    }

    // ----------------------
    // Accessors and Mutators
    // ----------------------
    public void setDB(DBConnectionManager dB) {
        this.dB = dB;
    }

    public DBConnectionManager getDB() {
        return this.dB;
    }

    public void setForeignMgrs(Array_Of_IBusinessMgr<IBusinessMgr> foreignMgrs) {
        this.foreignMgrs = foreignMgrs;
    }

  public void setForeignMgrs(Array_Of_BusinessMgr<IBusinessMgr> foreignMgrs) {
        this.foreignMgrs = (Array_Of_IBusinessMgr<IBusinessMgr>)foreignMgrs;
    }
    public Array_Of_IBusinessMgr<IBusinessMgr> getForeignMgrs() {
        return this.foreignMgrs;
    }

    public void setStatementCache(SqlStatementCache statementCache) {
        this.statementCache = statementCache;
    }

    public SqlStatementCache getStatementCache() {
        return this.statementCache;
    }

    public boolean getIsAnchored() {
        return invoker != null;
    }

    public void setIsAnchored(boolean isAnchored) {
        if (isAnchored && invoker == null) {
            // Anchor the object, creating an invoker for it.
            this.invoker = new ServiceInvoker(this);
        }
        else if (!isAnchored && invoker != null) {
            this.invoker = null;
        }
    }

    /**
     * Get the invoker for this class. This method should only be called from the proxy, hence the protected level visibility.
     */
    protected ServiceInvoker getInvoker(BusinessDBMgr pService) {
        return pService.invoker;
    }

    // -------
    // Methods
    // -------
    /**
     * executeSql<p>
     * ExecuteSql<br>
     *     The ExecuteSql method prepares and sends the SQL text contained in the<br>
     *     sqlText parameter to the DBSession.  Data used for placeholders in the<br>
     *     sqlText is passed in the sqlData parameter and bound to the statement<br>
     *     before execution.  The SqlQuery object used to generate the SQL text<br>
     *     is passed in sqlQuery for reference.  ExecuteSql can be used for<br>
     *     delete, insert, or update SQL statements, but not for select SQL<br>
     *     statements as these return result values with which ExecuteSql is not<br>
     *     prepared to deal.<br>
     * <p>
     *     Prior to preparing the SQL statement the StatementCache is checked.<br>
     *     If the desired statement is found then the prepare step is avoided<br>
     *     and the cached SQL statement may be executed with the new input<br>
     *     values provided in the sqlData parameter.  If the SQL statement is<br>
     *     not found in the cache then it is prepared and added to the cache.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter contains the SqlQuery object that generated<br>
     *       the sqlText being executed.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter contains the text of the SQL statement to<br>
     *       be executed.<br>
     * <p>
     *     sqlData<br>
     *       The sqlData parameter contains the input values for any<br>
     *       placeholders in the SQL statement.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param sqlText Type: TextData
     * @param sqlData Type: SqlData
     */
    @SuppressWarnings("unchecked")
  public void executeSql(@Input SqlQuery sqlQuery, @Input TextData sqlText, @Input SqlData sqlData) {
        try {
            @SuppressWarnings("unused")
      int cmdType = 0;
            SqlStatement statement = null;
            int affectedRows = 0;
   
            //  There is text returned for each table but if nothing needs to be done
            //  to this particular table it might be empty.  We only want to execute
            //  non-null queries so we check that now.
            //
            if (sqlText.getActualSize() <= 0) {
                return;
            }

   
            {
                statement = (SqlStatement)this.getStatementCache().find(sqlText);
   
                if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_UPDATE, 1, this, "SQLupdate")) {
                    if (statement != null) {
                        Logger.getLogger("task.part.logmgr").info("using cached statement: ");
                    }
                    if (this.getTrace().test(0, 0, Trace.ES_UPDATE, 50, (Object)null, (String)null)) {
                        Logger.getLogger("task.part.logmgr").info(this.formatSqlText(sqlText, sqlData));
                    }
                    else {
                        Logger.getLogger("task.part.logmgr").info(this.formatSqlText(sqlText, (SqlData)null));
                    }
                }
   
                if (statement == null) {
   
                    statement = new SqlStatement();
                    ParameterHolder qq_aTypeHolder = new ParameterHolder();
                    ParameterHolder qq_aColMapHolder = new ParameterHolder();
                    PreparedStatement qq_tempStatement = this.getDB().getDynamicStatement(
                                    sqlText.toString(), qq_aTypeHolder, qq_aColMapHolder);
                    cmdType = qq_aTypeHolder.getInt();
                    statement.setInputData(new DBDataSet(qq_tempStatement, (ArrayList)qq_aColMapHolder.getObject()));
                    statement.setHandle(qq_tempStatement);
   
                    this.getStatementCache().enter(statement, sqlText);
   
                }
   
                //  Now set the values we are updating or inserting as well as values
                //  for constraints.
                //
                for (int j = 1; j <= sqlData.getValues().size(); j++) {
                    statement.getInputData().setValue(j, sqlData.getValues().get(j-1));
                }
   
                int qq_rows;
                if (statement.getHandle().execute()) {
                    throw new UsageException("Statement execution resulted in a result set when an update counter was expected.");
                }
                else {
                    qq_rows = statement.getHandle().getUpdateCount();
                }
                affectedRows = qq_rows;
                if (affectedRows != 1 && sqlQuery.getQuery().getOriginalClass() != null) {
                    throw new Error(Error.CM_CLASS_CHANGED, "ExecuteSQL", this, sqlQuery.getQuery().getOriginalClass().getInstanceKey(), sqlQuery.getQuery().newClass()).getException();
                }
                else if (affectedRows == 0) {
                    throw new Error(Error.BM_NO_UPDATE, "ExecuteSQL", this, sqlQuery.getQuery().getKey(), sqlQuery.getQuery().newClass()).getException();
                }
   
                if (!(this.getStatementCache().getOn())) {
                    try {
                        statement.getHandle().close();
                    } catch (java.sql.SQLException qq_SQLEx) {
                        throw new SQLErrorCodeSQLExceptionTranslator().translate("SQL tasks", "", qq_SQLEx );
                    }
                }
   
            }
        }
        catch (SQLException e) {
            DataAccessException qq_dae = new SQLErrorCodeSQLExceptionTranslator().translate("SQL tasks", "", e );
            ErrorMgr.addError(e);
            ErrorMgr.addError(qq_dae);
            throw qq_dae;
        }
    }

    /**
     * formatSqlText<p>
     * FormatSqlText<br>
     *     The FormatSqlText method returns a Text object containing the text of<br>
     *     the SQL statement about to be executed and the input values for the<br>
     *     placeholders.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter specifies the text of the SQL statement about<br>
     *       to be executed.<br>
     * <p>
     *     sqlData<br>
     *       The sqlData parameter holds the input values used for the SQL<br>
     *       statement.<br>
     * <p>
     *     returns<br>
     *       The return value of the FormatSqlText method is a TextData object<br>
     *       whose value contains the SQL text and the input values formatted<br>
     *       into a printable string.<br>
     * <p>
     * @param sqlText Type: TextData
     * @param sqlData Type: SqlData (Input) (default in Forte: NIL)
     * @return TextData
     */
    public TextData formatSqlText(@Input TextData sqlText, @Input SqlData sqlData) {
        TextData str = new TextData();

        str.setValue( "running SQL <" );
        str.concat(sqlText);
        str.concat(">");
        if (sqlData != null) {
            if (sqlData.getValues().size() <= 0) {
                str.concat(" with no input values");
            }
            else {
                str.concat(" with input values: ");
                for (int i = 1; i <= sqlData.getValues().size(); i++) {
                    if (i > 1) {
                        str.concat(", ");
                    }
                    if (sqlData.getValues().get(i-1).getIsNull()) {
                        str.concat("<NULL>");
                    }
                    else if (sqlData.getValues().get(i-1) instanceof DoubleData && ((DoubleData)(sqlData.getValues().get(i-1))).getValue() < 1e+012 && ((DoubleData)(sqlData.getValues().get(i-1))).getValue() > 1e-012) {
                        str.concat(new NumericFormat(new TextData("#.############"), NumericFormat.qq_Resolver.cTEMPLATE).formatNumeric((DoubleData)(sqlData.getValues().get(i-1))));
                    }
                    else {
                        str.concat(sqlData.getValues().get(i-1).getClass().getSimpleName());
                        str.concat(":");
                        str.concat(sqlData.getValues().get(i-1));
                    }
                }
            }
        }

        return str;
    }

    /**
     * formatSqlText<p>
     * FormatSqlText<br>
     *     The FormatSqlText method returns a Text object containing the text of<br>
     *     the SQL statement about to be executed and the input values for the<br>
     *     placeholders.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter specifies the text of the SQL statement about<br>
     *       to be executed.<br>
     * <p>
     *     returns<br>
     *       The return value of the FormatSqlText method is a TextData object<br>
     *       whose value contains the SQL text and the input values formatted<br>
     *       into a printable string.<br>
     * <p>
     * @param sqlText Type: TextData
     * @return TextData
     */
    public TextData formatSqlText(@Input TextData sqlText) {
      return formatSqlText(sqlText, null);
    }

    /**
     * newKey<p>
     * NewKey<br>
     *     The NewKey method fills in the key attributes of a BusinessClass by<br>
     *     requesting one from its associated BusinessMgr.<br>
     * <p>
     *     source<br>
     *       The source parameter holds the BusinessClass which is to get a<br>
     *       new key.<br>
     * <p>
     * @param source Type: BusinessClass
     */
    public void newKey(@Input BusinessClass source) {
        throw new Error(Error.GEN_UNIMPLEMENTED, "NewKey", this).getException();
    }

    /**
     * select<p>
     * Select<br>
     *     The Select method builds and executes the SQL query described by<br>
     *     the query parameter.<br>
     * <p>
     *     query<br>
     *       The query parameter holds the BusinessQuery describing what should<br>
     *       be selected from the database.<br>
     * <p>
     * @param query Type: BusinessQuery
     * @return Array_Of_BusinessClass<BusinessClass>
     */
    public Array_Of_BusinessClass<BusinessClass> select(@Input BusinessQuery query) {
        Array_Of_BusinessClass<BusinessClass> result = null;
        SqlQuery sQLquery = query.returnSqlQuery(this.getDB());
        TextData str = null;

        query.processJoins();

    Array_Of_ConstraintAttr<ConstraintAttr> orderBy = query.getOrderConstraints();
        int lastInOrder = 0;

        for (int i = 1; i <= orderBy.size(); i++) {
            lastInOrder = orderBy.size();
            if (orderBy.get(i-1).getAttr() != i || orderBy.get(i-1).getEntity() != query) {
                lastInOrder = i-1;
                break;
            }
        }

        if (lastInOrder >= query.getNumKeyAttrs()) {
        }
        else if (lastInOrder == orderBy.size()) {
            for (int i = lastInOrder+1; i <= query.getNumKeyAttrs(); i++) {
                orderBy.add(new ConstraintAttr(i, query));
                query.addConstraint(i, ConstraintOperation.OP_ORDERBY, (DataValue)null);
            }
        }
        else {
            //
            //  We're not completely ordered by the primary key, we'll try to add
            //  order by constraints for the rest of the key attributes.  But we
            //  cannot add any that are already specified, and we will stop adding
            //  them if we find one out of order (e.g. if the third key attribute
            //  is ordered before the second key attribute).
            //
            int lastFound = lastInOrder;
            int itemsToCheck = orderBy.size();
            check:
            for (int i = lastInOrder+1; i <= query.getNumKeyAttrs(); i++) {
                for (int j = lastInOrder+1; j <= lastFound; j++) {
                    if ((orderBy.get(j-1).getAttr() >= i ||  -orderBy.get(j-1).getAttr() >= i) && orderBy.get(j-1).getEntity() == query) {
                        break check;
                    }
                }
                for (int j = lastFound+1; j <= itemsToCheck; j++) {
                    if (orderBy.get(j-1).getAttr() == i && orderBy.get(j-1).getEntity() == query) {
                        lastFound = j;
                        continue check;
                    }
                    else if ( -orderBy.get(j-1).getAttr() == i && orderBy.get(j-1).getEntity() == query) {
                        break check;
                    }
                }
                orderBy.add(new ConstraintAttr(i, query));
                query.addConstraint(i, ConstraintOperation.OP_ORDERBY, (DataValue)null);
                lastFound = itemsToCheck;
            }
        }

        //
        //  Build the SQL query that needs to be executed.  query describes what needs
        //  to be done in terms of the BusinessClass.  BuildQuery returns an SQLquery
        //  which describes what needs to be done in terms of SQL.
        //
        // ---------------------------------
        // Parameters for call to BuildQuery
        // ---------------------------------
        ParameterHolder_SqlQuery qq_query = new ParameterHolder_SqlQuery(sQLquery);
        query.buildQuery(qq_query);
        sQLquery = (SqlQuery)qq_query.getObject();

        str = sQLquery.getText().get(0);

        result = this.SQLselect(sQLquery, str, sQLquery.getData().get(0));

        query.getExecuteInfo().setStatus(query.getExecuteInfo().getStatus()|QueryExecuteInfo.ST_EXECUTED);

        if (result.size() > 0) {

            //
            //  Now we have to get any foreign classes that weren't joined in.
            //
            Array_Of_BusinessQuery<BusinessQuery> queries = new Array_Of_BusinessQuery<BusinessQuery>();
            queries.add(query);

            Array_Of_BusinessQuery<BusinessQuery> qq_localVector = query.getForeignClasses();
            if (qq_localVector != null) {
                for (BusinessQuery dep : qq_localVector) {
                    if (dep.hasAttr(0)) {
                        queries.set(1, dep);
                        BusinessDBMgr mgr = (BusinessDBMgr)(this.getForeignMgrs().get(query.getForeignAttrMgr(dep.getParentAttr())-1));
                        if (mgr == null) {
                            mgr = (BusinessDBMgr)this.getParentService().getMgr(dep);
                        }
                        mgr.selectForeign(sQLquery, result, queries, null);
                    }
                }
            }

        }

        return result;
    }

    /**
     * selectCorrelated<p>
     * SelectCorrelated<br>
     *     So far we have fetched all the independent and foreign BusinessClasses<br>
     *    that can be joined together (usually all the "to-one" associations).<br>
     *    Now we need to get all the foreign BusinessClasses that cannot be<br>
     *    joined-in ("to-many" associations and some optional associations) and<br>
     *     add them to the independent classes.  We do this by running queries for<br>
     *     each foreign class.  Dependending on the foreign key and the order<br>
     *     constraints on the primary we may be able to run just one query for<br>
     *     each foreign class using the query that generated the parent classes<br>
     *     as a constraint (in addition to any constraints on the foreign entities<br>
     *     themselves).  This will get us all the foreign  classes for all the<br>
     *     parent classes in one fell swoop (one query).  We then sort them out by<br>
     *     key and attach them to the appropriate parent classes.  A bit more work<br>
     *     for us but a lot fewer queries.  When we cannot run one query for the<br>
     *     foreign class then we have to run one query for each BusinessClass in<br>
     *     the result set using the values of the foreign key from the parent<br>
     *     BusinessClass as a constraint.<br>
     * <p>
     *     sqlQuery<br>
     *       The SqlQuery that generated the independent classes contained in<br>
     *       result.<br>
     * <p>
     *     result<br>
     *       The independent classes generated by sqlQuery.  These classes need<br>
     *       to have a foreign class attached as specified by the last item in<br>
     *       the queries  parameter.<br>
     * <p>
     *     queries<br>
     *       An array of BusinessQuerys.  queries[Items-1] contains the query<br>
     *       that generated the independent classes.  queries[Items] contains<br>
     *       the query we need to run to generated the foreign class.<br>
     * <p>
     *     orderBy<br>
     *       The ordering contraints used for the independent classes.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param result Type: Array_Of_BusinessClass<BusinessClass>
     * @param queries Type: Array_Of_BusinessQuery<BusinessQuery>
     * @param orderBy Type: Array_Of_ConstraintAttr<ConstraintAttr>
     */
    @SuppressWarnings("unchecked")
  public void selectCorrelated(@Input SqlQuery sqlQuery, @Input Array_Of_BusinessClass<BusinessClass> result, @Input Array_Of_BusinessQuery<BusinessQuery> queries, @Input Array_Of_ConstraintAttr<ConstraintAttr> orderBy) {
        BusinessQuery query = queries.get(queries.size()-1-1);
        BusinessQuery dep = queries.get(queries.size()-1);

        Array_Of_BusinessClass<BusinessClass> depResult = null;
        // The result set for the current
        //   dependent entity.
        int depRow = 0;
        // The row in depResult we are
        //   currently processing.
        Array_Of_BusinessClass<BusinessClass> depAttr = null;
        // The attribute of the independent
        //   entity that is the current
        //   dependent entity.
        // Describes the attributes that
        Array_Of_QueryAttrMap<QueryAttrMap> attrMap = null;
        //   join the independent entity
        //   to the dependent entity.
        int t = 0;
        // a table index
        TextData c = null;
        int maxRows = 0;

        orderBy = query.getExecuteInfo().getOrderBy();

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

        attrMap = query.getForeignAttrMap(dep.getParentAttr());

        boolean oneQuery = false;
        //
        //  Time to make the arduous test of whether or not we can run one query
        //  (we call this a collective query).  If we have already executed this
        //  query we use the answer we figured out the first time.  Otherwise we
        //  figure it out for ourselves.  We start by assuming no.  Basically the
        //  primary has to be ordered by the child's referencing key.  There are
        //  however a number of other conditions which can defeat this.
        //
        if ((dep.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_EXECUTED) > 0) {

            oneQuery = (dep.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_COLLECTIVE) > 0;

        }
        else if (queries.size() == 2 && result.size() > 1 && attrMap.size() <= orderBy.size() && (sqlQuery.getOptions()&SqlQuery.OPT_NO_COLLECTIVE) == 0 && (attrMap.size() <= 1 || (sqlQuery.getOptions()&SqlQuery.OPT_COLLECTIVE_FOR_ONE) == 0)) {

            oneQuery = true;

            for (int i = 1; i <= attrMap.size(); i++) {
                if (attrMap.get(i-1).getLocal() != orderBy.get(i-1).getAttr() || orderBy.get(i-1).getEntity() != query) {
                    oneQuery = false;
                    break;
                }
            }
            //
            //  So now we know the primary is ordered by the referencing key.
            //  Now we need to check that the child hasn't been ordered by
            //  something other than referencing key.
            //
            if (oneQuery) {
                Array_Of_ConstraintAttr<ConstraintAttr> depOrderBy = dep.getOrderConstraints();
                if (depOrderBy.size() > 0) {
                    maxRows = attrMap.size();
                    if (maxRows > depOrderBy.size()) {
                        maxRows = depOrderBy.size();
                    }
                    for (int i = 1; i <= maxRows; i++) {
                        if (attrMap.get(i-1).getForeign() != depOrderBy.get(i-1).getAttr() || depOrderBy.get(i-1).getEntity() != dep) {
                            oneQuery = false;
                            break;
                        }
                    }
                }
                if (oneQuery) {
                    //
                    //  Add order constraints for the foreign key so that the
                    //  foreign BusinessClasses come back in the same order as
                    //  the independent BusinessClasses.
                    //
                    if (attrMap.size() > depOrderBy.size()) {
                        for (int i = depOrderBy.size()+1; i <= attrMap.size(); i++) {
                            dep.addConstraint(attrMap.get(i-1).getForeign(), ConstraintOperation.OP_ORDERBY, (DataValue)null);
                        }
                        dep.getExecuteInfo().setOrderBy(null);
                        // force this to be re-computed.
                    }
                }
                else {
                    //
                    //  The child isn't ordered by the referencing key but we
                    //  may be able to prepend order constraints so that it
                    //  is.
                    //
                    oneQuery = true;
                    if (attrMap != null) {
                        for (QueryAttrMap attr : attrMap) {
                            if (depOrderBy != null) {
                                for (ConstraintAttr o : depOrderBy) {
                                    if (attr.getForeign() == o.getAttr() || o.getEntity() != dep) {
                                        oneQuery = false;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                    if (oneQuery) {
                        // prepend order constraints
                        for (int i = attrMap.size(); i >= 1; i--) {
                            dep.getConstraint().getStack().add(0, new ConstraintOperation(ConstraintOperation.OP_ORDERBY));
                            dep.getConstraint().getStack().add(0, new ConstraintAttr(attrMap.get(i-1).getForeign(), dep));
                        }
                        dep.getExecuteInfo().setOrderBy(null);
                        // force this to be re-computed.
                    }
                }
            }
        }

        if (!(oneQuery)) {

            DataValue val = null;

            if (result != null) {
                ProcessResult:
                for (BusinessClass entity : result) {

                    BusinessClass leafClass = entity;

                    for (int i = 2; i <= queries.size()-1; i++) {
                        // ------------------------------
                        // Parameters for call to GetAttr
                        // ------------------------------
                        ParameterHolder_BusinessClass qq_value = new ParameterHolder_BusinessClass();
                        leafClass.getAttr(queries.get(i-1).getParentAttr(), qq_value);
                        leafClass = (BusinessClass)qq_value.getObject();
                        if (leafClass == null) {
                            continue ProcessResult;
                        }
                    }

                    if (leafClass != null) {

                        //
                        //  The first time through we need to add the constraint to
                        //  restrict the result set to the current row in the parent
                        //
                        if (dep.getExecuteInfo().getDependentValues() == null) {
                            dep.getExecuteInfo().setDependentValues(new Array_Of_DataValue<DataValue>());
                            if (attrMap != null) {
                                for (QueryAttrMap attr : attrMap) {
                                    val = leafClass.getAttr(attr.getLocal());
                                    if (val == null) {
                                        throw new Error(Error.BM_NEED_FOREIGN_KEY, "SQLselect", this, new IntegerData(queries.get(queries.size()-1-1).getParentAttr()), new IntegerData(attr.getLocal())).getException();
                                    }
                                    val = CloneHelper.clone(val, false);
                                    dep.getExecuteInfo().getDependentValues().add(val);
                                    dep.addConstraint(attr.getForeign(), ConstraintOperation.OP_EQ, val);
                                }
                            }
                        }
                        else {
                            //
                            //  Need to set value for constraint to identify the current
                            //  row (leafClass)
                            //
                            for (int i = 1; i <= attrMap.size(); i++) {
                                dep.getExecuteInfo().getDependentValues().get(i-1).setValue(leafClass.getAttr(attrMap.get(i-1).getLocal()));
                            }
                        }

                        Array_Of_BusinessClass<BusinessClass> fresult = this.select(dep);

                        if ((query.getForeignAttrMult(dep.getParentAttr())&BusinessQuery.ASSOC_MULT_ONE_MASK) == 0) {
                            leafClass.setAttr(dep.getParentAttr(), fresult);
                        }
                        else {
                            if (fresult.size() > 1) {
                                throw new Error(Error.BM_TOO_MANY_ROWS, "SelectCorrelated", this, new TextData( leafClass.getClass().getSimpleName() ), new IntegerData(dep.getParentAttr())).getException();
                            }
                            else if (fresult.size() == 1) {
                                leafClass.setAttr(dep.getParentAttr(), fresult.get(0));
                            }
                        }
                    }

                }
            }

            return;

        }

        TextData queryText = new TextData();

        //
        //  Make sure the foreign query selects all the columns comprising the join key
        //
        if (attrMap != null) {
            for (QueryAttrMap attr : attrMap) {
                dep.addAttr(attr.getForeign(), (BusinessQuery)null);
            }
        }

        //
        //  Add a constraint for the independent query.  This will be of the form:
        //
        //    (myCol1, myCol2, ...) in (select HisCol1, HisCol2, ...)
        //
        //  So we are going to put an "in" constraint on the constraint stack.
        //  What the "in" operator expects is: N attributes (the myCol1, myCol2, ...
        //  part), followed by the select, followed by any input values needed
        //  by the select (remember the query we ran for the independent entities
        //  may have had constraints itself and those constraints will have needed
        //  input values).  So far so good.  Now on to the tricky stuff.  The
        //  original query that got the independent entities was selecting all
        //  sorts of stuff we don't need.  All we want it to select are the columns
        //  which join the tables for the independent entity to the tables for
        //  the dependent entity.  These columns are furnished for us by the
        //  GetForeignAttrMap method.  We do that by clearing the column list that
        //  was being selected and adding back just the columns we need.  But
        //  enough of the story, lets get on with the show ...
        //

        if ((dep.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_EXECUTED) != 0) {

            if (sqlQuery.getData().get(0).getValues().size() > 0) {
                dep.getExecuteInfo().getSqlQuery().setData(CloneHelper.clone(sqlQuery.getData(), true));
            }

            int limitAttr = orderBy.get(0).getAttr();
            if (limitAttr < 0) {
                limitAttr =  -limitAttr;
            }
            dep.getExecuteInfo().getSqlQuery().getData().get(0).getValues().add(result.get(result.size()-1).getAttr(limitAttr));

        }
        else {

            dep.getExecuteInfo().setStatus(dep.getExecuteInfo().getStatus()|QueryExecuteInfo.ST_COLLECTIVE);

            SqlQuery depQuery = CloneHelper.clone(sqlQuery, false);

            //  The original query might have returned many rows but been externally
            //  limited by our max rows constraint.  Put on an extra constraint that
            //  will simulate this so the poor DBMS doesn't have to create an
            //  inordinately large intermediate result.
            //
            depQuery.setData(CloneHelper.clone(depQuery.getData(), true));
            depQuery.setWhereClause(CloneHelper.clone(depQuery.getWhereClause(), true));
            int limitAttr = orderBy.get(0).getAttr();
            int op = ConstraintOperation.OP_LE;
            if (limitAttr < 0) {
                limitAttr =  -limitAttr;
                op = ConstraintOperation.OP_GE;
            }
            t = 1;
            // ------------------------------------
            // Parameters for call to GetColumnName
            // ------------------------------------
            ParameterHolder_integer qq_tableIndex = new ParameterHolder_integer(t);
            ParameterHolder_TextData qq_columnName = new ParameterHolder_TextData();
            query.getColumnName(limitAttr, qq_tableIndex, qq_columnName);
            t = qq_tableIndex.getInt();
            c = (TextData)qq_columnName.getObject();
            depQuery.addConstraint(t, c, op, result.get(result.size()-1).getAttr(limitAttr));

            //
            //  Since its a stack we push the last thing first, the input values.
            //
            if (depQuery.getData().get(0).getValues().size() > 0) {
                dep.getConstraint().addSqlData(depQuery.getData().get(0));
            }

            //  Now we need the text of the subselect.  The problem is we don't know
            //  what it is yet since we haven't done our fire drill with the columns
            //  yet.  Since object references are all pointers we can push the
            //  queryText object on now and fill in its value later when we know what
            //  it is.
            //
            dep.getConstraint().addValue(queryText);

            depQuery.clearColumnList();
            depQuery.setOrderClause(new TextData(""));

            //  Now we need to push our attributes on the constraint stack and add
            //  new columns to the subselect query which correspond to them.
            //
            //  attr.local will be the attribute in the independent class.
            //  attr.foreign will be the attribute in the dependent class.
            //
            if (attrMap != null) {
                for (QueryAttrMap attr : attrMap) {

                    //  Translate the attribute index to a tableIndex/columnName pair and
                    //  add it to the query for the subselect.
                    //
                    t = 1;
                    // ------------------------------------
                    // Parameters for call to GetColumnName
                    // ------------------------------------
                    ParameterHolder_integer qq_tableIndex1 = new ParameterHolder_integer(t);
                    ParameterHolder_TextData qq_columnName1 = new ParameterHolder_TextData();
                    query.getColumnName(attr.getLocal(), qq_tableIndex1, qq_columnName1);
                    t = qq_tableIndex1.getInt();
                    c = (TextData)qq_columnName1.getObject();
                    depQuery.addColumn(t, c, (DataValue)null);

                    //  Push our attribute (the myCol1, myCol2, ... thing) on the stack.
                    //
                    dep.getConstraint().addAttr(dep, attr.getForeign(), 1);

                }
            }

            //  End the mess with the "in" operator.
            //
            dep.getConstraint().addOperation(ConstraintOperation.OP_IN);

            //  Now that we have put all those new column names on the query we are
            //  ready to get the text of the query for the subselect.  queryText is
            //  the object we previously pushed on the constraint stack and so we
            //  set its value to the query text.  Before we get the query text we
            //  turn off the ForUpdate attribute if it was set since we only want
            //  the for update on the outer select not on the sub-select.
            //
            depQuery.setForUpdate(false);
            queryText.setValue( depQuery.getText().get(0) );

            //
            //  As a performance enhancement we check that the foreign key is the same
            //  as the Key attribute of the BusinessClass.  If that is the case
            //  then we can just use the key to compare against, otherwise we
            //  build the foreign key to compare against for each record.  We
            //  check on both the primary and foreign (dependent) sides.
            //

            dep.getExecuteInfo().setUseInstanceKey(true);
            if (query.getNumKeyAttrs() != attrMap.size()) {
                dep.getExecuteInfo().setUseInstanceKey(false);
            }
            else {
                for (int i = 1; i <= attrMap.size(); i++) {
                    if (attrMap.get(i-1).getLocal() != i) {
                        dep.getExecuteInfo().setUseInstanceKey(false);
                        break;
                    }
                }
            }

            dep.getExecuteInfo().setUseDependentKey(true);
            if (query.getNumKeyAttrs() < attrMap.size()) {
                dep.getExecuteInfo().setUseDependentKey(false);
            }
            else {
                for (int i = 1; i <= attrMap.size(); i++) {
                    if (attrMap.get(i-1).getForeign() != i) {
                        dep.getExecuteInfo().setUseDependentKey(false);
                        break;
                    }
                }
            }

        }

        BusinessKey instanceKey = null;
        if (!(dep.getExecuteInfo().getUseInstanceKey())) {
            instanceKey = new BusinessKey();
        }

        BusinessKey dependentKey = null;
        if (!(dep.getExecuteInfo().getUseDependentKey())) {
            dependentKey = new BusinessKey();
        }

        if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_SELECT, 255, this, "Select")) {
            Logger.getLogger("task.part.logmgr").info("Categorization: useInstanceKey = ");
            Logger.getLogger("task.part.logmgr").info( Boolean.toString(dep.getExecuteInfo().getUseInstanceKey()));
            Logger.getLogger("task.part.logmgr").info(", useForeignKey = ");
            Logger.getLogger("task.part.logmgr").info( Boolean.toString(dep.getExecuteInfo().getUseDependentKey()));
        }

        //  Now that we have got that extra little detail of the "in" constraint
        //  taken care of we are ready to run the query and get the results.  We
        //  find the dependent entity's manager and ask him to do that for us.
        //
        depResult = this.select(dep);

        depRow = 1;
        //
        //  depResult now contains all the dependent entities for all the
        //  independent entities.  We have to sort out the dependent entities
        //  and attach them to the right independent entity.  Fortunately they
        //  come back in key order so we can do it in
        //  one pass.  We go through the result list (the independent entities)
        //  and for each one we snarf up rows from depResult (the dependent
        //  entities) until we get one that is for some subsequent entity.
        //
        if (result != null) {
            for (BusinessClass entity : result) {

                //  Instantiate attribute in the independent entity that contains
                //  the dependent entities.
                //
                depAttr = null;
                if ((query.getForeignAttrMult(dep.getParentAttr())&BusinessQuery.ASSOC_MULT_ONE_MASK) == 0) {
                    // ------------------------------
                    // Parameters for call to NewAttr
                    // ------------------------------
                    ParameterHolder_BusinessClass_Array qq_value = new ParameterHolder_BusinessClass_Array();
                    entity.newAttr(dep.getParentAttr(), qq_value);
                    depAttr = (Array_Of_BusinessClass<BusinessClass>)qq_value.getObject();
                }

                if (dep.getExecuteInfo().getUseInstanceKey()) {
                    instanceKey = entity.getInstanceKey();
                }
                else {
                    for (int i = 1; i <= attrMap.size(); i++) {
                        instanceKey.getValues().set(i-1, entity.getAttr(attrMap.get(i-1).getLocal()));
                    }
                }

                //  Snarf up dependent entities.
                //   

                //  Create the dependent entity's foreign key to compare against
                //  the independent entity.
                //
                while (depRow <= depResult.size()) {
                    if (dep.getExecuteInfo().getUseDependentKey()) {
                        dependentKey = depResult.get(depRow-1).getInstanceKey();
                    }
                    else {
                        for (int i = 1; i <= attrMap.size(); i++) {
                            dependentKey.getValues().set(i-1, depResult.get(depRow-1).getAttr(attrMap.get(i-1).getForeign()));
                        }
                    }

                    //  If the key's are equal, or if the independent entity's key is
                    //  shorter than the dependent entity, then this independent entity
                    //  is for us.  Remember CMP_SHORTER means that all the
                    //  corresponding values were equal but object's value list was
                    //  shorter than the source.
                    //
                    if (instanceKey.compare(dependentKey) <= BusinessKey.CMP_SHORTER) {

                        if (depAttr == null) {
                            entity.setAttr(dep.getParentAttr(), depResult.get(depRow-1));
                        }
                        else {
                            depAttr.add(depResult.get(depRow-1));
                        }

                    }
                    else {
                        //
                        //  Whoops, its not for us.  Drop out of this loop and we'll
                        //  go on to the next independent entity.
                        //
                        break;

                    }

                    depRow = depRow+1;

                }

            }
        }
    }

    /**
     * selectForeign<p>
     * SelectForeign<br>
     *     So far we have fetched all the independent and foreign BusinessClasses<br>
     *    that can be joined together (usually all the "to-one" associations).<br>
     *    Now we need to get all the foreign BusinessClasses that cannot be<br>
     *    joined-in ("to-many" associations and some optional associations) and<br>
     *     add them to the independent classes.  We do this by searching the query<br>
     *     tree recursively for queries that have not been joined.  When we find<br>
     *     unprocessed foreign queries we use SelectCorrelated  to process them by<br>
     *     running a query (or multiple queries) to get the foreign classes.<br>
     * <p>
     *     sqlQuery<br>
     *       The SqlQuery that generated the independent classes contained in<br>
     *       result.<br>
     * <p>
     *     result<br>
     *       The independent classes generated by sqlQuery.  These classes need<br>
     *       to have a foreign class attached as specified by the last item in<br>
     *       the queries  parameter.<br>
     * <p>
     *     queries<br>
     *       An array of BusinessQuerys.  queries[Items-1] contains the query<br>
     *       that generated the independent classes.  queries[Items] contains<br>
     *       the query we need to run to generated the foreign class.<br>
     * <p>
     *     orderBy<br>
     *       The ordering contraints used for the independent classes.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param result Type: Array_Of_BusinessClass<BusinessClass>
     * @param queries Type: Array_Of_BusinessQuery<BusinessQuery>
     * @param orderBy Type: Array_Of_ConstraintAttr<ConstraintAttr>
     */
    public void selectForeign(@Input SqlQuery sqlQuery, @Input Array_Of_BusinessClass<BusinessClass> result, @Input Array_Of_BusinessQuery<BusinessQuery> queries, @Input Array_Of_ConstraintAttr<ConstraintAttr> orderBy) {
        BusinessQuery foreignQuery = queries.get(queries.size()-1);

        if ((foreignQuery.getExecuteInfo().getStatus()&QueryExecuteInfo.ST_JOINED) == 0) {
            this.selectCorrelated(sqlQuery, result, queries, orderBy);
        }
        else {
            Array_Of_BusinessQuery<BusinessQuery> qq_localVector = foreignQuery.getForeignClasses();
            if (qq_localVector != null) {
                for (BusinessQuery ffq : qq_localVector) {
                    queries.add(ffq);
                    ((BusinessDBMgr)(this.getForeignMgrs().get(foreignQuery.getForeignAttrMgr(ffq.getParentAttr())-1))).selectForeign(sqlQuery, result, queries, orderBy);
                    queries.deleteRow(queries.size()- 1);
                }
            }
        }
    }

    /**
     * qq_setDB<p>
     * Method renamed by jcTOOL from SetDB to qq_setDB
     * because it conflicted with an attribute<p>
     * SetDB<br>
     *      The SetDB method is used to specify the database session to use for<br>
     *      this BusinessMgr.<br>
     * <p>
     * @param db Type: DBConnectionManager
     */
    public void qq_setDB(@Input DBConnectionManager db) {
        this.setStatementCache(new SqlStatementCache(db));

        this.setDB(db);

        if (this.getForeignMgrs() != null) {
            for (IBusinessMgr m : this.getForeignMgrs()) {
                ((BusinessDBMgr)m).qq_setDB(db);
            }
        }
    }

    /**
     * setup<p>
     * Setup<br>
     *     The Setup method is used to initialize the BusinessMgr.  It<br>
     *     should be invoked once before any other method is used.<br>
     * <p>
     *     This method will be overridden by the manager's generated class.<br>
     * <p>
     *     Setup instantiates and initializes foreign BusinessMgrs, and<br>
     *     sets the database session, and statement cache in use from the<br>
     *     ParentService.<br>
     * <p>
     *     managers<br>
     *       The managers parameter contains a list of BusinessDBMgrs which<br>
     *       have already been initialized by the ParentService.  If this<br>
     *       class needs to initialize any foreign managers it may do so and<br>
     *       should add them to this list.  If managers is not provided then<br>
     *       this class is a root manager known directly by the<br>
     *       BusinessServiceMgr.<br>
     * <p>
     * @param managers Type: Array_Of_BusinessMgr<BusinessMgr> (Input) (default in Forte: NIL)
     */
    public void setup(@Input Array_Of_IBusinessMgr<IBusinessMgr> managers) {
        throw new Error(Error.GEN_UNIMPLEMENTED, "Setup", this).getException();
    }

    /**
     * SQLdelete<p>
     * SQLdelete<br>
     *     The SQLdelete method uses the ExecuteSql method to execute SQL delete<br>
     *     statements.  SQLdelete, SQLinsert, and SQLupdate are invoked by the<br>
     *     Update method.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter contains the SqlQuery object that generated<br>
     *       the sqlText being executed.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter contains the text of the SQL statement to<br>
     *       be executed.<br>
     * <p>
     *     sqlData<br>
     *       The sqlData parameter contains the input values for any<br>
     *       placeholders in the SQL statement.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param sqlText Type: TextData
     * @param sqlData Type: SqlData
     */
    public void SQLdelete(@Input SqlQuery sqlQuery, @Input TextData sqlText, @Input SqlData sqlData) {
        this.executeSql(sqlQuery, sqlText, sqlData);
    }

    /**
     * SQLinsert<p>
     * SQLinsert<br>
     *     The SQLinsert method uses the ExecuteSql method to execute SQL insert<br>
     *     statements.  SQLdelete, SQLinsert, and SQLupdate are invoked by the<br>
     *     Update method.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter contains the SqlQuery object that generated<br>
     *       the sqlText being executed.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter contains the text of the SQL statement to<br>
     *       be executed.<br>
     * <p>
     *     sqlData<br>
     *       The sqlData parameter contains the input values for any<br>
     *       placeholders in the SQL statement.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param sqlText Type: TextData
     * @param sqlData Type: SqlData
     */
    public void SQLinsert(@Input SqlQuery sqlQuery, @Input TextData sqlText, @Input SqlData sqlData) {
        this.executeSql(sqlQuery, sqlText, sqlData);
    }

    /**
     * SQLselect<p>
     * SQLselect<br>
     *     The SQLselect method prepares and sends the SQL text contained in the<br>
     *     sqlText parameter to the DBSession.  Data used for placeholders in the<br>
     *     sqlText is passed in the sqlData parameter and bound to the statement<br>
     *     before execution.  The SqlQuery object used to generate the SQL text<br>
     *     is passed in sqlQuery for reference.  The SQL statement is run within<br>
     *     a cursor and any result values returned are packaged into<br>
     *     BusinessClasses of the appropriate sub-class and returned as the<br>
     *     functional result.<br>
     * <p>
     *     Prior to preparing the SQL statement the StatementCache is checked.<br>
     *     If the desired statement is found then the prepare step is avoided<br>
     *     and the cached SQL statement may be executed with the new input<br>
     *     values provided in the sqlData parameter.  If the SQL statement is<br>
     *     not found in the cache then it is prepared and added to the cache.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter contains the SqlQuery object that generated<br>
     *       the sqlText being executed.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter contains the text of the SQL statement to<br>
     *       be executed.<br>
     * <p>
     *     sqlData<br>
     *       The sqlData parameter contains the input values for any<br>
     *       placeholders in the SQL statement.<br>
     * <p>
     *     return value<br>
     *       The return value is an array of BusinessClasses containing any<br>
     *       result values returned by the SQL statement.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param sqlText Type: TextData
     * @param sqlData Type: SqlData
     * @return Array_Of_BusinessClass<BusinessClass>
     */
    @SuppressWarnings("unchecked")
  public Array_Of_BusinessClass<BusinessClass> SQLselect(@Input SqlQuery sqlQuery, @Input TextData sqlText, @Input SqlData sqlData) {
        try {
            int fetchRows = 0;
            int maxRows = 0;
            int rowCount = 0;
            int attrIndex = 0;
            DBDataSet resultData = null;
            SqlStatement statement = null;
            Array_Of_BusinessClass<BusinessClass> result = sqlQuery.getQuery().newArray();
   
            //  There is text returned for each table but if nothing needs to be done
            //  to this particular table it might be empty.  We only want to execute
            //  non-null queries so we check that now.
            //
            if (sqlText.getActualSize() > 0) {
   
                maxRows = sqlQuery.getMaxRows();
                if (maxRows == 0) {
                    maxRows = 2147483647;
                }
   
                statement = (SqlStatement)this.getStatementCache().find(sqlText);
   
                if (this.getTrace().getOn() && this.getTrace().test(0, 0, Trace.ES_SELECT, 1, this, "SQLselect")) {
                    if (statement != null) {
                        Logger.getLogger("task.part.logmgr").info("using cached statement: ");
                    }
                    if (this.getTrace().test(0, 0, Trace.ES_SELECT, 50, (Object)null, (String)null)) {
                        Logger.getLogger("task.part.logmgr").info(this.formatSqlText(sqlText, sqlQuery.getData().get(0)));
                    }
                    else {
                        Logger.getLogger("task.part.logmgr").info(this.formatSqlText(sqlText, (SqlData)null));
                    }
                }
   
                if (statement == null) {
   
                    statement = new SqlStatement();
   
                    if (sqlQuery.getForUpdate() && this.getDB().getDBVendorType() == Constants.DB_VT_RDB) {
                      sqlQuery.getColumnList();
                        ParameterHolder qq_aTypeHolder = new ParameterHolder();
                        ParameterHolder qq_aColMapHolder = new ParameterHolder();
                        PreparedStatement qq_tempStatement = this.getDB().getDynamicStatement(
                                        sqlText.toString(), qq_aTypeHolder, qq_aColMapHolder, true);
                        statement.setInputData(new DBDataSet(qq_tempStatement, (ArrayList)qq_aColMapHolder.getObject()));
                        statement.setHandle(qq_tempStatement);
                    }
                    else {
                        ParameterHolder qq_aTypeHolder = new ParameterHolder();
                        ParameterHolder qq_aColMapHolder = new ParameterHolder();
                        PreparedStatement qq_tempStatement = this.getDB().getDynamicStatement(
                                        sqlText.toString(), qq_aTypeHolder, qq_aColMapHolder);
                        statement.setInputData(new DBDataSet(qq_tempStatement, (ArrayList)qq_aColMapHolder.getObject()));
                        statement.setHandle(qq_tempStatement);
                    }
   
                    this.getStatementCache().enter(statement, sqlText);
   
                }
   
                //
                //  Set the input values (constraints in this case).
                //
                for (int i = 1; i <= sqlData.getValues().size(); i++) {
                    statement.getInputData().setValue(i, sqlData.getValues().get(i-1));
                }
   
                PreparedStatement qq_statement = statement.getHandle();
                @SuppressWarnings("unused")
        int qq_rowType;
                if (qq_statement.execute()) {
                    resultData = new DBDataSet(qq_statement, qq_statement.getResultSet());
                    qq_rowType = GenericDBMS.Constants.DB_RS_ROW;
                }
                else {
                    resultData = null;
                    qq_rowType = GenericDBMS.Constants.DB_RS_NONE;
                }
   
                fetchRows = resultData.getMaxRows();
                if (fetchRows < 2) {
                    //
                    //  The first time we fetch 10 rows.  If there is more we will up this to 30.
                    //
                    fetchRows = 10;
                }
   
                rowCount = 0;
   
                //  Loop through each row returned from the DB creating a
                //  BusinessClass for each one and filling it with the data in the row.
                //
                PreparedStatement qq_tempStatement = statement.getHandle();
                qq_tempStatement.setFetchSize(fetchRows);
                if (resultData == null)
                    resultData = new DBDataSet(qq_tempStatement, qq_tempStatement.getResultSet());
                while ((rowCount < maxRows) && (resultData.getResultSet().next())) {

                  if (rowCount+1 > maxRows) {
                        break;
                    }
                   
                    rowCount = rowCount+1;

                    //
                    //  Get a new BusinessClass of the appropriate subclass.
                    //
                    BusinessClass entity = sqlQuery.getQuery().newClass();

                    //
                    //  Fill it in with the data from the current row of resultData.
                    //
                    attrIndex = 0;
                    // -------------------------------
                    // Parameters for call to SetAttrs
                    // -------------------------------
                    ParameterHolder_integer qq_index = new ParameterHolder_integer(attrIndex);
                    sqlQuery.getQuery().setAttrs(entity, resultData, qq_index);
                    attrIndex = qq_index.getInt();

                    //
                    //  Set the status of the BusinessClass.  It can be updated unless
                    //  we're a restricted manager.
                    //
                    entity.setInstanceStatus(BusinessClass.ST_READWRITE);
                    if (this.getReadOnly()) {
                        entity.setInstanceStatus(BusinessClass.ST_READONLY);
                    }

                    //
                    //  Finally add this entity to the result set.
                    //
                    result.add(entity);

                    // AGD:20/3/08 Below code does not translate to Java so commented out
                    // It is not really needed and was only there to try to optimise the cursor fetch sizes
                    //  If we've already got 20 rows and there are more we'll get them 30
                    //  at a time.
                    //
                    //if ((((resultData.getResultSet() == null) ? 0 : 1) == fetchRows) && (rowCount >= 20)) {
                    //    fetchRows = 30;
                    //}
                }


   
                // this.getDB().CloseCursor()
   
                if (!(this.getStatementCache().getOn())) {
                    try {
                        statement.getHandle().close();
                    } catch (java.sql.SQLException qq_SQLEx) {
                        throw new SQLErrorCodeSQLExceptionTranslator().translate("SQL tasks", "", qq_SQLEx );
                    }
                }
   
            }
   
            return result;
        }
        catch (SQLException e) {
            DataAccessException qq_dae = new SQLErrorCodeSQLExceptionTranslator().translate("SQL tasks", "", e );
            ErrorMgr.addError(e);
            ErrorMgr.addError(qq_dae);
            throw qq_dae;
        }
    }

    /**
     * SQLupdate<p>
     * SQLupdate<br>
     *     The SQLupdate method uses the ExecuteSql method to execute SQL update<br>
     *     statements.  SQLdelete, SQLinsert, and SQLupdate are invoked by the<br>
     *     Update method.<br>
     * <p>
     *     sqlQuery<br>
     *       The sqlQuery parameter contains the SqlQuery object that generated<br>
     *       the sqlText being executed.<br>
     * <p>
     *     sqlText<br>
     *       The sqlText parameter contains the text of the SQL statement to<br>
     *       be executed.<br>
     * <p>
     *     sqlData<br>
     *       The sqlData parameter contains the input values for any<br>
     *       placeholders in the SQL statement.<br>
     * <p>
     * @param sqlQuery Type: SqlQuery
     * @param sqlText Type: TextData
     * @param sqlData Type: SqlData
     */
    public void SQLupdate(@Input SqlQuery sqlQuery, @Input TextData sqlText, @Input SqlData sqlData) {
        this.executeSql(sqlQuery, sqlText, sqlData);
    }

    /**
     * update<p>
     * Update<br>
     *     The Update method builds and executes the SQL query described by<br>
     *     the query parameter.<br>
     * <p>
     *     query<br>
     *       The query parameter holds the BusinessQuery describing what should<br>
     *       be updated in the database.<br>
     * <p>
     * @param query Type: BusinessQuery
     */
    public void update(@Input BusinessQuery query) {
        SqlQuery sQLquery = query.getSqlQuery(this.getDB());
        Array_Of_TextData<TextData> queries = null;
        IBusinessMgr mgr = null;
        int mgrIndex = 0;

        if (this.getReadOnly()) {
            throw new Error(Error.BM_CANT_UPDATE, "UpdateQuery", this).getException();
        }

        //
        //  Build the SQL query that needs to be executed.  query describes what needs
        //  to be done in terms of the BusinessClass.  BuildQuery returns an SQLquery
        //  which describes what needs to be done in terms of SQL.
        //
        // ---------------------------------
        // Parameters for call to BuildQuery
        // ---------------------------------
        ParameterHolder_SqlQuery qq_query = new ParameterHolder_SqlQuery(sQLquery);
        query.buildQuery(qq_query);
        sQLquery = (SqlQuery)qq_query.getObject();

        //
        //  Delete operations get processed on dependent entities first so we do not
        //  run afoul of any referential integrity constraints in the database.
        //
        if (sQLquery.getOperation() == BusinessQuery.OP_DELETE) {
            Array_Of_BusinessQuery<BusinessQuery> qq_localVector = query.getForeignClasses();
            if (qq_localVector != null) {
                for (BusinessQuery f : qq_localVector) {
                    mgrIndex = query.getForeignAttrMgr(f.getParentAttr());
                    if (mgrIndex > 0) {
                        mgr = this.getForeignMgrs().get(mgrIndex-1);
                        if (!(mgr.getReadOnly())) {
                            mgr.update(f);
                        }
                    }
                }
            }
        }

        //
        //  Get the SQL text of the queries to be executed.  There can be more than
        //  one because a BusinessClass can be comprised of more than one databaes
        //  table and only one table can be updated by a single query (which is
        //  different than select where lots of tables can be selected from).
        //
        queries = sQLquery.getText();

        switch (sQLquery.getOperation()) {

            case BusinessQuery.OP_INSERT: {
                for (int i1 = 1; i1 <= queries.size(); i1++) {
                    this.SQLinsert(sQLquery, queries.get(i1-1), sQLquery.getData().get(i1-1));
                }

                break;
            }
            case BusinessQuery.OP_UPDATE: {
                for (int i1 = 1; i1 <= queries.size(); i1++) {
                    this.SQLupdate(sQLquery, queries.get(i1-1), sQLquery.getData().get(i1-1));
                }

                break;
            }
            case BusinessQuery.OP_DELETE: {
                for (int i1 = queries.size(); i1 >= 1; i1--) {
                    this.SQLdelete(sQLquery, queries.get(i1-1), sQLquery.getData().get(i1-1));
                }

                break;
            }
        }

        //  And now we need to run any dependent queries, unless of course this
        //  was a delete we already took care of those.
        //
        if (sQLquery.getOperation() != BusinessQuery.OP_DELETE) {
            Array_Of_BusinessQuery<BusinessQuery> qq_localVector = query.getForeignClasses();
            if (qq_localVector != null) {
                for (BusinessQuery f : qq_localVector) {
                    mgrIndex = query.getForeignAttrMgr(f.getParentAttr());
                    if (mgrIndex > 0) {
                        mgr = this.getForeignMgrs().get(mgrIndex-1);
                        if (!(mgr.getReadOnly())) {
                            mgr.update(f);
                        }
                    }
                }
            }
        }
    }

    /**
     * Get the proxy class which will forwards remote requests to this class. This
     * must be kept as a method so it can be overridden in all subclasses, ensuring
     * a proxy to the lowest level subclass is returned.
     */
    public AnchoredProxy getProxy() {
        return new BusinessDBMgrProxy(this);
    }

     /**
   * Override the writeReplace method to replace this class with a proxy to it
   * (if it's anchored)
   *
   * @return
   * @throws ObjectStreamException
   */
    public Object writeReplace() throws ObjectStreamException {
        if (getIsAnchored()) {
            AnchoredProxy proxy = this.getProxy();
            //System.out.println("Replacing " + this + " with " + proxy + " in writeReplace");
            return proxy;
        }
        else {
            return this;
        }
    }

    /**
     * Satisfy the {@link RemoteEventProxy} interface
     */
    /* (non-Javadoc)
     * @see Framework.RemoteEventProxy#registerInterest(java.lang.String, Framework.RemoteEvent, java.lang.String)
     */
    public String registerInterest(String pHostName, RemoteEvent pAnchoredObject, String pEvent)  {
        return EventManager.registerInterest(pHostName, pAnchoredObject, this, pEvent);
    }

    /* (non-Javadoc)
     * @see Framework.RemoteEventProxy#postEvent(java.lang.String, java.util.Hashtable)
     */
  public void postEvent(String pEventName, Hashtable<String, Object> pParameters) {
        EventManager.postEvent(this, pEventName, pParameters);
    }

    /* (non-Javadoc)
     * @see Framework.RemoteEventProxy#deregisterInterest(java.lang.String, Framework.RemoteEvent, java.lang.String)
     */
    public void deregisterInterest(String pHostName, RemoteEvent pAnchoredObject, String pEvent)  {
        EventManager.deregisterInterest(pHostName, pAnchoredObject, this, pEvent);
    }
// end class BusinessDBMgr
// c Pass 2 Conversion Time: 4032 milliseconds
TOP

Related Classes of Express.services.BusinessDBMgr

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.