|                                                                                                              1
 21
 22  package org.apache.derby.iapi.types;
 23
 24  import org.apache.derby.iapi.types.SQLInteger;
 25
 26  import org.apache.derby.iapi.reference.SQLState;
 27
 28  import org.apache.derby.iapi.services.io.ArrayInputStream;
 29
 30  import org.apache.derby.iapi.error.StandardException;
 31
 32  import org.apache.derby.iapi.db.DatabaseContext;
 33  import org.apache.derby.iapi.types.DataValueDescriptor;
 34  import org.apache.derby.iapi.types.TypeId;
 35
 36  import org.apache.derby.iapi.types.NumberDataValue;
 37  import org.apache.derby.iapi.types.DateTimeDataValue;
 38
 39  import org.apache.derby.iapi.services.context.ContextService;
 40
 41  import org.apache.derby.iapi.services.io.StoredFormatIds;
 42
 43  import org.apache.derby.iapi.services.sanity.SanityManager;
 44
 45  import org.apache.derby.iapi.types.DataType;
 46
 47  import org.apache.derby.iapi.services.cache.ClassSize;
 48  import org.apache.derby.iapi.services.i18n.LocaleFinder;
 49  import org.apache.derby.iapi.util.StringUtil;
 50
 51  import java.sql.Date
  ; 52  import java.sql.Time
  ; 53  import java.sql.Timestamp
  ; 54  import java.sql.Types
  ; 55  import java.sql.PreparedStatement
  ; 56
 57  import java.util.Calendar
  ; 58  import java.util.GregorianCalendar
  ; 59
 60  import java.io.ObjectOutput
  ; 61  import java.io.ObjectInput
  ; 62  import java.io.IOException
  ; 63
 64  import java.sql.ResultSet
  ; 65  import java.sql.SQLException
  ; 66
 67  import java.text.DateFormat
  ; 68  import java.text.ParseException
  ; 69
 70
 82
 83  public final class SQLDate extends DataType
 84                          implements DateTimeDataValue
 85  {
 86
 87      private int encodedDate;
 89          private String
  valueString; 91
 92      private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( SQLDate.class);
 93
 94      public int estimateMemoryUsage()
 95      {
 96          return BASE_MEMORY_USAGE + ClassSize.estimateMemoryUsage( valueString);
 97      }
 99      int getEncodedDate()
 100     {
 101         return encodedDate;
 102     }
 103
 104
 108
 109     public String
  getString() 110     {
 111                 if (!isNull())
 113         {
 114             if (valueString == null)
 115             {
 116                 valueString = encodedDateToString(encodedDate);
 117             }
 118             return valueString;
 119         }
 120         else
 121         {
 122             if (SanityManager.DEBUG)
 123             {
 124                 if (valueString != null)
 125                 {
 126                     SanityManager.THROWASSERT(
 127                         "valueString expected to be null, not " +
 128                         valueString);
 129                 }
 130             }
 131             return null;
 132         }
 133     }
 134
 135
 139     public Timestamp
  getTimestamp( Calendar  cal) 140     {
 141         if (isNull())
 142         {
 143             return null;
 144         }
 145         else
 146                         return newTimestamp(cal);
 148     }
 149
 150     private long getTimeInMillis( Calendar
  cal) 151     {
 152         if( cal == null)
 153             cal = new GregorianCalendar
  (); 154         cal.clear();
 155         cal.set( getYear( encodedDate), getMonth( encodedDate)-1, getDay( encodedDate));
 156         return cal.getTime().getTime();
 157     }
 158
 159     private Timestamp
  newTimestamp(java.util.Calendar  cal) 160     {
 161         return new Timestamp
  (getTimeInMillis( cal)); 162     }
 163
 164
 168     public Object
  getObject() 169     {
 170         return getDate( (Calendar
  ) null); 171     }
 172
 173     public int getLength()
 174     {
 175         return 4;
 176     }
 177
 178
 179     public String
  getTypeName() 180     {
 181         return "DATE";
 182     }
 183
 184
 187
 188
 193     public int getTypeFormatId() {
 194         return StoredFormatIds.SQL_DATE_ID;
 195     }
 196
 197
 201     public void writeExternal(ObjectOutput
  out) throws IOException  { 202
 203         if (SanityManager.DEBUG)
 204             SanityManager.ASSERT(!isNull(), "writeExternal() is not supposed to be called for null values.");
 205
 206         out.writeInt(encodedDate);
 207     }
 208
 209
 214     public void readExternal(ObjectInput
  in) throws IOException  215     {
 216         encodedDate = in.readInt();
 217
 218                 valueString = null;
 220     }
 221     public void readExternalFromArray(ArrayInputStream in) throws IOException
  222     {
 223         encodedDate = in.readInt();
 224
 225                 valueString = null;
 227     }
 228
 229
 232
 233
 234     public DataValueDescriptor getClone()
 235     {
 236                 return new SQLDate(encodedDate);
 238     }
 239
 240
 243     public DataValueDescriptor getNewNull()
 244     {
 245         return new SQLDate();
 246     }
 247
 251
 252     public void restoreToNull()
 253     {
 254                 encodedDate = 0;
 256
 257                 valueString = null;
 259     }
 260
 261
 264
 265
 270     public void setValueFromResultSet(ResultSet
  resultSet, int colNumber, 271                                       boolean isNullable)
 272         throws SQLException
  , StandardException 273     {
 274         setValue(resultSet.getDate(colNumber), (Calendar
  ) null); 275     }
 276
 277
 285     public int compare(DataValueDescriptor other)
 286         throws StandardException
 287     {
 288
 291         if (typePrecedence() < other.typePrecedence())
 292         {
 293             return - (other.compare(this));
 294         }
 295
 296
 297         boolean thisNull, otherNull;
 298
 299         thisNull = this.isNull();
 300         otherNull = other.isNull();
 301
 302
 308         if (thisNull || otherNull)
 309         {
 310             if (!thisNull)                      return -1;
 312             if (!otherNull)                     return 1;
 314             return 0;
 315         }
 316
 317
 320
 321         int comparison;
 322
 323         int otherVal = 0;
 324
 325
 328         if (other instanceof SQLDate)
 329         {
 330             otherVal = ((SQLDate)other).encodedDate;
 331         }
 332         else
 333         {
 334
 337             otherVal = SQLDate.computeEncodedDate(other.getDate(new GregorianCalendar
  ())); 338         }
 339         if (encodedDate > otherVal)
 340             comparison = 1;
 341         else if (encodedDate < otherVal)
 342             comparison = -1;
 343         else
 344             comparison = 0;
 345
 346         return comparison;
 347     }
 348
 349
 352     public boolean compare(int op,
 353                            DataValueDescriptor other,
 354                            boolean orderedNulls,
 355                            boolean unknownRV)
 356         throws StandardException
 357     {
 358         if (!orderedNulls)              {
 360             if (this.isNull() || other.isNull())
 361                 return unknownRV;
 362         }
 363
 364
 365         return super.compare(op, other, orderedNulls, unknownRV);
 366     }
 367
 368
 371
 372
 375
 376
 377     public SQLDate() {
 378     }
 379
 380     public SQLDate(Date
  value) throws StandardException 381     {
 382         parseDate(value);
 383     }
 384
 385     private void parseDate( java.util.Date
  value) throws StandardException 386     {
 387         encodedDate = computeEncodedDate(value);
 388     }
 389
 390     private SQLDate(int encodedDate) {
 391         this.encodedDate = encodedDate;
 392     }
 393
 394
 409     public SQLDate( String
  dateStr, boolean isJdbcEscape, LocaleFinder localeFinder) 410         throws StandardException
 411     {
 412         parseDate( dateStr, isJdbcEscape, localeFinder, (Calendar
  ) null); 413     }
 414
 415
 430     public SQLDate( String
  dateStr, boolean isJdbcEscape, LocaleFinder localeFinder, Calendar  cal) 431         throws StandardException
 432     {
 433         parseDate( dateStr, isJdbcEscape, localeFinder, cal);
 434     }
 435
 436     static final char ISO_SEPARATOR = '-';
 437     private static final char[] ISO_SEPARATOR_ONLY = {ISO_SEPARATOR};
 438     private static final char IBM_USA_SEPARATOR = '/';
 439     private static final char[] IBM_USA_SEPARATOR_ONLY = {IBM_USA_SEPARATOR};
 440     private static final char IBM_EUR_SEPARATOR = '.';
 441     private static final char[] IBM_EUR_SEPARATOR_ONLY = {IBM_EUR_SEPARATOR};
 442     private static final char[] END_OF_STRING = {(char) 0};
 443
 444     private void parseDate( String
  dateStr, boolean isJdbcEscape, LocaleFinder localeFinder, Calendar  cal) 445         throws StandardException
 446     {
 447         boolean validSyntax = true;
 448         DateTimeParser parser = new DateTimeParser( dateStr);
 449         int year = 0;
 450         int month = 0;
 451         int day = 0;
 452         StandardException thrownSE = null;
 453
 454         try
 455         {
 456             switch( parser.nextSeparator())
 457             {
 458             case ISO_SEPARATOR:
 459                 encodedDate = SQLTimestamp.parseDateOrTimestamp( parser, false)[0];
 460                 valueString = parser.getTrimmedString();
 461                 return;
 462
 463             case IBM_USA_SEPARATOR:
 464                 if( isJdbcEscape)
 465                 {
 466                     validSyntax = false;
 467                     break;
 468                 }
 469                 month = parser.parseInt( 2, true, IBM_USA_SEPARATOR_ONLY, false);
 470                 day = parser.parseInt( 2, true, IBM_USA_SEPARATOR_ONLY, false);
 471                 year = parser.parseInt( 4, false, END_OF_STRING, false);
 472                 break;
 473
 474             case IBM_EUR_SEPARATOR:
 475                 if( isJdbcEscape)
 476                 {
 477                     validSyntax = false;
 478                     break;
 479                 }
 480                 day = parser.parseInt( 2, true, IBM_EUR_SEPARATOR_ONLY, false);
 481                 month = parser.parseInt( 2, true, IBM_EUR_SEPARATOR_ONLY, false);
 482                 year = parser.parseInt( 4, false, END_OF_STRING, false);
 483                 break;
 484
 485             default:
 486                 validSyntax = false;
 487             }
 488         }
 489         catch( StandardException se)
 490         {
 491             validSyntax = false;
 492             thrownSE = se;
 493         }
 494         if( validSyntax)
 495         {
 496             valueString = parser.checkEnd();
 497             encodedDate = computeEncodedDate( year, month, day);
 498         }
 499         else
 500         {
 501                         dateStr = StringUtil.trimTrailing( dateStr);
 503             DateFormat
  dateFormat = null; 504             if( localeFinder == null)
 505                 dateFormat = DateFormat.getDateInstance();
 506             else if( cal == null)
 507                 dateFormat = localeFinder.getDateFormat();
 508             else
 509                 dateFormat = (DateFormat
  ) localeFinder.getDateFormat().clone(); 510             if( cal != null)
 511                 dateFormat.setCalendar( cal);
 512             try
 513             {
 514                 encodedDate = computeEncodedDate( dateFormat.parse( dateStr), cal);
 515             }
 516             catch( ParseException
  pe) 517             {
 518                                 try
 520                 {
 521                     encodedDate = SQLTimestamp.parseLocalTimestamp( dateStr, localeFinder, cal)[0];
 522                 }
 523                 catch( ParseException
  pe2) 524                 {
 525                     if( thrownSE != null)
 526                         throw thrownSE;
 527                     throw StandardException.newException( SQLState.LANG_DATE_SYNTAX_EXCEPTION);
 528                 }
 529             }
 530             valueString = dateStr;
 531         }
 532     }
 534
 538     void setObject(Object
  theValue) throws StandardException 539     {
 540         setValue((Date
  ) theValue); 541     }
 542
 543     protected void setFrom(DataValueDescriptor theValue) throws StandardException {
 544
 545                 if (theValue instanceof SQLDate) {
 547             restoreToNull();
 548             encodedDate = ((SQLDate) theValue).encodedDate;
 549         }
 550         else
 551         {
 552             Calendar
  cal = new GregorianCalendar  (); 553             setValue(theValue.getDate( cal), cal);
 554         }
 555     }
 556
 557
 561     public void setValue(Date
  value, Calendar  cal) throws StandardException 562     {
 563         restoreToNull();
 564         encodedDate = computeEncodedDate((java.util.Date
  ) value, cal); 565     }
 566
 567
 571     public void setValue(Timestamp
  value, Calendar  cal) throws StandardException 572     {
 573         restoreToNull();
 574         encodedDate = computeEncodedDate((java.util.Date
  ) value, cal); 575     }
 576
 577
 578     public void setValue(String
  theValue) 579         throws StandardException
 580     {
 581         restoreToNull();
 582
 583         if (theValue != null)
 584         {
 585             DatabaseContext databaseContext = (DatabaseContext) ContextService.getContext(DatabaseContext.CONTEXT_ID);
 586             parseDate( theValue,
 587                        false,
 588                        (databaseContext == null) ? null : databaseContext.getDatabase(),
 589                        (Calendar
  ) null); 590         }
 591     }
 592
 593
 596
 597
 602     public NumberDataValue getYear(NumberDataValue result)
 603                             throws StandardException
 604     {
 605         if (SanityManager.DEBUG)
 606         {
 607             SanityManager.ASSERT(!isNull(), "getYear called on a null");
 608         }
 609         return SQLDate.setSource(getYear(encodedDate), result);
 610     }
 611
 612
 617     public NumberDataValue getMonth(NumberDataValue result)
 618                             throws StandardException
 619     {
 620         if (SanityManager.DEBUG)
 621         {
 622             SanityManager.ASSERT(!isNull(), "getMonth called on a null");
 623         }
 624         return SQLDate.setSource(getMonth(encodedDate), result);
 625     }
 626
 627
 632     public NumberDataValue getDate(NumberDataValue result)
 633                             throws StandardException
 634     {
 635         if (SanityManager.DEBUG)
 636         {
 637             SanityManager.ASSERT(!isNull(), "getDate called on a null");
 638         }
 639         return SQLDate.setSource(getDay(encodedDate), result);
 640     }
 641
 642
 647     public NumberDataValue getHours(NumberDataValue result)
 648                             throws StandardException
 649     {
 650         if (SanityManager.DEBUG)
 651         {
 652             SanityManager.ASSERT(!isNull(), "getHours called on null.");
 653         }
 654         throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
 655                         "getHours", "Date");
 656     }
 657
 658
 663     public NumberDataValue getMinutes(NumberDataValue result)
 664                             throws StandardException
 665     {
 666         if (SanityManager.DEBUG)
 667         {
 668             SanityManager.ASSERT(!isNull(), "getMinutes called on null.");
 669         }
 670         throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
 671                         "getMinutes", "Date");
 672     }
 673
 674
 679     public NumberDataValue getSeconds(NumberDataValue result)
 680                             throws StandardException
 681     {
 682         if (SanityManager.DEBUG)
 683         {
 684             SanityManager.ASSERT(!isNull(), "getSeconds called on null.");
 685         }
 686         throw StandardException.newException(SQLState.LANG_UNARY_FUNCTION_BAD_TYPE,
 687                         "getSeconds", "Date");
 688     }
 689
 690
 693
 694     public String
  toString() 695     {
 696         if (isNull())
 697         {
 698             return "NULL";
 699         }
 700         else
 701         {
 702             return getDate( (Calendar
  ) null).toString(); 703         }
 704     }
 705
 706
 709     public int hashCode()
 710     {
 711         return encodedDate;
 712     }
 713
 714
 715     public int  typePrecedence()
 716     {
 717         return TypeId.DATE_PRECEDENCE;
 718     }
 719
 720
 726     public final boolean isNull()
 727     {
 728         return (encodedDate == 0);
 729     }
 730
 731
 737     public Date
  getDate( Calendar  cal) 738     {
 739         if (encodedDate != 0)
 740             return new Date
  ( getTimeInMillis( cal)); 741
 742         return null;
 743     }
 744
 745
 751     static int getYear(int encodedDate)
 752     {
 753         return (encodedDate >>> 16);
 754     }
 755
 756
 762     static int getMonth(int encodedDate)
 763     {
 764         return ((encodedDate >>> 8) & 0x00ff);
 765     }
 766
 767
 773     static int getDay(int encodedDate)
 774     {
 775         return (encodedDate & 0x00ff);
 776     }
 777
 788     static int computeEncodedDate(Calendar
  cal) throws StandardException 789     {
 790         return computeEncodedDate(cal.get(Calendar.YEAR),
 791                                   cal.get(Calendar.MONTH) + 1,
 792                                   cal.get(Calendar.DATE));
 793     }
 794
 795     static int computeEncodedDate( int y, int m, int d) throws StandardException
 796     {
 797         int maxDay = 31;
 798         switch( m)
 799         {
 800         case 4:
 801         case 6:
 802         case 9:
 803         case 11:
 804             maxDay = 30;
 805             break;
 806
 807         case 2:
 808                         maxDay = ((y % 4) == 0 && ((y % 100) != 0 || (y % 400) == 0)) ? 29 : 28;
 810             break;
 811         }
 812         if( y < 1 || y > 9999
 813             || m < 1 || m > 12
 814             || d < 1 || d > maxDay)
 815             throw StandardException.newException( SQLState.LANG_DATE_RANGE_EXCEPTION);
 816         return (y << 16) + (m << 8) + d;
 817     }
 818
 819
 827     static void dateToString( int year, int month, int day, StringBuffer
  sb) 828     {
 829         String
  yearStr = Integer.toString( year); 830         for( int i = yearStr.length(); i < 4; i++)
 831             sb.append( '0');
 832         sb.append(yearStr);
 833         sb.append(ISO_SEPARATOR);
 834
 835         String
  monthStr = Integer.toString( month); 836         String
  dayStr = Integer.toString( day); 837         if (monthStr.length() == 1)
 838             sb.append('0');
 839         sb.append(monthStr);
 840         sb.append(ISO_SEPARATOR);
 841         if (dayStr.length() == 1)
 842             sb.append('0');
 843         sb.append(dayStr);
 844     }
 846
 851     static String
  encodedDateToString(int encodedDate) 852     {
 853         StringBuffer
  vstr = new StringBuffer  (); 854         dateToString( getYear(encodedDate), getMonth(encodedDate), getDay(encodedDate), vstr);
 855         return vstr.toString();
 856     }
 857
 858
 860
 866     protected String
  getNationalString(LocaleFinder localeFinder) throws StandardException 867     {
 868         if (isNull())
 869         {
 870             return getString();
 871         }
 872
 873         return localeFinder.getDateFormat().format(getDate(new GregorianCalendar
  ())); 874     }
 875
 876
 884     static NumberDataValue setSource(int value,
 885                                         NumberDataValue source)
 886                                     throws StandardException {
 887
 893         if (source == null)
 894             source = new SQLInteger();
 895
 896         source.setValue(value);
 897
 898         return source;
 899     }
 900
 904     private static int computeEncodedDate(java.util.Date
  value) throws StandardException 905     {
 906         return computeEncodedDate( value, null);
 907     }
 908
 909     static int computeEncodedDate(java.util.Date
  value, Calendar  currentCal) throws StandardException 910     {
 911         if (value == null)
 912             return 0;                   if( currentCal == null)
 914             currentCal = new GregorianCalendar
  (); 915         currentCal.setTime(value);
 916         return SQLDate.computeEncodedDate(currentCal);
 917     }
 918
 919
 920
 928     public static DateTimeDataValue computeDateFunction( DataValueDescriptor operand,
 929                                                          DataValueFactory dvf) throws StandardException
 930     {
 931         try
 932         {
 933             if( operand.isNull())
 934                 return new SQLDate();
 935             if( operand instanceof SQLDate)
 936                 return (SQLDate) operand.getClone();
 937
 938             if( operand instanceof SQLTimestamp)
 939             {
 940                 DateTimeDataValue retVal = new SQLDate();
 941                 retVal.setValue( operand);
 942                 return retVal;
 943             }
 944             if( operand instanceof NumberDataValue)
 945             {
 946                 int daysSinceEpoch = operand.getInt();
 947                 if( daysSinceEpoch <= 0 || daysSinceEpoch > 3652059)
 948                     throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
 949                                                           operand.getString(), "date");
 950                 Calendar
  cal = new GregorianCalendar  ( 1970, 0, 1, 12, 0, 0); 951                 cal.add( Calendar.DATE, daysSinceEpoch - 1);
 952                 return new SQLDate( computeEncodedDate( cal.get( Calendar.YEAR),
 953                                                         cal.get( Calendar.MONTH) + 1,
 954                                                         cal.get( Calendar.DATE)));
 955             }
 956             String
  str = operand.getString(); 957             if( str.length() == 7)
 958             {
 959                                 int year = SQLTimestamp.parseDateTimeInteger( str, 0, 4);
 961                 int dayOfYear = SQLTimestamp.parseDateTimeInteger( str, 4, 3);
 962                 if( dayOfYear < 1 || dayOfYear > 366)
 963                     throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
 964                                                           operand.getString(), "date");
 965                 Calendar
  cal = new GregorianCalendar  ( year, 0, 1, 2, 0, 0); 966                 cal.add( Calendar.DAY_OF_YEAR, dayOfYear - 1);
 967                 int y = cal.get( Calendar.YEAR);
 968                 if( y != year)
 969                     throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
 970                                                           operand.getString(), "date");
 971                 return new SQLDate( computeEncodedDate( year,
 972                                                         cal.get( Calendar.MONTH) + 1,
 973                                                         cal.get( Calendar.DATE)));
 974             }
 975                         return dvf.getDateValue( str, false);
 977         }
 978         catch( StandardException se)
 979         {
 980             if( SQLState.LANG_DATE_SYNTAX_EXCEPTION.startsWith( se.getSQLState()))
 981                 throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT,
 982                                                       operand.getString(), "date");
 983             throw se;
 984         }
 985     }
 987
 990     public void setInto(PreparedStatement
  ps, int position) throws SQLException  , StandardException { 991
 992                   ps.setDate(position, getDate((Calendar
  ) null)); 993      }
 994
 995
 996
 1010    public DateTimeDataValue timestampAdd( int intervalType,
 1011                                           NumberDataValue intervalCount,
 1012                                           java.sql.Date
  currentDate, 1013                                           DateTimeDataValue resultHolder)
 1014        throws StandardException
 1015    {
 1016        return toTimestamp().timestampAdd( intervalType, intervalCount, currentDate, resultHolder);
 1017    }
 1018
 1019    private SQLTimestamp toTimestamp() throws StandardException
 1020    {
 1021        return new SQLTimestamp( getEncodedDate(), 0, 0);
 1022    }
 1023
 1024
 1039    public NumberDataValue timestampDiff( int intervalType,
 1040                                          DateTimeDataValue time1,
 1041                                          java.sql.Date
  currentDate, 1042                                          NumberDataValue resultHolder)
 1043        throws StandardException
 1044    {
 1045        return toTimestamp().timestampDiff( intervalType, time1, currentDate, resultHolder);
 1046    }
 1047}
 1048
                                                                                                                                                                                                             |                                                                       
 
 
 
 
 
                                                                                   Popular Tags                                                                                                                                                                                              |