[cvs] expresso commit by rauld: Refactored searchAndRetrieveList() to make

JCorporate Ltd jcorp at jcorporate.com
Mon Jan 17 17:00:12 UTC 2005


Log Message:
-----------
Refactored searchAndRetrieveList() to make use of the new getSQLSelectStatement() method.
Contributed by Yves Henri Amaizo

Modified Files:
--------------
    expresso/expresso-web/WEB-INF/src/com/jcorporate/expresso/core/dbobj:
        MultiDBObject.java

Revision Data
-------------
Index: MultiDBObject.java
===================================================================
RCS file: /home/javacorp/.cvs/expresso/expresso/expresso-web/WEB-INF/src/com/jcorporate/expresso/core/dbobj/MultiDBObject.java,v
retrieving revision 1.64
retrieving revision 1.65
diff -Lexpresso-web/WEB-INF/src/com/jcorporate/expresso/core/dbobj/MultiDBObject.java -Lexpresso-web/WEB-INF/src/com/jcorporate/expresso/core/dbobj/MultiDBObject.java -u -r1.64 -r1.65
--- expresso-web/WEB-INF/src/com/jcorporate/expresso/core/dbobj/MultiDBObject.java
+++ expresso-web/WEB-INF/src/com/jcorporate/expresso/core/dbobj/MultiDBObject.java
@@ -92,7 +92,6 @@
 import java.util.StringTokenizer;
 import java.util.Vector;
 
