Coverage report

  %line %branch
org.apache.torque.util.SQLBuilder
77% 
85% 

 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.util.HashSet;
 23  
 import java.util.Iterator;
 24  
 import java.util.List;
 25  
 import java.util.Map;
 26  
 import java.util.Set;
 27  
 
 28  
 import org.apache.commons.lang.StringUtils;
 29  
 import org.apache.commons.logging.Log;
 30  
 import org.apache.commons.logging.LogFactory;
 31  
 import org.apache.torque.Torque;
 32  
 import org.apache.torque.TorqueException;
 33  
 import org.apache.torque.adapter.DB;
 34  
 import org.apache.torque.map.ColumnMap;
 35  
 import org.apache.torque.map.DatabaseMap;
 36  
 import org.apache.torque.util.Criteria.Criterion;
 37  
 
 38  
 /**
 39  
  * Factored out code that is used to process SQL tables. This code comes
 40  
  * from BasePeer and is put here to reduce complexity in the BasePeer class.
 41  
  * You should not use the methods here directly!
 42  
  *
 43  
  * @author <a href="mailto:hps@intermeta.de">Henning P. Schmiedehausen</a>
 44  
  * @author <a href="mailto:fischer@seitenbau.de">Thomas Fischer</a>
 45  
  * @version $Id: SQLBuilder.java 535596 2007-05-06 10:47:39Z tfischer $
 46  
  */
 47  
 public final class SQLBuilder
 48  
 {
 49  
     /** Logging */
 50  24
     protected static final Log log = LogFactory.getLog(SQLBuilder.class);
 51  
 
 52  
     /** Function Characters */
 53  12
     public static final String[] COLUMN_CHARS = {".", "*"};
 54  12
     public static final String[] DELIMITERS = {" ", ",", "(", ")", "<", ">"};
 55  
 
 56  
     /**
 57  
      * Private constructor to prevent instantiation.
 58  
      *
 59  
      * Class contains only static method ans should therefore not be
 60  
      * instantiated.
 61  
      */
 62  
     private SQLBuilder()
 63  0
     {
 64  0
     }
 65  
 
 66  
     /**
 67  
      * Fully qualify a table name with an optional schema reference
 68  
      *
 69  
      * @param table The table name to use. If null is passed in, null is returned.
 70  
      * @param dbName The name of the database to which this tables belongs.
 71  
      *               If null is passed, the default database is used.
 72  
      *
 73  
      * @return The table name to use inside the SQL statement. If null is passed
 74  
      *         into this method, null is returned.
 75  
      * @exception TorqueException if an error occurs
 76  
      */
 77  
     public static String getFullTableName(
 78  
             final String table,
 79  
             final String dbName)
 80  
         throws TorqueException
 81  
     {
 82  204
         if (table != null)
 83  
         {
 84  204
             int dotIndex = table.indexOf(".");
 85  
 
 86  204
             if (dotIndex == -1) // No schema given
 87  
             {
 88  198
                 String targetDBName = (dbName == null)
 89  
                         ? Torque.getDefaultDB()
 90  
                         : dbName;
 91  
 
 92  198
                 String targetSchema = Torque.getSchema(targetDBName);
 93  
 
 94  
                 // If we have a default schema, fully qualify the
 95  
                 // table and return.
 96  198
                 if (StringUtils.isNotEmpty(targetSchema))
 97  
                 {
 98  0
                     return new StringBuffer()
 99  
                             .append(targetSchema)
 100  
                             .append(".")
 101  
                             .append(table)
 102  
                             .toString();
 103  
                 }
 104  
             }
 105  
         }
 106  
 
 107  204
         return table;
 108  
     }
 109  
 
 110  
     /**
 111  
      * Remove a possible schema name from the table name.
 112  
      *
 113  
      * @param table The table name to use
 114  
      *
 115  
      * @return The table name with a possible schema name
 116  
      *         stripped off
 117  
      */
 118  
     public static String getUnqualifiedTableName(final String table)
 119  
     {
 120  162
         if (table != null)
 121  
         {
 122  156
             int dotIndex = table.lastIndexOf("."); // Do we have a dot?
 123  
 
 124  156
             if (++dotIndex > 0) // Incrementation allows for better test _and_ substring...
 125  
             {
 126  0
                 return table.substring(dotIndex);
 127  
             }
 128  
         }
 129  
 
 130  162
         return table;
 131  
     }
 132  
 
 133  
     /**
 134  
      * Removes a possible function name or clause from a column name
 135  
      *
 136  
      * @param name The column name, possibly containing a clause
 137  
      *
 138  
      * @return The column name
 139  
      *
 140  
      * @throws TorqueException If the column name was malformed
 141  
      */
 142  
     private static String removeSQLFunction(final String name)
 143  
             throws TorqueException
 144  
     {
 145  
         // Empty name => return it
 146  108
         if (StringUtils.isEmpty(name))
 147  
         {
 148  12
             return name;
 149  
         }
 150  
 
 151  
         // Find Table.Column
 152  96
         int dotIndex = name.indexOf('.');
 153  96
         if (dotIndex == -1)
 154  
         {
 155  24
             dotIndex = name.indexOf("*");
 156  
         }
 157  96
         if (dotIndex == -1)
 158  
         {
 159  6
             throw new TorqueException("removeSQLFunction() : Column name "
 160  
                     + name
 161  
                     + " does not contain a . or a *");
 162  
         }
 163  90
         String pre = name.substring(0, dotIndex);
 164  90
         String post = name.substring(dotIndex + 1, name.length());
 165  90
         int startIndex = StringUtils.lastIndexOfAny(pre, DELIMITERS);
 166  90
         int endIndex = StringUtils.indexOfAny(post, DELIMITERS);
 167  90
         if (startIndex < 0 && endIndex < 0)
 168  
         {
 169  24
             return name;
 170  
         }
 171  
         else
 172  
         {
 173  66
             if (endIndex < 0)
 174  
             {
 175  18
                 endIndex = post.length();
 176  
             }
 177  
             // if startIndex == -1 the formula is correct
 178  66
             return name.substring(startIndex + 1, dotIndex + 1 + endIndex);
 179  
         }
 180  
     }
 181  
 
 182  
     /**
 183  
      * Returns a table name from an identifier. Each identifier is to be qualified
 184  
      * as [schema.]table.column. This could also contain FUNCTION([schema.]table.column).
 185  
      *
 186  
      * @param name The (possible fully qualified) identifier name
 187  
      *
 188  
      * @return the fully qualified table name
 189  
      *
 190  
      * @throws TorqueException If the identifier name was malformed
 191  
      */
 192  
     public static String getTableName(final String name, class="keyword">final String dbName)
 193  
             throws TorqueException
 194  
     {
 195  102
         final String testName = removeSQLFunction(name);
 196  
 
 197  96
         if (StringUtils.isEmpty(testName))
 198  
         {
 199  12
             throwMalformedColumnNameException(
 200  
                     "getTableName",
 201  
                     name);
 202  
         }
 203  
 
 204  
         // Everything before the last dot is the table name
 205  84
         int rightDotIndex = testName.lastIndexOf('.');
 206  
 
 207  84
         if (rightDotIndex < 0)
 208  
         {
 209  18
             if ("*".equals(testName))
 210  
             {
 211  18
                 return null;
 212  
             }
 213  
 
 214  0
             throwMalformedColumnNameException(
 215  
                     "getTableName",
 216  
                     name);
 217  
         }
 218  
 
 219  66
         return getFullTableName(testName.substring(0, rightDotIndex), dbName);
 220  
     }
 221  
 
 222  
 
 223  
 
 224  
     /**
 225  
      * Returns a set of all tables and possible aliases referenced
 226  
      * from a criterion. The resulting Set can be directly used to
 227  
      * build a WHERE clause
 228  
      *
 229  
      * @param crit A Criteria object
 230  
      * @param tableCallback A Callback Object
 231  
      * @return A Set of tables.
 232  
      */
 233  
     public static Set getTableSet(
 234  
             final Criteria crit,
 235  
             final TableCallback tableCallback)
 236  
     {
 237  0
         HashSet tables = new HashSet();
 238  
 
 239  
         // Loop over all the Criterions
 240  0
         for (Iterator it = crit.keySet().iterator(); it.hasNext();)
 241  
         {
 242  0
             String key = (String) it.next();
 243  0
             Criteria.Criterion c = crit.getCriterion(key);
 244  0
             List tableNames = c.getAllTables();
 245  
 
 246  
             // Loop over all Tables referenced in this criterion.
 247  0
             for (Iterator it2 = tableNames.iterator(); it2.hasNext();)
 248  
             {
 249  0
                 String name = (String) it2.next();
 250  0
                 String aliasName = crit.getTableForAlias(name);
 251  
 
 252  
                 // If the tables have an alias, add an "<xxx> AS <yyy> statement"
 253  0
                 if (StringUtils.isNotEmpty(aliasName))
 254  
                 {
 255  0
                     String newName =
 256  
                             new StringBuffer(name.length() + aliasName.length() + 4)
 257  
                             .append(aliasName)
 258  
                             .append(" AS ")
 259  
                             .append(name)
 260  
                             .toString();
 261  0
                     name = newName;
 262  
                 }
 263  0
                 tables.add(name);
 264  
             }
 265  
 
 266  0
             if (tableCallback != null)
 267  
             {
 268  0
                 tableCallback.process(tables, key, crit);
 269  
             }
 270  
         }
 271  
 
 272  0
         return tables;
 273  
     }
 274  
 
 275  
     /**
 276  
      * Builds a Query clause for Updating and deleting
 277  
      *
 278  
      * @param crit a <code>Criteria</code> value
 279  
      * @param params a <code>List</code> value
 280  
      * @param qc a <code>QueryCallback</code> value
 281  
      * @return a <code>Query</code> value
 282  
      * @exception TorqueException if an error occurs
 283  
      */
 284  
     public static Query buildQueryClause(final Criteria crit,
 285  
             final List params,
 286  
             final QueryCallback qc)
 287  
             throws TorqueException
 288  
     {
 289  102
         Query query = new Query();
 290  
 
 291  102
         final String dbName = crit.getDbName();
 292  102
         final DB db = Torque.getDB(dbName);
 293  102
         final DatabaseMap dbMap = Torque.getDatabaseMap(dbName);
 294  
 
 295  102
         JoinBuilder.processJoins(db, dbMap, crit, query);
 296  102
         processModifiers(crit, query);
 297  102
         processSelectColumns(crit, query, dbName);
 298  102
         processAsColumns(crit, query);
 299  102
         processCriterions(db, dbMap, dbName, crit, query,  params, qc);
 300  102
         processGroupBy(crit, query);
 301  102
         processHaving(crit, query);
 302  102
         processOrderBy(db, dbMap, crit, query);
 303  102
         processLimits(crit, query);
 304  
 
 305  102
         if (log.isDebugEnabled())
 306  
         {
 307  102
             log.debug(query.toString());
 308  
         }
 309  102
         return query;
 310  
     }
 311  
 
 312  
 
 313  
     /**
 314  
      * adds the select columns from the criteria to the query
 315  
      * @param criteria the criteria from which the select columns are taken
 316  
      * @param query the query to which the select columns should be added
 317  
      * @throws TorqueException if the select columns can not be processed
 318  
      */
 319  
     private static void processSelectColumns(
 320  
             final Criteria criteria,
 321  
             final Query query,
 322  
             final String dbName)
 323  
         throws TorqueException
 324  
     {
 325  102
         UniqueList selectClause = query.getSelectClause();
 326  102
         UniqueList select = criteria.getSelectColumns();
 327  
 
 328  114
         for (int i = 0; i < select.size(); i++)
 329  
         {
 330  12
             String identifier = (String) select.get(i);
 331  12
             selectClause.add(identifier);
 332  12
             addTableToFromClause(getTableName(identifier, dbName), criteria, query);
 333  
         }
 334  102
     }
 335  
 
 336  
     /**
 337  
      * adds the As-columns from the criteria to the query.
 338  
      * @param criteria the criteria from which the As-columns are taken
 339  
      * @param query the query to which the As-columns should be added
 340  
      */
 341  
     private static void processAsColumns(
 342  
             final Criteria criteria,
 343  
             final Query query)
 344  
     {
 345  102
         UniqueList querySelectClause = query.getSelectClause();
 346  102
         Map criteriaAsColumns = criteria.getAsColumns();
 347  
 
 348  102
         for (Iterator it = criteriaAsColumns.entrySet().iterator(); it.hasNext();)
 349  
         {
 350  0
             Map.Entry entry = (Map.Entry) it.next();
 351  0
             String key = (String) entry.getKey();
 352  0
             querySelectClause.add(
 353  
                     new StringBuffer()
 354  
                     .append(entry.getValue())
 355  
                     .append(SqlEnum.AS)
 356  
                     .append(key)
 357  
                     .toString());
 358  
         }
 359  102
     }
 360  
 
 361  
     /**
 362  
      * adds the Modifiers from the criteria to the query
 363  
      * @param criteria the criteria from which the Modifiers are taken
 364  
      * @param query the query to which the Modifiers should be added
 365  
      */
 366  
     private static void processModifiers(
 367  
             final Criteria criteria,
 368  
             final Query query)
 369  
     {
 370  102
         UniqueList selectModifiers = query.getSelectModifiers();
 371  102
         UniqueList modifiers = criteria.getSelectModifiers();
 372  102
         for (int i = 0; i < modifiers.size(); i++)
 373  
         {
 374  0
             selectModifiers.add(modifiers.get(i));
 375  
         }
 376  102
     }
 377  
 
 378  
     /**
 379  
      * adds the Criterion-objects from the criteria to the query
 380  
      * @param criteria the criteria from which the Criterion-objects are taken
 381  
      * @param query the query to which the Criterion-objects should be added
 382  
      * @param params the parameters if a prepared statement should be built,
 383  
      *        or null if a normal statement should be built.
 384  
      * @throws TorqueException if the Criterion-objects can not be processed
 385  
      */
 386  
     private static void processCriterions(
 387  
             final DB db,
 388  
             final DatabaseMap dbMap,
 389  
             final String dbName,
 390  
             final Criteria crit,
 391  
             final Query query,
 392  
             final List params,
 393  
             final QueryCallback qc)
 394  
         throws TorqueException
 395  
     {
 396  102
         UniqueList whereClause = query.getWhereClause();
 397  
 
 398  102
         for (Iterator it = crit.keySet().iterator(); it.hasNext();)
 399  
         {
 400  108
             String key = (String) it.next();
 401  108
             Criteria.Criterion criterion = crit.getCriterion(key);
 402  108
             Criteria.Criterion[] someCriteria =
 403  
                     criterion.getAttachedCriterion();
 404  
 
 405  108
             String table = null;
 406  246
             for (int i = 0; i < someCriteria.length; i++)
 407  
             {
 408  138
                 String tableName = someCriteria[i].getTable();
 409  
 
 410  
                 // add the table to the from clause, if it is not already
 411  
                 // contained there
 412  
                 // it is important that this piece of code is executed AFTER
 413  
                 // the joins are processed
 414  138
                 addTableToFromClause(getFullTableName(tableName, dbName), crit, query);
 415  
 
 416  138
                 table = crit.getTableForAlias(tableName);
 417  138
                 if (table == null)
 418  
                 {
 419  138
                     table = tableName;
 420  
                 }
 421  
 
 422  138
                 boolean ignoreCase =  ((crit.isIgnoreCase() || someCriteria[i].isIgnoreCase())
 423  
                         && (dbMap.getTable(table)
 424  
                                 .getColumn(someCriteria[i].getColumn())
 425  
                                 .getType()
 426  
                                 instanceof String));
 427  
 
 428  138
                 someCriteria[i].setIgnoreCase(ignoreCase);
 429  
             }
 430  
 
 431  108
             criterion.setDB(db);
 432  108
             whereClause.add(qc.process(criterion, params));
 433  54
         }
 434  102
     }
 435  
 
 436  
     /**
 437  
      * adds the OrderBy-Columns from the criteria to the query
 438  
      * @param criteria the criteria from which the OrderBy-Columns are taken
 439  
      * @param query the query to which the OrderBy-Columns should be added
 440  
      * @throws TorqueException if the OrderBy-Columns can not be processed
 441  
      */
 442  
     private static void processOrderBy(
 443  
             final DB db,
 444  
             final DatabaseMap dbMap,
 445  
             final Criteria crit,
 446  
             final Query query)
 447  
             throws TorqueException
 448  
     {
 449  102
         UniqueList orderByClause = query.getOrderByClause();
 450  102
         UniqueList selectClause = query.getSelectClause();
 451  
 
 452  102
         UniqueList orderBy = crit.getOrderByColumns();
 453  
 
 454  102
         if (orderBy != null && orderBy.size() > 0)
 455  
         {
 456  
             // Check for each String/Character column and apply
 457  
             // toUpperCase().
 458  12
             for (int i = 0; i < orderBy.size(); i++)
 459  
             {
 460  6
                 String orderByColumn = (String) orderBy.get(i);
 461  
 
 462  6
                 String strippedColumnName
 463  
                         = removeSQLFunction(orderByColumn);
 464  6
                 int dotPos = strippedColumnName.lastIndexOf('.');
 465  6
                 if (dotPos == -1)
 466  
                 {
 467  
                     // We are not able to look up the table in the
 468  
                     // tableMap, as no table name is given. Simply add
 469  
                     // the orderBy and hope the user knows what he is
 470  
                     // doing.
 471  0
                     orderByClause.add(orderByColumn);
 472  0
                     continue;
 473  
                 }
 474  
 
 475  6
                 String tableName = strippedColumnName.substring(0, dotPos);
 476  6
                 String table = crit.getTableForAlias(tableName);
 477  6
                 if (table == null)
 478  
                 {
 479  0
                     table = tableName;
 480  
                 }
 481  
 
 482  
                 // See if there's a space (between the column list and sort
 483  
                 // order in ORDER BY table.column DESC).
 484  6
                 int spacePos = strippedColumnName.indexOf(' ');
 485  
                 String columnName;
 486  6
                 if (spacePos == -1)
 487  
                 {
 488  6
                     columnName =
 489  
                             strippedColumnName.substring(dotPos + 1);
 490  3
                 }
 491  
                 else
 492  
                 {
 493  0
                     columnName = strippedColumnName.substring(
 494  
                             dotPos + 1,
 495  
                             spacePos);
 496  
                 }
 497  6
                 ColumnMap column = dbMap.getTable(table).getColumn(columnName);
 498  
 
 499  
                 // only ignore case in order by for string columns
 500  
                 // which do not have a function around them
 501  6
                 if (column.getType() instanceof String
 502  
                         && orderByColumn.indexOf('(') == -1)
 503  
                 {
 504  
                     // find space pos relative to orderByColumn
 505  6
                     spacePos = orderByColumn.indexOf(' ');
 506  6
                     if (spacePos == -1)
 507  
                     {
 508  0
                         orderByClause.add(
 509  
                                 db.ignoreCaseInOrderBy(orderByColumn));
 510  
                     }
 511  
                     else
 512  
                     {
 513  6
                         orderByClause.add(
 514  
                                 db.ignoreCaseInOrderBy(
 515  
                                         orderByColumn.substring(0, spacePos))
 516  
                                 + orderByColumn.substring(spacePos));
 517  
                     }
 518  6
                     selectClause.add(
 519  
                             db.ignoreCaseInOrderBy(tableName + '.' + columnName));
 520  3
                 }
 521  
                 else
 522  
                 {
 523  0
                     orderByClause.add(orderByColumn);
 524  
                 }
 525  
             }
 526  
         }
 527  102
     }
 528  
 
 529  
     /**
 530  
      * adds the GroupBy-Columns from the criteria to the query
 531  
      * @param criteria the criteria from which the GroupBy-Columns are taken
 532  
      * @param query the query to which the GroupBy-Columns should be added
 533  
      * @throws TorqueException if the GroupBy-Columns can not be processed
 534  
      */
 535  
     private static void processGroupBy(
 536  
             final Criteria crit,
 537  
             final Query query)
 538  
             throws TorqueException
 539  
     {
 540  102
         UniqueList groupByClause = query.getGroupByClause();
 541  102
         UniqueList groupBy = crit.getGroupByColumns();
 542  
 
 543  
         // need to allow for multiple group bys
 544  102
         if (groupBy != null)
 545  
         {
 546  102
             for (int i = 0; i < groupBy.size(); i++)
 547  
             {
 548  0
                 String columnName = (String) groupBy.get(i);
 549  0
                 String column = (String) crit.getAsColumns().get(columnName);
 550  
 
 551  0
                 if (column == null)
 552  
                 {
 553  0
                     column = columnName;
 554  
                 }
 555  
 
 556  0
                 if (column.indexOf('.') != -1)
 557  
                 {
 558  0
                     groupByClause.add(column);
 559  
                 }
 560  
                 else
 561  
                 {
 562  0
                     throwMalformedColumnNameException("group by",
 563  
                             column);
 564  
                 }
 565  
             }
 566  
         }
 567  102
     }
 568  
 
 569  
     /**
 570  
      * adds the Having-Columns from the criteria to the query
 571  
      * @param criteria the criteria from which the Having-Columns are taken
 572  
      * @param query the query to which the Having-Columns should be added
 573  
      * @throws TorqueException if the Having-Columns can not be processed
 574  
      */
 575  
     private static void processHaving(
 576  
             final Criteria crit,
 577  
             final Query query)
 578  
             throws TorqueException
 579  
     {
 580  102
         Criteria.Criterion having = crit.getHaving();
 581  102
         if (having != null)
 582  
         {
 583  
             //String groupByString = null;
 584  0
             query.setHaving(having.toString());
 585  
         }
 586  102
     }
 587  
 
 588  
     /**
 589  
      * adds a Limit clause to the query if supported by the database
 590  
      * @param criteria the criteria from which the Limit and Offset values
 591  
      *        are taken
 592  
      * @param query the query to which the Limit clause should be added
 593  
      * @throws TorqueException if the Database adapter cannot be obtained
 594  
      */
 595  
     private static void processLimits(
 596  
             final Criteria crit,
 597  
             final Query query)
 598  
             throws TorqueException
 599  
     {
 600  102
         int limit = crit.getLimit();
 601  102
         int offset = crit.getOffset();
 602  
 
 603  102
         if (offset > 0 || limit >= 0)
 604  
         {
 605  36
             DB db = Torque.getDB(crit.getDbName());
 606  36
             db.generateLimits(query, offset, limit);
 607  
         }
 608  102
     }
 609  
 
 610  
     /**
 611  
      * Throws a TorqueException with the malformed column name error
 612  
      * message.  The error message looks like this:<p>
 613  
      *
 614  
      * <code>
 615  
      *     Malformed column name in Criteria [criteriaPhrase]:
 616  
      *     '[columnName]' is not of the form 'table.column'
 617  
      * </code>
 618  
      *
 619  
      * @param criteriaPhrase a String, one of "select", "join", or "order by"
 620  
      * @param columnName a String containing the offending column name
 621  
      * @throws TorqueException Any exceptions caught during processing will be
 622  
      *         rethrown wrapped into a TorqueException.
 623  
      */
 624  
     public static void throwMalformedColumnNameException(
 625  
         final String criteriaPhrase,
 626  
         final String columnName)
 627  
         throws TorqueException
 628  
     {
 629  12
         StringBuffer sb = new StringBuffer()
 630  
                 .append("Malformed column name in Criteria ")
 631  
                 .append(criteriaPhrase)
 632  
                 .append(": '")
 633  
                 .append(StringUtils.isEmpty(columnName) ? "<empty>" : columnName)
 634  
                 .append("' is not of the form 'table.column'");
 635  
 
 636  12
         throw new TorqueException(sb.toString());
 637  
     }
 638  
 
 639  
     /**
 640  
      * Returns the tablename which can be added to a From Clause.
 641  
      * This takes care of any aliases that might be defined.
 642  
      * For example, if an alias "a" for the table AUTHOR is defined
 643  
      * in the Criteria criteria, getTableNameForFromClause("a", criteria)
 644  
      * returns "AUTHOR a".
 645  
      * @param tableName the name of a table
 646  
      *        or the alias for a table
 647  
      * @param criteria a criteria object to resolve a possible alias
 648  
      * @return either the tablename itself if tableOrAliasName is not an alias,
 649  
      *         or a String of the form "tableName tableOrAliasName"
 650  
      *         if tableOrAliasName is an alias for a table name
 651  
      */
 652  
     public static String getTableNameForFromClause(
 653  
             final String tableName,
 654  
             final Criteria criteria)
 655  
     {
 656  162
         String shortTableName = getUnqualifiedTableName(tableName);
 657  
 
 658  
         // Most of the time, the alias would be for the short name...
 659  162
         String aliasName = criteria.getTableForAlias(shortTableName);
 660  162
         if (StringUtils.isEmpty(aliasName))
 661  
         {
 662  
             // But we should also check the FQN...
 663  156
             aliasName = criteria.getTableForAlias(tableName);
 664  
         }
 665  
 
 666  162
         if (StringUtils.isNotEmpty(aliasName))
 667  
         {
 668  
             // If the tables have an alias, add an "<xxx> <yyy> statement"
 669  
             // <xxx> AS <yyy> causes problems on oracle
 670  6
             return new StringBuffer(
 671  
                     tableName.length() + aliasName.length() + 1)
 672  
                     .append(aliasName)
 673  
                     .append(" ")
 674  
                     .append(tableName)
 675  
                     .toString();
 676  
         }
 677  
 
 678  156
         return tableName;
 679  
     }
 680  
 
 681  
     /**
 682  
      * Checks if the Tablename tableName is already contained in a from clause.
 683  
      * If tableName and the tablenames in fromClause are generated by
 684  
      * getTablenameForFromClause(String, Criteria), (which they usually are),
 685  
      * then different aliases for the same table are treated
 686  
      * as different tables: E.g.
 687  
      * fromClauseContainsTableName(fromClause, "table_a a") returns false if
 688  
      * fromClause contains only another alias for table_a ,
 689  
      * e.g. "table_a aa" and the unaliased tablename "table_a".
 690  
      * Special case: If tableName is null, true is returned.
 691  
      * @param fromClause a list containing only elements of type.
 692  
      *        Query.FromElement
 693  
      * @param tableName the tablename to check
 694  
      * @return if the Tablename tableName is already contained in a from clause.
 695  
      *         If tableName is null, true is returned.
 696  
      */
 697  
     public static boolean fromClauseContainsTableName(
 698  
             final UniqueList fromClause,
 699  
             final String tableName)
 700  
     {
 701  162
         if (tableName == null)
 702  
         {
 703  
             // usually this function is called to see if tableName should be
 704  
             // added to the fromClause. As null should not be added,
 705  
             // true is returned.
 706  6
             return true;
 707  
         }
 708  156
         for (Iterator it = fromClause.iterator(); it.hasNext();)
 709  
         {
 710  54
             Query.FromElement fromElement
 711  
                     = (Query.FromElement) it.next();
 712  54
             if (tableName.equals(fromElement.getTableName()))
 713  
             {
 714  48
                 return true;
 715  
             }
 716  3
         }
 717  108
         return false;
 718  
     }
 719  
 
 720  
     /**
 721  
      * adds a table to the from clause of a query, if it is not already
 722  
      * contained there.
 723  
      * @param tableOrAliasName the name of a table
 724  
      *        or the alias for a table
 725  
      * @param criteria a criteria object to resolve a possible alias
 726  
      * @param query the query where the the tablename should be added
 727  
      *        to the from clause
 728  
      * @return the table in the from clause which represents the
 729  
      *         supplied tableOrAliasName
 730  
      */
 731  
     private static String addTableToFromClause(
 732  
             final String tableName,
 733  
             final Criteria criteria,
 734  
             Query query)
 735  
     {
 736  150
         String tableNameForFromClause
 737  
                 = getTableNameForFromClause(tableName, criteria);
 738  
 
 739  150
         UniqueList queryFromClause = query.getFromClause();
 740  
 
 741  
         // it is important that this piece of code is executed AFTER
 742  
         // the joins are processed
 743  150
         if (!fromClauseContainsTableName(
 744  
             queryFromClause,
 745  
             tableNameForFromClause))
 746  
         {
 747  96
             Query.FromElement fromElement
 748  
                     = new Query.FromElement(
 749  
                             tableNameForFromClause, null, class="keyword">null);
 750  96
             queryFromClause.add(fromElement);
 751  
         }
 752  150
         return tableNameForFromClause;
 753  
     }
 754  
 
 755  
     /**
 756  
      * Inner Interface that defines the Callback method for
 757  
      * the Table creation loop.
 758  
      */
 759  
     public interface TableCallback
 760  
     {
 761  
         /**
 762  
          * Callback Method for getTableSet()
 763  
          *
 764  
          * @param tables The current table name
 765  
          * @param key The current criterion key.
 766  
          * @param crit The Criteria used in getTableSet()
 767  
          */
 768  
         void process(Set tables, String key, Criteria crit);
 769  
     }
 770  
 
 771  
     /**
 772  
      * Inner Interface that defines the Callback method for
 773  
      * the buildQuery Criterion evaluation
 774  
      */
 775  
     public interface QueryCallback
 776  
     {
 777  
         /**
 778  
          * The callback for building a query String
 779  
          *
 780  
          * @param criterion The current criterion
 781  
          * @param params The parameter list passed to buildQueryString()
 782  
          * @return WHERE SQL fragment for this criterion
 783  
          */
 784  
         String process(Criterion criterion, List params);
 785  
     }
 786  
 
 787  
 }

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