Coverage Report - org.kuali.rice.core.framework.persistence.jdbc.sql.SqlBuilder
 
Classes in this File Line Coverage Branch Coverage Complexity
SqlBuilder
0%
0/179
0%
0/100
3.133
SqlBuilder$JoinType
0%
0/1
N/A
3.133
SqlBuilder$SQLBuilderException
0%
0/2
N/A
3.133
 
 1  
 /**
 2  
  * Copyright 2005-2011 The Kuali Foundation
 3  
  *
 4  
  * Licensed under the Educational Community License, Version 2.0 (the "License");
 5  
  * you may not use this file except in compliance with the License.
 6  
  * You may obtain a copy of the License at
 7  
  *
 8  
  * http://www.opensource.org/licenses/ecl2.php
 9  
  *
 10  
  * Unless required by applicable law or agreed to in writing, software
 11  
  * distributed under the License is distributed on an "AS IS" BASIS,
 12  
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 13  
  * See the License for the specific language governing permissions and
 14  
  * limitations under the License.
 15  
  */
 16  
 package org.kuali.rice.core.framework.persistence.jdbc.sql;
 17  
 
 18  
 import org.apache.commons.lang.StringUtils;
 19  
 import org.kuali.rice.core.api.CoreConstants;
 20  
 import org.kuali.rice.core.api.datetime.DateTimeService;
 21  
 import org.kuali.rice.core.api.exception.RiceRuntimeException;
 22  
 import org.kuali.rice.core.api.resourceloader.GlobalResourceLoader;
 23  
 import org.kuali.rice.core.api.search.SearchOperator;
 24  
 import org.kuali.rice.core.api.util.RiceConstants;
 25  
 import org.kuali.rice.core.api.util.type.TypeUtils;
 26  
 import org.kuali.rice.core.framework.persistence.platform.DatabasePlatform;
 27  
 import org.kuali.rice.core.web.format.BooleanFormatter;
 28  
 
 29  
 import java.math.BigDecimal;
 30  
 import java.sql.Date;
 31  
 import java.sql.Timestamp;
 32  
 import java.text.ParseException;
 33  
 import java.text.SimpleDateFormat;
 34  
 
 35  
 /**
 36  
  * This is a description of what this class does - Garey don't forget to fill this in.
 37  
  *
 38  
  * @author Kuali Rice Team (rice.collab@kuali.org)
 39  
  *
 40  
  */
 41  0
 public class SqlBuilder {
 42  0
         private static final org.apache.log4j.Logger LOG = org.apache.log4j.Logger.getLogger(SqlBuilder.class);
 43  
 
 44  
         private DateTimeService dateTimeService;
 45  
         private DatabasePlatform dbPlatform;
 46  
         
 47  
         public static final  String EMPTY_STRING = "";
 48  
 
 49  0
     public static final class JoinType {
 50  
 
 51  
         }
 52  
 
 53  
         /**
 54  
          * @param clazz
 55  
          * @return true if the given Class is an join type
 56  
          * @throws IllegalArgumentException
 57  
          *             if the given Class is null
 58  
          */
 59  
         public static boolean isJoinClass(Class clazz) {
 60  0
                 return clazz.isAssignableFrom(JoinType.class);
 61  
         }
 62  
 
 63  
         public Criteria createCriteria(String columnName, String searchValue, String tableName, String tableAlias, Class propertyType) {
 64  0
                 return createCriteria(columnName, searchValue, tableName, tableAlias, propertyType, false, true);
 65  
         }
 66  
 
 67  
     public Criteria createCriteria(String columnName, String searchValue, String tableName, String tableAlias, Class propertyType, boolean caseInsensitive) {
 68  0
         return createCriteria(columnName, searchValue, tableName, tableAlias, propertyType, caseInsensitive, true);
 69  
     }
 70  
 
 71  
         public Criteria createCriteria(String columnName, String searchValue, String tableName, String tableAlias, Class propertyType, boolean caseInsensitive, boolean allowWildcards) {
 72  
 
 73  0
                 if (propertyType == null) {
 74  0
                         return null;
 75  
                 }
 76  
 
 77  0
                 Criteria criteria = new Criteria(tableName, tableAlias);
 78  0
                 criteria.setDbPlatform(this.getDbPlatform());
 79  
 
 80  
                 // build criteria
 81  0
                 addCriteria(columnName, searchValue, propertyType, caseInsensitive, allowWildcards, criteria);
 82  0
                 return criteria;
 83  
         }
 84  
 
 85  
         public void andCriteria(String columnName, String searchValue, String tableName, String tableAlias, Class propertyType, boolean caseInsensitive, boolean allowWildcards, Criteria addToThisCriteria) {
 86  0
                 Criteria crit = createCriteria(columnName,searchValue, tableName, tableAlias, propertyType, caseInsensitive, allowWildcards);
 87  
 
 88  0
                 addToThisCriteria.and(crit);
 89  0
         }
 90  
         public void andCriteria(Criteria addToThisCriteria, Criteria newCriteria) {
 91  0
                 addToThisCriteria.and(newCriteria);
 92  0
         }
 93  
         public void orCriteria(String columnName, String searchValue, String tableName, String tableAlias, Class propertyType, boolean caseInsensitive, boolean allowWildcards, Criteria addToThisCriteria) {
 94  0
                 Criteria crit = createCriteria(columnName, searchValue,tableName, tableAlias, propertyType, caseInsensitive, allowWildcards);
 95  
 
 96  0
                 addToThisCriteria.or(crit);
 97  0
         }
 98  
 
 99  
         public void addCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, boolean allowWildcards, Criteria criteria) {
 100  
 
 101  0
                 if(SqlBuilder.isJoinClass(propertyType)){ // treat this as a join table.
 102  0
                         String temp = SQLUtils.cleanString(propertyValue);
 103  0
                         criteria.eq(propertyName, temp, propertyType);
 104  0
                         return;
 105  
                 }
 106  
 
 107  0
                 if (StringUtils.contains(propertyValue, SearchOperator.OR.op())) {
 108  0
                         addOrCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, allowWildcards);
 109  0
                         return;
 110  
                 }
 111  
 
 112  0
                 if ( StringUtils.contains(propertyValue, SearchOperator.AND.op())) {
 113  0
                         addAndCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, allowWildcards);
 114  0
                         return;
 115  
                 }
 116  
 
 117  0
                 if (TypeUtils.isStringClass(propertyType)) {
 118  0
                         if (StringUtils.contains(propertyValue,
 119  
                                         SearchOperator.NOT.op())) {
 120  0
                                 addNotCriteria(propertyName, propertyValue, propertyType,
 121  
                                                 caseInsensitive, criteria, allowWildcards);
 122  0
             } else if (propertyValue != null && (
 123  
                                             StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())
 124  
                                             || propertyValue.startsWith(">")
 125  
                                             || propertyValue.startsWith("<") ) ) {
 126  0
                                 addStringRangeCriteria(propertyName, propertyValue, criteria, propertyType, caseInsensitive, allowWildcards);
 127  
                         } else {
 128  
                                 //if (!allowWildcards) {
 129  
                                 //        propertyValue = StringUtils.replace(propertyValue, "*", "\\*");
 130  
                                 //}
 131  
                                 // KULRICE-85 : made string searches case insensitive - used new
 132  
                                 // DBPlatform function to force strings to upper case
 133  0
                                 if (caseInsensitive) {
 134  
                                         // TODO: What to do here now that the JPA version does not extend platform aware?
 135  0
                                         propertyName = getDbPlatform().getUpperCaseFunction() + "(__JPA_ALIAS__." + propertyName + ")";
 136  
                                         //propertyName = "UPPER("+ tableAlias + "." + propertyName + ")";
 137  0
                                         propertyValue = propertyValue.toUpperCase();
 138  
                                 }
 139  0
                                 criteria.like(propertyName, propertyValue,propertyType, allowWildcards);
 140  
                         }
 141  0
                 } else if (TypeUtils.isIntegralClass(propertyType) || TypeUtils.isDecimalClass(propertyType)) {
 142  0
                         addNumericRangeCriteria(propertyName, propertyValue, criteria, propertyType);
 143  0
                 } else if (TypeUtils.isTemporalClass(propertyType)) {
 144  0
                         addDateRangeCriteria(propertyName, propertyValue, criteria, propertyType);
 145  0
                 } else if (TypeUtils.isBooleanClass(propertyType)) {
 146  0
                         String temp = SQLUtils.cleanString(propertyValue);
 147  0
                         criteria.eq(propertyName, new BooleanFormatter().convertFromPresentationFormat(temp), propertyType);
 148  0
                 } else {
 149  0
                         LOG.error("not adding criterion for: " + propertyName + "," + propertyType + "," + propertyValue);
 150  
                 }
 151  0
         }
 152  
 
 153  
         private void addOrCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria, boolean allowWildcards) {
 154  0
                 addLogicalOperatorCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, SearchOperator.OR.op(), allowWildcards);
 155  0
         }
 156  
 
 157  
         private void addAndCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria, boolean allowWildcards) {
 158  0
                 addLogicalOperatorCriteria(propertyName, propertyValue, propertyType, caseInsensitive, criteria, SearchOperator.AND.op(), allowWildcards);
 159  0
         }
 160  
 
 161  
         private void addNotCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria, boolean allowWildcards) {
 162  0
                 String[] splitPropVal = StringUtils.split(propertyValue, SearchOperator.NOT.op());
 163  
 
 164  0
                 int strLength = splitPropVal.length;
 165  
                 // if more than one NOT operator assume an implicit and (i.e. !a!b = !a&!b)
 166  0
                 if (strLength > 1) {
 167  0
                         String expandedNot = SearchOperator.NOT + StringUtils.join(splitPropVal, SearchOperator.AND.op() + SearchOperator.NOT.op());
 168  
                         // we know that since this method is called, treatWildcardsAndOperatorsAsLiteral is false
 169  0
                         addCriteria(propertyName, expandedNot, propertyType, caseInsensitive, allowWildcards, criteria);
 170  0
                 } else {
 171  
                         // only one so add a not like
 172  0
                         criteria.notLike(propertyName, splitPropVal[0], propertyType, allowWildcards);
 173  
                 }
 174  0
         }
 175  
 
 176  
         private void addLogicalOperatorCriteria(String propertyName, String propertyValue, Class propertyType, boolean caseInsensitive, Criteria criteria, String splitValue, boolean allowWildcards) {
 177  0
                 String[] splitPropVal = StringUtils.split(propertyValue, splitValue);
 178  
 
 179  0
                 Criteria subCriteria = new Criteria("N/A");
 180  0
                 for (String element : splitPropVal) {
 181  0
                         Criteria predicate = new Criteria("N/A", criteria.getAlias());
 182  
                         // we know that since this method is called, treatWildcardsAndOperatorsAsLiteral is false
 183  0
                         addCriteria(propertyName, element, propertyType, caseInsensitive, allowWildcards, predicate);
 184  0
                         if (splitValue == SearchOperator.OR.op()) {
 185  0
                                 subCriteria.or(predicate);
 186  
                         }
 187  0
                         if (splitValue == SearchOperator.AND.op()) {
 188  0
                                 subCriteria.and(predicate);
 189  
                         }
 190  
                 }
 191  
 
 192  0
                 criteria.and(subCriteria);
 193  0
         }
 194  
 
 195  
         private Timestamp parseDate(String dateString) {
 196  0
                 dateString = dateString.trim();
 197  
                 try {
 198  0
                         Timestamp dt =  this.getDateTimeService().convertToSqlTimestamp(dateString);
 199  0
                         return dt;
 200  0
                 } catch (ParseException ex) {
 201  0
                         return null;
 202  
                 }
 203  
         }
 204  
         public boolean isValidDate(String dateString){
 205  
                 //FIXME: wtf - weird!
 206  
                 try {
 207  0
                         this.createCriteria("date", dateString.trim(), "validation", "test", Date.class);
 208  0
                         return true;
 209  0
                 } catch (Exception ex) {
 210  0
                         return false;
 211  
                 }
 212  
         }
 213  
 
 214  
         public static boolean containsRangeCharacters(String string){
 215  0
                 boolean bRet = false;
 216  0
                 for (SearchOperator op : SearchOperator.RANGE_CHARACTERS) {
 217  0
             if(StringUtils.contains(string, op.op())){
 218  0
                     bRet = true;
 219  
             }
 220  
         }
 221  0
                 return bRet;
 222  
         }
 223  
 
 224  
         private void addDateRangeCriteria(String propertyName, String propertyValue, Criteria criteria, Class propertyType) {
 225  
 
 226  0
                 if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) {
 227  0
                         String[] rangeValues = propertyValue.split("\\.\\."); // this translate to the .. operator
 228  0
                         criteria.between(propertyName, parseDate(SQLUtils.cleanDate(rangeValues[0])), parseDate(cleanUpperBound(SQLUtils.cleanDate(rangeValues[1]))), propertyType);
 229  0
                 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
 230  0
                         criteria.gte(propertyName, parseDate(SQLUtils.cleanDate(propertyValue)), propertyType);
 231  0
                 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
 232  0
                         criteria.lte(propertyName, parseDate(cleanUpperBound(SQLUtils.cleanDate(propertyValue))),propertyType);
 233  0
                 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN.op())) {
 234  
                         // we clean the upper bound here because if you say >12/22/09, it translates greater than
 235  
                         // the date... as in whole date. ie. the next day on.
 236  0
                         criteria.gt(propertyName, parseDate(cleanUpperBound(SQLUtils.cleanDate(propertyValue))), propertyType);
 237  0
                 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN.op())) {
 238  0
                         criteria.lt(propertyName, parseDate(SQLUtils.cleanDate(propertyValue)), propertyType);
 239  
                 } else {
 240  0
                         String sDate = convertSimpleDateToDateRange(SQLUtils.cleanDate(propertyValue));
 241  0
                         if(sDate.contains(SearchOperator.BETWEEN.op())){
 242  0
                                 addDateRangeCriteria(propertyName, sDate, criteria, propertyType);
 243  
                         }else{
 244  0
                                 criteria.eq(propertyName, parseDate(sDate), propertyType);
 245  
                         }
 246  
                 }
 247  0
         }
 248  
 
 249  
         public static boolean isValidNumber(String value){
 250  
                 try{
 251  0
                 stringToBigDecimal(value);
 252  0
                         return true;
 253  0
                 }catch(Exception ex){
 254  0
                         return false;
 255  
                 }
 256  
         }
 257  
 
 258  
         public static String cleanNumeric(String value){
 259  0
                 String cleanedValue = value.replaceAll("[^-0-9.]", "");
 260  
                 // ensure only one "minus" at the beginning, if any
 261  0
                 if (cleanedValue.lastIndexOf('-') > 0) {
 262  0
                         if (cleanedValue.charAt(0) == '-') {
 263  0
                                 cleanedValue = "-" + cleanedValue.replaceAll("-", "");
 264  
                         } else {
 265  0
                                 cleanedValue = cleanedValue.replaceAll("-", "");
 266  
                         }
 267  
                 }
 268  
                 // ensure only one decimal in the string
 269  0
                 int decimalLoc = cleanedValue.lastIndexOf('.');
 270  0
                 if (cleanedValue.indexOf('.') != decimalLoc) {
 271  0
                         cleanedValue = cleanedValue.substring(0, decimalLoc).replaceAll("\\.", "") + cleanedValue.substring(decimalLoc);
 272  
                 }
 273  0
                 return cleanedValue;
 274  
         }
 275  
 
 276  
         public static BigDecimal stringToBigDecimal(String value) {
 277  
 
 278  
                 //try {
 279  0
                         return new BigDecimal(cleanNumeric(value));
 280  
                 /*
 281  
                 } catch (NumberFormatException ex) {
 282  
                         GlobalVariables.getMessageMap().putError(KRADConstants.DOCUMENT_ERRORS, RiceKeyConstants.ERROR_CUSTOM, new String[] { "Invalid Numeric Input: " + value });
 283  
                         return null;
 284  
                 }*/
 285  
         }
 286  
 
 287  
         private void addNumericRangeCriteria(String propertyName, String propertyValue, Criteria criteria, Class propertyType) {
 288  
 
 289  0
                 if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) {
 290  0
                         String[] rangeValues = propertyValue.split("\\.\\."); // this translate to the .. operator
 291  0
                         criteria.between(propertyName, stringToBigDecimal(rangeValues[0]), stringToBigDecimal(rangeValues[1]), propertyType);
 292  0
                 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
 293  0
                         criteria.gte(propertyName, stringToBigDecimal(propertyValue), propertyType);
 294  0
                 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
 295  0
                         criteria.lte(propertyName, stringToBigDecimal(propertyValue), propertyType);
 296  0
                 } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN.op())) {
 297  0
                         criteria.gt(propertyName, stringToBigDecimal(propertyValue), propertyType);
 298  0
                 } else if (propertyValue.startsWith(SearchOperator.LESS_THAN.op())) {
 299  0
                         criteria.lt(propertyName, stringToBigDecimal(propertyValue), propertyType);
 300  
                 } else {
 301  0
                         criteria.eq(propertyName, stringToBigDecimal(propertyValue), propertyType);
 302  
                 }
 303  0
         }
 304  
 
 305  
         private void addStringRangeCriteria(String propertyName, String propertyValue, Criteria criteria, Class propertyType, boolean caseInsensitive, boolean allowWildcards) {
 306  
 
 307  0
                 if (StringUtils.contains(propertyValue, SearchOperator.BETWEEN.op())) {
 308  0
                         String[] rangeValues = propertyValue.split("\\.\\."); // this translate to the .. operator
 309  0
                         propertyName = this.getCaseAndLiteralPropertyName(propertyName, caseInsensitive);
 310  0
                         String val1 = this.getCaseAndLiteralPropertyValue(rangeValues[0], caseInsensitive, allowWildcards);
 311  0
                         String val2 = this.getCaseAndLiteralPropertyValue(rangeValues[1], caseInsensitive, allowWildcards);
 312  0
                         criteria.between(propertyName, val1, val2, propertyType);
 313  0
                 } else{
 314  0
                         propertyName = this.getCaseAndLiteralPropertyName(propertyName, caseInsensitive);
 315  0
                         String value = this.getCaseAndLiteralPropertyValue(SQLUtils.cleanString(propertyValue), caseInsensitive, allowWildcards);
 316  
 
 317  0
                         if (propertyValue.startsWith(SearchOperator.GREATER_THAN_EQUAL.op())) {
 318  0
                                 criteria.gte(propertyName, value, propertyType);
 319  0
                         } else if (propertyValue.startsWith(SearchOperator.LESS_THAN_EQUAL.op())) {
 320  0
                                 criteria.lte(propertyName, value, propertyType);
 321  0
                         } else if (propertyValue.startsWith(SearchOperator.GREATER_THAN.op())) {
 322  0
                                 criteria.gt(propertyName, value, propertyType);
 323  0
                         } else if (propertyValue.startsWith(SearchOperator.LESS_THAN.op())) {
 324  0
                                 criteria.lt(propertyName, value, propertyType);
 325  
                         }
 326  
                 }
 327  0
         }
 328  
 
 329  
         private String getCaseAndLiteralPropertyName(String propertyName, boolean caseInsensitive){
 330  
                 // KULRICE-85 : made string searches case insensitive - used new
 331  
                 // DBPlatform function to force strings to upper case
 332  0
                 if (caseInsensitive) {
 333  
                         // TODO: What to do here now that the JPA version does not extend platform aware?
 334  0
                         propertyName = getDbPlatform().getUpperCaseFunction() + "(__JPA_ALIAS__." + propertyName + ")";
 335  
 
 336  
                 }
 337  0
                 return propertyName;
 338  
         }
 339  
         private String getCaseAndLiteralPropertyValue(String propertyValue, boolean caseInsensitive, boolean allowWildcards){
 340  
                 //if (!allowWildcards) {
 341  
                 //        propertyValue = StringUtils.replace(propertyValue, "*", "\\*");
 342  
                 //}
 343  
                 // KULRICE-85 : made string searches case insensitive - used new
 344  
                 // DBPlatform function to force strings to upper case
 345  0
                 if (caseInsensitive) {
 346  
                         //propertyName = "UPPER("+ tableAlias + "." + propertyName + ")";
 347  0
                         propertyValue = propertyValue.toUpperCase();
 348  
                 }
 349  0
                 return propertyValue;
 350  
         }
 351  
 
 352  
 
 353  
         protected DateTimeService getDateTimeService(){
 354  0
                 if (dateTimeService == null) {
 355  0
                         dateTimeService = GlobalResourceLoader.getService(CoreConstants.Services.DATETIME_SERVICE);
 356  
             }
 357  0
             return dateTimeService;
 358  
         }
 359  
 
 360  
         /**
 361  
          * @param dateTimeService
 362  
          *            the dateTimeService to set
 363  
          */
 364  
         public void setDateTimeService(DateTimeService dateTimeService) {
 365  0
                 this.dateTimeService = dateTimeService;
 366  0
         }
 367  
 
 368  
         public DatabasePlatform getDbPlatform() {
 369  0
             if (dbPlatform == null) {
 370  0
                     dbPlatform = (DatabasePlatform) GlobalResourceLoader.getService(RiceConstants.DB_PLATFORM);
 371  
             }
 372  0
             return dbPlatform;
 373  
     }
 374  
 
 375  
         public void setDbPlatform(DatabasePlatform dbPlatform){
 376  0
                 this.dbPlatform = dbPlatform;
 377  0
         }
 378  
 
 379  
          /**
 380  
      * When dealing with upperbound dates, it is a business requirement that if a timestamp isn't already
 381  
      * stated append 23:59:59 to the end of the date.  This ensures that you are searching for the entire
 382  
      * day.
 383  
      */
 384  
     private String cleanUpperBound(String stringDate){
 385  
             final java.sql.Timestamp dt;
 386  
             try {
 387  0
                         dt = getDateTimeService().convertToSqlTimestamp(stringDate);
 388  0
                 } catch (ParseException e) {
 389  0
                         throw new SQLBuilderException(e);
 390  0
                 }
 391  0
                 SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
 392  
 
 393  0
                 if("00:00:00".equals(sdfTime.format(dt)) && !StringUtils.contains(stringDate, "00:00:00") && !StringUtils.contains(stringDate, "12:00 AM")){
 394  0
                         stringDate = stringDate + " 23:59:59";
 395  
                 }
 396  0
                 return stringDate;
 397  
     }
 398  
 
 399  
     /**
 400  
     *
 401  
     * This method will take a whole date like 03/02/2009 and convert it into
 402  
     * 03/02/2009 .. 03/02/20009 00:00:00
 403  
     *
 404  
     * This is used for non-range searchable attributes
 405  
     *
 406  
     * @param stringDate
 407  
     * @return
 408  
     */
 409  
    private String convertSimpleDateToDateRange(String stringDate){
 410  
            final java.sql.Timestamp dt;
 411  
            try {
 412  0
                            dt = getDateTimeService().convertToSqlTimestamp(stringDate);
 413  0
            } catch (ParseException e) {
 414  0
                    throw new SQLBuilderException(e);
 415  0
            }
 416  0
            SimpleDateFormat sdfTime = new SimpleDateFormat("HH:mm:ss");
 417  
 
 418  0
            if("00:00:00".equals(sdfTime.format(dt)) && !StringUtils.contains(stringDate, "00:00:00") && !StringUtils.contains(stringDate, "12:00 AM")){
 419  0
                    stringDate = stringDate + " .. " + stringDate + " 23:59:59";
 420  
            }
 421  
 
 422  0
                 return stringDate;
 423  
    }
 424  
 
 425  0
         public static final class SQLBuilderException extends RiceRuntimeException {
 426  
                 public SQLBuilderException(Throwable t) {
 427  0
                         super(t);
 428  0
                 }
 429  
         }
 430  
 }