-
 /**
  * This class handles SQL joins with java coding only.  It is not deprectated, but
  * @see com.jcorporate.expresso.core.dataobjects.jdbc.JoinedDataObject for a more flexible approach to joins
@@ -127,361 +126,392 @@
  */
 public class MultiDBObject {
 
-    // ----------------------------------------------------
-    // 2003-11-05 /ebn-ma: added...
-    /**
-     * Holds the shortName of these DBObjects, which have to be ignored in the
-     * where-clause because they are still used in a on-clause of a join.
-     * Ex.: ignoreInWhereClause = ",bt,,an,,qu,";
-     * if (ignoreInWhereClause.indexOf(",bt,") >= 0) { continue; }
-     */
-    private String ignoreInWhereClause = "";
-
-    /**
-     * Hold the join-conditions in "original" form.
-     * For the getThisMultiDBObj method and for to create the from-clause
-     * at execution-time.
-     */
-    private Vector originalJoins = new Vector();
-
-    /**
-     * If we are using a custom from clause for this query, it's stored here.
-     * If null, then build the from clause with the join or the foreign-key
-     * definitions.
-     * Do not include the sql-keyword FROM.
-     * Note: If you define a customFromClause, you will usually have to define
-     * a custemWhereClause too.
-     */
-    private String customFromClause = null;
-    // 2003-11-05 /ebn-ma: ...added
-    // ----------------------------------------------------
-
-    /**
-     * Use a DISTINCT keyword right after SELECT keyword
-     */
-    private boolean selectDistinct = false;
-
-    /**
-     * Attributes of this DB Object
-     */
-    private HashMap attributes = null;
-
-    /**
-     * The number of records we must skip over before we start reading
-     * the <code>ResultSet</code> proper in a searchAndRetrieve.
-     * 0 means no limit
-     * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
-     */
-    transient protected int offsetRecord = 0;
-
-    /**
-     * If we are using a custom where clause for this query, this flag will
-     * signify if we need to append the custom where clause to that generated
-     * by the setForeignKey() calls
-     */
-    private boolean appendCustomWhereClause = false;
-
-    /**
-     * Static variables for join type
-     */
-    protected static final int INNER_JOIN = 0;
-    protected static final int RIGHT_JOIN = 1;
-    protected static final int LEFT_JOIN = 2;
-
-    /**
-     * Constant for shortName DBObject attribute
-     */
-    protected static final String SHORT_NAME = "shortName";
-
-    /**
-     * 'FROM' clause formed by calls to setJoin().
-     */
-    private String fromClause = null;
-
-    /**
-     * If set to true, the shortname for the DBObject will be used as an alias
-     * in the query; defaults to false for backward-compatiblity
-     */
-    private boolean shortNameAsAlias = false;
-
-    /**
-     * Return an "attribute". Attributes are temporary (e.g. not stored in the DBMS)
-     * values associated with this particular DB object instance.
-     *
-     * @param attribName The attribute name to check
-     * @return the object associated with this attribute
-     */
-    public Object getAttribute(String attribName) {
-        if (attributes != null) {
-            return attributes.get(attribName);
-        } else {
-            return null;
+  // ----------------------------------------------------
+  // 2003-11-05 /ebn-ma: added...
+  /**
+   * Holds the shortName of these DBObjects, which have to be ignored in the
+   * where-clause because they are still used in a on-clause of a join.
+   * Ex.: ignoreInWhereClause = ",bt,,an,,qu,";
+   * if (ignoreInWhereClause.indexOf(",bt,") >= 0) { continue; }
+   */
+  private String ignoreInWhereClause = "";
+
+  /**
+   * Hold the join-conditions in "original" form.
+   * For the getThisMultiDBObj method and for to create the from-clause
+   * at execution-time.
+   */
+  private Vector originalJoins = new Vector();
+
+  /**
+   * If we are using a custom from clause for this query, it's stored here.
+   * If null, then build the from clause with the join or the foreign-key
+   * definitions.
+   * Do not include the sql-keyword FROM.
+   * Note: If you define a customFromClause, you will usually have to define
+   * a custemWhereClause too.
+   */
+  private String customFromClause = null;
+  // 2003-11-05 /ebn-ma: ...added
+  // ----------------------------------------------------
+
+  /**
+   * Use a DISTINCT keyword right after SELECT keyword
+   */
+  private boolean selectDistinct = false;
+
+  /**
+   * Attributes of this DB Object
+   */
+  private HashMap attributes = null;
+
+  /**
+   * The number of records we must skip over before we start reading
+   * the <code>ResultSet</code> proper in a searchAndRetrieve.
+   * 0 means no limit
+   * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
+   */
+  transient protected int offsetRecord = 0;
+
+  /**
+   * If we are using a custom where clause for this query, this flag will
+   * signify if we need to append the custom where clause to that generated
+   * by the setForeignKey() calls
+   */
+  private boolean appendCustomWhereClause = false;
+
+  /**
+   * Static variables for join type
+   */
+  protected static final int INNER_JOIN = 0;
+  protected static final int RIGHT_JOIN = 1;
+  protected static final int LEFT_JOIN = 2;
+
+  /**
+   * Constant for shortName DBObject attribute
+   */
+  protected static final String SHORT_NAME = "shortName";
+
+  /**
+   * 'FROM' clause formed by calls to setJoin().
+   */
+  private String fromClause = null;
+
+  /**
+   * If set to true, the shortname for the DBObject will be used as an alias
+   * in the query; defaults to false for backward-compatiblity
+   */
+  private boolean shortNameAsAlias = false;
+
+  /**
+   * Return an "attribute". Attributes are temporary (e.g. not stored in the DBMS)
+   * values associated with this particular DB object instance.
+   *
+   * @param attribName The attribute name to check
+   * @return the object associated with this attribute
+   */
+  public Object getAttribute(String attribName) {
+    if (attributes != null) {
+      return attributes.get(attribName);
+    }
+    else {
+      return null;
+    }
+  }
+
+  /* getAttribute(String) */
+
+  /**
+   * Set an attribute. Attributes are temporary (e.g. not stored in the DBMS) values
+   * associated with this particular DB object instance.
+   *
+   * @param attribName  The name of the attribute being defined
+   * @param attribValue The object to store under this attribute name
+   */
+  public synchronized void setAttribute(String attribName,
+                                        Object attribValue) {
+    if (attributes == null) {
+      attributes = new HashMap();
+    }
+
+    attributes.put(attribName, attribValue);
+  }
+
+  /* setAttribute(String, Object) */
+
+  /**
+   * A DB Object can be told to only retrieve a certain number of records. If a
+   * "max records" value has been specified, this method provides access to it.
+   *
+   * @return The maximum number of records that should be retrieved, or zero
+   *         if no max has been set
+   */
+  public int getMaxRecords() {
+    return maxRecords;
+  }
+
+  /* getMaxRecords() */
+
+  /**
+   * Specifies the number of records that should be skipped over
+   * before any data from the <code>ResultSet</code>
+   * is retrieved in any subsequent
+   * searchAndRetrieve() call. Records will be skipped over (in the specified
+   * sort order) until the record counts is equal to or greater
+   * than the offset record. Specifying zero indicates that no
+   * records should be skipped over and the
+   * <code>ResultSet</code> immediately from the start.
+   *
+   * @param newOffset The maximum number of records to retrieve.
+   * @throws DBException If the max number is less than 0
+   *                     <p/>
+   *                     author Peter Pilgrim <peterp  at  xenonsoft dot demon dot co dot  uk>
+   *                     date Tue Feb 05 23:06:38 GMT 2002
+   */
+  public synchronized void setOffsetRecord(int newOffset) throws DBException {
+    if (newOffset < 0) {
+      throw new DBException("Offset records can't be less than 0");
+    }
+
+    offsetRecord = newOffset;
+  }
+
+  /* setOffsetRecord(int) */
+
+  /**
+   * Gets the number of records that be skipped. The offset records.
+   * A DB Object can be told to skip a certain number of
+   * records, before reading records from the <code>ResultSet</code>.
+   * <p/>
+   * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
+   *
+   * @return The maximum number of records that should be
+   *         skipped over before reading the data records.
+   * @see #setOffsetRecord(int)
+   */
+  public int getOffsetRecord() {
+    return offsetRecord;
+  }
+
+  /* getOffsetRecord() */
+
+  // ----------------------------------------------------
+  // 2003-11-05 /ebn-ma: added...
+  /**
+   * Specify a custom "from" clause for the SQL used to retrieve
+   * records for this object.
+   *
+   * @param newCustomFrom java.lang.String
+   */
+  public synchronized void setCustomFromClause(String newCustomFrom) {
+    customFromClause = newCustomFrom;
+  }
+
+  /**
+   * Gets the customFromClause
+   *
+   * @return customFromClause
+   */
+  public String getCustomFromClause() {
+    return customFromClause;
+  }
+
+  /**
+   * Build a string consisting of an SQL 'from' clause using the
+   * customFromClause, the foreign-key or the join definitions.
+   * The result will be found in property fromClause.
+   *
+   * @return true = success.
+   *         <p/>
+   *         Modify by Yves Henri AMAIZO <amy_amaizo at compuserve.com>
+   * @since $DatabaseSchema  $Date$
+   */
+  public boolean buildFromClause() throws DBException {
+    boolean success = false;
+    FastStringBuffer fsb = new FastStringBuffer(256);
+    int dboCount = myDBObjects.size();
+
+    try {
+      // ----------------------------------------------------
+      if (customFromClause != null &&
+          customFromClause.trim().length() > 0) {
+        // As long as a customFromClause is defined , we will use it.
+        fromClause = customFromClause;
+        success = true;
+      }
+      // ----------------------------------------------------
+      else if (!originalJoins.isEmpty()) {
+        if (!originalRelations.isEmpty()) {
+          throw new DBException(thisClass + "count()" +
+                                "You cannot mix set???Join() with setForeignKey() definitions." +
+                                "Use setInnerJoin() instead of setForeignKey().");
         }
-    } /* getAttribute(String) */
 
+        // Build the from clause with the join definitions...
+        fromClause = null;
+        String oneJoin = null;
 
-    /**
-     * Set an attribute. Attributes are temporary (e.g. not stored in the DBMS) values
-     * associated with this particular DB object instance.
-     *
-     * @param attribName  The name of the attribute being defined
-     * @param attribValue The object to store under this attribute name
-     */
-    public synchronized void setAttribute(String attribName,
-                                          Object attribValue) {
-        if (attributes == null) {
-            attributes = new HashMap();
-        }
-
-        attributes.put(attribName, attribValue);
-    } /* setAttribute(String, Object) */
-
-
-    /**
-     * A DB Object can be told to only retrieve a certain number of records. If a
-     * "max records" value has been specified, this method provides access to it.
-     *
-     * @return The maximum number of records that should be retrieved, or zero
-     *         if no max has been set
-     */
-    public int getMaxRecords() {
-        return maxRecords;
-    } /* getMaxRecords() */
-
-    /**
-     * Specifies the number of records that should be skipped over
-     * before any data from the <code>ResultSet</code>
-     * is retrieved in any subsequent
-     * searchAndRetrieve() call. Records will be skipped over (in the specified
-     * sort order) until the record counts is equal to or greater
-     * than the offset record. Specifying zero indicates that no
-     * records should be skipped over and the
-     * <code>ResultSet</code> immediately from the start.
-     *
-     * @param newOffset The maximum number of records to retrieve.
-     * @throws DBException If the max number is less than 0
-     *                     <p/>
-     *                     author Peter Pilgrim <peterp  at  xenonsoft dot demon dot co dot  uk>
-     *                     date Tue Feb 05 23:06:38 GMT 2002
-     */
-    public synchronized void setOffsetRecord(int newOffset)
-            throws DBException {
-        if (newOffset < 0) {
-            throw new DBException("Offset records can't be less than 0");
-        }
-
-        offsetRecord = newOffset;
-    } /* setOffsetRecord(int) */
-
-    /**
-     * Gets the number of records that be skipped. The offset records.
-     * A DB Object can be told to skip a certain number of
-     * records, before reading records from the <code>ResultSet</code>.
-     * <p/>
-     * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
-     *
-     * @return The maximum number of records that should be
-     *         skipped over before reading the data records.
-     * @see #setOffsetRecord(int)
-     */
-    public int getOffsetRecord() {
-        return offsetRecord;
-    } /* getOffsetRecord() */
-
-    // ----------------------------------------------------
-    // 2003-11-05 /ebn-ma: added...
-    /**
-     * Specify a custom "from" clause for the SQL used to retrieve
-     * records for this object.
-     *
-     * @param newCustomFrom java.lang.String
-     */
-    public synchronized void setCustomFromClause(String newCustomFrom) {
-        customFromClause = newCustomFrom;
-    }
+        for (Enumeration n = originalJoins.elements();
+             n.hasMoreElements(); ) {
+          oneJoin = (String) n.nextElement();
 
-    /**
-     * Gets the customFromClause
-     *
-     * @return customFromClause
-     */
-    public String getCustomFromClause() {
-        return customFromClause;
-    }
+          StringTokenizer stk = new StringTokenizer(oneJoin, "|");
+          String leftDbo = stk.nextToken();
+          String leftField = stk.nextToken();
+          String rightDbo = stk.nextToken();
+          String rightField = stk.nextToken();
+          String joinTyp = stk.nextToken().toLowerCase();
+
+          if ("left".equals(joinTyp)) {
+            buildJoin(leftDbo, leftField, rightDbo, rightField, LEFT_JOIN);
+          }
+          else if ("inner".equals(joinTyp)) {
+            buildJoin(leftDbo, leftField, rightDbo, rightField, INNER_JOIN);
+          }
+          else if ("right".equals(joinTyp)) {
+            buildJoin(leftDbo, leftField, rightDbo, rightField, RIGHT_JOIN);
+          }
+          else {
+            throw new DBException(thisClass + "count()" +
+                                  "Missing join-type in '" + oneJoin + "'");
+          }
+        }
+        success = true;
+      }
+      // ----------------------------------------------------
+      else if (!originalRelations.isEmpty() || dboCount == 1) {
+        // To build the relations with the foreign-key definitions,
+        // we need to have all the DBObejcts in the from clause.
+        // If this is not the special case, where our Object has only
+        // one embedded DBObject: We have to link them later in the
+        // where clause.
+        boolean needComma = false;
+        DBObject oneObj = null;
 
-    /**
-     * Build a string consisting of an SQL 'from' clause using the
-     * customFromClause, the foreign-key or the join definitions.
-     * The result will be found in property fromClause.
-     *
-     * @return true = success.
-     *         <p/>
-     *         Modify by Yves Henri AMAIZO <amy_amaizo at compuserve.com>
-     * @since $DatabaseSchema  $Date$
-     */
-    public boolean buildFromClause() throws DBException {
-        boolean success = false;
-        FastStringBuffer fsb = new FastStringBuffer(256);
-        int dboCount = myDBObjects.size();
+        for (Enumeration eachObj = myDBObjects.elements();
+             eachObj.hasMoreElements(); ) {
+          oneObj = (DBObject) eachObj.nextElement();
 
-        try {
-            // ----------------------------------------------------
-            if (customFromClause != null &&
-                    customFromClause.trim().length() > 0) {
-                // As long as a customFromClause is defined , we will use it.
-                fromClause = customFromClause;
-                success = true;
-            }
-            // ----------------------------------------------------
-            else if (!originalJoins.isEmpty()) {
-                if (!originalRelations.isEmpty()) {
-                    throw new DBException(thisClass + "count()" +
-                            "You cannot mix set???Join() with setForeignKey() definitions." +
-                            "Use setInnerJoin() instead of setForeignKey().");
-                }
-
-                // Build the from clause with the join definitions...
-                fromClause = null;
-                String oneJoin = null;
-
-                for (Enumeration n = originalJoins.elements();
-                     n.hasMoreElements();) {
-                    oneJoin = (String) n.nextElement();
-
-                    StringTokenizer stk = new StringTokenizer(oneJoin, "|");
-                    String leftDbo = stk.nextToken();
-                    String leftField = stk.nextToken();
-                    String rightDbo = stk.nextToken();
-                    String rightField = stk.nextToken();
-                    String joinTyp = stk.nextToken().toLowerCase();
-
-                    if ("left".equals(joinTyp)) {
-                        buildJoin(leftDbo, leftField, rightDbo, rightField, LEFT_JOIN);
-                    } else if ("inner".equals(joinTyp)) {
-                        buildJoin(leftDbo, leftField, rightDbo, rightField, INNER_JOIN);
-                    } else if ("right".equals(joinTyp)) {
-                        buildJoin(leftDbo, leftField, rightDbo, rightField, RIGHT_JOIN);
-                    } else {
-                        throw new DBException(thisClass + "count()" +
-                                "Missing join-type in '" + oneJoin + "'");
-                    }
-                }
-                success = true;
-            }
-            // ----------------------------------------------------
-            else if (!originalRelations.isEmpty() || dboCount == 1) {
-                // To build the relations with the foreign-key definitions,
-                // we need to have all the DBObejcts in the from clause.
-                // If this is not the special case, where our Object has only
-                // one embedded DBObject: We have to link them later in the
-                // where clause.
-                boolean needComma = false;
-                DBObject oneObj = null;
-
-                for (Enumeration eachObj = myDBObjects.elements();
-                     eachObj.hasMoreElements();) {
-                    oneObj = (DBObject) eachObj.nextElement();
-
-                    if (needComma) {
-                        fsb.append(",");
-                    }
+          if (needComma) {
+            fsb.append(",");
+          }
 //Edit by Christian Reibnegger 2004-12-03
 //Including the DB-Name in the SQL-FROM-Statement
 //***********************************************
-                    try {
-                        String dbKey = oneObj.getDataContext();
-                        String dataContext = oneObj.getMappedDataContext();
-
-                        if (!dbKey.equals(dataContext)) {
-
-                            // Get The DataBaseName from the ConfigContext
-                            com.jcorporate.expresso.core.misc.ConfigContext ctx =
-                                    ConfigManager.getContext(oneObj.getMappedDataContext());
-                            ConfigJdbc confJdbc = ctx.getJdbc();
-                            String serverURL = confJdbc.getUrl();
-                            int lastIndex = serverURL.lastIndexOf("/");
-                            String dbName = serverURL.substring(lastIndex + 1);
-
-                            // append the DatabaseName to the SQL-FROM-Statement
-                            fsb.append(dbName + ".");
-                        }
-                    } catch (IndexOutOfBoundsException iOOBex) {
-                        throw new DBException(this + " IndexOutOfBoundsException: " + iOOBex.getMessage());
-                    }
-
-                    String targetTable = oneObj.getJDBCMetaData().getTargetSQLTable(oneObj.getDataContext());
-                    String tableName = getTableName(oneObj);
-                    fsb.append(targetTable);
-                    // AS keyword to set table short name is not standard and not supported by all
-                    // SQL manipulation languages. This need to be set properly with each driver
-                    // Keyword to be set in expresso config file for table alias name syntax
-
-                    if (!targetTable.equals(tableName)) {
-                        if (ConfigManager.getJdbcRequired(getDataContext()).getTableAliasKeyword() != null) {
-                            fsb.append(
-                                    " " + ConfigManager.getJdbcRequired(getDataContext()).getTableAliasKeyword() + " " + tableName);
-                        } else {
-                            fsb.append(" AS " + tableName);
-                        }
-                    }
-
-                    needComma = true;
-                }
-
-                fromClause = fsb.toString();
-                success = true;
+           try {
+             String dbKey = oneObj.getDataContext();
+             String dataContext = oneObj.getMappedDataContext();
+
+             if (!dbKey.equals(dataContext)) {
+
+               // Get The DataBaseName from the ConfigContext
+               com.jcorporate.expresso.core.misc.ConfigContext ctx =
+                   ConfigManager.getContext(oneObj.getMappedDataContext());
+               ConfigJdbc confJdbc = ctx.getJdbc();
+               String serverURL = confJdbc.getUrl();
+               int lastIndex = serverURL.lastIndexOf("/");
+               String dbName = serverURL.substring(lastIndex + 1);
+
+               // append the DatabaseName to the SQL-FROM-Statement
+               fsb.append(dbName + ".");
+             }
+           }
+           catch (IndexOutOfBoundsException iOOBex) {
+             throw new DBException(this +" IndexOutOfBoundsException: " +
+                                   iOOBex.getMessage());
+           }
+
+          String targetTable = oneObj.getJDBCMetaData().getTargetSQLTable(
+              oneObj.getDataContext());
+          String tableName = getTableName(oneObj);
+          fsb.append(targetTable);
+          // AS keyword to set table short name is not standard and not supported by all
+          // SQL manipulation languages. This need to be set properly with each driver
+          // Keyword to be set in expresso config file for table alias name syntax
+
+          if (!targetTable.equals(tableName)) {
+            if (ConfigManager.getJdbcRequired(getDataContext()).
+                getTableAliasKeyword() != null) {
+              fsb.append(
+                  " " +
+                  ConfigManager.getJdbcRequired(getDataContext()).
+                  getTableAliasKeyword() +
+                  " " + tableName);
             }
-            // ----------------------------------------------------
             else {
-                // build clause
-                boolean needComma = false;
-
-                for (Enumeration eachObj = myDBObjects.elements();
-                     eachObj.hasMoreElements();) {
-                    DBObject oneObj = (DBObject) eachObj.nextElement();
-
-                    if (needComma) {
-                        fsb.append(",");
-                    }
-
-                    String targetTable = oneObj.getJDBCMetaData().getTargetSQLTable(oneObj.getDataContext());
-                    String tableName = getTableName(oneObj);
-                    fsb.append(targetTable);
-                    if (!targetTable.equals(tableName)) {
-                        if (ConfigManager.getJdbcRequired(getDataContext()).getTableAliasKeyword() != null) {
-                            fsb.append(
-                                    " " + ConfigManager.getJdbcRequired(getDataContext()).getTableAliasKeyword() + " " + tableName);
-                        } else {
-                            fsb.append(" AS " + tableName);
-                        }
-                    }
+              //fsb.append(" AS " + tableName);
+              // AS keyword to set table short name is not standard and not supported by all
+              // SQL manipulation languages. This need to be set properly with each driver
+              // Standard SQL implementation is space. AS keyword should be added in expresso config
+              fsb.append(" " + tableName);
+            }
+          }
+
+          needComma = true;
+        }
+
+        fromClause = fsb.toString();
+        success = true;
+      }
+      // ----------------------------------------------------
+      else {
+        // build clause
+        boolean needComma = false;
 
-                    needComma = true;
-                }
+        for (Enumeration eachObj = myDBObjects.elements();
+             eachObj.hasMoreElements(); ) {
+          DBObject oneObj = (DBObject) eachObj.nextElement();
 
-                fromClause = fsb.toString();
-                success = true;
+          if (needComma) {
+            fsb.append(",");
+          }
+
+          String targetTable = oneObj.getJDBCMetaData().getTargetSQLTable(
+              oneObj.getDataContext());
+          String tableName = getTableName(oneObj);
+          fsb.append(targetTable);
+          if (!targetTable.equals(tableName)) {
+            if (ConfigManager.getJdbcRequired(getDataContext()).
+                getTableAliasKeyword() != null) {
+              fsb.append(
+                  " " +
+                  ConfigManager.getJdbcRequired(getDataContext()).
+                  getTableAliasKeyword() +
+                  " " + tableName);
+            }
+            else {
+              fsb.append(" AS " + tableName);
             }
-        } catch (Throwable t) {
-            throw new DBException(t);
-        } finally {
-            fsb.release();
+          }
+
+          needComma = true;
         }
 
-        return (success);
+        fromClause = fsb.toString();
+        success = true;
+      }
+    }
+    catch (Throwable t) {
+      throw new DBException(t);
+    }
+    finally {
+      fsb.release();
     }
-    // 2003-11-05 /ebn-ma: ...added
-    // ----------------------------------------------------
 
+    return (success);
+  }
 
-    /**
-     * Just like find, but only retrieves the count, not the records themselves.
-     *
-     * @return integer Count of the records matching the criteria
-     * @throws DBException If the search could not be completed
-     */
-    public synchronized int count(String expr)
-            throws DBException {
+  // 2003-11-05 /ebn-ma: ...added
+  // ----------------------------------------------------
+
+
+  /**
+   * Just like find, but only retrieves the count, not the records themselves.
+   *
+   * @return integer Count of the records matching the criteria
+   * @throws DBException If the search could not be completed
+   */
+  public synchronized int count(String expr) throws DBException {
 //        boolean needComma = false;
 //        DBObject oneObj = null;
 //        DBField oneField = null;
@@ -547,43 +577,45 @@
 //        }
 
 
-        DBConnectionPool myPool = null;
-        DBConnection myConnection = null;
+    DBConnectionPool myPool = null;
+    DBConnection myConnection = null;
 
-        try {
-            if (localConnection != null) {
-                myConnection = localConnection;
-            } else {
-                myPool = DBConnectionPool.getInstance(getDataContext());
-                myConnection = myPool.getConnection("com.jcorporate.expresso.core.dbobj.DBObject");
-            }
-
-            if (recordSet == null) {
-                String myName = (thisClass + "count()");
-                throw new DBException(myName +
-                        ":Database object not correctly initialized");
-            }
-
-            recordSet.clear();
-
-            FastStringBuffer myStatement = new FastStringBuffer(256);
-            myStatement.append("SELECT ");
-
-            if (selectDistinct) {
-                myStatement.append(" DISTINCT ");
-            }
-            if (StringUtil.isBlankOrNull(expr)) {
-                expr = "*";
-            }
-            myStatement.append("COUNT(" + expr + ") ");
-
-            // ----------------------------------------------------
-            // 2003-11-05 /ebn-ma: changed...
-            // We build the from clause every time we genereate a
-            // sql-statement. Because:
-            // If we use joins, this is the only chance to integrate
-            // filter-conditions that follow the actual values in
-            // the properties of the related DBObjects.
+    try {
+      if (localConnection != null) {
+        myConnection = localConnection;
+      }
+      else {
+        myPool = DBConnectionPool.getInstance(getDataContext());
+        myConnection = myPool.getConnection(
+            "com.jcorporate.expresso.core.dbobj.DBObject");
+      }
+
+      if (recordSet == null) {
+        String myName = (thisClass + "count()");
+        throw new DBException(myName +
+                              ":Database object not correctly initialized");
+      }
+
+      recordSet.clear();
+
+      FastStringBuffer myStatement = new FastStringBuffer(256);
+      myStatement.append("SELECT ");
+
+      if (selectDistinct) {
+        myStatement.append(" DISTINCT ");
+      }
+      if (StringUtil.isBlankOrNull(expr)) {
+        expr = "*";
+      }
+      myStatement.append("COUNT(" + expr + ") ");
+
+      // ----------------------------------------------------
+      // 2003-11-05 /ebn-ma: changed...
+      // We build the from clause every time we genereate a
+      // sql-statement. Because:
+      // If we use joins, this is the only chance to integrate
+      // filter-conditions that follow the actual values in
+      // the properties of the related DBObjects.
 
 //                myStatement.append(" FROM ");
 //                if (fromClause == null) {
@@ -611,1763 +643,1919 @@
 //                     */
 //                }
 
-            myStatement.append(" FROM ");
-            if (buildFromClause() &&
-                    fromClause != null &&
-                    fromClause.trim().length() > 0) {
-                myStatement.append(fromClause);
-            } else {
-                throw new DBException(thisClass + "count()" +
-                        " :Building of FROM clause failed.");
-            }
-            // 2003-11-05 /ebn-ma: ...changed
-            // ----------------------------------------------------
-
-            String whereClause;
-            if (customWhereClause != null) {
-                if (appendCustomWhereClause) {
-                    whereClause = buildWhereClause(true) + " AND " + customWhereClause;
-                } else {
-                    whereClause = " WHERE " + customWhereClause;
-                }
-            } else {
-                whereClause = buildWhereClause(true);
-            }
-
-            myStatement.append(whereClause);
-
-            appendCustomWhereClause = false;
-
-            if (log.isDebugEnabled()) {
-                log.debug("Executing " + myStatement.toString());
-            }
-
-            myConnection.execute(myStatement.toString());
-
-            if (myConnection.next()) {
-                return myConnection.getInt(1);
-            }
-        } finally {
-            if (localConnection == null) {
-                myPool.release(myConnection);
-            }
-        }
-
-
-        return 0;
-    } /* count() */
-
-    /**
-     * Just like find, but only retrieves the count, not the records themselves.
-     *
-     * @return integer Count of the records matching the criteria
-     * @throws DBException If the search could not be completed
-     */
-    public synchronized int count()
-            throws DBException {
-        return count("");
-    } /* count() */
-
-
-    /**
-     * Creates the limitation syntax optimisation stub
-     * to embed inside the SQL command that performs
-     * search and retrieve.
-     * <p/>
-     * <p>This method takes the limitation syntax string
-     * and performs a string replacement on the following
-     * tokens
-     * <p/>
-     * <ul>
-     * <p/>
-     * <li><b>%offset%</b><li><br>
-     * the number of rows in the <code>ResultSet</code> to skip
-     * before reading the data.
-     * <p/>
-     * <li><b>%maxrecord%</b><li><br>
-     * the maximum number of rows to read from  the <code>ResultSet</code>.
-     * Also known as the <i>rowlength</i>.
-     * <p/>
-     * <li><b>%endrecord%</b><li><br>
-     * the last record of in the <code>ResultSet</code> that the
-     * search and retrieved should retrieve. The end record number
-     * is equal to <code>( %offset% + %maxrecord% - 1 )</code>
-     * <p/>
-     * </ul>
-     * <p/>
-     * </p>
-     * <p/>
-     * <p/>
-     * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
-     *
-     * @param theConnection the db connection to make this stub from
-     * @return the limitation syntax stub string
-     * @see #searchAndRetrieveList()
-     * @see #setOffsetRecord( int )
-     * @see #setMaxRecords( int )
-     */
-    protected String makeLimitationStub(DBConnection theConnection) {
-        String limit = theConnection.getLimitationSyntax();
-        int offset = this.getOffsetRecord();
-        int maxrec = this.getMaxRecords();
-        int endrec = offset + maxrec - 1;
-        limit = StringUtil.replace(limit, "%offset%", Integer.toString(offset));
-        limit = StringUtil.replace(limit, "%maxrecords%",
-                Integer.toString(maxrec));
-
-        // limit = StringUtil.replace( limit, "%length%",    Integer.toString( maxrec ) );
-        limit = StringUtil.replace(limit, "%endrecord%",
-                Integer.toString(endrec));
-
-        return limit;
-    } /* makeLimitationStub(DBConnection) */
-
+      myStatement.append(" FROM ");
+      if (buildFromClause() &&
+          fromClause != null &&
+          fromClause.trim().length() > 0) {
+        myStatement.append(fromClause);
+      }
+      else {
+        throw new DBException(thisClass + "count()" +
+                              " :Building of FROM clause failed.");
+      }
+      // 2003-11-05 /ebn-ma: ...changed
+      // ----------------------------------------------------
+
+      String whereClause;
+      if (customWhereClause != null) {
+        if (appendCustomWhereClause) {
+          whereClause = buildWhereClause(true) + " AND " + customWhereClause;
+        }
+        else {
+          whereClause = " WHERE " + customWhereClause;
+        }
+      }
+      else {
+        whereClause = buildWhereClause(true);
+      }
+
+      myStatement.append(whereClause);
+
+      appendCustomWhereClause = false;
+
+      if (log.isDebugEnabled()) {
+        log.debug("Executing " + myStatement.toString());
+      }
+
+      myConnection.execute(myStatement.toString());
+
+      if (myConnection.next()) {
+        return myConnection.getInt(1);
+      }
+    }
+    finally {
+      if (localConnection == null) {
+        myPool.release(myConnection);
+      }
+    }
+
+    return 0;
+  }
+
+  /* count() */
+
+  /**
+   * Just like find, but only retrieves the count, not the records themselves.
+   *
+   * @return integer Count of the records matching the criteria
+   * @throws DBException If the search could not be completed
+   */
+  public synchronized int count() throws DBException {
+    return count("");
+  }
+
+  /* count() */
+
+  /**
+   * Creates the limitation syntax optimisation stub
+   * to embed inside the SQL command that performs
+   * search and retrieve.
+   * <p/>
+   * <p>This method takes the limitation syntax string
+   * and performs a string replacement on the following
+   * tokens
+   * <p/>
+   * <ul>
+   * <p/>
+   * <li><b>%offset%</b><li><br>
+   * the number of rows in the <code>ResultSet</code> to skip
+   * before reading the data.
+   * <p/>
+   * <li><b>%maxrecord%</b><li><br>
+   * the maximum number of rows to read from  the <code>ResultSet</code>.
+   * Also known as the <i>rowlength</i>.
+   * <p/>
+   * <li><b>%endrecord%</b><li><br>
+   * the last record of in the <code>ResultSet</code> that the
+   * search and retrieved should retrieve. The end record number
+   * is equal to <code>( %offset% + %maxrecord% - 1 )</code>
+   * <p/>
+   * </ul>
+   * <p/>
+   * </p>
+   * <p/>
+   * <p/>
+   * author Peter Pilgrim, Thu Jun 21 10:30:59 BST 2001
+   *
+   * @param theConnection the db connection to make this stub from
+   * @return the limitation syntax stub string
+   * @see #searchAndRetrieveList()
+   * @see #setOffsetRecord( int )
+   * @see #setMaxRecords( int )
+   */
+  protected String makeLimitationStub(DBConnection theConnection) {
+    String limit = theConnection.getLimitationSyntax();
+    int offset = this.getOffsetRecord();
+    int maxrec = this.getMaxRecords();
+    int endrec = offset + maxrec - 1;
+    limit = StringUtil.replace(limit, "%offset%", Integer.toString(offset));
+    limit = StringUtil.replace(limit, "%maxrecords%",
+                               Integer.toString(maxrec));
+
+    // limit = StringUtil.replace( limit, "%length%",    Integer.toString( maxrec ) );
+    limit = StringUtil.replace(limit, "%endrecord%",
+                               Integer.toString(endrec));
+
+    return limit;
+  }
+
+  /* makeLimitationStub(DBConnection) */
+
+  private static final String thisClass = MultiDBObject.class.getName() + ".";
+
+  /**
+   * Hash that contains the DB objects that relate to make up this query,
+   * indexed by the "short" name provided by the user.
+   */
+  private Hashtable myDBObjects = new Hashtable();
+
+  /**
+   * Vector to hold the "relations" between the different db objects that
+   * make up this query
+   */
+  private Vector relations = new Vector();
+  private String dbName = null;
+
+  /**
+   * This flag tells the buildWhereClause method(s) to either be case
+   * sensitive (normal queries) or to be case insensitive. The case
+   * insensitive query is useful when you want to do a search and retreive
+   * and want case insensitive matching.
+   */
+  private boolean caseSensitiveQuery = true;
+
+  /**
+   * broken into a vector
+   */
+  private Vector sortKeys = new Vector();
+
+  /**
+   * The vector of MultiDB objects retrieved by the last searchAndRetrieve method
+   */
+  private List recordSet = new ArrayList();
+
+  /**
+   * If we are using a custom where clause for this query, it's stored here. If
+   * null, then build the where clause
+   */
+  private String customWhereClause = null;
+
+  /**
+   * Hold the relations in "original" form - for the getThisMultiDBObj method
+   */
+  private Vector originalRelations = new Vector();
+
+  /**
+   * Local connection that we use if it's initialized, but
+   * if it's null we generate our own connection
+   */
+  protected DBConnection localConnection = null;
+
+  /* The max number of records we retrieve in a searchAndRetrieve.
+   * 0 means no limit
+   */
+  protected int maxRecords = 0;
+  private static Logger log = Logger.getLogger(MultiDBObject.class);
+
+  /**
+   * MultiDBObject constructor. calls setupFields.
+   */
+  public MultiDBObject() throws DBException {
+    setupFields();
+  }
+
+  /* MultiDBObject() */
+
+  /**
+   * MultiDBObject constructor which sets dbname from request
+   */
+  public MultiDBObject(ControllerRequest request) throws DBException {
+    this();
+    setDataContext(request.getDataContext());
+  }
+
+  /* MultiDBObject() */
+
+  /**
+   * Add a DB Object to the objects being used for this multidbobj query. The
+   * object is specified with a full classname, then a "short" name used to refer
+   * to it in this object. For example, the class name might be
+   * com.jcorporate.expresso.services.dbobj.SchemaList, the short name might be
+   * "schema".
+   *
+   * @param dbobjClassName java.lang.String
+   * @param shortName      java.lang.String
+   */
+  public void addDBObj(String dbobjClassName, String shortName) throws
+      DBException {
+    String myName = thisClass + "addDBObj(String, String)";
+
+    if (StringUtil.notNull(dbobjClassName).equals("")) {
+      throw new DBException(myName + ":Must specify a class name");
+    }
+    if (StringUtil.notNull(shortName).equals("")) {
+      throw new DBException(myName + ":Must specify a short name");
+    }
+
+    DBObject oneDBObj = null;
+
+    try {
+      Class c = ClassLocator.loadClass(dbobjClassName);
+      oneDBObj = (DBObject) c.newInstance();
+    }
+    catch (ClassNotFoundException cn) {
+      throw new DBException(myName + ":DBObject '" + dbobjClassName +
+                            "' not found", cn);
+    }
+    catch (InstantiationException ie) {
+      throw new DBException(myName + ":DBObject '" + dbobjClassName +
+                            "' cannot be instantiated", ie);
+    }
+    catch (IllegalAccessException iae) {
+      throw new DBException(myName +
+                            ":Illegal access loading DBObject '" +
+                            dbobjClassName + "'", iae);
+    }
+
+    addDBObj(oneDBObj, shortName);
+  }
+
+  public void addDBObj(DBObject oneDBObj, String shortName) throws DBException {
+    StringUtil.assertNotBlank(shortName, "Short name cannot be blank here");
+    oneDBObj.setAttribute(SHORT_NAME, shortName);
+    myDBObjects.put(shortName, oneDBObj);
+
+    if (getDataContext() == null) {
+      setDataContext(oneDBObj.getDataContext());
+    }
+
+    /* Check to see if all of the db objects are in the same database */
+    oneDBObj.setDataContext(getDataContext());
+
+    if (!oneDBObj.getDataContext().equals(getDataContext())) {
+      throw new DBException("DB Object '" +
+                            oneDBObj.getClass().getName() +
+                            "' was mapped to db/context '" +
+                            oneDBObj.getDataContext() +
+                            "', but this MultiDBObject is in context '" +
+                            getDataContext() + "'");
+    }
+  }
+
+  /* addDBOj(String, String) */
+
+  /**
+   * Build and return a string consisting of an SQL 'where' clause
+   * using the current field values as criteria for the search. See
+   * setCustomWhereClause for information on specifying a more complex where clause.
+   *
+   * @param useAllFields True if all fields are to be used,
+   *                     false for only key fields
+   * @return The where clause to use in a query.
+   */
+  public String buildWhereClause(boolean useAllFields) throws DBException {
+    FastStringBuffer fsb = FastStringBuffer.getInstance();
+    try {
+      return buildWhereClauseBuffer(useAllFields, fsb).toString();
+    }
+    finally {
+      fsb.release();
+    }
+  }
+
+  /* buildWhereClause(boolean) */
+
+  // ----------------------------------------------------
+  // 2003-11-05 /ebn-ma: added...
+  // Method is overwritten for to support a new parameter dboAlias.
+  /**
+   * Build and return a string consisting of an SQL 'where' clause
+   * using the current field values as criteria for the search. See
+   * setCustomWhereClause for information on specifying a more complex where clause.
+   *
+   * @param useAllFields True if all fields are to be used, false for only key fields
+   * @return java.lang.String.
+   */
+  protected String buildWhereClauseBuffer(boolean useAllFields,
+                                          FastStringBuffer myStatement) throws
+      DBException {
+    return buildWhereClauseBuffer(useAllFields, myStatement, " ").toString();
+  }
+
+  // 2003-11-05 /ebn-ma: ...added
+  // ----------------------------------------------------
+
+  // ----------------------------------------------------
+  // 2003-11-05 /ebn-ma: changed...
+  // Method supports a new parameter dboAlias. With the help of this parameter
+  // we build selective clauses for a single DBObject.
+  // These clauses are used in method buildJoin.
+  /**
+   * Build and return a string consisting of an SQL 'where' clause
+   * using the current field values as criteria for the search. See
+   * setCustomWhereClause for information on specifying a more complex where clause.
+   *
+   * @param useAllFields True if all fields are to be used, false for only key fields
+   * @param myStatement  Buffer for to build the new where-clause.
+   * @param dboAlias     Build the where-clause for this DBObject. If empty,
+   *                     work with all DBObjects that are not marked to be ignored.
+   * @return java.lang.String.
+   */
+  protected String buildWhereClauseBuffer(boolean useAllFields,
+                                          FastStringBuffer myStatement,
+                                          String dboAlias) throws DBException {
+
+    /* list of field names (with table names prefixed) */
+    Vector fields = new Vector();
+    DBObject oneObj = null;
+    String fieldName = null;
+    Hashtable byTableName = new Hashtable();
+
+    if (useAllFields) {
+      for (Enumeration eachObj = myDBObjects.elements();
+           eachObj.hasMoreElements(); ) {
+        oneObj = (DBObject) eachObj.nextElement();
+        byTableName.put(getTableName(oneObj), oneObj);
 
-    private static final String thisClass = MultiDBObject.class.getName() + ".";
-
-    /**
-     * Hash that contains the DB objects that relate to make up this query,
-     * indexed by the "short" name provided by the user.
-     */
-    private Hashtable myDBObjects = new Hashtable();
-
-    /**
-     * Vector to hold the "relations" between the different db objects that
-     * make up this query
-     */
-    private Vector relations = new Vector();
-    private String dbName = null;
-
-    /**
-     * This flag tells the buildWhereClause method(s) to either be case
-     * sensitive (normal queries) or to be case insensitive. The case
-     * insensitive query is useful when you want to do a search and retreive
-     * and want case insensitive matching.
-     */
-    private boolean caseSensitiveQuery = true;
-
-    /**
-     * broken into a vector
-     */
-    private Vector sortKeys = new Vector();
-
-    /**
-     * The vector of MultiDB objects retrieved by the last searchAndRetrieve method
-     */
-    private List recordSet = new ArrayList();
-
-    /**
-     * If we are using a custom where clause for this query, it's stored here. If
-     * null, then build the where clause
-     */
-    private String customWhereClause = null;
-
-    /**
-     * Hold the relations in "original" form - for the getThisMultiDBObj method
-     */
-    private Vector originalRelations = new Vector();
-
-    /**
-     * Local connection that we use if it's initialized, but
-     * if it's null we generate our own connection
-     */
-    protected DBConnection localConnection = null;
-
-    /* The max number of records we retrieve in a searchAndRetrieve.
-    * 0 means no limit
-    */
-    protected int maxRecords = 0;
-    private static Logger log = Logger.getLogger(MultiDBObject.class);
-
-    /**
-     * MultiDBObject constructor. calls setupFields.
-     */
-    public MultiDBObject()
-            throws DBException {
-        setupFields();
-    } /* MultiDBObject() */
-
-    /**
-     * MultiDBObject constructor which sets dbname from request
-     */
-    public MultiDBObject(ControllerRequest request)
-            throws DBException {
-        this();
-        setDataContext(request.getDataContext());
-    } /* MultiDBObject() */
-
-    /**
-     * Add a DB Object to the objects being used for this multidbobj query. The
-     * object is specified with a full classname, then a "short" name used to refer
-     * to it in this object. For example, the class name might be
-     * com.jcorporate.expresso.services.dbobj.SchemaList, the short name might be
-     * "schema".
-     *
-     * @param dbobjClassName java.lang.String
-     * @param shortName      java.lang.String
-     */
-    public void addDBObj(String dbobjClassName, String shortName)
-            throws DBException {
-        String myName = thisClass + "addDBObj(String, String)";
-
-        if (StringUtil.notNull(dbobjClassName).equals("")) {
-            throw new DBException(myName + ":Must specify a class name");
-        }
-        if (StringUtil.notNull(shortName).equals("")) {
-            throw new DBException(myName + ":Must specify a short name");
-        }
-
-        DBObject oneDBObj = null;
-
-        try {
-            Class c = ClassLocator.loadClass(dbobjClassName);
-            oneDBObj = (DBObject) c.newInstance();
-        } catch (ClassNotFoundException cn) {
-            throw new DBException(myName + ":DBObject '" + dbobjClassName +
-                    "' not found", cn);
-        } catch (InstantiationException ie) {
-            throw new DBException(myName + ":DBObject '" + dbobjClassName +
-                    "' cannot be instantiated", ie);
-        } catch (IllegalAccessException iae) {
-            throw new DBException(myName +
-                    ":Illegal access loading DBObject '" +
-                    dbobjClassName + "'", iae);
-        }
-
-        addDBObj(oneDBObj, shortName);
-    }
-
-    public void addDBObj(DBObject oneDBObj, String shortName)
-            throws DBException {
-        StringUtil.assertNotBlank(shortName, "Short name cannot be blank here");
-        oneDBObj.setAttribute(SHORT_NAME, shortName);
-        myDBObjects.put(shortName, oneDBObj);
-
-        if (getDataContext() == null) {
-            setDataContext(oneDBObj.getDataContext());
-        }
-
-        /* Check to see if all of the db objects are in the same database */
-        oneDBObj.setDataContext(getDataContext());
-
-        if (!oneDBObj.getDataContext().equals(getDataContext())) {
-            throw new DBException("DB Object '" +
-                    oneDBObj.getClass().getName() +
-                    "' was mapped to db/context '" +
-                    oneDBObj.getDataContext() +
-                    "', but this MultiDBObject is in context '" +
-                    getDataContext() + "'");
+        // ----------------------------------------------------
+        // 2003-11-05 /ebn-ma: added...
+        // Two cases:
+        // 1. If dboAlias tells us to compute the on-clause of a join,
+        //    then we will ignore every DBObject that is not the one
+        //    specified in dboAlias.
+        // 2. If dboAlias is empty, we are computing the where-clause of
+        //    our sql-statement.
+        //    In this case we ignore the current DBObject, if it is a
+        //    member of ignoreInWhereClause.
+        String thisDbo = (String) oneObj.getAttribute(SHORT_NAME);
+
+        if (dboAlias.trim().length() > 0) {
+          if (!thisDbo.equals(dboAlias)) {
+            continue;
+          }
         }
-    } /* addDBOj(String, String) */
-
-    /**
-     * Build and return a string consisting of an SQL 'where' clause
-     * using the current field values as criteria for the search. See
-     * setCustomWhereClause for information on specifying a more complex where clause.
-     *
-     * @param useAllFields True if all fields are to be used,
-     *                     false for only key fields
-     * @return The where clause to use in a query.
-     */
-    public String buildWhereClause(boolean useAllFields)
-            throws DBException {
-        FastStringBuffer fsb = FastStringBuffer.getInstance();
-        try {
-            return buildWhereClauseBuffer(useAllFields, fsb).toString();
-        } finally {
-            fsb.release();
+        else if (ignoreInWhereClause.indexOf("," + thisDbo + ",") >= 0) {
+          continue;
         }
-    } /* buildWhereClause(boolean) */
-
-    // ----------------------------------------------------
-    // 2003-11-05 /ebn-ma: added...
-    // Method is overwritten for to support a new parameter dboAlias.
-    /**
-     * Build and return a string consisting of an SQL 'where' clause
-     * using the current field values as criteria for the search. See
-     * setCustomWhereClause for information on specifying a more complex where clause.
-     *
-     * @param useAllFields True if all fields are to be used, false for only key fields
-     * @return java.lang.String.
-     */
-    protected String buildWhereClauseBuffer(boolean useAllFields, FastStringBuffer myStatement)
-            throws DBException {
-        return buildWhereClauseBuffer(useAllFields, myStatement, " ").toString();
-    }
-    // 2003-11-05 /ebn-ma: ...added
-    // ----------------------------------------------------
-
-    // ----------------------------------------------------
-    // 2003-11-05 /ebn-ma: changed...
-    // Method supports a new parameter dboAlias. With the help of this parameter
-    // we build selective clauses for a single DBObject.
-    // These clauses are used in method buildJoin.
-    /**
-     * Build and return a string consisting of an SQL 'where' clause
-     * using the current field values as criteria for the search. See
-     * setCustomWhereClause for information on specifying a more complex where clause.
-     *
-     * @param useAllFields True if all fields are to be used, false for only key fields
-     * @param myStatement  Buffer for to build the new where-clause.
-     * @param dboAlias     Build the where-clause for this DBObject. If empty,
-     *                     work with all DBObjects that are not marked to be ignored.
-     * @return java.lang.String.
-     */
-    protected String buildWhereClauseBuffer(boolean useAllFields, FastStringBuffer myStatement, String dboAlias)
-            throws DBException {
-
-        /* list of field names (with table names prefixed) */
-        Vector fields = new Vector();
-        DBObject oneObj = null;
-        String fieldName = null;
-        Hashtable byTableName = new Hashtable();
-
-        if (useAllFields) {
-            for (Enumeration eachObj = myDBObjects.elements();
-                 eachObj.hasMoreElements();) {
-                oneObj = (DBObject) eachObj.nextElement();
-                byTableName.put(getTableName(oneObj), oneObj);
-
-                // ----------------------------------------------------
-                // 2003-11-05 /ebn-ma: added...
-                // Two cases:
-                // 1. If dboAlias tells us to compute the on-clause of a join,
-                //    then we will ignore every DBObject that is not the one
-                //    specified in dboAlias.
-                // 2. If dboAlias is empty, we are computing the where-clause of
-                //    our sql-statement.
-                //    In this case we ignore the current DBObject, if it is a
-                //    member of ignoreInWhereClause.
-                String thisDbo = (String) oneObj.getAttribute(SHORT_NAME);
-
-                if (dboAlias.trim().length() > 0) {
-                    if (!thisDbo.equals(dboAlias)) {
-                        continue;
-                    }
-                } else if (ignoreInWhereClause.indexOf("," + thisDbo + ",") >= 0) {
-                    continue;
-                }
-                // 2003-11-05 /ebn-ma: ...added
-                // ----------------------------------------------------
-
-                for (Iterator i = oneObj.getMetaData().getFieldListArray().iterator(); i.hasNext();) {
-                    fieldName = (String) i.next();
-
-                    if (!oneObj.getMetaData().getFieldMetadata(fieldName).isVirtual()) {
-                        fields.addElement(getTableName(oneObj) + "." +
-                                fieldName);
-                    }
-                } /* for each field */
-            }
-        } else { /* for each db object */
-            for (Enumeration eachObj = myDBObjects.elements();
-                 eachObj.hasMoreElements();) {
-                oneObj = (DBObject) eachObj.nextElement();
-
-                // ----------------------------------------------------
-                // 2003-11-05 /ebn-ma: added...
-                // Two cases:
-                // 1. If dboAlias tells us to compute the on-clause of a join,
-                //    then we will ignore every DBObject that is not the one
-                //    specified in dboAlias.
-                // 2. If dboAlias is empty, we are computing the where-clause of
-                //    our sql-statement.
-                //    In this case we ignore the current DBObject, if it is a
-                //    member of ignoreInWhereClause.
-                String thisDbo = (String) oneObj.getAttribute(SHORT_NAME);
-
-                if (dboAlias.trim().length() > 0) {
-                    if (!thisDbo.equals(dboAlias)) {
-                        continue;
-                    }
-                } else if (ignoreInWhereClause.indexOf("," + thisDbo + ",") >= 0) {
-                    continue;
-                }
-                // 2003-11-05 /ebn-ma: ...added
-                // ----------------------------------------------------
-
-                for (Iterator i = oneObj.getKeyFieldListIterator();
-                     i.hasNext();) {
-                    fieldName = (String) i.next();
-
-                    if (!oneObj.getMetaData().getFieldMetadata(fieldName).isVirtual()) {
-                        fields.addElement(getTableName(oneObj) + "." +
-                                fieldName);
-                    }
-                } /* for each field */
-            } /* for each db object */
-        }
-
-        /* Now go thru each field - if it is non-empty, add it's criteria */
-
-        /* to the where clause. If it is empty, just skip to the next one */
-        boolean addWhere = true;
-        boolean addAnd = false;
-        String oneFieldName = null;
-        String oneTableName = null;
-        String oneFullName = null;
-        String oneFieldValue = null;
-        boolean skipText = false;
-
-        try {
-            ConfigJdbc myConfig = ConfigManager.getJdbcRequired(getDataContext());
-            skipText = myConfig.skipText();
-        } catch (ConfigurationException ce) {
-            throw new DBException(ce);
-        }
-
-        boolean skipField = false;
-
-        for (Enumeration fieldsToUse = fields.elements();
-             fieldsToUse.hasMoreElements();) {
-            oneFullName = (String) fieldsToUse.nextElement();
-
-            StringTokenizer stk = new StringTokenizer(oneFullName, ".");
-            int stkCount = stk.countTokens();
-            if (stkCount == 2) {
-                oneTableName = stk.nextToken();
-                oneFieldName = stk.nextToken();
-            } else if (stkCount == 3) {
-                String oneSchemaName = stk.nextToken();
-                oneTableName = stk.nextToken();
-                oneFieldName = stk.nextToken();
-                oneTableName = oneSchemaName + "." + oneTableName;
-            }
-
-            oneObj = (DBObject) byTableName.get(oneTableName);
-            skipField = false;
-            // ----------------------------------------------------
-            // 2003-11-18 /ebn-ma: changed...
-            // getField() makes a translation using the charset-filter.
-            // FieldRangeParser cannot succeed, if his control-characters
-            // are changed, e.g. '<' to '&lt'
-            // getFieldData() doesn't do this translation and so it works.
-            // Anyway: The corresponding code-block in JDBCUtil seems to be
-
-
-            // a better solution.
-            //  oneFieldValue =StringUtil.notNull(oneObj.getField(oneFieldName));
-
-
-            oneFieldValue = StringUtil.notNull(oneObj.getFieldData(oneFieldName));
-            // 2003-11-18 /ebn-ma: ...changed
-            // ----------------------------------------------------
-
-            String rangeString = oneObj.denotesRange(oneFieldValue);
-
-            if (!oneFieldValue.equals("")) {
-                oneFieldValue = oneObj.quoteIfNeeded(oneFieldName, rangeString);
-            }
-            if (oneFieldValue.equals("")) {
-                skipField = true;
-            }
-            if (oneFieldValue == null) {
-                skipField = true;
-            }
-            if (oneFieldValue.equals("\'\'")) {
-                skipField = true;
-            }
-            if ((oneObj.getMetaData().getType(oneFieldName).equals("text")) && (skipText)) {
-                skipField = true;
-            }
-            if (!skipField) {
-                // check to see if the field value is valid (protects agains sql injection)
-                String unalteredFieldValue = oneObj.getDataField(oneFieldName).asString();
-                if (rangeString != null) {
-                    FieldRangeParser rangeParser = new FieldRangeParser();
-                    boolean valid = rangeParser.isValidRange(oneObj.getFieldMetaData(oneFieldName),
-                            unalteredFieldValue);
-                    if (!valid) {
-                        throw new DBException("Invalid field range value: " + unalteredFieldValue);
-                    }
-                } else if (oneObj.containsWildCards(oneFieldValue)) {
-                    Object origValue = oneObj.getDataField(oneFieldName).getValue();
-
-                    String[] wildcards = null;
-                    wildcards = (String[]) oneObj.getConnectionPool().getWildCardsList().toArray(new String[0]);
-                    Filter filter = new Filter(wildcards, wildcards);
-                    String valueWithoutWildCards = filter.stripFilter(unalteredFieldValue);
-                    // if the value without wildcards is empty, then we know the field is valid
-                    if (!valueWithoutWildCards.equals("")) {
-                        oneObj.getDataField(oneFieldName).setValue(valueWithoutWildCards);
-                        oneObj.getDataField(oneFieldName).checkValue();
-                        oneObj.getDataField(oneFieldName).setValue(origValue);
-                    }
-                } else {
-                    oneObj.getDataField(oneFieldName).checkValue();
-                }
-
-
-                if (addWhere) {
-                    myStatement.append(" WHERE ");
-                    addWhere = false;
-                }
-                if (addAnd) {
-                    myStatement.append(" AND ");
-                }
-                if (oneObj.containsWildCards(oneFieldValue)) {
-                    if (caseSensitiveQuery) {
-                        myStatement.append(getTableName(oneObj) + "." +
-                                oneFieldName);
-                        myStatement.append(" LIKE ");
-                        myStatement.append(oneFieldValue);
-                    } else {
-                        myStatement.append("UPPER(");
-                        myStatement.append(getTableName(oneObj) + "." +
-                                oneFieldName);
-                        myStatement.append(") LIKE ");
-                        myStatement.append(oneFieldValue.toUpperCase());
-                    }
-                } else if (rangeString != null) {
-                    myStatement.append(getTableName(oneObj) + "." +
-                            oneFieldName);
-                    myStatement.append(" " + rangeString + " ");
-                    myStatement.append(oneFieldValue);
-                } else {
-                    if (caseSensitiveQuery) {
-                        myStatement.append(getTableName(oneObj) + "." +
-                                oneFieldName);
-                        myStatement.append(" = ");
-                        myStatement.append(oneFieldValue);
-                    } else {
-                        myStatement.append("UPPER(");
-                        myStatement.append(getTableName(oneObj) + "." +
-                                oneFieldName);
-                        myStatement.append(") = ");
-                        myStatement.append(oneFieldValue.toUpperCase());
-                    }
-                }
-
-                addAnd = true;
-            }
+        // 2003-11-05 /ebn-ma: ...added
+        // ----------------------------------------------------
 
-            /* if field is not skipped for some reason */
+        for (Iterator i = oneObj.getMetaData().getFieldListArray().iterator();
+             i.hasNext(); ) {
+          fieldName = (String) i.next();
+
+          if (!oneObj.getMetaData().getFieldMetadata(fieldName).isVirtual()) {
+            fields.addElement(getTableName(oneObj) + "." +
+                              fieldName);
+          }
         }
-
         /* for each field */
-        boolean needAnd = false;
-
-        /**
-         * FIXED: ma 17.10.2003
-         * FIXED: Don't do that at here. We do not need
-         * FIXED: WHERE, if we do not
-         * FIXED: have any where-condition.
-         * FIXED: So check that in the following for-loop.
-         *        if (addWhere) {
-         *            myStatement.append(" WHERE ");
-         *        } else {
-         *            needAnd = true;
-         *        }
-         */
+      }
+    }
+    else { /* for each db object */
+      for (Enumeration eachObj = myDBObjects.elements();
+           eachObj.hasMoreElements(); ) {
+        oneObj = (DBObject) eachObj.nextElement();
 
         // ----------------------------------------------------
-        // 2003-11-05 /ebn-ma: changed...
-        // If originalJoins is not empty, we are working with joins and
-        // define our relations in the from clause.
-        // In this case ignore all accidentially defined relations...
-        if (originalJoins.isEmpty()) {
-            String oneRelation = null;
-
-            for (Enumeration e = relations.elements(); e.hasMoreElements();) {
-                /**
-                 * FIXED: ma 17.10.2003  Here is a better
-                 * FIXED: place for addWhere...
-                 */
-                if (addWhere) {
-                    myStatement.append(" WHERE ");
-                    addWhere = false;
-                } else {
-                    needAnd = true;
-                }
-
-                oneRelation = (String) e.nextElement();
-
-                if (needAnd) {
-                    myStatement.append(" AND ");
-                }
-
-                myStatement.append(oneRelation);
-                needAnd = true;
-            }
+        // 2003-11-05 /ebn-ma: added...
+        // Two cases:
+        // 1. If dboAlias tells us to compute the on-clause of a join,
+        //    then we will ignore every DBObject that is not the one
+        //    specified in dboAlias.
+        // 2. If dboAlias is empty, we are computing the where-clause of
+        //    our sql-statement.
+        //    In this case we ignore the current DBObject, if it is a
+        //    member of ignoreInWhereClause.
+        String thisDbo = (String) oneObj.getAttribute(SHORT_NAME);
+
+        if (dboAlias.trim().length() > 0) {
+          if (!thisDbo.equals(dboAlias)) {
+            continue;
+          }
         }
-        // 2003-11-05 /ebn-ma: ...changed
+        else if (ignoreInWhereClause.indexOf("," + thisDbo + ",") >= 0) {
+          continue;
+        }
+        // 2003-11-05 /ebn-ma: ...added
         // ----------------------------------------------------
 
-        if (log.isDebugEnabled()) {
-            log.debug(myStatement.toString());
+        for (Iterator i = oneObj.getKeyFieldListIterator();
+             i.hasNext(); ) {
+          fieldName = (String) i.next();
+
+          if (!oneObj.getMetaData().getFieldMetadata(fieldName).isVirtual()) {
+            fields.addElement(getTableName(oneObj) + "." +
+                              fieldName);
+          }
         }
+        /* for each field */
+      }
+      /* for each db object */
+    }
 
-        return myStatement.toString();
-    } /* buildWhereClause(boolean) */
-
+    /* Now go thru each field - if it is non-empty, add it's criteria */
 
-    /**
-     * Insert the method's description here.
-     * <p/>
-     * Creation date: (10/3/00 10:48:12 AM)
-     *
-     * @throws com.jcorporate.expresso.core.db.DBException
-     *          The exception description.
+    /* to the where clause. If it is empty, just skip to the next one */
+    boolean addWhere = true;
+    boolean addAnd = false;
+    String oneFieldName = null;
+    String oneTableName = null;
+    String oneFullName = null;
+    String oneFieldValue = null;
+    boolean skipText = false;
+
+    try {
+      ConfigJdbc myConfig = ConfigManager.getJdbcRequired(getDataContext());
+      skipText = myConfig.skipText();
+    }
+    catch (ConfigurationException ce) {
+      throw new DBException(ce);
+    }
+
+    boolean skipField = false;
+
+    for (Enumeration fieldsToUse = fields.elements();
+         fieldsToUse.hasMoreElements(); ) {
+      oneFullName = (String) fieldsToUse.nextElement();
+
+      StringTokenizer stk = new StringTokenizer(oneFullName, ".");
+      int stkCount = stk.countTokens();
+      if (stkCount == 2) {
+        oneTableName = stk.nextToken();
+        oneFieldName = stk.nextToken();
+      }
+      else if (stkCount == 3) {
+        String oneSchemaName = stk.nextToken();
+        oneTableName = stk.nextToken();
+        oneFieldName = stk.nextToken();
+        oneTableName = oneSchemaName + "." + oneTableName;
+      }
+
+      oneObj = (DBObject) byTableName.get(oneTableName);
+      skipField = false;
+      // ----------------------------------------------------
+      // 2003-11-18 /ebn-ma: changed...
+      // getField() makes a translation using the charset-filter.
+      // FieldRangeParser cannot succeed, if his control-characters
+      // are changed, e.g. '<' to '&lt'
+      // getFieldData() doesn't do this translation and so it works.
+      // Anyway: The corresponding code-block in JDBCUtil seems to be
+
+
+      // a better solution.
+      //  oneFieldValue =StringUtil.notNull(oneObj.getField(oneFieldName));
+
+
+      oneFieldValue = StringUtil.notNull(oneObj.getFieldData(oneFieldName));
+      // 2003-11-18 /ebn-ma: ...changed
+      // ----------------------------------------------------
+
+      String rangeString = oneObj.denotesRange(oneFieldValue);
+
+      if (!oneFieldValue.equals("")) {
+        oneFieldValue = oneObj.quoteIfNeeded(oneFieldName, rangeString);
+      }
+      if (oneFieldValue.equals("")) {
+        skipField = true;
+      }
+      if (oneFieldValue == null) {
+        skipField = true;
+      }
+      if (oneFieldValue.equals("\'\'")) {
+        skipField = true;
+      }
+      if ( (oneObj.getMetaData().getType(oneFieldName).equals("text")) &&
+          (skipText)) {
+        skipField = true;
+      }
+      if (!skipField) {
+        // check to see if the field value is valid (protects agains sql injection)
+        String unalteredFieldValue = oneObj.getDataField(oneFieldName).asString();
+        if (rangeString != null) {
+          FieldRangeParser rangeParser = new FieldRangeParser();
+          boolean valid = rangeParser.isValidRange(oneObj.getFieldMetaData(
+              oneFieldName),
+              unalteredFieldValue);
+          if (!valid) {
+            throw new DBException("Invalid field range value: " +
+                                  unalteredFieldValue);
+          }
+        }
+        else if (oneObj.containsWildCards(oneFieldValue)) {
+          Object origValue = oneObj.getDataField(oneFieldName).getValue();
+
+          String[] wildcards = null;
+          wildcards = (String[]) oneObj.getConnectionPool().getWildCardsList().
+              toArray(new String[0]);
+          Filter filter = new Filter(wildcards, wildcards);
+          String valueWithoutWildCards = filter.stripFilter(unalteredFieldValue);
+          // if the value without wildcards is empty, then we know the field is valid
+          if (!valueWithoutWildCards.equals("")) {
+            oneObj.getDataField(oneFieldName).setValue(valueWithoutWildCards);
+            oneObj.getDataField(oneFieldName).checkValue();
+            oneObj.getDataField(oneFieldName).setValue(origValue);
+          }
+        }
+        else {
+          oneObj.getDataField(oneFieldName).checkValue();
+        }
+
+        if (addWhere) {
+          myStatement.append(" WHERE ");
+          addWhere = false;
+        }
+        if (addAnd) {
+          myStatement.append(" AND ");
+        }
+        if (oneObj.containsWildCards(oneFieldValue)) {
+          if (caseSensitiveQuery) {
+            myStatement.append(getTableName(oneObj) + "." +
+                               oneFieldName);
+            myStatement.append(" LIKE ");
+            myStatement.append(oneFieldValue);
+          }
+          else {
+            myStatement.append("UPPER(");
+            myStatement.append(getTableName(oneObj) + "." +
+                               oneFieldName);
+            myStatement.append(") LIKE ");
+            myStatement.append(oneFieldValue.toUpperCase());
+          }
+        }
+        else if (rangeString != null) {
+          myStatement.append(getTableName(oneObj) + "." +
+                             oneFieldName);
+          myStatement.append(" " + rangeString + " ");
+          myStatement.append(oneFieldValue);
+        }
+        else {
+          if (caseSensitiveQuery) {
+            myStatement.append(getTableName(oneObj) + "." +
+                               oneFieldName);
+            myStatement.append(" = ");
+            myStatement.append(oneFieldValue);
+          }
+          else {
+            myStatement.append("UPPER(");
+            myStatement.append(getTableName(oneObj) + "." +
+                               oneFieldName);
+            myStatement.append(") = ");
+            myStatement.append(oneFieldValue.toUpperCase());
+          }
+        }
+
+        addAnd = true;
+      }
+
+      /* if field is not skipped for some reason */
+    }
+
+    /* for each field */
+    boolean needAnd = false;
+
+    /**
+     * FIXED: ma 17.10.2003
+     * FIXED: Don't do that at here. We do not need
+     * FIXED: WHERE, if we do not
+     * FIXED: have any where-condition.
+     * FIXED: So check that in the following for-loop.
+     *        if (addWhere) {
+     *            myStatement.append(" WHERE ");
+     *        } else {
+     *            needAnd = true;
+     *        }
      */
-    public void clear()
-            throws com.jcorporate.expresso.core.db.DBException {
-        DBObject oneObj = null;
 
-        for (Enumeration eachObj = myDBObjects.elements();
-             eachObj.hasMoreElements();) {
-            oneObj = (DBObject) eachObj.nextElement();
-            oneObj.clear();
-        }
+    // ----------------------------------------------------
+    // 2003-11-05 /ebn-ma: changed...
+    // If originalJoins is not empty, we are working with joins and
+    // define our relations in the from clause.
+    // In this case ignore all accidentially defined relations...
+    if (originalJoins.isEmpty()) {
+      String oneRelation = null;
 
+      for (Enumeration e = relations.elements(); e.hasMoreElements(); ) {
         /**
-         * FIXED: ma 17.10.2003  Kill the fromClause here!
+         * FIXED: ma 17.10.2003  Here is a better
+         * FIXED: place for addWhere...
          */
-        fromClause = null;
-
-    } /* clear() */
-
-
-    /**
-     * Return the name of the context/database connection that this DB object is
-     * using. If none is set, then we are using the "default" database/context.
-     *
-     * @return the name of the datacontext
-     * @deprecated 12/2004; use getDataContext instead
-     */
-    public synchronized String getDBName() {
-        return getDataContext();
-    } /* getDBName() */
-
-    /**
-     * Return the name of the context/database connection that this DB object is
-     * using. If none is set, then we are using the "default" database/context.
-     *
-     * @return the name of the datacontext
-     */
-    public synchronized String getDataContext() {
-        // set from RequestRegistry if this is first access
-        if (dbName == null || dbName.length() == 0) {
-            try {
-                this.setDataContext(RequestRegistry.getDataContext());
-            } catch (Exception ex) {
-                log.warn("Problem getting data context from Registry: " +
-                        ex.getClass().getName() + ", msg: " + ex.getMessage());
-                try {
-                    setDataContext(DBConnection.DEFAULT_DB_CONTEXT_NAME);
-                } catch (DBException de) {
-                    log.error("Unable to set database to 'default'", de);
-                }
-            }
-
+        if (addWhere) {
+          myStatement.append(" WHERE ");
+          addWhere = false;
         }
-
-        return dbName;
-    }
-
-
-    /**
-     * This returns the encapsulated instance of the 'model' DBObject
-     * that was provided in 'addDBObj()';
-     * <p/>
-     * After a searchAndRetrieveList(), each MultiDBObject in the list has,
-     * encapsulated, an object of each type which was previously added as a model.
-     * Fields of this encapsulated object have been filled from whatever was retrieved.
-     * The original query object has just the original model instance.
-     *
-     * @param shortName the shortname of the model object
-     * @return the instance encapsulated by this MultiDBObject
-     *         author Abhi
-     * @throws DBException upon error
-     * @see #addDBObj(String, String)
-     *      Creation date: (02/01/2002 9:33 AM)
-     */
-    public DBObject getDBObject(String shortName)
-            throws DBException {
-
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
-        if (oneObj == null) {
-            String myName = thisClass + "getDBObject(String)";
-            throw new DBException(myName + ":No such object as '"
-                    + shortName + "'");
-        }
-        return oneObj;
-    } /* getDBObject(String) */
-
-
-    /**
-     * Get the actual DBField value specified by fieldname
-     * <p/>
-     * Creation date: (9/18/00 11:37:10 AM)
-     *
-     * @param shortName the shortname of the field
-     * @param fieldName name of the field to retrieve
-     * @return The value of the field/
-     */
-    public String getField(String shortName, String fieldName)
-            throws DBException {
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
-
-        if (oneObj == null) {
-            String myName = thisClass + "getField(String, String)";
-            throw new DBException(myName + ":No such object as '" + shortName +
-                    "'");
+        else {
+          needAnd = true;
         }
 
-        return oneObj.getField(fieldName);
-    } /* getFields(String, STring) */
-
-
-    private DBObject getByShortName(String shortName)
-            throws DBException {
-        StringUtil.assertNotBlank(shortName, "Short name may not be blank");
-
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
+        oneRelation = (String) e.nextElement();
 
-        if (oneObj == null) {
-            throw new DBException("No such object as '" + shortName + "'");
+        if (needAnd) {
+          myStatement.append(" AND ");
         }
 
-        return oneObj;
-    }
-
-    public String getFieldDecimalFormatted(String shortName, String fieldName,
-                                           String formatPattern)
-            throws DBException {
-        return getByShortName(shortName).getFieldDecimalFormatted(fieldName,
-                formatPattern);
-    } /* getFieldDecimalFormatted(String, String) */
-
-
-    public float getFieldFloat(String shortName, String fieldName)
-            throws DBException {
-        return getByShortName(shortName).getFieldFloat(fieldName);
-    } /* getFieldFloat(String, String) */
-
-    /**
-     * Returns a double object
-     * author Peter Pilgrim <peterp at xenonsoft.demon.co.uk>
-     * date Wed Jul 24 19:36:37 BST 2002
-     */
-    public double getFieldDouble(String shortName, String fieldName)
-            throws DBException {
-        return getByShortName(shortName).getFieldDouble(fieldName);
-    } /* getFieldDouble(String, String) */
-
-    /**
-     * Returns a BigDecimal object
-     * author Peter Pilgrim <peterp at xenonsoft.demon.co.uk>
-     * date Wed Jul 24 19:36:37 BST 2002
-     */
-    public BigDecimal getFieldBigDecimal(String shortName, String fieldName)
-            throws DBException {
-        return getByShortName(shortName).getFieldBigDecimal(fieldName);
-    } /* getFieldBigDecimal(String, String) */
-
-    public Date getFieldDate(String shortName, String fieldName)
-            throws DBException {
-        return getByShortName(shortName).getFieldDate(fieldName);
-    } /* getFieldDate(String, String) */
-
-
-    public int getFieldInt(String shortName, String fieldName)
-            throws DBException {
-        return getByShortName(shortName).getFieldInt(fieldName);
+        myStatement.append(oneRelation);
+        needAnd = true;
+      }
     }
+    // 2003-11-05 /ebn-ma: ...changed
+    // ----------------------------------------------------
 
-    public long getFieldLong(String shortName, String fieldName)
-            throws DBException {
-        return getByShortName(shortName).getFieldLong(fieldName);
+    if (log.isDebugEnabled()) {
+      log.debug(myStatement.toString());
     }
 
-    /**
-     * Construct a new MultiDBObject
-     *
-     * @return new MultiDBObject
-     * @throws DBException upon error
-     */
-    protected MultiDBObject getThisMultiDBObj()
-            throws DBException {
-        MultiDBObject newObj = new MultiDBObject();
-        newObj.setDataContext(getDataContext());
-
-        String oneKey = null;
-        DBObject oneDBObj = null;
-
-        for (Enumeration ek = myDBObjects.keys(); ek.hasMoreElements();) {
-            oneKey = (String) ek.nextElement();
-            oneDBObj = (DBObject) myDBObjects.get(oneKey);
-            newObj.addDBObj(oneDBObj.newInstance(), oneKey);
-        }
-
-        String oneRelation = null;
+    return myStatement.toString();
+  }
 
-        for (Enumeration er = originalRelations.elements();
-             er.hasMoreElements();) {
-            oneRelation = (String) er.nextElement();
-
-            StringTokenizer stk = new StringTokenizer(oneRelation, "|");
-            newObj.setForeignKey(stk.nextToken(), stk.nextToken(),
-                    stk.nextToken(), stk.nextToken());
-        }
-
-        // ----------------------------------------------------
-        // 2003-11-05 /ebn-ma: added...
-        // In the new Object we will also need this join-definitions.
-        String oneJoin = null;
-
-        for (Enumeration n = originalJoins.elements();
-             n.hasMoreElements();) {
-            oneJoin = (String) n.nextElement();
+  /* buildWhereClause(boolean) */
 
-            StringTokenizer stk = new StringTokenizer(oneJoin, "|");
-            String leftDbo = stk.nextToken();
-            String leftField = stk.nextToken();
-            String rightDbo = stk.nextToken();
-            String rightField = stk.nextToken();
-            String joinTyp = stk.nextToken().toLowerCase();
-
-            if ("left".equals(joinTyp)) {
-                newObj.setLeftJoin(leftDbo, leftField, rightDbo, rightField);
-            } else if ("inner".equals(joinTyp)) {
-                newObj.setInnerJoin(leftDbo, leftField, rightDbo, rightField);
-            } else if ("right".equals(joinTyp)) {
-                newObj.setRightJoin(leftDbo, leftField, rightDbo, rightField);
-            }
-        }
-        // 2003-11-05 /ebn-ma: ...added
-        // ----------------------------------------------------
-
-        return newObj;
-    } /* getThisMultiDBObj() */
-
-    /**
-     * Search and retrieve in a particular order
-     *
-     * @param sortKeyString A pipe-delimited list of key fields to sort
-     *                      the returned set by
-     * @return Vector A vector of new database objects retrieved by the search
-     * @throws DBException If the search could not be completed
-     * @deprecated Use searchAndRetrieveList(String) instead
-     */
-    public synchronized Vector searchAndRetrieve(String sortKeyString)
-            throws DBException {
-
-        return new Vector(searchAndRetrieveList(sortKeyString));
-    } /* searchAndRetrieve(String) */
-
-    /**
-     * Search and retrieve in a particular order
-     *
-     * @param sortKeyString A pipe-delimited list of key fields to sort
-     *                      the returned set by
-     * @return A list of new database objects retrieved by the search
-     * @throws DBException If the search could not be completed
-     */
-    public synchronized List searchAndRetrieveList(String sortKeyString) throws DBException {
-
-        sortKeys.clear();
-        if (sortKeyString != null) {
-            StringTokenizer stk = new StringTokenizer(sortKeyString, "|");
-            while (stk.hasMoreTokens()) {
-                sortKeys.addElement(stk.nextToken());
-            }
-        }
-
-        return searchAndRetrieveList();
+  /**
+   * Insert the method's description here.
+   * <p/>
+   * Creation date: (10/3/00 10:48:12 AM)
+   *
+   * @throws com.jcorporate.expresso.core.db.DBException
+   *          The exception description.
+   */
+  public void clear() throws com.jcorporate.expresso.core.db.DBException {
+    DBObject oneObj = null;
+
+    for (Enumeration eachObj = myDBObjects.elements();
+         eachObj.hasMoreElements(); ) {
+      oneObj = (DBObject) eachObj.nextElement();
+      oneObj.clear();
     }
 
     /**
-     * Search and retrieve in a particular order
-     *
-     * @return A list of new database objects retrieved by the search
-     * @throws DBException If the search could not be completed
-     */
-    public synchronized List searchAndRetrieveList() throws DBException {
-        boolean needComma = false;
-        DBObject oneObj = null;
-
-        HashMap rtrvListByTable = new HashMap();
-
-        DBConnectionPool myPool = null;
-        DBConnection myConnection = null;
-
+     * FIXED: ma 17.10.2003  Kill the fromClause here!
+     */
+    fromClause = null;
+
+  }
+
+  /* clear() */
+
+  /**
+   * Return the name of the context/database connection that this DB object is
+   * using. If none is set, then we are using the "default" database/context.
+   *
+   * @return the name of the datacontext
+   * @deprecated 12/2004; use getDataContext instead
+   */
+  public synchronized String getDBName() {
+    return getDataContext();
+  }
+
+  /* getDBName() */
+
+  /**
+   * Return the name of the context/database connection that this DB object is
+   * using. If none is set, then we are using the "default" database/context.
+   *
+   * @return the name of the datacontext
+   */
+  public synchronized String getDataContext() {
+    // set from RequestRegistry if this is first access
+    if (dbName == null || dbName.length() == 0) {
+      try {
+        this.setDataContext(RequestRegistry.getDataContext());
+      }
+      catch (Exception ex) {
+        log.warn("Problem getting data context from Registry: " +
+                 ex.getClass().getName() + ", msg: " + ex.getMessage());
         try {
-            if (localConnection != null) {
-                myConnection = localConnection;
-            } else {
-                myPool = DBConnectionPool.getInstance(getDataContext());
-                myConnection = myPool.getConnection("com.jcorporate.expresso.core.dbobj.DBObject");
-            }
-
-            if (recordSet == null) {
-                String myName = (thisClass + "searchAndRetrieve()");
-                throw new DBException(myName +
-                        ":Database object not correctly initialized");
-            }
-
-            recordSet.clear();
-
-            String fieldName = null;
-            FastStringBuffer myStatement = new FastStringBuffer(256);
-            myStatement.append("SELECT ");
-
-            if (myConnection.getLimitationPosition() == DBConnection.LIMITATION_AFTER_SELECT &&
-                    (offsetRecord > 0 || maxRecords > 0)) {
-
-                // Insert limitation stub after table nomination
-                String limitStub = makeLimitationStub(myConnection);
-
-                myStatement.append(" ");
-                myStatement.append(limitStub);
-                myStatement.append(" ");
-            }
-
-            if (selectDistinct) {
-                myStatement.append(" ");
-                myStatement.append("DISTINCT");
-                myStatement.append(" ");
-            }
-
-            for (Enumeration eachObj = myDBObjects.elements();
-                 eachObj.hasMoreElements();) {
-                oneObj = (DBObject) eachObj.nextElement();
-
-                ArrayList retrievedFieldList = (ArrayList) rtrvListByTable.get(getTableName(oneObj));
-                if (retrievedFieldList == null) {
-                    retrievedFieldList = new ArrayList();
-                    rtrvListByTable.put(getTableName(oneObj), retrievedFieldList);
-                }
-
-                if (oneObj.anyFieldsDistinct) {
-                    String oneFieldName = null;
-                    for (Iterator i = oneObj.getDistinctFieldArrayList().iterator();
-                         i.hasNext();
-                            ) {
-                        oneFieldName = (String) i.next();
-                        if (needComma) {
-                            myStatement.append(", ");
-                        }
-                        myStatement.append(" ");
-                        myStatement.append(myPool.getDistinctRowsetKeyword());
-                        myStatement.append(" ");
-                        myStatement.append(selectFieldString(oneObj, oneFieldName));
-                        retrievedFieldList.add(oneFieldName);
-                        needComma = true;
-                    }
-                } else if (oneObj.anyFieldsToRetrieveMulti) {
-                    String oneFieldName = null;
-                    for (Iterator i = oneObj.getFieldsToRetrieveIterator();
-                         i.hasNext();
-                            ) {
-                        oneFieldName = (String) i.next();
-                        if (needComma) {
-                            myStatement.append(", ");
-                        }
-                        myStatement.append(selectFieldString(oneObj, oneFieldName));
-                        retrievedFieldList.add(oneFieldName);
-                        needComma = true;
-                    } /* for each field */
-                } else {
-                    for (Iterator i = oneObj.getMetaData().getFieldListArray().iterator();
-                         i.hasNext();
-                            ) {
-                        fieldName = (String) i.next();
-                        DataFieldMetaData metaData =
-                                oneObj.getFieldMetaData(fieldName);
-
-                        if (!metaData.isVirtual()
-                                && !metaData.isBinaryObjectType()) {
-                            if (needComma) {
-                                myStatement.append(", ");
-                            }
-
-                            myStatement.append(selectFieldString(oneObj, fieldName));
-                            retrievedFieldList.add(fieldName);
-                            needComma = true;
-                        }
-
-                        /* if field is not virtual & not binary*/
-                    }
-
-                    /* for each field */
-                }
-            }
-
-            myStatement.append(" FROM ");
-            if (buildFromClause() &&
-                    fromClause != null &&
-                    fromClause.trim().length() > 0) {
-                myStatement.append(fromClause);
-            } else {
-                throw new DBException(thisClass + "count()" +
-                        " :Building of FROM clause failed.");
-            }
-            // 2003-11-05 /ebn-ma: ...changed
-            // ----------------------------------------------------
-
-            if (myConnection.getLimitationPosition() == DBConnection.LIMITATION_AFTER_TABLE &&
-                    (offsetRecord > 0 || maxRecords > 0)) {
-
-                // Insert limitation stub after table nomination
-                String limitStub = makeLimitationStub(myConnection);
-                myStatement.append(" ");
-                myStatement.append(limitStub);
-                myStatement.append(" ");
-            }
-
-            String whereClause;
-            if (customWhereClause != null) {
-                if (appendCustomWhereClause) {
-                    whereClause = buildWhereClause(true) + " AND " + customWhereClause;
-                } else {
-                    whereClause = " WHERE " + customWhereClause;
-                }
-            } else {
-                whereClause = buildWhereClause(true);
-            }
-
-            myStatement.append(whereClause);
-
-            appendCustomWhereClause = false;
-
-            if (myConnection.getLimitationPosition() == DBConnection.LIMITATION_AFTER_WHERE &&
-                    (offsetRecord > 0 || maxRecords > 0)) {
-
-                // Insert limitation stub after table nomination
-                String limitStub = makeLimitationStub(myConnection);
-
-                if (whereClause.length() > 0) {
-                    myStatement.append(" AND");
-                }
-
-                myStatement.append(" ");
-                myStatement.append(limitStub);
-                myStatement.append(" ");
-            }
-
-            /* Add the ORDER BY clause if any sortKeys are specified */
-            if (sortKeys.size() > 0) {
-                myStatement.append(" ORDER BY ");
-
-                boolean needComma2 = false;
-
-                for (Enumeration e = sortKeys.elements(); e.hasMoreElements();) {
-                    if (needComma2) {
-                        myStatement.append(", ");
-                    }
-
-                    myStatement.append((String) e.nextElement());
-                    needComma2 = true;
-                }
-            }
-
-            if (myConnection.getLimitationPosition() == DBConnection.LIMITATION_AFTER_ORDER_BY &&
-                    (offsetRecord > 0 || maxRecords > 0)) {
-                myStatement.append(" ");
-                myStatement.append(makeLimitationStub(myConnection));
-            }
-
-            if (log.isDebugEnabled()) {
-                log.debug("Executing " + myStatement.toString());
-            }
-
-            myConnection.execute(myStatement.toString());
-
-            int returnRecordCount = 0;
-            int loopCount = 0;
-            while (myConnection.next()) {
-                loopCount++;
-
-                //If there's limitation syntax on, then the first record will be the
-                //maximum record.
-                if (loopCount <= offsetRecord && offsetRecord > 0 &&
-                        myConnection.getLimitationPosition() == DBConnection.LIMITATION_DISABLED) {
-                    continue;
-                }
-
-                returnRecordCount++;
-
-                // maxRecords = 0 by default, so I guess this means 0 doesn't count as max number... should default to -1 ??  LAH 12/03
-                if ((returnRecordCount > maxRecords) && (maxRecords > 0)) {
-                    break;
-                }
-
-
-                if (log.isDebugEnabled()) {
-                    log.debug("Returning row " + loopCount);
-                }
-
-                MultiDBObject myObj = getThisMultiDBObj();
-                String oneFieldValue = null;
-                int i = 1;
-
-                for (Enumeration eachObj = myDBObjects.elements();
-                     eachObj.hasMoreElements();) {
-                    oneObj = (DBObject) eachObj.nextElement();
-
-                    ArrayList retrievedFieldList = (ArrayList) rtrvListByTable.get(getTableName(oneObj));
-                    // The following should never happen .... but CYA
-                    if (retrievedFieldList == null) {
-                        retrievedFieldList = new ArrayList();
-                    }
-                    for (Iterator it = retrievedFieldList.listIterator();
-                         it.hasNext();) {
-                        fieldName = (String) it.next();
-                        DataFieldMetaData metaData = oneObj.getFieldMetaData(fieldName);
-
-                        if (!metaData.isVirtual() && !metaData.isBinaryObjectType()) {
-                            try {
-                                oneFieldValue = myConnection.getString(i);
-                            } catch (DBException de) {
-                                String myName = (thisClass + "searchAndRetrieve()");
-                                throw new DBException(myName +
-                                        ":Error retrieving field '" +
-                                        getTableName(oneObj) +
-                                        "." + fieldName + "'",
-                                        de);
-                            }
-
-                            i++;
-
-                            if (log.isDebugEnabled()) {
-                                log.debug("Setting " +
-                                        getTableName(oneObj) + "." +
-                                        fieldName + " to " + oneFieldValue);
-                            }
-
-                            myObj.setField((String) oneObj.getAttribute(SHORT_NAME),
-                                    fieldName, oneFieldValue);
-                        }
-                    }
-                } /* each db object */
-
-
-                myObj.setDataContext(getDataContext());
-                recordSet.add(myObj);
-            }
-
-            /* each row retrieved from the db */
-        } finally {
-            if (localConnection == null) {
-                myPool.release(myConnection);
-            }
+          setDataContext(DBConnection.DEFAULT_DB_CONTEXT_NAME);
+        }
+        catch (DBException de) {
+          log.error("Unable to set database to 'default'", de);
         }
+      }
 
-        return recordSet;
     }
 
-    /**
-     * This tells the buildWhereClause to either respect case (true) or
-     * ignore case (false). You can call this method before doing a search and
-     * retreive if you want to match without worrying about case. For example
-     * if you where to call this method with isCaseSensitiveQuery = FALSE
-     * then this comparison would match in the search:
-     * <p/>
-     * vendor_name actual value = "My Name"
-     * <p/>
-     * query value = "my name"
-     * <p/>
-     * This would match in a search and retrieve.
-     * <p/>
-     * author Adam Rossi, PlatinumSolutions
-     *
-     * @param isCaseSensitiveQuery boolean
-     */
-    public void setCaseSensitiveQuery(boolean isCaseSensitiveQuery) {
-        caseSensitiveQuery = isCaseSensitiveQuery;
+    return dbName;
+  }
+
+  /**
+   * This returns the encapsulated instance of the 'model' DBObject
+   * that was provided in 'addDBObj()';
+   * <p/>
+   * After a searchAndRetrieveList(), each MultiDBObject in the list has,
+   * encapsulated, an object of each type which was previously added as a model.
+   * Fields of this encapsulated object have been filled from whatever was retrieved.
+   * The original query object has just the original model instance.
+   *
+   * @param shortName the shortname of the model object
+   * @return the instance encapsulated by this MultiDBObject
+   *         author Abhi
+   * @throws DBException upon error
+   * @see #addDBObj(String, String)
+   *      Creation date: (02/01/2002 9:33 AM)
+   */
+  public DBObject getDBObject(String shortName) throws DBException {
+
+    DBObject oneObj = (DBObject) myDBObjects.get(shortName);
+    if (oneObj == null) {
+      String myName = thisClass + "getDBObject(String)";
+      throw new DBException(myName + ":No such object as '"
+                            + shortName + "'");
+    }
+    return oneObj;
+  }
+
+  /* getDBObject(String) */
+
+  /**
+   * Get the actual DBField value specified by fieldname
+   * <p/>
+   * Creation date: (9/18/00 11:37:10 AM)
+   *
+   * @param shortName the shortname of the field
+   * @param fieldName name of the field to retrieve
+   * @return The value of the field/
+   */
+  public String getField(String shortName, String fieldName) throws DBException {
+    DBObject oneObj = (DBObject) myDBObjects.get(shortName);
+
+    if (oneObj == null) {
+      String myName = thisClass + "getField(String, String)";
+      throw new DBException(myName + ":No such object as '" + shortName +
+                            "'");
+    }
+
+    return oneObj.getField(fieldName);
+  }
+
+  /* getFields(String, STring) */
+
+  private DBObject getByShortName(String shortName) throws DBException {
+    StringUtil.assertNotBlank(shortName, "Short name may not be blank");
+
+    DBObject oneObj = (DBObject) myDBObjects.get(shortName);
+
+    if (oneObj == null) {
+      throw new DBException("No such object as '" + shortName + "'");
+    }
+
+    return oneObj;
+  }
+
+  public String getFieldDecimalFormatted(String shortName, String fieldName,
+                                         String formatPattern) throws
+      DBException {
+    return getByShortName(shortName).getFieldDecimalFormatted(fieldName,
+        formatPattern);
+  }
+
+  /* getFieldDecimalFormatted(String, String) */
+
+  public float getFieldFloat(String shortName, String fieldName) throws
+      DBException {
+    return getByShortName(shortName).getFieldFloat(fieldName);
+  }
+
+  /* getFieldFloat(String, String) */
+
+  /**
+   * Returns a double object
+   * author Peter Pilgrim <peterp at xenonsoft.demon.co.uk>
+   * date Wed Jul 24 19:36:37 BST 2002
+   */
+  public double getFieldDouble(String shortName, String fieldName) throws
+      DBException {
+    return getByShortName(shortName).getFieldDouble(fieldName);
+  }
+
+  /* getFieldDouble(String, String) */
+
+  /**
+   * Returns a BigDecimal object
+   * author Peter Pilgrim <peterp at xenonsoft.demon.co.uk>
+   * date Wed Jul 24 19:36:37 BST 2002
+   */
+  public BigDecimal getFieldBigDecimal(String shortName, String fieldName) throws
+      DBException {
+    return getByShortName(shortName).getFieldBigDecimal(fieldName);
+  }
+
+  /* getFieldBigDecimal(String, String) */
+
+  public Date getFieldDate(String shortName, String fieldName) throws
+      DBException {
+    return getByShortName(shortName).getFieldDate(fieldName);
+  }
+
+  /* getFieldDate(String, String) */
+
+  public int getFieldInt(String shortName, String fieldName) throws DBException {
+    return getByShortName(shortName).getFieldInt(fieldName);
+  }
+
+  public long getFieldLong(String shortName, String fieldName) throws
+      DBException {
+    return getByShortName(shortName).getFieldLong(fieldName);
+  }
+
+  /**
+   * Construct a new MultiDBObject
+   *
+   * @return new MultiDBObject
+   * @throws DBException upon error
+   */
+  protected MultiDBObject getThisMultiDBObj() throws DBException {
+    MultiDBObject newObj = new MultiDBObject();
+    newObj.setDataContext(getDataContext());
+
+    String oneKey = null;
+    DBObject oneDBObj = null;
+
+    for (Enumeration ek = myDBObjects.keys(); ek.hasMoreElements(); ) {
+      oneKey = (String) ek.nextElement();
+      oneDBObj = (DBObject) myDBObjects.get(oneKey);
+      newObj.addDBObj(oneDBObj.newInstance(), oneKey);
+    }
+
+    String oneRelation = null;
+
+    for (Enumeration er = originalRelations.elements();
+         er.hasMoreElements(); ) {
+      oneRelation = (String) er.nextElement();
+
+      StringTokenizer stk = new StringTokenizer(oneRelation, "|");
+      newObj.setForeignKey(stk.nextToken(), stk.nextToken(),
+                           stk.nextToken(), stk.nextToken());
     }
 
-    /**
-     * Specify a custom "where" clause for the SQL used to retrieve records for
-     * this object. The where clause 'reset' after each call to searchAndRetrieve()
-     * or other retrieval methods, so it must be set just before the call to
-     * retrieve the records is made. If no custom where clause is specified by this
-     * method, the where clause is built from the field values in the object.
-     * <p/>
-     * DO NOT INCLUDE THE 'where' KEYWORD. Just what comes after the 'where'
-     *
-     * @param newCustomWhere java.lang.String
-     */
-    public synchronized void setCustomWhereClause(String newCustomWhere) {
-        setCustomWhereClause(newCustomWhere, false);
-    } /* setCustomWhereClause(String) */
-
-    /**
-     * Specify a custom "where" clause for the SQL used to retrieve records for
-     * this object. The where clause 'reset' after each call to searchAndRetrieve()
-     * or other retrieval methods, so it must be set just before the call to
-     * retrieve the records is made. If no custom where clause is specified by this
-     * method, the where clause is built from the field values in the object.
-     *
-     * @param newCustomWhere java.lang.String
-     * @param append         true if the custom where clause is to be appended to the 'built'
-     *                       where clause; THIS IS DIFFERENT THAN DBObject where 'append' means to append another condition onto the custom where clause
-     */
-    public synchronized void setCustomWhereClause(String newCustomWhere, boolean append) {
-        customWhereClause = newCustomWhere;
-        appendCustomWhereClause = append;
-    } /* setCustomWhereClause(String, boolean) */
-
     // ----------------------------------------------------
     // 2003-11-05 /ebn-ma: added...
-    /**
-     * Gets the customWhereClause
-     *
-     * @return customFromClause
-     */
-    public String getCustomWhereClause() {
-        return customWhereClause;
-    }
+    // In the new Object we will also need this join-definitions.
+    String oneJoin = null;
 
-    /**
-     * Specify if the customWhereClause should be appended to a generated
-     * whereClause.
-     *
-     * @param newValue true = append to whereClause, else overwrite it.
-     */
-    public synchronized void setAppendCustomWhereClause(boolean newValue) {
-        appendCustomWhereClause = newValue;
-    }
-
-    /**
-     * Gets the settings of appendCustomWhereClause.
-     *
-     * @return appendCustomWhereClause
-     */
-    public boolean getAppendCustomWhereClause() {
-        return appendCustomWhereClause;
+    for (Enumeration n = originalJoins.elements();
+         n.hasMoreElements(); ) {
+      oneJoin = (String) n.nextElement();
+
+      StringTokenizer stk = new StringTokenizer(oneJoin, "|");
+      String leftDbo = stk.nextToken();
+      String leftField = stk.nextToken();
+      String rightDbo = stk.nextToken();
+      String rightField = stk.nextToken();
+      String joinTyp = stk.nextToken().toLowerCase();
+
+      if ("left".equals(joinTyp)) {
+        newObj.setLeftJoin(leftDbo, leftField, rightDbo, rightField);
+      }
+      else if ("inner".equals(joinTyp)) {
+        newObj.setInnerJoin(leftDbo, leftField, rightDbo, rightField);
+      }
+      else if ("right".equals(joinTyp)) {
+        newObj.setRightJoin(leftDbo, leftField, rightDbo, rightField);
+      }
     }
     // 2003-11-05 /ebn-ma: ...added
     // ----------------------------------------------------
 
-    /**
-     * Set the database name/context for this multi db object. If setDataContext is not called,
-     * the "default" db name and context is used. See
-     * com.jcorporate.expresso.core.misc.ConfigManager for information about multiple
-     * contexts. Note that setting a db/context name only affects the object when it
-     * allocates it's own db connections - if a specific connection is used (via the
-     * setConnection(DBConnection) method) then that connection must be already
-     * associated with the correct db/context.
-     *
-     * @param newOther The name of the context or database to use
-     * @deprecated 12/2004 v5.6; use setDataContext() instead
-     */
-    public synchronized void setDBName(String newOther)
-            throws DBException {
-        dbName = newOther;
-    } /* setDBName(String) */
-
-    /**
-     * Set the database name/context for this multi db object. If setDataContext is not called,
-     * the "default" db name and context is used. See
-     * com.jcorporate.expresso.core.misc.ConfigManager for information about multiple
-     * contexts. Note that setting a db/context name only affects the object when it
-     * allocates it's own db connections - if a specific connection is used (via the
-     * setConnection(DBConnection) method) then that connection must be already
-     * associated with the correct db/context.
-     *
-     * @param context The name of the context or database to use
-     */
-    public synchronized void setDataContext(String context)
-            throws DBException {
-        dbName = context;
-    } /* setDataContext(String) */
-
-
-    /**
-     * Specify that the DISTINCT keyword for unique rows must be specified right
-     * after the SELECT keyword
-     *
-     * @param flag true if DISTINCT supported right after SELECT, false (default) otherwise.
-     */
-    public void setSelectDistinct(boolean flag) {
-        selectDistinct = flag;
-    }
-
-    /**
-     * Specify a select list of fields to retrieve from a particular DBObject component
-     *
-     * @param shortName  The alias for the DBObject
-     * @param fieldNames Pipe("|")-separated list of fieldnames
-     */
-    public void setFieldsToRetrieve(String shortName, String fieldNames) throws DBException {
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
-
-        if (oneObj == null) {
-            String myName = thisClass + "setFieldsToRetrieve(String, String)";
-            throw new DBException(myName + ":No such object as '" + shortName +
-                    "'");
-        }
-
-        oneObj.setFieldsToRetrieve(fieldNames);
-    }
+    return newObj;
+  }
 
-    /**
-     * Specify to retrieve NO fields from a particular DBObject component
-     * <p/>
-     * author Zaz Harris, SRI International
-     *
-     * @param shortName The alias for the DBObject
-     */
-    public void setFieldsToRetrieveToNone(String shortName) throws DBException {
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
+  /* getThisMultiDBObj() */
 
-        if (oneObj == null) {
-            String myName = thisClass + "setFieldsToRetrieveToNone(String)";
-            throw new DBException(myName + ":No such object as '" + shortName +
-                    "'");
+  /**
+   * Search and retrieve in a particular order
+   *
+   * @param sortKeyString A pipe-delimited list of key fields to sort
+   *                      the returned set by
+   * @return Vector A vector of new database objects retrieved by the search
+   * @throws DBException If the search could not be completed
+   * @deprecated Use searchAndRetrieveList(String) instead
+   */
+  public synchronized Vector searchAndRetrieve(String sortKeyString) throws
+      DBException {
+
+    return new Vector(searchAndRetrieveList(sortKeyString));
+  }
+
+  /* searchAndRetrieve(String) */
+
+  /**
+   * Search and retrieve in a particular order
+   *
+   * @param sortKeyString A pipe-delimited list of key fields to sort
+   *                      the returned set by
+   * @return A list of new database objects retrieved by the search
+   * @throws DBException If the search could not be completed
+   */
+  public synchronized List searchAndRetrieveList(String sortKeyString) throws
+      DBException {
+
+    sortKeys.clear();
+    if (sortKeyString != null) {
+      StringTokenizer stk = new StringTokenizer(sortKeyString, "|");
+      while (stk.hasMoreTokens()) {
+        sortKeys.addElement(stk.nextToken());
+      }
+    }
+
+    return searchAndRetrieveList();
+  }
+
+  /**
+   * Search and retrieve in a particular order
+   *
+   * @return A list of new database objects retrieved by the search
+   * @throws DBException If the search could not be completed
+   */
+  public synchronized List searchAndRetrieveList() throws DBException {
+
+    DBObject oneObj = null;
+
+    HashMap rtrvListByTable = new HashMap();
+
+    DBConnectionPool myPool = null;
+    DBConnection myConnection = null;
+
+    try {
+      if (localConnection != null) {
+        myConnection = localConnection;
+      }
+      else {
+        myPool = DBConnectionPool.getInstance(getDataContext());
+        myConnection = myPool.getConnection(
+            "com.jcorporate.expresso.core.dbobj.DBObject");
+      }
+
+      if (recordSet == null) {
+        String myName = (thisClass + "searchAndRetrieve()");
+        throw new DBException(myName +
+                              ":Database object not correctly initialized");
+      }
+
+      recordSet.clear();
+
+      myConnection.execute(getSQLSelectStatement(myPool, myConnection));
+
+      int returnRecordCount = 0;
+      int loopCount = 0;
+      while (myConnection.next()) {
+        loopCount++;
+
+        //If there's limitation syntax on, then the first record will be the
+        //maximum record.
+        if (loopCount <= offsetRecord && offsetRecord > 0 &&
+            myConnection.getLimitationPosition() ==
+            DBConnection.LIMITATION_DISABLED) {
+          continue;
+        }
+
+        returnRecordCount++;
+
+        // maxRecords = 0 by default, so I guess this means 0 doesn't count as max number... should default to -1 ??  LAH 12/03
+        if ( (returnRecordCount > maxRecords) && (maxRecords > 0)) {
+          break;
         }
 
-        oneObj.retrieveFields = null;
-        oneObj.anyFieldsToRetrieveMulti = true;
-    }
-
-    /**
-     * Specify a field to be retieved uniquely froma component DBObject
-     *
-     * @param shortName The alias for the DBObject
-     * @param fieldName The field to mark as unique
-     * @param flag      true=distinct, flase=all matching rows
-     */
-    public void setFieldDistinct(String shortName, String fieldName, boolean flag) throws DBException {
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
-
-        if (oneObj == null) {
-            String myName = thisClass + "setFieldDistinct(String, String, boolean)";
-            throw new DBException(myName + ":No such object as '" + shortName +
-                    "'");
+        if (log.isDebugEnabled()) {
+          log.debug("Returning row " + loopCount);
         }
 
-        oneObj.setFieldDistinct(fieldName, flag);
-    }
+        MultiDBObject myObj = getThisMultiDBObj();
+        String oneFieldValue = null;
+        int i = 1;
 
-    /**
-     * Insert the method's description here.
-     * <p/>
-     * Creation date: (9/18/00 11:37:10 AM)
-     *
-     * @param shortName  the short name to set
-     * @param fieldName  the fieldname to set
-     * @param fieldValue the value to set the field at.
-     */
-    public void setField(String shortName, String fieldName, String fieldValue)
-            throws DBException {
-        DBObject oneObj = (DBObject) myDBObjects.get(shortName);
-
-        if (oneObj == null) {
-            String myName = thisClass + "setField(String, String, String)";
-            throw new DBException(myName + ":No such object as '" + shortName +
-                    "'");
-        }
+        for (Enumeration eachObj = myDBObjects.elements();
+             eachObj.hasMoreElements(); ) {
+          oneObj = (DBObject) eachObj.nextElement();
 
-        oneObj.setField(fieldName, fieldValue);
-    } /* setField(String, String, String) */
+          ArrayList retrievedFieldList = (ArrayList) rtrvListByTable.get(
+              getTableName(oneObj));
+          // The following should never happen .... but CYA
+          if (retrievedFieldList == null) {
+            retrievedFieldList = new ArrayList();
+          }
+          for (Iterator it = retrievedFieldList.listIterator();
+               it.hasNext(); ) {
+            java.lang.String fieldName = (String) it.next();
+            DataFieldMetaData metaData = oneObj.getFieldMetaData(fieldName);
+
+            if (!metaData.isVirtual() && !metaData.isBinaryObjectType()) {
+              try {
+                oneFieldValue = myConnection.getString(i);
+              }
+              catch (DBException de) {
+                String myName = (thisClass + "searchAndRetrieve()");
+                throw new DBException(myName +
+                                      ":Error retrieving field '" +
+                                      getTableName(oneObj) +
+                                      "." + fieldName + "'",
+                                      de);
+              }
+
+              i++;
+
+              if (log.isDebugEnabled()) {
+                log.debug("Setting " +
+                          getTableName(oneObj) + "." +
+                          fieldName + " to " + oneFieldValue);
+              }
+
+              myObj.setField( (String) oneObj.getAttribute(SHORT_NAME),
+                             fieldName, oneFieldValue);
+            }
+          }
+        }
+        /* each db object */
+
+        myObj.setDataContext(getDataContext());
+        recordSet.add(myObj);
+      }
+
+      /* each row retrieved from the db */
+    }
+    finally {
+      if (localConnection == null) {
+        myPool.release(myConnection);
+      }
+    }
+
+    return recordSet;
+  }
+
+  /**
+   * get the SQL select statment to be executed, if searchAnd RetrieveList happenned
+   * on this MULTIDBOBJECT
+   *
+   * @return String of select statement to be executed
+   * @throws DBException If the search could not be completed
+   */
+  public synchronized String getSQLSelectStatement() throws DBException {
+    DBConnectionPool myPool = null;
+    DBConnection myConnection = null;
+    try {
+      if (localConnection != null) {
+        myConnection = localConnection;
+      }
+      else {
+        myPool = DBConnectionPool.getInstance(getDBName());
+        myConnection = myPool.getConnection(
+            "com.jcorporate.expresso.core.dbobj.DBObject");
+      }
+      return getSQLSelectStatement(myPool, myConnection);
+    }
+    finally {
+      if (localConnection == null) {
+        myPool.release(myConnection);
+      }
+    }
+  }
+
+  /**
+   * get the SQL select statment to be executed, if searchAnd RetrieveList happenned
+   * on this MULTIDBOBJECT
+   * The use of this method is when building complex custom WHERE clauses
+   * with nested queries one can call it to get the nested select built dynamically
+   *
+   * @return String of select statement to be executed
+   * @throws DBException If the search could not be completed
+   * author Yves Henri AMAIZO
+   */
+  public synchronized String getSQLSelectStatement(DBConnectionPool myPool,
+      DBConnection myConnection) throws DBException {
+
+    boolean needComma = false;
+    DBObject oneObj = null;
+
+    HashMap rtrvListByTable = new HashMap();
+
+    String fieldName = null;
+    FastStringBuffer myStatement = new FastStringBuffer(256);
+    try {
+      myStatement.append("SELECT ");
+
+      if (myConnection.getLimitationPosition() ==
+          DBConnection.LIMITATION_AFTER_SELECT &&
+          (offsetRecord > 0 || maxRecords > 0)) {
+
+        // Insert limitation stub after table nomination
+        String limitStub = makeLimitationStub(myConnection);
+
+        myStatement.append(" ");
+        myStatement.append(limitStub);
+        myStatement.append(" ");
+      }
+
+      if (selectDistinct) {
+        myStatement.append(" ");
+        myStatement.append("DISTINCT");
+        myStatement.append(" ");
+      }
+
+      for (Enumeration eachObj = myDBObjects.elements();
+           eachObj.hasMoreElements(); ) {
+        oneObj = (DBObject) eachObj.nextElement();
+
+        ArrayList retrievedFieldList = (ArrayList) rtrvListByTable.get(
+            getTableName(oneObj));
+        if (retrievedFieldList == null) {
+          retrievedFieldList = new ArrayList();
+          rtrvListByTable.put(getTableName(oneObj), retrievedFieldList);
+        }
+
+        if (oneObj.anyFieldsDistinct) {
+          String oneFieldName = null;
+          for (Iterator i = oneObj.getDistinctFieldArrayList().iterator();
+               i.hasNext();
+              ) {
+            oneFieldName = (String) i.next();
+            if (needComma) {
+              myStatement.append(", ");
+            }
+            myStatement.append(" ");
+            myStatement.append(myPool.getDistinctRowsetKeyword());
+            myStatement.append(" ");
+            myStatement.append(selectFieldString(oneObj, oneFieldName));
+            retrievedFieldList.add(oneFieldName);
+            needComma = true;
+          }
+        }
+        else if (oneObj.anyFieldsToRetrieveMulti) {
+          String oneFieldName = null;
+          for (Iterator i = oneObj.getFieldsToRetrieveIterator();
+               i.hasNext();
+              ) {
+            oneFieldName = (String) i.next();
+            if (needComma) {
+              myStatement.append(", ");
+            }
+            myStatement.append(selectFieldString(oneObj, oneFieldName));
+            retrievedFieldList.add(oneFieldName);
+            needComma = true;
+          }
+          /* for each field */
+        }
+        else {
+          for (Iterator i = oneObj.getMetaData().getFieldListArray().iterator();
+               i.hasNext();
+              ) {
+            fieldName = (String) i.next();
+            DataFieldMetaData metaData =
+                oneObj.getFieldMetaData(fieldName);
+
+            if (!metaData.isVirtual()
+                && !metaData.isBinaryObjectType()) {
+              if (needComma) {
+                myStatement.append(", ");
+              }
+
+              myStatement.append(selectFieldString(oneObj, fieldName));
+