Coverage report

  %line %branch
org.apache.torque.adapter.DBOracle
66% 
100% 

 1  
 package org.apache.torque.adapter;
 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.sql.Connection;
 23  
 import java.sql.SQLException;
 24  
 import java.sql.Statement;
 25  
 import java.text.SimpleDateFormat;
 26  
 import java.util.Date;
 27  
 import java.util.HashSet;
 28  
 import java.util.ListIterator;
 29  
 import java.util.Set;
 30  
 
 31  
 import org.apache.torque.util.Query;
 32  
 import org.apache.torque.util.UniqueList;
 33  
 
 34  
 /**
 35  
  * This code should be used for an Oracle database pool.
 36  
  *
 37  
  * @author <a href="mailto:jon@clearink.com">Jon S. Stevens</a>
 38  
  * @author <a href="mailto:bmclaugh@algx.net">Brett McLaughlin</a>
 39  
  * @author <a href="mailto:bschneider@vecna.com">Bill Schneider</a>
 40  
  * @author <a href="mailto:dlr@finemaltcoding.com">Daniel Rall</a>
 41  
  * @version $Id: DBOracle.java 476550 2006-11-18 16:08:37Z tfischer $
 42  
  */
 43  
 public class DBOracle extends AbstractDBAdapter
 44  
 {
 45  
     /**
 46  
      * Serial version
 47  
      */
 48  
     private static final long serialVersionUID = 8966976210230241194L;
 49  
 
 50  
     /** date format used in getDateString() */
 51  
     private static final String DATE_FORMAT = "dd-MM-yyyy HH:mm:ss";
 52  
 
 53  
     /**
 54  
      * Empty constructor.
 55  
      */
 56  4
     protected DBOracle()
 57  88
     {
 58  92
     }
 59  
 
 60  
     /**
 61  
      * This method is used to ignore case.
 62  
      *
 63  
      * @param in The string to transform to upper case.
 64  
      * @return The upper case string.
 65  
      */
 66  
     public String toUpperCase(String in)
 67  
     {
 68  0
         return new StringBuffer("UPPER(").append(in).append(")").toString();
 69  
     }
 70  
 
 71  
     /**
 72  
      * This method is used to ignore case.
 73  
      *
 74  
      * @param in The string whose case to ignore.
 75  
      * @return The string in a case that can be ignored.
 76  
      */
 77  
     public String ignoreCase(String in)
 78  
     {
 79  0
         return new StringBuffer("UPPER(").append(in).append(")").toString();
 80  
     }
 81  
 
 82  
     /**
 83  
      * This method is used to format any date string.
 84  
      *
 85  
      * @param date the Date to format
 86  
      * @return The date formatted String for Oracle.
 87  
      */
 88  
     public String getDateString(Date date)
 89  
     {
 90  0
         return "TO_DATE('" + new SimpleDateFormat(DATE_FORMAT).format(date)
 91  
                 + "', 'DD-MM-YYYY HH24:MI:SS')";
 92  
     }
 93  
 
 94  
     /**
 95  
      * @see org.apache.torque.adapter.DB#getIDMethodType()
 96  
      */
 97  
     public String getIDMethodType()
 98  
     {
 99  0
         return SEQUENCE;
 100  
     }
 101  
 
 102  
     /**
 103  
      * Returns the next key from a sequence.  Uses the following
 104  
      * implementation:
 105  
      *
 106  
      * <blockquote><code><pre>
 107  
      * select sequenceName.nextval from dual
 108  
      * </pre></code></blockquote>
 109  
      *
 110  
      * @param sequenceName The name of the sequence (should be of type
 111  
      * <code>String</code>).
 112  
      * @return SQL to retreive the next database key.
 113  
      * @see org.apache.torque.adapter.DB#getIDMethodSQL(Object)
 114  
      */
 115  
     public String getIDMethodSQL(Object sequenceName)
 116  
     {
 117  0
         return ("select " + sequenceName + ".nextval from dual");
 118  
     }
 119  
 
 120  
     /**
 121  
      * Locks the specified table.
 122  
      *
 123  
      * @param con The JDBC connection to use.
 124  
      * @param table The name of the table to lock.
 125  
      * @exception SQLException No Statement could be created or executed.
 126  
      */
 127  
     public void lockTable(Connection con, String table) throws SQLException
 128  
     {
 129  0
         Statement statement = con.createStatement();
 130  
 
 131  0
         StringBuffer stmt = new StringBuffer();
 132  0
         stmt.append("SELECT next_id FROM ")
 133  
                 .append(table)
 134  
                 .append(" FOR UPDATE");
 135  
 
 136  0
         statement.executeQuery(stmt.toString());
 137  0
     }
 138  
 
 139  
     /**
 140  
      * Unlocks the specified table.
 141  
      *
 142  
      * @param con The JDBC connection to use.
 143  
      * @param table The name of the table to unlock.
 144  
      * @exception SQLException No Statement could be created or executed.
 145  
      */
 146  
     public void unlockTable(Connection con, String table) throws SQLException
 147  
     {
 148  
         // Tables in Oracle are unlocked when a commit is issued.  The
 149  
         // user may have issued a commit but do it here to be sure.
 150  0
         con.commit();
 151  0
     }
 152  
 
 153  
     /**
 154  
      * This method is used to check whether the database supports
 155  
      * limiting the size of the resultset.
 156  
      *
 157  
      * @return LIMIT_STYLE_ORACLE.
 158  
      * @deprecated This should not be exposed to the outside
 159  
      */
 160  
     public int getLimitStyle()
 161  
     {
 162  0
         return DB.LIMIT_STYLE_ORACLE;
 163  
     }
 164  
 
 165  
     /**
 166  
      * Return true for Oracle
 167  
      * @see org.apache.torque.adapter.AbstractDBAdapter#supportsNativeLimit()
 168  
      */
 169  
     public boolean supportsNativeLimit()
 170  
     {
 171  0
         return true;
 172  
     }
 173  
 
 174  
     /**
 175  
      * Return true for Oracle
 176  
      * @see org.apache.torque.adapter.AbstractDBAdapter#supportsNativeOffset()
 177  
      */
 178  
     public boolean supportsNativeOffset()
 179  
     {
 180  0
         return true;
 181  
     }
 182  
 
 183  
     /**
 184  
      * Build Oracle-style query with limit or offset.
 185  
      * If the original SQL is in variable: query then the requlting
 186  
      * SQL looks like this:
 187  
      * <pre>
 188  
      * SELECT B.* FROM (
 189  
      *          SELECT A.*, rownum as TORQUE$ROWNUM FROM (
 190  
      *                  query
 191  
      *          ) A
 192  
      *     ) B WHERE B.TORQUE$ROWNUM > offset AND B.TORQUE$ROWNUM
 193  
      *     <= offset + limit
 194  
      * </pre>
 195  
      *
 196  
      * @param query The query to modify
 197  
      * @param offset the offset Value
 198  
      * @param limit the limit Value
 199  
      */
 200  
     public void generateLimits(Query query, int offset, class="keyword">int limit)
 201  
     {
 202  96
         StringBuffer preLimit = new StringBuffer()
 203  4
         .append("SELECT B.* FROM ( ")
 204  4
         .append("SELECT A.*, rownum AS TORQUE$ROWNUM FROM ( ");
 205  
 
 206  96
         StringBuffer postLimit = new StringBuffer()
 207  4
                 .append(" ) A ")
 208  4
                 .append(" ) B WHERE ");
 209  
 
 210  92
         if (offset > 0)
 211  
         {
 212  0
             postLimit.append(" B.TORQUE$ROWNUM > ")
 213  
                     .append(offset);
 214  
 
 215  0
             if (limit >= 0)
 216  
             {
 217  0
                 postLimit.append(" AND B.TORQUE$ROWNUM <= ")
 218  
                         .append(offset + limit);
 219  0
             }
 220  
         }
 221  
         else
 222  
         {
 223  92
             postLimit.append(" B.TORQUE$ROWNUM <= ")
 224  4
                     .append(limit);
 225  
         }
 226  
 
 227  92
         query.setPreLimit(preLimit.toString());
 228  92
         query.setPostLimit(postLimit.toString());
 229  92
         query.setLimit(null);
 230  
 
 231  
         // the query must not contain same column names or aliases.
 232  
         // Find double column names and aliases and create unique aliases
 233  
         // TODO: does not work for functions yet
 234  92
         UniqueList selectColumns = query.getSelectClause();
 235  92
         int replacementSuffix = 0;
 236  92
         Set columnNames = new HashSet();
 237  
         // first pass: only remember aliased columns
 238  
         // No replacements need to take place because double aliases
 239  
         // are not allowed anyway
 240  
         // So alias names will be retained
 241  116
         for (ListIterator columnIt = selectColumns.listIterator();
 242  556
                 columnIt.hasNext();)
 243  
         {
 244  460
             String selectColumn = (String) columnIt.next();
 245  
 
 246  
             // check for sql function
 247  460
             if ((selectColumn.indexOf('(') != -1)
 248  20
                 || (selectColumn.indexOf(')') != -1))
 249  
             {
 250  
                 // Sql function. Disregard.
 251  0
                 continue;
 252  
             }
 253  
 
 254  
             // check if alias name exists
 255  460
             int spacePos = selectColumn.lastIndexOf(' ');
 256  460
             if (spacePos == -1)
 257  
             {
 258  
                 // no alias, disregard for now
 259  184
                 continue;
 260  
             }
 261  
 
 262  276
             String aliasName = selectColumn.substring(spacePos + 1);
 263  276
             columnNames.add(aliasName);
 264  264
         }
 265  
 
 266  
         // second pass. Regard ordinary columns only
 267  116
         for (ListIterator columnIt = selectColumns.listIterator();
 268  556
                 columnIt.hasNext();)
 269  
         {
 270  460
             String selectColumn = (String) columnIt.next();
 271  
 
 272  
             // check for sql function
 273  460
             if ((selectColumn.indexOf('(') != -1)
 274  20
                 || (selectColumn.indexOf(')') != -1))
 275  
             {
 276  
                 // Sql function. Disregard.
 277  0
                 continue;
 278  
             }
 279  
 
 280  
             {
 281  460
                 int spacePos = selectColumn.lastIndexOf(' ');
 282  460
                 if (spacePos != -1)
 283  
                 {
 284  
                     // alias, already processed in first pass
 285  276
                     continue;
 286  
                 }
 287  
             }
 288  
             // split into column name and tableName
 289  
             String column;
 290  
             {
 291  184
                 int dotPos = selectColumn.lastIndexOf('.');
 292  184
                 if (dotPos != -1)
 293  
                 {
 294  92
                     column = selectColumn.substring(dotPos + 1);
 295  88
                 }
 296  
                 else
 297  
                 {
 298  92
                     column = selectColumn;
 299  
                 }
 300  
             }
 301  184
             if (columnNames.contains(column))
 302  
             {
 303  
                 // column needs to be aliased
 304  
                 // get replacement name
 305  
                 String aliasName;
 306  6
                 do
 307  
                 {
 308  138
                     aliasName = "a" + replacementSuffix;
 309  138
                     ++replacementSuffix;
 310  
                 }
 311  138
                 while (columnNames.contains(aliasName));
 312  
 
 313  92
                 selectColumn = selectColumn + " " + aliasName;
 314  92
                 columnIt.set(selectColumn);
 315  92
                 columnNames.add(aliasName);
 316  88
             }
 317  
             else
 318  
             {
 319  92
                 columnNames.add(column);
 320  
             }
 321  176
         }
 322  92
     }
 323  
 
 324  
     /**
 325  
      * This method is for the SqlExpression.quoteAndEscape rules.  The rule is,
 326  
      * any string in a SqlExpression with a BACKSLASH will either be changed to
 327  
      * "\\" or left as "\".  SapDB does not need the escape character.
 328  
      *
 329  
      * @return false.
 330  
      */
 331  
     public boolean escapeText()
 332  
     {
 333  0
         return false;
 334  
     }
 335  
 
 336  
     /**
 337  
      * Whether an escape clause in like should be used.
 338  
      * Example : select * from AUTHOR where AUTHOR.NAME like '\_%' ESCAPE '\';
 339  
      *
 340  
      * Oracle needs this, so this implementation always returns
 341  
      * <code>true</code>.
 342  
      *
 343  
      * @return whether the escape clause should be appended or not.
 344  
      */
 345  
     public boolean useEscapeClauseForLike()
 346  
     {
 347  0
         return true;
 348  
     }
 349  
 }

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