Coverage report

  %line %branch
org.apache.torque.util.BasePeer$5
0% 
0% 

 1  
 package org.apache.torque.util;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 import java.io.Serializable;
 23  
 import java.sql.Connection;
 24  
 import java.sql.PreparedStatement;
 25  
 import java.sql.SQLException;
 26  
 import java.sql.Statement;
 27  
 import java.util.ArrayList;
 28  
 import java.util.Collections;
 29  
 import java.util.HashSet;
 30  
 import java.util.Iterator;
 31  
 import java.util.List;
 32  
 import java.util.Map;
 33  
 import java.util.Set;
 34  
 
 35  
 import org.apache.commons.lang.StringUtils;
 36  
 import org.apache.commons.logging.Log;
 37  
 import org.apache.commons.logging.LogFactory;
 38  
 import org.apache.torque.Database;
 39  
 import org.apache.torque.Torque;
 40  
 import org.apache.torque.TorqueException;
 41  
 import org.apache.torque.adapter.DB;
 42  
 import org.apache.torque.map.ColumnMap;
 43  
 import org.apache.torque.map.DatabaseMap;
 44  
 import org.apache.torque.map.MapBuilder;
 45  
 import org.apache.torque.map.TableMap;
 46  
 import org.apache.torque.oid.IdGenerator;
 47  
 import org.apache.torque.om.NumberKey;
 48  
 import org.apache.torque.om.ObjectKey;
 49  
 import org.apache.torque.om.SimpleKey;
 50  
 import org.apache.torque.om.StringKey;
 51  
 
 52  
 import com.workingdogs.village.Column;
 53  
 import com.workingdogs.village.DataSet;
 54  
 import com.workingdogs.village.DataSetException;
 55  
 import com.workingdogs.village.KeyDef;
 56  
 import com.workingdogs.village.QueryDataSet;
 57  
 import com.workingdogs.village.Record;
 58  
 import com.workingdogs.village.Schema;
 59  
 import com.workingdogs.village.TableDataSet;
 60  
 
 61  
 /**
 62  
  * This is the base class for all Peer classes in the system.  Peer
 63  
  * classes are responsible for isolating all of the database access
 64  
  * for a specific business object.  They execute all of the SQL
 65  
  * against the database.  Over time this class has grown to include
 66  
  * utility methods which ease execution of cross-database queries and
 67  
  * the implementation of concrete Peers.
 68  
  *
 69  
  * @author <a href="mailto:frank.kim@clearink.com">Frank Y. Kim</a>
 70  
  * @author <a href="mailto:jmcnally@collab.net">John D. McNally</a>
 71  
  * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
 72  
  * @author <a href="mailto:stephenh@chase3000.com">Stephen Haberman</a>
 73  
  * @author <a href="mailto:mpoeschl@marmot.at">Martin Poeschl</a>
 74  
  * @author <a href="mailto:vido@ldh.org">Augustin Vidovic</a>
 75  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 76  
  * @version $Id: BasePeer.java 591648 2007-11-03 16:34:00Z tfischer $
 77  
  */
 78  
 public abstract class BasePeer
 79  
         implements Serializable
 80  
 {
 81  
     /** Constant criteria key to reference ORDER BY columns. */
 82  
     public static final String ORDER_BY = "ORDER BY";
 83  
 
 84  
     /**
 85  
      * Constant criteria key to remove Case Information from
 86  
      * search/ordering criteria.
 87  
      */
 88  
     public static final String IGNORE_CASE = "IgNOrE cAsE";
 89  
 
 90  
     /** Classes that implement this class should override this value. */
 91  
     public static final String TABLE_NAME = "TABLE_NAME";
 92  
 
 93  
     /** the log */
 94  
     protected static final Log log = LogFactory.getLog(BasePeer.class);
 95  
 
 96  
     private static void throwTorqueException(Exception e)
 97  
         throws TorqueException
 98  
     {
 99  
         if (e instanceof TorqueException)
 100  
         {
 101  
             throw (TorqueException) e;
 102  
         }
 103  
         else
 104  
         {
 105  
             throw new TorqueException(e);
 106  
         }
 107  
     }
 108  
 
 109  
     /**
 110  
      * Sets up a Schema for a table.  This schema is then normally
 111  
      * used as the argument for initTableColumns().
 112  
      *
 113  
      * @param tableName The name of the table.
 114  
      * @return A Schema.
 115  
      */
 116  
     public static Schema initTableSchema(String tableName)
 117  
     {
 118  
         return initTableSchema(tableName, Torque.getDefaultDB());
 119  
     }
 120  
 
 121  
     /**
 122  
      * Sets up a Schema for a table.  This schema is then normally
 123  
      * used as the argument for initTableColumns
 124  
      *
 125  
      * @param tableName The propery name for the database in the
 126  
      * configuration file.
 127  
      * @param dbName The name of the database.
 128  
      * @return A Schema.
 129  
      */
 130  
     public static Schema initTableSchema(String tableName, String dbName)
 131  
     {
 132  
         Schema schema = null;
 133  
         Connection con = null;
 134  
 
 135  
         try
 136  
         {
 137  
             con = Torque.getConnection(dbName);
 138  
             schema = new Schema().schema(con, tableName);
 139  
         }
 140  
         catch (Exception e)
 141  
         {
 142  
             log.error(e);
 143  
             throw new Error("Error in BasePeer.initTableSchema("
 144  
                     + tableName
 145  
                     + "): "
 146  
                     + e.getMessage());
 147  
         }
 148  
         finally
 149  
         {
 150  
             Torque.closeConnection(con);
 151  
         }
 152  
         return schema;
 153  
     }
 154  
 
 155  
     /**
 156  
      * Creates a Column array for a table based on its Schema.
 157  
      *
 158  
      * @param schema A Schema object.
 159  
      * @return A Column[].
 160  
      */
 161  
     public static Column[] initTableColumns(Schema schema)
 162  
     {
 163  
         Column[] columns = null;
 164  
         try
 165  
         {
 166  
             int numberOfColumns = schema.numberOfColumns();
 167  
             columns = new Column[numberOfColumns];
 168  
             for (int i = 0; i < numberOfColumns; i++)
 169  
             {
 170  
                 columns[i] = schema.column(i + 1);
 171  
             }
 172  
         }
 173  
         catch (Exception e)
 174  
         {
 175  
             log.error(e);
 176  
             throw new Error(
 177  
                 "Error in BasePeer.initTableColumns(): " + e.getMessage());
 178  
         }
 179  
         return columns;
 180  
     }
 181  
 
 182  
     /**
 183  
      * Convenience method to create a String array of column names.
 184  
      *
 185  
      * @param columns A Column[].
 186  
      * @return A String[].
 187  
      */
 188  
     public static String[] initColumnNames(Column[] columns)
 189  
     {
 190  
         String[] columnNames = new String[columns.length];
 191  
         for (int i = 0; i < columns.length; i++)
 192  
         {
 193  
             columnNames[i] = columns[i].name().toUpperCase();
 194  
         }
 195  
         return columnNames;
 196  
     }
 197  
 
 198  
     /**
 199  
      * Convenience method to create a String array of criteria keys.
 200  
      *
 201  
      * @param tableName Name of table.
 202  
      * @param columnNames A String[].
 203  
      * @return A String[].
 204  
      */
 205  
     public static String[] initCriteriaKeys(
 206  
         String tableName,
 207  
         String[] columnNames)
 208  
     {
 209  
         String[] keys = new String[columnNames.length];
 210  
         for (int i = 0; i < columnNames.length; i++)
 211  
         {
 212  
             keys[i] = tableName + "." + columnNames[i].toUpperCase();
 213  
         }
 214  
         return keys;
 215  
     }
 216  
 
 217  
     /**
 218  
      * Convenience method that uses straight JDBC to delete multiple
 219  
      * rows.  Village throws an Exception when multiple rows are
 220  
      * deleted.
 221  
      *
 222  
      * @param con A Connection.
 223  
      * @param table The table to delete records from.
 224  
      * @param column The column in the where clause.
 225  
      * @param value The value of the column.
 226  
      * @throws TorqueException Any exceptions caught during processing will be
 227  
      *         rethrown wrapped into a TorqueException.
 228  
      */
 229  
     public static void deleteAll(
 230  
         Connection con,
 231  
         String table,
 232  
         String column,
 233  
         int value)
 234  
         throws TorqueException
 235  
     {
 236  
         Statement statement = null;
 237  
         try
 238  
         {
 239  
             statement = con.createStatement();
 240  
 
 241  
             StringBuffer query = new StringBuffer();
 242  
             query.append("DELETE FROM ")
 243  
                 .append(table)
 244  
                 .append(" WHERE ")
 245  
                 .append(column)
 246  
                 .append(" = ")
 247  
                 .append(value);
 248  
 
 249  
             statement.executeUpdate(query.toString());
 250  
         }
 251  
         catch (SQLException e)
 252  
         {
 253  
             throw new TorqueException(e);
 254  
         }
 255  
         finally
 256  
         {
 257  
             if (statement != null)
 258  
             {
 259  
                 try
 260  
                 {
 261  
                     statement.close();
 262  
                 }
 263  
                 catch (SQLException e)
 264  
                 {
 265  
                     throw new TorqueException(e);
 266  
                 }
 267  
             }
 268  
         }
 269  
     }
 270  
 
 271  
     /**
 272  
      * Convenience method that uses straight JDBC to delete multiple
 273  
      * rows.  Village throws an Exception when multiple rows are
 274  
      * deleted.  This method attempts to get the default database from
 275  
      * the pool.
 276  
      *
 277  
      * @param table The table to delete records from.
 278  
      * @param column The column in the where clause.
 279  
      * @param value The value of the column.
 280  
      * @throws TorqueException Any exceptions caught during processing will be
 281  
      *         rethrown wrapped into a TorqueException.
 282  
      */
 283  
     public static void deleteAll(String table, String column, int value)
 284  
         throws TorqueException
 285  
     {
 286  
         Connection con = null;
 287  
         try
 288  
         {
 289  
             // Get a connection to the db.
 290  
             con = Torque.getConnection(Torque.getDefaultDB());
 291  
             deleteAll(con, table, column, value);
 292  
         }
 293  
         finally
 294  
         {
 295  
             Torque.closeConnection(con);
 296  
         }
 297  
     }
 298  
 
 299  
     /**
 300  
      * Method to perform deletes based on values and keys in a
 301  
      * Criteria.
 302  
      *
 303  
      * @param criteria The criteria to use.
 304  
      * @throws TorqueException Any exceptions caught during processing will be
 305  
      *         rethrown wrapped into a TorqueException.
 306  
      * @deprecated This method causes unexpected results when joins are used.
 307  
      *              Please use doDelete(Criteria, String).
 308  
      */
 309  
     public static void doDelete(Criteria criteria) throws TorqueException
 310  
     {
 311  
         doDelete(criteria, (String) null);
 312  
     }
 313  
 
 314  
     /**
 315  
      * Method to perform deletes based on values and keys in a
 316  
      * Criteria.
 317  
      * This method is protected because it may cause ambiguity between
 318  
      * doDelete(Criteria,Connection) and this method. It will be made public
 319  
      * once doDelete(Criteria, Connection) is removed.
 320  
      *
 321  
      * @param criteria The criteria to use.
 322  
      * @param tableName the name of the table to delete records from.
 323  
      *         If set to null, the name of the table(s) can be extracted from
 324  
      *         the criteria, but this can cause unexpected results.
 325  
      * @throws TorqueException Any exceptions caught during processing will be
 326  
      *         rethrown wrapped into a TorqueException.
 327  
      */
 328  
     protected static void doDelete(Criteria criteria, String tableName) throws TorqueException
 329  
     {
 330  
         Connection con = null;
 331  
         try
 332  
         {
 333  
             con = Transaction.beginOptional(
 334  
                     criteria.getDbName(),
 335  
                     criteria.isUseTransaction());
 336  
             doDelete(criteria, tableName, con);
 337  
             Transaction.commit(con);
 338  
         }
 339  
         catch (TorqueException e)
 340  
         {
 341  
             Transaction.safeRollback(con);
 342  
             throw e;
 343  
         }
 344  
     }
 345  
 
 346  
     /**
 347  
      * Method to perform deletes based on values and keys in a Criteria.
 348  
      *
 349  
      * @param criteria The criteria to use.
 350  
      * @param con A Connection.
 351  
      * @throws TorqueException Any exceptions caught during processing will be
 352  
      *         rethrown wrapped into a TorqueException.
 353  
      * @deprecated This method causes unexpected results when joins are used.
 354  
      *              Please use doDelete(Criteria, String, Connection).
 355  
      */
 356  
     public static void doDelete(Criteria criteria, Connection con)
 357  
         throws TorqueException
 358  
     {
 359  
         doDelete(criteria, null, con);
 360  
     }
 361  
 
 362  
     /**
 363  
      * Method to perform deletes based on values and keys in a Criteria.
 364  
      *
 365  
      * @param criteria The criteria to use.
 366  
      * @param tableName the name of the table to delete records from.
 367  
      *         If set to null, the name of the table(s) can be extracted from
 368  
      *         the criteria, but this can cause unexpected results.
 369  
      * @param con A Connection.
 370  
      * @throws TorqueException Any exceptions caught during processing will be
 371  
      *         rethrown wrapped into a TorqueException.
 372  
      */
 373  
     public static void doDelete(Criteria criteria, String tableName, Connection con)
 374  
         throws TorqueException
 375  
     {
 376  
         String dbName = criteria.getDbName();
 377  
         final DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
 378  
 
 379  
         // This Callback adds all tables to the Table set which
 380  
         // are referenced from a cascading criteria. As a result, all
 381  
         // data that is referenced through foreign keys will also be
 382  
         // deleted.
 383  
         SQLBuilder.TableCallback tc = new SQLBuilder.TableCallback() {
 384  
                 public void process (Set tables, String key, Criteria crit)
 385  
                 {
 386  
                     if (crit.isCascade())
 387  
                     {
 388  
                         // This steps thru all the columns in the database.
 389  
                         TableMap[] tableMaps = dbMap.getTables();
 390  
                         for (int i = 0; i < tableMaps.length; i++)
 391  
                         {
 392  
                             ColumnMap[] columnMaps = tableMaps[i].getColumns();
 393  
 
 394  
                             for (int j = 0; j < columnMaps.length; j++)
 395  
                             {
 396  
                                 // Only delete rows where the foreign key is
 397  
                                 // also a primary key.  Other rows need
 398  
                                 // updating, but that is not implemented.
 399  
                                 if (columnMaps[j].isForeignKey()
 400  
                                         && columnMaps[j].isPrimaryKey()
 401  
                                         && key.equals(columnMaps[j].getRelatedName()))
 402  
                                 {
 403  
                                     tables.add(tableMaps[i].getName());
 404  
                                     crit.add(columnMaps[j].getFullyQualifiedName(),
 405  
                                             crit.getValue(key));
 406  
                                 }
 407  
                             }
 408  
                         }
 409  
                     }
 410  
                 }
 411  
             };
 412  
 
 413  
         Set tables;
 414  
         if (tableName == null)
 415  
         {
 416  
             tables = SQLBuilder.getTableSet(criteria, tc);
 417  
         }
 418  
         else
 419  
         {
 420  
             tables = new HashSet(1);
 421  
             tables.add(tableName);
 422  
         }
 423  
 
 424  
         try
 425  
         {
 426  
             processTables(criteria, tables, con, new ProcessCallback() {
 427  
                     public void process(String table, String dbName, Record rec)
 428  
                         throws Exception
 429  
                     {
 430  
                         rec.markToBeDeleted();
 431  
                         rec.save();
 432  
                     }
 433  
                 });
 434  
         }
 435  
         catch (Exception e)
 436  
         {
 437  
             throwTorqueException(e);
 438  
         }
 439  
     }
 440  
 
 441  
     /**
 442  
      * Method to perform inserts based on values and keys in a
 443  
      * Criteria.
 444  
      * <p>
 445  
      * If the primary key is auto incremented the data in Criteria
 446  
      * will be inserted and the auto increment value will be returned.
 447  
      * <p>
 448  
      * If the primary key is included in Criteria then that value will
 449  
      * be used to insert the row.
 450  
      * <p>
 451  
      * If no primary key is included in Criteria then we will try to
 452  
      * figure out the primary key from the database map and insert the
 453  
      * row with the next available id using util.db.IDBroker.
 454  
      * <p>
 455  
      * If no primary key is defined for the table the values will be
 456  
      * inserted as specified in Criteria and -1 will be returned.
 457  
      *
 458  
      * @param criteria Object containing values to insert.
 459  
      * @return An Object which is the id of the row that was inserted
 460  
      * (if the table has a primary key) or null (if the table does not
 461  
      * have a primary key).
 462  
      * @throws TorqueException Any exceptions caught during processing will be
 463  
      *         rethrown wrapped into a TorqueException.
 464  
      */
 465  
     public static ObjectKey doInsert(Criteria criteria) throws TorqueException
 466  
     {
 467  
         Connection con = null;
 468  
         ObjectKey id = null;
 469  
 
 470  
         try
 471  
         {
 472  
             con = Transaction.beginOptional(
 473  
                     criteria.getDbName(),
 474  
                     criteria.isUseTransaction());
 475  
             id = doInsert(criteria, con);
 476  
             Transaction.commit(con);
 477  
         }
 478  
         catch (TorqueException e)
 479  
         {
 480  
             Transaction.safeRollback(con);
 481  
             throw e;
 482  
         }
 483  
 
 484  
         return id;
 485  
     }
 486  
 
 487  
     /**
 488  
      * Method to perform inserts based on values and keys in a
 489  
      * Criteria.
 490  
      * <p>
 491  
      * If the primary key is auto incremented the data in Criteria
 492  
      * will be inserted and the auto increment value will be returned.
 493  
      * <p>
 494  
      * If the primary key is included in Criteria then that value will
 495  
      * be used to insert the row.
 496  
      * <p>
 497  
      * If no primary key is included in Criteria then we will try to
 498  
      * figure out the primary key from the database map and insert the
 499  
      * row with the next available id using util.db.IDBroker.
 500  
      * <p>
 501  
      * If no primary key is defined for the table the values will be
 502  
      * inserted as specified in Criteria and null will be returned.
 503  
      *
 504  
      * @param criteria Object containing values to insert.
 505  
      * @param con A Connection.
 506  
      * @return An Object which is the id of the row that was inserted
 507  
      * (if the table has a primary key) or null (if the table does not
 508  
      * have a primary key).
 509  
      * @throws TorqueException Any exceptions caught during processing will be
 510  
      *         rethrown wrapped into a TorqueException.
 511  
      */
 512  
     public static ObjectKey doInsert(Criteria criteria, Connection con)
 513  
         throws TorqueException
 514  
     {
 515  
         SimpleKey id = null;
 516  
 
 517  
         // Get the table name and method for determining the primary
 518  
         // key value.
 519  
         String table = null;
 520  
         Iterator keys = criteria.keySet().iterator();
 521  
         if (keys.hasNext())
 522  
         {
 523  
             table = criteria.getTableName((String) keys.next());
 524  
         }
 525  
         else
 526  
         {
 527  
             throw new TorqueException("Database insert attempted without "
 528  
                     + "anything specified to insert");
 529  
         }
 530  
 
 531  
         String dbName = criteria.getDbName();
 532  
         Database database = Torque.getDatabase(dbName);
 533  
         DatabaseMap dbMap = database.getDatabaseMap();
 534  
         TableMap tableMap = dbMap.getTable(table);
 535  
         Object keyInfo = tableMap.getPrimaryKeyMethodInfo();
 536  
         IdGenerator keyGen
 537  
                 = database.getIdGenerator(tableMap.getPrimaryKeyMethod());
 538  
 
 539  
         ColumnMap pk = getPrimaryKey(criteria);
 540  
 
 541  
         // If the keyMethod is SEQUENCE or IDBROKERTABLE, get the id
 542  
         // before the insert.
 543  
         if (keyGen != null && keyGen.isPriorToInsert())
 544  
         {
 545  
             // pk will be null if there is no primary key defined for the table
 546  
             // we're inserting into.
 547  
             if (pk != null && !criteria.containsKey(pk.getFullyQualclass="keyword">ifiedName()))
 548  
             {
 549  
                 id = getId(pk, keyGen, con, keyInfo);
 550  
                 criteria.add(pk.getFullyQualifiedName(), id);
 551  
             }
 552  
         }
 553  
 
 554  
         // Use Village to perform the insert.
 555  
         TableDataSet tds = null;
 556  
         try
 557  
         {
 558  
             String tableName = SQLBuilder.getFullTableName(table, dbName);
 559  
             tds = new TableDataSet(con, tableName);
 560  
             Record rec = tds.addRecord();
 561  
             // not the fully qualified name, insertOrUpdateRecord wants to use table as an index...
 562  
             BasePeer.insertOrUpdateRecord(rec, table, dbName, criteria);
 563  
         }
 564  
         catch (DataSetException e)
 565  
         {
 566  
             throwTorqueException(e);
 567  
         }
 568  
         catch (SQLException e)
 569  
         {
 570  
             throwTorqueException(e);
 571  
         }
 572  
         catch (TorqueException e)
 573  
         {
 574  
             throwTorqueException(e);
 575  
         }
 576  
         finally
 577  
         {
 578  
             VillageUtils.close(tds);
 579  
         }
 580  
 
 581  
         // If the primary key column is auto-incremented, get the id
 582  
         // now.
 583  
         if (keyGen != null && keyGen.isPostInsert())
 584  
         {
 585  
             id = getId(pk, keyGen, con, keyInfo);
 586  
         }
 587  
 
 588  
         return id;
 589  
     }
 590  
 
 591  
     /**
 592  
      * Create an Id for insertion in the Criteria
 593  
      *
 594  
      * @param pk ColumnMap for the Primary key
 595  
      * @param keyGen The Id Generator object
 596  
      * @param con The SQL Connection to run the id generation under
 597  
      * @param keyInfo KeyInfo Parameter from the Table map
 598  
      *
 599  
      * @return A simple Key representing the new Id value
 600  
      * @throws TorqueException Possible errors get wrapped in here.
 601  
      */
 602  
     private static SimpleKey getId(ColumnMap pk, IdGenerator keyGen, Connection con, Object keyInfo)
 603  
             throws TorqueException
 604  
     {
 605  
         SimpleKey id = null;
 606  
 
 607  
         try
 608  
         {
 609  
             if (pk != null && keyGen != class="keyword">null)
 610  
             {
 611  
                 if (pk.getType() instanceof Number)
 612  
                 {
 613  
                     id = new NumberKey(
 614  
                             keyGen.getIdAsBigDecimal(con, keyInfo));
 615  
                 }
 616  
                 else
 617  
                 {
 618  
                     id = new StringKey(keyGen.getIdAsString(con, keyInfo));
 619  
                 }
 620  
             }
 621  
         }
 622  
         catch (Exception e)
 623  
         {
 624  
             throwTorqueException(e);
 625  
         }
 626  
         return id;
 627  
     }
 628  
 
 629  
     /**
 630  
      * Grouping of code used in both doInsert() and doUpdate()
 631  
      * methods.  Sets up a Record for saving.
 632  
      *
 633  
      * @param rec A Record.
 634  
      * @param table Name of table.
 635  
      * @param criteria A Criteria.
 636  
      * @throws TorqueException Any exceptions caught during processing will be
 637  
      *         rethrown wrapped into a TorqueException.
 638  
      */
 639  
     private static void insertOrUpdateRecord(
 640  
         Record rec,
 641  
         String table,
 642  
         String dbName,
 643  
         Criteria criteria)
 644  
         throws TorqueException
 645  
     {
 646  
         DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
 647  
 
 648  
         ColumnMap[] columnMaps = dbMap.getTable(table).getColumns();
 649  
         boolean shouldSave = false;
 650  
         for (int j = 0; j < columnMaps.length; j++)
 651  
         {
 652  
             ColumnMap colMap = columnMaps[j];
 653  
             String colName = colMap.getColumnName();
 654  
             String key = new StringBuffer(colMap.getTableName())
 655  
                     .append('.')
 656  
                     .append(colName)
 657  
                     .toString();
 658  
             if (criteria.containsKey(key))
 659  
             {
 660  
                 try
 661  
                 {
 662  
                     VillageUtils.setVillageValue(criteria, key, rec, colName);
 663  
                     shouldSave = true;
 664  
                 }
 665  
                 catch (Exception e)
 666  
                 {
 667  
                     throwTorqueException(e);
 668  
                 }
 669  
             }
 670  
         }
 671  
 
 672  
         if (shouldSave)
 673  
         {
 674  
             try
 675  
             {
 676  
                 rec.save();
 677  
             }
 678  
             catch (Exception e)
 679  
             {
 680  
                 throwTorqueException(e);
 681  
             }
 682  
         }
 683  
         else
 684  
         {
 685  
             throw new TorqueException("No changes to save");
 686  
         }
 687  
     }
 688  
 
 689  
     /**
 690  
      * Method to create an SQL query for display only based on values in a
 691  
      * Criteria.
 692  
      *
 693  
      * @param criteria A Criteria.
 694  
      * @return the SQL query for display
 695  
      * @exception TorqueException Trouble creating the query string.
 696  
      */
 697  
     static String createQueryDisplayString(Criteria criteria)
 698  
         throws TorqueException
 699  
     {
 700  
         return createQuery(criteria).toString();
 701  
     }
 702  
 
 703  
     /**
 704  
      * Method to create an SQL query for actual execution based on values in a
 705  
      * Criteria.
 706  
      *
 707  
      * @param criteria A Criteria.
 708  
      * @return the SQL query for actual execution
 709  
      * @exception TorqueException Trouble creating the query string.
 710  
      */
 711  
     public static String createQueryString(Criteria criteria)
 712  
         throws TorqueException
 713  
     {
 714  
         Query query = createQuery(criteria);
 715  
         return query.toString();
 716  
     }
 717  
 
 718  
     /**
 719  
      * Method to create an SQL query based on values in a Criteria.  Note that
 720  
      * final manipulation of the limit and offset are performed when the query
 721  
      * is actually executed.
 722  
      *
 723  
      * @param criteria A Criteria.
 724  
      * @return the sql query
 725  
      * @exception TorqueException Trouble creating the query string.
 726  
      */
 727  
     static Query createQuery(Criteria criteria)
 728  
         throws TorqueException
 729  
     {
 730  
         return SQLBuilder.buildQueryClause(criteria, null, new SQLBuilder.QueryCallback() {
 731  
                 public String process(Criteria.Criterion criterion, List params)
 732  
                 {
 733  
                     return criterion.toString();
 734  
                 }
 735  
             });
 736  
     }
 737  
 
 738  
     /**
 739  
      * Returns all results.
 740  
      *
 741  
      * @param criteria A Criteria.
 742  
      * @return List of Record objects.
 743  
      * @throws TorqueException Any exceptions caught during processing will be
 744  
      *         rethrown wrapped into a TorqueException.
 745  
      */
 746  
     public static List doSelect(Criteria criteria) throws TorqueException
 747  
     {
 748  
         Connection con = null;
 749  
         List results = null;
 750  
 
 751  
         try
 752  
         {
 753  
             con = Transaction.beginOptional(
 754  
                     criteria.getDbName(),
 755  
                     criteria.isUseTransaction());
 756  
             results = doSelect(criteria, con);
 757  
             Transaction.commit(con);
 758  
         }
 759  
         catch (TorqueException e)
 760  
         {
 761  
             Transaction.safeRollback(con);
 762  
             throw e;
 763  
         }
 764  
         return results;
 765  
     }
 766  
 
 767  
     /**
 768  
      * Returns all results.
 769  
      *
 770  
      * @param criteria A Criteria.
 771  
      * @param con A Connection.
 772  
      * @return List of Record objects.
 773  
      * @throws TorqueException Any exceptions caught during processing will be
 774  
      *         rethrown wrapped into a TorqueException.
 775  
      */
 776  
     public static List doSelect(Criteria criteria, Connection con)
 777  
         throws TorqueException
 778  
     {
 779  
         Query query = createQuery(criteria);
 780  
         DB dbadapter = Torque.getDB(criteria.getDbName());
 781  
 
 782  
         // Call Village depending on the capabilities of the DB
 783  
         return executeQuery(query.toString(),
 784  
                 dbadapter.supportsNativeOffset() ? 0 : criteria.getOffset(),
 785  
                 dbadapter.supportsNativeLimit() ? -1 : criteria.getLimit(),
 786  
                 criteria.isSingleRecord(),
 787  
                 con);
 788  
     }
 789  
 
 790  
     /**
 791  
      * Utility method which executes a given sql statement.  This
 792  
      * method should be used for select statements only.  Use
 793  
      * executeStatement for update, insert, and delete operations.
 794  
      *
 795  
      * @param queryString A String with the sql statement to execute.
 796  
      * @return List of Record objects.
 797  
      * @throws TorqueException Any exceptions caught during processing will be
 798  
      *         rethrown wrapped into a TorqueException.
 799  
      */
 800  
     public static List executeQuery(String queryString) throws TorqueException
 801  
     {
 802  
         return executeQuery(queryString, Torque.getDefaultDB(), false);
 803  
     }
 804  
 
 805  
     /**
 806  
      * Utility method which executes a given sql statement.  This
 807  
      * method should be used for select statements only.  Use
 808  
      * executeStatement for update, insert, and delete operations.
 809  
      *
 810  
      * @param queryString A String with the sql statement to execute.
 811  
      * @param dbName The database to connect to.
 812  
      * @return List of Record objects.
 813  
      * @throws TorqueException Any exceptions caught during processing will be
 814  
      *         rethrown wrapped into a TorqueException.
 815  
      */
 816  
     public static List executeQuery(String queryString, String dbName)
 817  
         throws TorqueException
 818  
     {
 819  
         return executeQuery(queryString, dbName, false);
 820  
     }
 821  
 
 822  
     /**
 823  
      * Method for performing a SELECT.  Returns all results.
 824  
      *
 825  
      * @param queryString A String with the sql statement to execute.
 826  
      * @param dbName The database to connect to.
 827  
      * @param singleRecord Whether or not we want to select only a
 828  
      * single record.
 829  
      * @return List of Record objects.
 830  
      * @throws TorqueException Any exceptions caught during processing will be
 831  
      *         rethrown wrapped into a TorqueException.
 832  
      */
 833  
     public static List executeQuery(
 834  
         String queryString,
 835  
         String dbName,
 836  
         boolean singleRecord)
 837  
         throws TorqueException
 838  
     {
 839  
         return executeQuery(queryString, 0, -1, dbName, singleRecord);
 840  
     }
 841  
 
 842  
     /**
 843  
      * Method for performing a SELECT.  Returns all results.
 844  
      *
 845  
      * @param queryString A String with the sql statement to execute.
 846  
      * @param singleRecord Whether or not we want to select only a
 847  
      * single record.
 848  
      * @param con A Connection.
 849  
      * @return List of Record objects.
 850  
      * @throws TorqueException Any exceptions caught during processing will be
 851  
      *         rethrown wrapped into a TorqueException.
 852  
      */
 853  
     public static List executeQuery(
 854  
         String queryString,
 855  
         boolean singleRecord,
 856  
         Connection con)
 857  
         throws TorqueException
 858  
     {
 859  
         return executeQuery(queryString, 0, -1, singleRecord, con);
 860  
     }
 861  
 
 862  
     /**
 863  
      * Method for performing a SELECT.
 864  
      *
 865  
      * @param queryString A String with the sql statement to execute.
 866  
      * @param start The first row to return.
 867  
      * @param numberOfResults The number of rows to return.
 868  
      * @param dbName The database to connect to.
 869  
      * @param singleRecord Whether or not we want to select only a
 870  
      * single record.
 871  
      * @return List of Record objects.
 872  
      * @throws TorqueException Any exceptions caught during processing will be
 873  
      *         rethrown wrapped into a TorqueException.
 874  
      */
 875  
     public static List executeQuery(
 876  
         String queryString,
 877  
         int start,
 878  
         int numberOfResults,
 879  
         String dbName,
 880  
         boolean singleRecord)
 881  
         throws TorqueException
 882  
     {
 883  
         Connection con = null;
 884  
         List results = null;
 885  
         try
 886  
         {
 887  
             con = Torque.getConnection(dbName);
 888  
             // execute the query
 889  
             results = executeQuery(
 890  
                     queryString,
 891  
                     start,
 892  
                     numberOfResults,
 893  
                     singleRecord,
 894  
                     con);
 895  
         }
 896  
         finally
 897  
         {
 898  
             Torque.closeConnection(con);
 899  
         }
 900  
         return results;
 901  
     }
 902  
 
 903  
     /**
 904  
      * Method for performing a SELECT.  Returns all results.
 905  
      *
 906  
      * @param queryString A String with the sql statement to execute.
 907  
      * @param start The first row to return.
 908  
      * @param numberOfResults The number of rows to return.
 909  
      * @param singleRecord Whether or not we want to select only a
 910  
      * single record.
 911  
      * @param con A Connection.
 912  
      * @return List of Record objects.
 913  
      * @throws TorqueException Any exceptions caught during processing will be
 914  
      *         rethrown wrapped into a TorqueException.
 915  
      */
 916  
     public static List executeQuery(
 917  
         String queryString,
 918  
         int start,
 919  
         int numberOfResults,
 920  
         boolean singleRecord,
 921  
         Connection con)
 922  
         throws TorqueException
 923  
     {
 924  
         QueryDataSet qds = null;
 925  
         List results = Collections.EMPTY_LIST;
 926  
         try
 927  
         {
 928  
             // execute the query
 929  
             long startTime = System.currentTimeMillis();
 930  
             qds = new QueryDataSet(con, queryString);
 931  
             if (log.isDebugEnabled())
 932  
             {
 933  
                 log.debug("Elapsed time="
 934  
                         + (System.currentTimeMillis() - startTime) + " ms");
 935  
             }
 936  
             results = getSelectResults(
 937  
                     qds, start, numberOfResults, singleRecord);
 938  
         }
 939  
         catch (DataSetException e)
 940  
         {
 941  
             throwTorqueException(e);
 942  
         }
 943  
         catch (SQLException e)
 944  
         {
 945  
             throwTorqueException(e);
 946  
         }
 947  
         finally
 948  
         {
 949  
             VillageUtils.close(qds);
 950  
         }
 951  
         return results;
 952  
     }
 953  
 
 954  
     /**
 955  
      * Returns all records in a QueryDataSet as a List of Record
 956  
      * objects.  Used for functionality like util.LargeSelect.
 957  
      *
 958  
      * @see #getSelectResults(QueryDataSet, int, int, boolean)
 959  
      * @param qds the QueryDataSet
 960  
      * @return a List of Record objects
 961  
      * @throws TorqueException Any exceptions caught during processing will be
 962  
      *         rethrown wrapped into a TorqueException.
 963  
      */
 964  
     public static List getSelectResults(QueryDataSet qds)
 965  
         throws TorqueException
 966  
     {
 967  
         return getSelectResults(qds, 0, -1, false);
 968  
     }
 969  
 
 970  
     /**
 971  
      * Returns all records in a QueryDataSet as a List of Record
 972  
      * objects.  Used for functionality like util.LargeSelect.
 973  
      *
 974  
      * @see #getSelectResults(QueryDataSet, int, int, boolean)
 975  
      * @param qds the QueryDataSet
 976  
      * @param singleRecord
 977  
      * @return a List of Record objects
 978  
      * @throws TorqueException Any exceptions caught during processing will be
 979  
      *         rethrown wrapped into a TorqueException.
 980  
      */
 981  
     public static List getSelectResults(QueryDataSet qds, boolean singleRecord)
 982  
         throws TorqueException
 983  
     {
 984  
         return getSelectResults(qds, 0, -1, singleRecord);
 985  
     }
 986  
 
 987  
     /**
 988  
      * Returns numberOfResults records in a QueryDataSet as a List
 989  
      * of Record objects.  Starting at record 0.  Used for
 990  
      * functionality like util.LargeSelect.
 991  
      *
 992  
      * @see #getSelectResults(QueryDataSet, int, int, boolean)
 993  
      * @param qds the QueryDataSet
 994  
      * @param numberOfResults
 995  
      * @param singleRecord
 996  
      * @return a List of Record objects
 997  
      * @throws TorqueException Any exceptions caught during processing will be
 998  
      *         rethrown wrapped into a TorqueException.
 999  
      */
 1000  
     public static List getSelectResults(
 1001  
         QueryDataSet qds,
 1002  
         int numberOfResults,
 1003  
         boolean singleRecord)
 1004  
         throws TorqueException
 1005  
     {
 1006  
         List results = null;
 1007  
         if (numberOfResults != 0)
 1008  
         {
 1009  
             results = getSelectResults(qds, 0, numberOfResults, singleRecord);
 1010  
         }
 1011  
         return results;
 1012  
     }
 1013  
 
 1014  
     /**
 1015  
      * Returns numberOfResults records in a QueryDataSet as a List
 1016  
      * of Record objects.  Starting at record start.  Used for
 1017  
      * functionality like util.LargeSelect.
 1018  
      *
 1019  
      * @param qds The <code>QueryDataSet</code> to extract results
 1020  
      * from.
 1021  
      * @param start The index from which to start retrieving
 1022  
      * <code>Record</code> objects from the data set.
 1023  
      * @param numberOfResults The number of results to return (or
 1024  
      * <code> -1</code> for all results).
 1025  
      * @param singleRecord Whether or not we want to select only a
 1026  
      * single record.
 1027  
      * @return A <code>List</code> of <code>Record</code> objects.
 1028  
      * @exception TorqueException If any <code>Exception</code> occurs.
 1029  
      */
 1030  
     public static List getSelectResults(
 1031  
         QueryDataSet qds,
 1032  
         int start,
 1033  
         int numberOfResults,
 1034  
         boolean singleRecord)
 1035  
         throws TorqueException
 1036  
     {
 1037  
         List results = null;
 1038  
         try
 1039  
         {
 1040  
             if (numberOfResults < 0)
 1041  
             {
 1042  
                 results = new ArrayList();
 1043  
                 qds.fetchRecords();
 1044  
             }
 1045  
             else
 1046  
             {
 1047  
                 results = new ArrayList(numberOfResults);
 1048  
                 qds.fetchRecords(start, numberOfResults);
 1049  
             }
 1050  
 
 1051  
             int startRecord = 0;
 1052  
 
 1053  
             //Offset the correct number of records
 1054  
             if (start > 0 && numberOfResults <= 0)
 1055  
             {
 1056  
                 startRecord = start;
 1057  
             }
 1058  
 
 1059  
             // Return a List of Record objects.
 1060  
             for (int i = startRecord; i < qds.size(); i++)
 1061  
             {
 1062  
                 Record rec = qds.getRecord(i);
 1063  
                 results.add(rec);
 1064  
             }
 1065  
 
 1066  
             if (results.size() > 1 && singleRecord)
 1067  
             {
 1068  
                 handleMultipleRecords(qds);
 1069  
             }
 1070  
         }
 1071  
         catch (Exception e)
 1072  
         {
 1073  
             throwTorqueException(e);
 1074  
         }
 1075  
         return results;
 1076  
     }
 1077  
 
 1078  
     /**
 1079  
      * Helper method which returns the primary key contained
 1080  
      * in the given Criteria object.
 1081  
      *
 1082  
      * @param criteria A Criteria.
 1083  
      * @return ColumnMap if the Criteria object contains a primary
 1084  
      *          key, or null if it doesn't.
 1085  
      * @throws TorqueException Any exceptions caught during processing will be
 1086  
      *         rethrown wrapped into a TorqueException.
 1087  
      */
 1088  
     private static ColumnMap getPrimaryKey(Criteria criteria)
 1089  
         throws TorqueException
 1090  
     {
 1091  
         // Assume all the keys are for the same table.
 1092  
         String key = (String) criteria.keys().nextElement();
 1093  
 
 1094  
         String table = criteria.getTableName(key);
 1095  
         ColumnMap pk = null;
 1096  
 
 1097  
         if (!table.equals(""))
 1098  
         {
 1099  
             DatabaseMap dbMap = Torque.getDatabaseMap(criteria.getDbName());
 1100  
             if (dbMap == null)
 1101  
             {
 1102  
                 throw new TorqueException("dbMap is null");
 1103  
             }
 1104  
             if (dbMap.getTable(table) == null)
 1105  
             {
 1106  
                 throw new TorqueException("dbMap.getTable() is null");
 1107  
             }
 1108  
 
 1109  
             ColumnMap[] columns = dbMap.getTable(table).getColumns();
 1110  
 
 1111  
             for (int i = 0; i < columns.length; i++)
 1112  
             {
 1113  
                 if (columns[i].isPrimaryKey())
 1114  
                 {
 1115  
                     pk = columns[i];
 1116  
                     break;
 1117  
                 }
 1118  
             }
 1119  
         }
 1120  
         return pk;
 1121  
     }
 1122  
 
 1123  
     /**
 1124  
      * Convenience method used to update rows in the DB.  Checks if a
 1125  
      * <i>single</i> int primary key is specified in the Criteria
 1126  
      * object and uses it to perform the udpate.  If no primary key is
 1127  
      * specified an Exception will be thrown.
 1128  
      * <p>
 1129  
      * Use this method for performing an update of the kind:
 1130  
      * <p>
 1131  
      * "WHERE primary_key_id = an int"
 1132  
      * <p>
 1133  
      * To perform an update with non-primary key fields in the WHERE
 1134  
      * clause use doUpdate(criteria, criteria).
 1135  
      *
 1136  
      * @param updateValues A Criteria object containing values used in
 1137  
      *        set clause.
 1138  
      * @throws TorqueException Any exceptions caught during processing will be
 1139  
      *         rethrown wrapped into a TorqueException.
 1140  
      */
 1141  
     public static void doUpdate(Criteria updateValues) throws TorqueException
 1142  
     {
 1143  
         Connection con = null;
 1144  
         try
 1145  
         {
 1146  
             con = Transaction.beginOptional(
 1147  
                     updateValues.getDbName(),
 1148  
                     updateValues.isUseTransaction());
 1149  
             doUpdate(updateValues, con);
 1150  
             Transaction.commit(con);
 1151  
         }
 1152  
         catch (TorqueException e)
 1153  
         {
 1154  
             Transaction.safeRollback(con);
 1155  
             throw e;
 1156  
         }
 1157  
     }
 1158  
 
 1159  
     /**
 1160  
      * Convenience method used to update rows in the DB.  Checks if a
 1161  
      * <i>single</i> int primary key is specified in the Criteria
 1162  
      * object and uses it to perform the udpate.  If no primary key is
 1163  
      * specified an Exception will be thrown.
 1164  
      * <p>
 1165  
      * Use this method for performing an update of the kind:
 1166  
      * <p>
 1167  
      * "WHERE primary_key_id = an int"
 1168  
      * <p>
 1169  
      * To perform an update with non-primary key fields in the WHERE
 1170  
      * clause use doUpdate(criteria, criteria).
 1171  
      *
 1172  
      * @param updateValues A Criteria object containing values used in
 1173  
      * set clause.
 1174  
      * @param con A Connection.
 1175  
      * @throws TorqueException Any exceptions caught during processing will be
 1176  
      *         rethrown wrapped into a TorqueException.
 1177  
      */
 1178  
     public static void doUpdate(Criteria updateValues, Connection con)
 1179  
         throws TorqueException
 1180  
     {
 1181  
         ColumnMap pk = getPrimaryKey(updateValues);
 1182  
         Criteria selectCriteria = null;
 1183  
 
 1184  
         if (pk != null && updateValues.containsKey(pk.getFullyQualclass="keyword">ifiedName()))
 1185  
         {
 1186  
             selectCriteria = new Criteria(2);
 1187  
             selectCriteria.put(pk.getFullyQualifiedName(),
 1188  
                 updateValues.remove(pk.getFullyQualifiedName()));
 1189  
         }
 1190  
         else
 1191  
         {
 1192  
             throw new TorqueException("No PK specified for database update");
 1193  
         }
 1194  
 
 1195  
         doUpdate(selectCriteria, updateValues, con);
 1196  
     }
 1197  
 
 1198  
     /**
 1199  
      * Method used to update rows in the DB.  Rows are selected based
 1200  
      * on selectCriteria and updated using values in updateValues.
 1201  
      * <p>
 1202  
      * Use this method for performing an update of the kind:
 1203  
      * <p>
 1204  
      * WHERE some_column = some value AND could_have_another_column =
 1205  
      * another value AND so on...
 1206  
      *
 1207  
      * @param selectCriteria A Criteria object containing values used in where
 1208  
      *        clause.
 1209  
      * @param updateValues A Criteria object containing values used in set
 1210  
      *        clause.
 1211  
      * @throws TorqueException Any exceptions caught during processing will be
 1212  
      *         rethrown wrapped into a TorqueException.
 1213  
      */
 1214  
     public static void doUpdate(Criteria selectCriteria, Criteria updateValues)
 1215  
         throws TorqueException
 1216  
     {
 1217  
         Connection con = null;
 1218  
         try
 1219  
         {
 1220  
             con = Transaction.beginOptional(
 1221  
                     selectCriteria.getDbName(),
 1222  
                     updateValues.isUseTransaction());
 1223  
             doUpdate(selectCriteria, updateValues, con);
 1224  
             Transaction.commit(con);
 1225  
         }
 1226  
         catch (TorqueException e)
 1227  
         {
 1228  
             Transaction.safeRollback(con);
 1229  
             throw e;
 1230  
         }
 1231  
     }
 1232  
 
 1233  
     /**
 1234  
      * Method used to update rows in the DB.  Rows are selected based
 1235  
      * on criteria and updated using values in updateValues.
 1236  
      * <p>
 1237  
      * Use this method for performing an update of the kind:
 1238  
      * <p>
 1239  
      * WHERE some_column = some value AND could_have_another_column =
 1240  
      * another value AND so on.
 1241  
      *
 1242  
      * @param criteria A Criteria object containing values used in where
 1243  
      *        clause.
 1244  
      * @param updateValues A Criteria object containing values used in set
 1245  
      *        clause.
 1246  
      * @param con A Connection.
 1247  
      * @throws TorqueException Any exceptions caught during processing will be
 1248  
      *         rethrown wrapped into a TorqueException.
 1249  
      */
 1250  
     public static void doUpdate(
 1251  
         Criteria criteria,
 1252  
         final Criteria updateValues,
 1253  
         Connection con)
 1254  
         throws TorqueException
 1255  
     {
 1256  
         Set tables = SQLBuilder.getTableSet(criteria, null);
 1257  
 
 1258  
         try
 1259  
         {
 1260  
             processTables(criteria, tables, con, new ProcessCallback() {
 1261  
                     public void process (String table, String dbName, Record rec)
 1262  
                         throws Exception
 1263  
                     {
 1264  
                         // Callback must be called with table name without Schema!
 1265  
                         BasePeer.insertOrUpdateRecord(rec, table, dbName, updateValues);
 1266  
                     }
 1267  
                 });
 1268  
         }
 1269  
         catch (Exception e)
 1270  
         {
 1271  
             throwTorqueException(e);
 1272  
         }
 1273  
     }
 1274  
 
 1275  
     /**
 1276  
      * Utility method which executes a given sql statement.  This
 1277  
      * method should be used for update, insert, and delete
 1278  
      * statements.  Use executeQuery() for selects.
 1279  
      *
 1280  
      * @param statementString A String with the sql statement to execute.
 1281  
      * @return The number of rows affected.
 1282  
      * @throws TorqueException Any exceptions caught during processing will be
 1283  
      *         rethrown wrapped into a TorqueException.
 1284  
      */
 1285  
     public static int executeStatement(String statementString) throws TorqueException
 1286  
     {
 1287  
         return executeStatement(statementString, Torque.getDefaultDB());
 1288  
     }
 1289  
 
 1290  
     /**
 1291  
      * Utility method which executes a given sql statement.  This
 1292  
      * method should be used for update, insert, and delete
 1293  
      * statements.  Use executeQuery() for selects.
 1294  
      *
 1295  
      * @param statementString A String with the sql statement to execute.
 1296  
      * @param dbName Name of database to connect to.
 1297  
      * @return The number of rows affected.
 1298  
      * @throws TorqueException Any exceptions caught during processing will be
 1299  
      *         rethrown wrapped into a TorqueException.
 1300  
      */
 1301  
     public static int executeStatement(String statementString, String dbName)
 1302  
         throws TorqueException
 1303  
     {
 1304  
         Connection con = null;
 1305  
         int rowCount = -1;
 1306  
         try
 1307  
         {
 1308  
             con = Torque.getConnection(dbName);
 1309  
             rowCount = executeStatement(statementString, con);
 1310  
         }
 1311  
         finally
 1312  
         {
 1313  
             Torque.closeConnection(con);
 1314  
         }
 1315  
         return rowCount;
 1316  
     }
 1317  
 
 1318  
     /**
 1319  
      * Utility method which executes a given sql statement.  This
 1320  
      * method should be used for update, insert, and delete
 1321  
      * statements.  Use executeQuery() for selects.
 1322  
      *
 1323  
      * @param statementString A String with the sql statement to execute.
 1324  
      * @param con A Connection.
 1325  
      * @return The number of rows affected.
 1326  
      * @throws TorqueException Any exceptions caught during processing will be
 1327  
      *         rethrown wrapped into a TorqueException.
 1328  
      */
 1329  
     public static int executeStatement(String statementString, Connection con)
 1330  
         throws TorqueException
 1331  
     {
 1332  
         int rowCount = -1;
 1333  
         Statement statement = null;
 1334  
         try
 1335  
         {
 1336  
             statement = con.createStatement();
 1337  
             rowCount = statement.executeUpdate(statementString);
 1338  
         }
 1339  
         catch (SQLException e)
 1340  
         {
 1341  
             throw new TorqueException(e);
 1342  
         }
 1343  
         finally
 1344  
         {
 1345  
             if (statement != null)
 1346  
             {
 1347  
                 try
 1348  
                 {
 1349  
                     statement.close();
 1350  
                 }
 1351  
                 catch (SQLException e)
 1352  
                 {
 1353  
                     throw new TorqueException(e);
 1354  
                 }
 1355  
             }
 1356  
         }
 1357  
         return rowCount;
 1358  
     }
 1359  
 
 1360  
     /**
 1361  
      * If the user specified that (s)he only wants to retrieve a
 1362  
      * single record and multiple records are retrieved, this method
 1363  
      * is called to handle the situation.  The default behavior is to
 1364  
      * throw an exception, but subclasses can override this method as
 1365  
      * needed.
 1366  
      *
 1367  
      * @param ds The DataSet which contains multiple records.
 1368  
      * @exception TorqueException Couldn't handle multiple records.
 1369  
      */
 1370  
     protected static void handleMultipleRecords(DataSet ds)
 1371  
         throws TorqueException
 1372  
     {
 1373  
         throw new TorqueException("Criteria expected single Record and "
 1374  
                 + "Multiple Records were selected");
 1375  
     }
 1376  
 
 1377  
     /**
 1378  
      * This method returns the MapBuilder specified in the name
 1379  
      * parameter.  You should pass in the full path to the class, ie:
 1380  
      * org.apache.torque.util.db.map.TurbineMapBuilder.  The
 1381  
      * MapBuilder instances are cached in the TorqueInstance for speed.
 1382  
      *
 1383  
      * @param name name of the MapBuilder
 1384  
      * @return A MapBuilder, not null
 1385  
      * @throws TorqueException if the Map Builder cannot be instantiated
 1386  
      * @deprecated Use Torque.getMapBuilder(name) instead
 1387  
      */
 1388  
     public static MapBuilder getMapBuilder(String name)
 1389  
         throws TorqueException
 1390  
     {
 1391  
         return Torque.getMapBuilder(name);
 1392  
     }
 1393  
 
 1394  
     /**
 1395  
      * Performs a SQL <code>select</code> using a PreparedStatement.
 1396  
      * Note: this method does not handle null criteria values.
 1397  
      *
 1398  
      * @param criteria
 1399  
      * @param con
 1400  
      * @return a List of Record objects.
 1401  
      * @throws TorqueException Error performing database query.
 1402  
      */
 1403  
     public static List doPSSelect(Criteria criteria, Connection con)
 1404  
         throws TorqueException
 1405  
     {
 1406  
         List v = null;
 1407  
 
 1408  
         StringBuffer qry = new StringBuffer();
 1409  
         List params = new ArrayList(criteria.size());
 1410  
 
 1411  
         createPreparedStatement(criteria, qry, params);
 1412  
 
 1413  
         PreparedStatement statement = null;
 1414  
         try
 1415  
         {
 1416  
             statement = con.prepareStatement(qry.toString());
 1417  
 
 1418  
             for (int i = 0; i < params.size(); i++)
 1419  
             {
 1420  
                 Object param = params.get(i);
 1421  
                 if (param instanceof java.sql.Date)
 1422  
                 {
 1423  
                     statement.setDate(i + 1, (java.sql.Date) param);
 1424  
                 }
 1425  
                 else if (param instanceof NumberKey)
 1426  
                 {
 1427  
                     statement.setBigDecimal(i + 1,
 1428  
                         ((NumberKey) param).getBigDecimal());
 1429  
                 }
 1430  
                 else if (param instanceof Integer)
 1431  
                 {
 1432  
                     statement.setInt(i + 1, ((Integer) param).intValue());
 1433  
                 }
 1434  
                 else
 1435  
                 {
 1436  
                     statement.setString(i + 1, param.toString());
 1437  
                 }
 1438  
             }
 1439  
 
 1440  
             QueryDataSet qds = null;
 1441  
             try
 1442  
             {
 1443  
                 qds = new QueryDataSet(statement.executeQuery());
 1444  
                 v = getSelectResults(qds);
 1445  
             }
 1446  
             finally
 1447  
             {
 1448  
                 VillageUtils.close(qds);
 1449  
             }
 1450  
         }
 1451  
         catch (DataSetException e)
 1452  
         {
 1453  
             throwTorqueException(e);
 1454  
         }
 1455  
         catch (SQLException e)
 1456  
         {
 1457  
             throwTorqueException(e);
 1458  
         }
 1459  
         finally
 1460  
         {
 1461  
             if (statement != null)
 1462  
             {
 1463  
                 try
 1464  
                 {
 1465  
                     statement.close();
 1466  
                 }
 1467  
                 catch (SQLException e)
 1468  
                 {
 1469  
                     throw new TorqueException(e);
 1470  
                 }
 1471  
             }
 1472  
         }
 1473  
         return v;
 1474  
     }
 1475  
 
 1476  
     /**
 1477  
      * Do a Prepared Statement select according to the given criteria
 1478  
      *
 1479  
      * @param criteria
 1480  
      * @return a List of Record objects.
 1481  
      * @throws TorqueException Any exceptions caught during processing will be
 1482  
      *         rethrown wrapped into a TorqueException.
 1483  
      */
 1484  
     public static List doPSSelect(Criteria criteria) throws TorqueException
 1485  
     {
 1486  
         Connection con = Torque.getConnection(criteria.getDbName());
 1487  
         List v = null;
 1488  
 
 1489  
         try
 1490  
         {
 1491  
             v = doPSSelect(criteria, con);
 1492  
         }
 1493  
         finally
 1494  
         {
 1495  
             Torque.closeConnection(con);
 1496  
         }
 1497  
         return v;
 1498  
     }
 1499  
 
 1500  
     /**
 1501  
      * Create a new PreparedStatement.  It builds a string representation
 1502  
      * of a query and a list of PreparedStatement parameters.
 1503  
      *
 1504  
      * @param criteria
 1505  
      * @param queryString
 1506  
      * @param params
 1507  
      * @throws TorqueException Any exceptions caught during processing will be
 1508  
      *         rethrown wrapped into a TorqueException.
 1509  
      */
 1510  
     public static void createPreparedStatement(
 1511  
         Criteria criteria,
 1512  
         StringBuffer queryString,
 1513  
         List params)
 1514  
         throws TorqueException
 1515  
     {
 1516  
         Query query = SQLBuilder.buildQueryClause(criteria, params, new SQLBuilder.QueryCallback() {
 1517  0
                 public String process(Criteria.Criterion criterion, List params)
 1518  
                 {
 1519  0
                     StringBuffer sb = new StringBuffer();
 1520  0
                     criterion.appendPsTo(sb, params);
 1521  0
                     return sb.toString();
 1522  
                 }
 1523  
             });
 1524  
 
 1525  
         String sql = query.toString();
 1526  
         log.debug(sql);
 1527  
 
 1528  
         queryString.append(sql);
 1529  
     }
 1530  
 
 1531  
     /**
 1532  
      * Checks all columns in the criteria to see whether
 1533  
      * booleanchar and booleanint columns are queried with a boolean.
 1534  
      * If yes, the query values are mapped onto values the database
 1535  
      * does understand, i.e. 0 and 1 for booleanints and N and Y for
 1536  
      * booleanchar columns.
 1537  
      *
 1538  
      * @param criteria The criteria to be checked for booleanint and booleanchar
 1539  
      *        columns.
 1540  
      * @param defaultTableMap the table map to be used if the table name is
 1541  
      *        not given in a column.
 1542  
      * @throws TorqueException if the database map for the criteria cannot be
 1543  
      *         retrieved.
 1544  
      */
 1545  
     public static void correctBooleans(
 1546  
             Criteria criteria,
 1547  
             TableMap defaultTableMap)
 1548  
         throws TorqueException
 1549  
     {
 1550  
         Iterator keyIt = criteria.keySet().iterator();
 1551  
         while (keyIt.hasNext())
 1552  
         {
 1553  
             String key = (String) keyIt.next();
 1554  
             String columnName;
 1555  
             TableMap tableMap = null;
 1556  
             int dotPosition = key.lastIndexOf(".");
 1557  
             if (dotPosition == -1)
 1558  
             {
 1559  
                 columnName = key;
 1560  
                 tableMap = defaultTableMap;
 1561  
             }
 1562  
             else
 1563  
             {
 1564  
                 columnName = key.substring(dotPosition + 1);
 1565  
                 String tableName = key.substring(0, dotPosition);
 1566  
                 String databaseName = criteria.getDbName();
 1567  
                 if (databaseName == null)
 1568  
                 {
 1569  
                     databaseName = Torque.getDefaultDB();
 1570  
                 }
 1571  
                 DatabaseMap databaseMap = Torque.getDatabaseMap(databaseName);
 1572  
                 if (databaseMap != null)
 1573  
                 {
 1574  
                     tableMap = databaseMap.getTable(tableName);
 1575  
                 }
 1576  
                 if (tableMap == null)
 1577  
                 {
 1578  
                     // try aliases
 1579  
                     Map aliases = criteria.getAliases();
 1580  
                     if (aliases.get(tableName) != null)
 1581  
                     {
 1582  
                         tableName = (String) aliases.get(tableName);
 1583  
                         tableMap = databaseMap.getTable(tableName);
 1584  
                     }
 1585  
                 }
 1586  
             }
 1587  
             if (tableMap == null)
 1588  
             {
 1589  
                 // no description of table available, do not modify anything
 1590  
                 continue;
 1591  
             }
 1592  
 
 1593  
             ColumnMap columnMap = tableMap.getColumn(columnName);
 1594  
             if (columnMap != null)
 1595  
             {
 1596  
                 if ("BOOLEANINT".equals(columnMap.getTorqueType()))
 1597  
                 {
 1598  
                     Criteria.Criterion criterion = criteria.getCriterion(key);
 1599  
                     replaceBooleanValues(
 1600  
                             criterion,
 1601  
                             new Integer(1),
 1602  
                             new Integer(0));
 1603  
                 }
 1604  
                 else if ("BOOLEANCHAR".equals(columnMap.getTorqueType()))
 1605  
                 {
 1606  
                     Criteria.Criterion criterion = criteria.getCriterion(key);
 1607  
                     replaceBooleanValues(criterion, "Y", "N");
 1608  
                  }
 1609  
             }
 1610  
         }
 1611  
     }
 1612  
 
 1613  
     /**
 1614  
      * Replaces any Boolean value in the criterion and its attached Criterions
 1615  
      * by trueValue if the Boolean equals <code>Boolean.TRUE</code>
 1616  
      * and falseValue if the Boolean equals <code>Boolean.FALSE</code>.
 1617  
      *
 1618  
      * @param criterion the criterion to replace Boolean values in.
 1619  
      * @param trueValue the value by which Boolean.TRUE should be replaced.
 1620  
      * @param falseValue the value by which Boolean.FALSE should be replaced.
 1621  
      */
 1622  
     private static void replaceBooleanValues(
 1623  
             Criteria.Criterion criterion,
 1624  
             Object trueValue,
 1625  
             Object falseValue)
 1626  
     {
 1627  
         // attachedCriterions also contains the criterion itself,
 1628  
         // so no additional treatment is needed for the criterion itself.
 1629  
         Criteria.Criterion[] attachedCriterions
 1630  
             = criterion.getAttachedCriterion();
 1631  
         for (int i = 0; i < attachedCriterions.length; ++i)
 1632  
         {
 1633  
             Object criterionValue
 1634  
                     = attachedCriterions[i].getValue();
 1635  
             if (criterionValue instanceof Boolean)
 1636  
             {
 1637  
                 Boolean booleanValue = (Boolean) criterionValue;
 1638  
                 attachedCriterions[i].setValue(
 1639  
                         Boolean.TRUE.equals(booleanValue)
 1640  
                                 ? trueValue
 1641  
                                 : falseValue);
 1642  
             }
 1643  
 
 1644  
         }
 1645  
 
 1646  
     }
 1647  
 
 1648  
     /**
 1649  
      * Process the result of a Table list generation.
 1650  
      * This runs the statements onto the list of tables and
 1651  
      * provides a callback hook to add functionality.
 1652  
      *
 1653  
      * This method should've been in SQLBuilder, but is uses the handleMultipleRecords callback thingie..
 1654  
      *
 1655  
      * @param crit The criteria
 1656  
      * @param tables A set of Tables to run on
 1657  
      * @param con The SQL Connection to run the statements on
 1658  
      * @param pc A ProcessCallback object
 1659  
      *
 1660  
      * @throws Exception An Error occured (should be wrapped into TorqueException)
 1661  
      */
 1662  
     private static void processTables(Criteria crit, Set tables, Connection con, ProcessCallback pc)
 1663  
             throws Exception
 1664  
     {
 1665  
         String dbName = crit.getDbName();
 1666  
         DB db = Torque.getDB(dbName);
 1667  
         DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
 1668  
 
 1669  
         // create the statements for the tables
 1670  
         for (Iterator it = tables.iterator(); it.hasNext();)
 1671  
         {
 1672  
             String table = (String) it.next();
 1673  
             KeyDef kd = new KeyDef();
 1674  
             Set whereClause = new HashSet();
 1675  
 
 1676  
             ColumnMap[] columnMaps = dbMap.getTable(table).getColumns();
 1677  
 
 1678  
             for (int j = 0; j < columnMaps.length; j++)
 1679  
             {
 1680  
                 ColumnMap colMap = columnMaps[j];
 1681  
                 if (colMap.isPrimaryKey())
 1682  
                 {
 1683  
                     kd.addAttrib(colMap.getColumnName());
 1684  
                 }
 1685  
 
 1686  
                 String key = new StringBuffer(colMap.getTableName())
 1687  
                         .append('.')
 1688  
                         .append(colMap.getColumnName())
 1689  
                         .toString();
 1690  
 
 1691  
                 if (crit.containsKey(key))
 1692  
                 {
 1693  
                     if (crit
 1694  
                             .getComparison(key)
 1695  
                             .equals(Criteria.CUSTOM))
 1696  
                     {
 1697  
                         whereClause.add(crit.getString(key));
 1698  
                     }
 1699  
                     else
 1700  
                     {
 1701  
                         whereClause.add(
 1702  
                                 SqlExpression.build(
 1703  
                                         colMap.getColumnName(),
 1704  
                                         crit.getValue(key),
 1705  
                                         crit.getComparison(key),
 1706  
                                         crit.isIgnoreCase(),
 1707  
                                         db));
 1708  
                     }
 1709  
                 }
 1710  
             }
 1711  
 
 1712  
             // Execute the statement for each table
 1713  
             TableDataSet tds = null;
 1714  
             try
 1715  
             {
 1716  
                 String tableName = SQLBuilder.getFullTableName(table, dbName);
 1717  
 
 1718  
                 // Get affected records.
 1719  
                 tds = new TableDataSet(con, tableName, kd);
 1720  
                 String sqlSnippet = StringUtils.join(whereClause.iterator(), " AND ");
 1721  
 
 1722  
                 if (log.isDebugEnabled())
 1723  
                 {
 1724  
                     log.debug("BasePeer: whereClause=" + sqlSnippet);
 1725  
                 }
 1726  
 
 1727  
                 tds.where(sqlSnippet);
 1728  
                 tds.fetchRecords();
 1729  
 
 1730  
                 if (tds.size() > 1 && crit.isSingleRecord())
 1731  
                 {
 1732  
                     handleMultipleRecords(tds);
 1733  
                 }
 1734  
 
 1735  
                 for (int j = 0; j < tds.size(); j++)
 1736  
                 {
 1737  
                     Record rec = tds.getRecord(j);
 1738  
 
 1739  
                     if (pc != null)
 1740  
                     {
 1741  
                         // Table name _without_ schema!
 1742  
                         pc.process(table, dbName, rec);
 1743  
                     }
 1744  
                 }
 1745  
             }
 1746  
             finally
 1747  
             {
 1748  
                 VillageUtils.close(tds);
 1749  
             }
 1750  
         }
 1751  
     }
 1752  
 
 1753  
     /**
 1754  
      * Inner Interface that defines the Callback method for
 1755  
      * the Record Processing
 1756  
      */
 1757  
     protected interface ProcessCallback
 1758  
     {
 1759  
         void process (String table, String dbName, Record rec)
 1760  
                 throws Exception;
 1761  
     }
 1762  
 }

This report is generated by jcoverage, Maven and Maven JCoverage Plugin.