1 21 22 package org.apache.derby.iapi.types; 23 24 import org.apache.derby.iapi.reference.SQLState; 25 26 import org.apache.derby.iapi.services.io.ArrayInputStream; 27 28 import org.apache.derby.iapi.error.StandardException; 29 import org.apache.derby.iapi.db.DatabaseContext; 30 31 import org.apache.derby.iapi.types.DataValueDescriptor; 32 import org.apache.derby.iapi.types.TypeId; 33 34 import org.apache.derby.iapi.types.NumberDataValue; 35 import org.apache.derby.iapi.types.DateTimeDataValue; 36 37 import org.apache.derby.iapi.services.io.StoredFormatIds; 38 import org.apache.derby.iapi.services.context.ContextService; 39 40 import org.apache.derby.iapi.services.sanity.SanityManager; 41 import org.apache.derby.iapi.types.DataType; 42 import org.apache.derby.iapi.services.i18n.LocaleFinder; 43 import org.apache.derby.iapi.services.cache.ClassSize; 44 import org.apache.derby.iapi.util.StringUtil; 45 import org.apache.derby.iapi.util.ReuseFactory; 46 47 import org.apache.derby.iapi.types.SQLDouble; 48 import org.apache.derby.iapi.types.SQLTime; 49 50 import java.sql.Date ; 51 import java.sql.Time ; 52 import java.sql.Timestamp ; 53 import java.sql.Types ; 54 import java.sql.ResultSet ; 55 import java.sql.SQLException ; 56 import java.sql.PreparedStatement ; 57 58 import java.util.Calendar ; 59 import java.util.GregorianCalendar ; 60 61 import java.io.ObjectOutput ; 62 import java.io.ObjectInput ; 63 import java.io.IOException ; 64 65 import java.text.DateFormat ; 66 import java.text.ParseException ; 67 68 83 84 public final class SQLTimestamp extends DataType 85 implements DateTimeDataValue 86 { 87 88 static final int MAX_FRACTION_DIGITS = 6; static final int FRACTION_TO_NANO = 1000; 91 static final int ONE_BILLION = 1000000000; 92 93 private int encodedDate; 94 private int encodedTime; 95 private int nanos; 96 97 private String valueString; 99 100 104 105 private static final int BASE_MEMORY_USAGE = ClassSize.estimateBaseFromCatalog( SQLTimestamp.class); 106 107 public int estimateMemoryUsage() 108 { 109 int sz = BASE_MEMORY_USAGE + ClassSize.estimateMemoryUsage( valueString); 110 return sz; 111 } 113 public String getString() 114 { 115 if (!isNull()) 116 { 117 if (valueString == null) 118 { 119 valueString = getTimestamp((Calendar ) null).toString(); 120 124 int separatorIdx = valueString.indexOf( '-'); 125 if( separatorIdx >= 0 && separatorIdx < 4) 126 { 127 StringBuffer sb = new StringBuffer (); 128 for( ; separatorIdx < 4; separatorIdx++) 129 sb.append('0'); 130 sb.append( valueString); 131 valueString = sb.toString(); 132 } 133 } 134 135 return valueString; 136 } 137 else 138 { 139 if (SanityManager.DEBUG) 140 { 141 if (valueString != null) 142 { 143 SanityManager.THROWASSERT( 144 "valueString expected to be null, not " + 145 valueString); 146 } 147 } 148 return null; 149 } 150 } 151 152 153 161 public Date getDate( Calendar cal) throws StandardException 162 { 163 if (isNull()) 164 return null; 165 return newDate(cal); 166 } 167 168 private Date newDate(java.util.Calendar cal) throws StandardException 169 { 170 if( cal == null) 171 cal = new GregorianCalendar (); 172 cal.clear(); 173 cal.set(Calendar.YEAR, SQLDate.getYear(encodedDate) ); 174 cal.set(Calendar.MONTH, SQLDate.getMonth(encodedDate)-1); 175 cal.set(Calendar.DATE, SQLDate.getDay(encodedDate) ); 176 cal.set(Calendar.HOUR_OF_DAY, 0); 177 cal.set(Calendar.MINUTE, 0); 178 cal.set(Calendar.SECOND, 0); 179 cal.set(Calendar.MILLISECOND, 0); 180 return new Date (cal.getTime().getTime()); 181 } 182 183 190 public Time getTime( Calendar cal) throws StandardException 191 { 192 if (isNull()) 193 return null; 194 return newTime(cal); 195 } 196 197 private Time newTime(java.util.Calendar cal) throws StandardException 198 { 199 if( cal == null) 200 cal = new GregorianCalendar (); 201 cal.clear(); 202 cal.set(Calendar.YEAR, 1970); 203 cal.set(Calendar.MONTH, Calendar.JANUARY); 204 cal.set(Calendar.DATE, 1); 205 cal.set(Calendar.HOUR_OF_DAY, SQLTime.getHour(encodedTime)); 206 cal.set(Calendar.MINUTE, SQLTime.getMinute(encodedTime)); 207 cal.set(Calendar.SECOND, SQLTime.getSecond(encodedTime)); 208 cal.set(Calendar.MILLISECOND, (int)(nanos/1000000)); 209 return new Time(cal.getTime().getTime()); 210 } 211 212 public Object getObject() 213 { 214 return getTimestamp((Calendar ) null); 215 } 216 217 218 public int getLength() 219 { 220 return 12; 221 } 222 223 224 public String getTypeName() 225 { 226 return "TIMESTAMP"; 227 } 228 229 232 233 238 public int getTypeFormatId() { 239 return StoredFormatIds.SQL_TIMESTAMP_ID; 240 } 241 242 246 public void writeExternal(ObjectOutput out) throws IOException { 247 248 if (SanityManager.DEBUG) 249 SanityManager.ASSERT(!isNull(), "writeExternal() is not supposed to be called for null values."); 250 251 255 out.writeInt(encodedDate); 256 out.writeInt(encodedTime); 257 out.writeInt(nanos); 258 } 259 260 265 public void readExternal(ObjectInput in) throws IOException 266 { 267 encodedDate = in.readInt(); 268 encodedTime = in.readInt(); 269 nanos = in.readInt(); 270 valueString = null; 272 } 273 public void readExternalFromArray(ArrayInputStream in) throws IOException 274 { 275 encodedDate = in.readInt(); 276 encodedTime = in.readInt(); 277 nanos = in.readInt(); 278 valueString = null; 280 } 281 282 285 286 287 public DataValueDescriptor getClone() 288 { 289 return new SQLTimestamp(encodedDate, encodedTime, nanos); 291 } 292 293 296 public DataValueDescriptor getNewNull() 297 { 298 return new SQLTimestamp(); 299 } 300 304 public void restoreToNull() 305 { 306 encodedDate = 0; 308 encodedTime = 0; 309 nanos = 0; 310 311 valueString = null; 313 } 314 315 318 319 324 public void setValueFromResultSet(ResultSet resultSet, int colNumber, 325 boolean isNullable) 326 throws SQLException , StandardException 327 { 328 setValue(resultSet.getTimestamp(colNumber), (Calendar ) null); 329 } 330 331 public int compare(DataValueDescriptor other) 332 throws StandardException 333 { 334 337 if (typePrecedence() < other.typePrecedence()) 338 { 339 return - (other.compare(this)); 340 } 341 342 boolean thisNull, otherNull; 343 344 thisNull = this.isNull(); 345 otherNull = other.isNull(); 346 347 353 if (thisNull || otherNull) 354 { 355 if (!thisNull) return -1; 357 if (!otherNull) return 1; 359 return 0; 360 } 361 362 365 366 int comparison; 367 368 int otherEncodedDate = 0; 369 int otherEncodedTime = 0; 370 int otherNanos = 0; 371 372 374 if (other instanceof SQLTimestamp) 375 { 376 SQLTimestamp st = (SQLTimestamp)other; 377 otherEncodedDate= st.encodedDate; 378 otherEncodedTime= st.encodedTime; 379 otherNanos= st.nanos; 380 } 381 else 382 { 383 386 Calendar cal = new GregorianCalendar (); 387 Timestamp otherts = other.getTimestamp(cal); 388 otherEncodedDate = SQLTimestamp.computeEncodedDate(otherts, cal); 389 otherEncodedTime = SQLTimestamp.computeEncodedTime(otherts, cal); 390 otherNanos = otherts.getNanos(); 391 } 392 if (encodedDate < otherEncodedDate) 393 comparison = -1; 394 else if (encodedDate > otherEncodedDate) 395 comparison = 1; 396 else if (encodedTime < otherEncodedTime) 397 comparison = -1; 398 else if (encodedTime > otherEncodedTime) 399 comparison = 1; 400 else if (nanos < otherNanos) 401 comparison = -1; 402 else if (nanos > otherNanos) 403 comparison = 1; 404 else 405 comparison = 0; 406 407 return comparison; 408 } 409 410 413 public boolean compare(int op, 414 DataValueDescriptor other, 415 boolean orderedNulls, 416 boolean unknownRV) 417 throws StandardException 418 { 419 if (!orderedNulls) { 421 if (this.isNull() || ((DataValueDescriptor)other).isNull()) 422 return unknownRV; 423 } 424 425 426 return super.compare(op, other, orderedNulls, unknownRV); 427 } 428 429 432 433 436 437 438 public SQLTimestamp() { } 439 440 441 public SQLTimestamp(Timestamp value) throws StandardException 442 { 443 setValue(value, (Calendar ) null); 444 } 445 446 SQLTimestamp(int encodedDate, int encodedTime, int nanos) { 447 448 this.encodedDate = encodedDate; 449 this.encodedTime = encodedTime; 450 this.nanos = nanos; 451 } 452 453 public SQLTimestamp( DataValueDescriptor date, DataValueDescriptor time) throws StandardException 454 { 455 Calendar cal = null; 456 if( date == null || date.isNull() 457 || time == null || time.isNull()) 458 return; 459 if( date instanceof SQLDate) 460 { 461 SQLDate sqlDate = (SQLDate) date; 462 encodedDate = sqlDate.getEncodedDate(); 463 } 464 else 465 { 466 cal = new GregorianCalendar (); 467 encodedDate = computeEncodedDate( date.getDate( cal), cal); 468 } 469 if( time instanceof SQLTime) 470 { 471 SQLTime sqlTime = (SQLTime) time; 472 encodedTime = sqlTime.getEncodedTime(); 473 } 474 else 475 { 476 if( cal == null) 477 cal = new GregorianCalendar (); 478 encodedTime = computeEncodedTime( time.getTime( cal), cal); 479 } 480 } 481 482 491 public SQLTimestamp( String timestampStr, boolean isJDBCEscape, LocaleFinder localeFinder) 492 throws StandardException 493 { 494 parseTimestamp( timestampStr, isJDBCEscape,localeFinder, (Calendar ) null); 495 } 496 497 506 public SQLTimestamp( String timestampStr, boolean isJDBCEscape, LocaleFinder localeFinder, Calendar cal) 507 throws StandardException 508 { 509 parseTimestamp( timestampStr, isJDBCEscape, localeFinder, cal); 510 } 511 512 static final char DATE_SEPARATOR = '-'; 513 private static final char[] DATE_SEPARATORS = { DATE_SEPARATOR}; 514 private static final char IBM_DATE_TIME_SEPARATOR = '-'; 515 private static final char ODBC_DATE_TIME_SEPARATOR = ' '; 516 private static final char[] DATE_TIME_SEPARATORS = {IBM_DATE_TIME_SEPARATOR, ODBC_DATE_TIME_SEPARATOR}; 517 private static final char[] DATE_TIME_SEPARATORS_OR_END 518 = {IBM_DATE_TIME_SEPARATOR, ODBC_DATE_TIME_SEPARATOR, (char) 0}; 519 private static final char IBM_TIME_SEPARATOR = '.'; 520 private static final char ODBC_TIME_SEPARATOR = ':'; 521 private static final char[] TIME_SEPARATORS = {IBM_TIME_SEPARATOR, ODBC_TIME_SEPARATOR}; 522 private static final char[] TIME_SEPARATORS_OR_END = {IBM_TIME_SEPARATOR, ODBC_TIME_SEPARATOR, (char) 0}; 523 private static final char[] END_OF_STRING = {(char) 0}; 524 525 private void parseTimestamp( String timestampStr, boolean isJDBCEscape, LocaleFinder localeFinder, Calendar cal) 526 throws StandardException 527 { 528 StandardException thrownSE = null; 529 DateTimeParser parser = new DateTimeParser( timestampStr); 530 try 531 { 532 int[] dateTimeNano = parseDateOrTimestamp( parser, true); 533 encodedDate = dateTimeNano[0]; 534 encodedTime = dateTimeNano[1]; 535 nanos = dateTimeNano[2]; 536 valueString = parser.getTrimmedString(); 537 return; 538 } 539 catch( StandardException se) 540 { 541 thrownSE = se; 542 } 543 try 545 { 546 timestampStr = StringUtil.trimTrailing( timestampStr); 547 int[] dateAndTime = parseLocalTimestamp( timestampStr, localeFinder, cal); 548 encodedDate = dateAndTime[0]; 549 encodedTime = dateAndTime[1]; 550 valueString = timestampStr; 551 return; 552 } 553 catch( ParseException pe){} 554 catch( StandardException se){} 555 if( thrownSE != null) 556 throw thrownSE; 557 throw StandardException.newException( SQLState.LANG_DATE_SYNTAX_EXCEPTION); 558 } 560 570 static int[] parseLocalTimestamp( String str, LocaleFinder localeFinder, Calendar cal) 571 throws StandardException, ParseException 572 { 573 DateFormat timestampFormat = null; 574 if(localeFinder == null) 575 timestampFormat = DateFormat.getDateTimeInstance(); 576 else if( cal == null) 577 timestampFormat = localeFinder.getTimestampFormat(); 578 else 579 timestampFormat = (DateFormat ) localeFinder.getTimestampFormat().clone(); 580 if( cal == null) 581 cal = new GregorianCalendar (); 582 else 583 timestampFormat.setCalendar( cal); 584 java.util.Date date = timestampFormat.parse( str); 585 586 return new int[] { computeEncodedDate( date, cal), computeEncodedTime( date, cal)}; 587 } 589 603 static int[] parseDateOrTimestamp( DateTimeParser parser, boolean timeRequired) 604 throws StandardException 605 { 606 int year = parser.parseInt( 4, false, DATE_SEPARATORS, false); 607 int month = parser.parseInt( 2, true, DATE_SEPARATORS, false); 608 int day = parser.parseInt( 2, true, timeRequired ? DATE_TIME_SEPARATORS : DATE_TIME_SEPARATORS_OR_END, false); 609 int hour = 0; 610 int minute = 0; 611 int second = 0; 612 int nano = 0; 613 if( parser.getCurrentSeparator() != 0) 614 { 615 char timeSeparator = (parser.getCurrentSeparator() == ODBC_DATE_TIME_SEPARATOR) 616 ? ODBC_TIME_SEPARATOR : IBM_TIME_SEPARATOR; 617 hour = parser.parseInt( 2, true, TIME_SEPARATORS, false); 618 if( timeSeparator == parser.getCurrentSeparator()) 619 { 620 minute = parser.parseInt( 2, false, TIME_SEPARATORS, false); 621 if( timeSeparator == parser.getCurrentSeparator()) 622 { 623 second = parser.parseInt( 2, false, TIME_SEPARATORS_OR_END, false); 624 if( parser.getCurrentSeparator() == '.') 625 nano = parser.parseInt( MAX_FRACTION_DIGITS, true, END_OF_STRING, true)*FRACTION_TO_NANO; 626 } 627 } 628 } 629 parser.checkEnd(); 630 return new int[] { SQLDate.computeEncodedDate( year, month, day), 631 SQLTime.computeEncodedTime( hour,minute,second), 632 nano}; 633 } 635 639 void setObject(Object theValue) throws StandardException 640 { 641 setValue((Timestamp ) theValue); 642 } 643 644 protected void setFrom(DataValueDescriptor theValue) throws StandardException { 645 646 if (theValue instanceof SQLTimestamp) { 647 restoreToNull(); 648 SQLTimestamp tvst = (SQLTimestamp) theValue; 649 encodedDate = tvst.encodedDate; 650 encodedTime = tvst.encodedTime; 651 nanos = tvst.nanos; 652 } 653 else 654 { 655 Calendar cal = new GregorianCalendar (); 656 setValue(theValue.getTimestamp( cal), cal); 657 } 658 } 659 660 665 public void setValue(Date value, Calendar cal) throws StandardException 666 { 667 restoreToNull(); 668 if( value != null) 669 { 670 if( cal == null) 671 cal = new GregorianCalendar (); 672 encodedDate = computeEncodedDate(value, cal); 673 } 674 675 } 676 677 681 public void setValue(Time value, Calendar cal) throws StandardException 682 { 683 restoreToNull(); 684 if (value != null) 685 { 686 692 Calendar today = GregorianCalendar.getInstance(); 693 encodedDate = SQLDate.computeEncodedDate(today); 694 if( cal == null) 695 cal = today; 696 encodedTime = computeEncodedTime(value, cal); 697 } 698 } 699 700 704 public void setValue(Timestamp value, Calendar cal) 705 throws StandardException 706 { 707 restoreToNull(); 708 setNumericTimestamp(value, cal); 709 } 710 711 712 public void setValue(String theValue) 713 throws StandardException 714 { 715 restoreToNull(); 716 717 if (theValue != null) 718 { 719 DatabaseContext databaseContext = (DatabaseContext) ContextService.getContext(DatabaseContext.CONTEXT_ID); 720 parseTimestamp( theValue, 721 false, 722 (databaseContext == null) ? null : databaseContext.getDatabase(), 723 (Calendar ) null); 724 } 725 726 } 727 728 731 732 733 738 public NumberDataValue getYear(NumberDataValue result) 739 throws StandardException 740 { 741 if (SanityManager.DEBUG) 742 { 743 SanityManager.ASSERT(!isNull(), "getYear called on a null"); 744 } 745 return SQLDate.setSource(SQLDate.getYear(encodedDate), result); 746 } 747 748 753 public NumberDataValue getMonth(NumberDataValue result) 754 throws StandardException 755 { 756 if (SanityManager.DEBUG) 757 { 758 SanityManager.ASSERT(!isNull(), "getMonth called on a null"); 759 } 760 return SQLDate.setSource(SQLDate.getMonth(encodedDate), result); 761 } 762 763 768 public NumberDataValue getDate(NumberDataValue result) 769 throws StandardException 770 { 771 if (SanityManager.DEBUG) 772 { 773 SanityManager.ASSERT(!isNull(), "getDate called on a null"); 774 } 775 return SQLDate.setSource(SQLDate.getDay(encodedDate), result); 776 } 777 778 783 public NumberDataValue getHours(NumberDataValue result) 784 throws StandardException 785 { 786 if (SanityManager.DEBUG) 787 { 788 SanityManager.ASSERT(!isNull(), "getHours called on a null"); 789 } 790 return SQLDate.setSource(SQLTime.getHour(encodedTime), result); 791 } 792 793 798 public NumberDataValue getMinutes(NumberDataValue result) 799 throws StandardException 800 { 801 if (SanityManager.DEBUG) 802 { 803 SanityManager.ASSERT(!isNull(), "getMinute called on a null"); 804 } 805 return SQLDate.setSource(SQLTime.getMinute(encodedTime), result); 806 } 807 808 813 public NumberDataValue getSeconds(NumberDataValue source) 814 throws StandardException 815 { 816 if (SanityManager.DEBUG) 817 { 818 SanityManager.ASSERT(!isNull(), "getSeconds called on a null"); 819 SanityManager.ASSERT(source == null || source instanceof SQLDouble, 820 "getSeconds for a timestamp was given a source other than a SQLDouble"); 821 } 822 NumberDataValue result; 823 824 if (source != null) 825 result = source; 826 else 827 result = new SQLDouble(); 828 829 result.setValue((double)(SQLTime.getSecond(encodedTime)) 830 + ((double)nanos)/1.0e9); 831 832 return result; 833 } 834 835 838 839 public String toString() 840 { 841 if (isNull()) 842 { 843 return "NULL"; 844 } 845 else 846 { 847 return getTimestamp( (Calendar ) null).toString(); 848 } 849 } 850 851 854 public int hashCode() 855 { 856 if (isNull()) 857 { 858 return 0; 859 } 860 861 return encodedDate + encodedTime + nanos; 863 } 864 865 866 public int typePrecedence() 867 { 868 return TypeId.TIMESTAMP_PRECEDENCE; 869 } 870 871 876 public final boolean isNull() 877 { 878 return (encodedDate == 0); 879 } 880 881 887 public Timestamp getTimestamp(java.util.Calendar cal) 888 { 889 if (isNull()) 890 return null; 891 return newTimestamp(cal); 892 } 893 894 private Timestamp newTimestamp(Calendar currentCal) 895 { 896 if( currentCal == null) 897 currentCal = new GregorianCalendar (); 898 setCalendar( currentCal); 899 Timestamp t = new Timestamp (currentCal.getTime().getTime()); 900 t.setNanos(nanos); 901 return t; 902 } 903 904 private void setCalendar( Calendar cal) 905 { 906 cal.clear(); 907 cal.set(Calendar.YEAR, SQLDate.getYear(encodedDate)); 908 909 cal.set(Calendar.MONTH, (SQLDate.getMonth(encodedDate)-1)); 910 cal.set(Calendar.DATE, SQLDate.getDay(encodedDate)); 911 cal.set(Calendar.HOUR_OF_DAY, SQLTime.getHour(encodedTime)); 912 cal.set(Calendar.MINUTE, SQLTime.getMinute(encodedTime)); 913 cal.set(Calendar.SECOND, SQLTime.getSecond(encodedTime)); 914 cal.set(Calendar.MILLISECOND, 0); 915 } 917 921 private void setNumericTimestamp(Timestamp value, Calendar cal) throws StandardException 922 { 923 if (SanityManager.DEBUG) 924 { 925 SanityManager.ASSERT(isNull(), "setNumericTimestamp called when already set"); 926 } 927 if (value != null) 928 { 929 if( cal == null) 930 cal = new GregorianCalendar (); 931 encodedDate = computeEncodedDate(value, cal); 932 encodedTime = computeEncodedTime(value, cal); 933 nanos = value.getNanos(); 934 } 935 936 } 937 938 940 946 protected String getNationalString(LocaleFinder localeFinder) throws StandardException 947 { 948 if (isNull()) 949 { 950 return getString(); 951 } 952 953 954 return localeFinder.getTimestampFormat().format(getTimestamp((Calendar ) null)); 955 } 956 957 966 private static int computeEncodedDate(java.util.Date value, Calendar currentCal) throws StandardException 967 { 968 if (value == null) 969 return 0; 970 971 currentCal.setTime(value); 972 return SQLDate.computeEncodedDate(currentCal); 973 } 974 983 private static int computeEncodedTime(java.util.Date value, Calendar currentCal) throws StandardException 984 { 985 currentCal.setTime(value); 986 return SQLTime.computeEncodedTime(currentCal); 987 } 988 989 990 public void setInto(PreparedStatement ps, int position) throws SQLException , StandardException { 991 992 ps.setTimestamp(position, getTimestamp((Calendar ) null)); 993 } 994 995 1000 public static DateTimeDataValue computeTimestampFunction( DataValueDescriptor operand, 1001 DataValueFactory dvf) throws StandardException 1002 { 1003 try 1004 { 1005 if( operand.isNull()) 1006 return new SQLTimestamp(); 1007 if( operand instanceof SQLTimestamp) 1008 return (SQLTimestamp) operand.getClone(); 1009 1010 String str = operand.getString(); 1011 if( str.length() == 14) 1012 { 1013 int year = parseDateTimeInteger( str, 0, 4); 1014 int month = parseDateTimeInteger( str, 4, 2); 1015 int day = parseDateTimeInteger( str, 6, 2); 1016 int hour = parseDateTimeInteger( str, 8, 2); 1017 int minute = parseDateTimeInteger( str, 10, 2); 1018 int second = parseDateTimeInteger( str, 12, 2); 1019 return new SQLTimestamp( SQLDate.computeEncodedDate( year, month, day), 1020 SQLTime.computeEncodedTime( hour,minute,second), 1021 0); 1022 } 1023 return dvf.getTimestampValue( str, false); 1025 } 1026 catch( StandardException se) 1027 { 1028 if( SQLState.LANG_DATE_SYNTAX_EXCEPTION.startsWith( se.getSQLState())) 1029 throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT, 1030 operand.getString(), "timestamp"); 1031 throw se; 1032 } 1033 } 1035 static int parseDateTimeInteger( String str, int start, int ndigits) throws StandardException 1036 { 1037 int end = start + ndigits; 1038 int retVal = 0; 1039 for( int i = start; i < end; i++) 1040 { 1041 char c = str.charAt( i); 1042 if( !Character.isDigit( c)) 1043 throw StandardException.newException( SQLState.LANG_DATE_SYNTAX_EXCEPTION); 1044 retVal = 10*retVal + Character.digit( c, 10); 1045 } 1046 return retVal; 1047 } 1049 1063 public DateTimeDataValue timestampAdd( int intervalType, 1064 NumberDataValue count, 1065 java.sql.Date currentDate, 1066 DateTimeDataValue resultHolder) 1067 throws StandardException 1068 { 1069 if( resultHolder == null) 1070 resultHolder = new SQLTimestamp(); 1071 SQLTimestamp tsResult = (SQLTimestamp) resultHolder; 1072 if( isNull() || count.isNull()) 1073 { 1074 tsResult.restoreToNull(); 1075 return resultHolder; 1076 } 1077 tsResult.setFrom( this); 1078 int intervalCount = count.getInt(); 1079 1080 switch( intervalType) 1081 { 1082 case FRAC_SECOND_INTERVAL: 1083 long nanos = this.nanos + intervalCount; 1085 if( nanos >= 0 && nanos < ONE_BILLION) 1086 tsResult.nanos = (int) nanos; 1087 else 1088 { 1089 int secondsInc = (int)(nanos/ONE_BILLION); 1090 if( nanos >= 0) 1091 tsResult.nanos = (int) (nanos % ONE_BILLION); 1092 else 1093 { 1094 secondsInc--; 1095 nanos -= secondsInc * (long)ONE_BILLION; tsResult.nanos = (int) nanos; 1097 } 1098 addInternal( Calendar.SECOND, secondsInc, tsResult); 1099 } 1100 break; 1101 1102 case SECOND_INTERVAL: 1103 addInternal( Calendar.SECOND, intervalCount, tsResult); 1104 break; 1105 1106 case MINUTE_INTERVAL: 1107 addInternal( Calendar.MINUTE, intervalCount, tsResult); 1108 break; 1109 1110 case HOUR_INTERVAL: 1111 addInternal( Calendar.HOUR, intervalCount, tsResult); 1112 break; 1113 1114 case DAY_INTERVAL: 1115 addInternal( Calendar.DATE, intervalCount, tsResult); 1116 break; 1117 1118 case WEEK_INTERVAL: 1119 addInternal( Calendar.DATE, intervalCount*7, tsResult); 1120 break; 1121 1122 case MONTH_INTERVAL: 1123 addInternal( Calendar.MONTH, intervalCount, tsResult); 1124 break; 1125 1126 case QUARTER_INTERVAL: 1127 addInternal( Calendar.MONTH, intervalCount*3, tsResult); 1128 break; 1129 1130 case YEAR_INTERVAL: 1131 addInternal( Calendar.YEAR, intervalCount, tsResult); 1132 break; 1133 1134 default: 1135 throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT, 1136 ReuseFactory.getInteger( intervalType), 1137 "TIMESTAMPADD"); 1138 } 1139 return tsResult; 1140 } 1142 private void addInternal( int calIntervalType, int count, SQLTimestamp tsResult) throws StandardException 1143 { 1144 Calendar cal = new GregorianCalendar (); 1145 setCalendar( cal); 1146 try 1147 { 1148 cal.add( calIntervalType, count); 1149 tsResult.encodedTime = SQLTime.computeEncodedTime( cal); 1150 tsResult.encodedDate = SQLDate.computeEncodedDate( cal); 1151 } 1152 catch( StandardException se) 1153 { 1154 String state = se.getSQLState(); 1155 if( state != null && state.length() > 0 && SQLState.LANG_DATE_RANGE_EXCEPTION.startsWith( state)) 1156 { 1157 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "TIMESTAMP"); 1158 } 1159 throw se; 1160 } 1161 } 1163 1178 public NumberDataValue timestampDiff( int intervalType, 1179 DateTimeDataValue time1, 1180 java.sql.Date currentDate, 1181 NumberDataValue resultHolder) 1182 throws StandardException 1183 { 1184 if( resultHolder == null) 1185 resultHolder = new SQLInteger(); 1186 1187 if( isNull() || time1.isNull()) 1188 { 1189 resultHolder.setToNull(); 1190 return resultHolder; 1191 } 1192 1193 SQLTimestamp ts1 = promote( time1, currentDate); 1194 1195 1198 Calendar cal = new GregorianCalendar (); 1199 setCalendar( cal); 1200 long thisInSeconds = cal.getTime().getTime()/1000; 1201 ts1.setCalendar( cal); 1202 long ts1InSeconds = cal.getTime().getTime()/1000; 1203 long secondsDiff = thisInSeconds - ts1InSeconds; 1204 int nanosDiff = nanos - ts1.nanos; 1205 if( nanosDiff < 0 && secondsDiff > 0) 1207 { 1208 secondsDiff--; 1209 nanosDiff += ONE_BILLION; 1210 } 1211 else if( nanosDiff > 0 && secondsDiff < 0) 1212 { 1213 secondsDiff++; 1214 nanosDiff -= ONE_BILLION; 1215 } 1216 long ldiff = 0; 1217 1218 switch( intervalType) 1219 { 1220 case FRAC_SECOND_INTERVAL: 1221 if( secondsDiff > Integer.MAX_VALUE/ONE_BILLION || secondsDiff < Integer.MIN_VALUE/ONE_BILLION) 1222 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER"); 1223 ldiff = secondsDiff*ONE_BILLION + nanosDiff; 1224 break; 1225 1226 case SECOND_INTERVAL: 1227 ldiff = secondsDiff; 1228 break; 1229 1230 case MINUTE_INTERVAL: 1231 ldiff = secondsDiff/60; 1232 break; 1233 1234 case HOUR_INTERVAL: 1235 ldiff = secondsDiff/(60*60); 1236 break; 1237 1238 case DAY_INTERVAL: 1239 ldiff = secondsDiff/(24*60*60); 1240 break; 1241 1242 case WEEK_INTERVAL: 1243 ldiff = secondsDiff/(7*24*60*60); 1244 break; 1245 1246 case QUARTER_INTERVAL: 1247 case MONTH_INTERVAL: 1248 if( Math.abs( secondsDiff) > 366*24*60*60) ldiff = 12*(secondsDiff/(366*24*60*60)); 1251 else 1252 ldiff = secondsDiff/(31*24*60*60); 1253 if( secondsDiff >= 0) 1254 { 1255 if (ldiff >= Integer.MAX_VALUE) 1256 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER"); 1257 cal.add( Calendar.MONTH, (int) (ldiff + 1)); 1259 for(;;) 1260 { 1261 if( cal.getTime().getTime()/1000 > thisInSeconds) 1262 break; 1263 cal.add( Calendar.MONTH, 1); 1264 ldiff++; 1265 } 1266 } 1267 else 1268 { 1269 if (ldiff <= Integer.MIN_VALUE) 1270 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER"); 1271 cal.add( Calendar.MONTH, (int) (ldiff - 1)); 1273 for(;;) 1274 { 1275 if( cal.getTime().getTime()/1000 < thisInSeconds) 1276 break; 1277 cal.add( Calendar.MONTH, -1); 1278 ldiff--; 1279 } 1280 } 1281 if( intervalType == QUARTER_INTERVAL) 1282 ldiff = ldiff/3; 1283 break; 1284 1285 case YEAR_INTERVAL: 1286 ldiff = secondsDiff/(366*24*60*60); 1288 if( secondsDiff >= 0) 1289 { 1290 if (ldiff >= Integer.MAX_VALUE) 1291 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER"); 1292 cal.add( Calendar.YEAR, (int) (ldiff + 1)); 1294 for(;;) 1295 { 1296 if( cal.getTime().getTime()/1000 > thisInSeconds) 1297 break; 1298 cal.add( Calendar.YEAR, 1); 1299 ldiff++; 1300 } 1301 } 1302 else 1303 { 1304 if (ldiff <= Integer.MIN_VALUE) 1305 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER"); 1306 cal.add( Calendar.YEAR, (int) (ldiff - 1)); 1308 for(;;) 1309 { 1310 if( cal.getTime().getTime()/1000 < thisInSeconds) 1311 break; 1312 cal.add( Calendar.YEAR, -1); 1313 ldiff--; 1314 } 1315 } 1316 break; 1317 1318 default: 1319 throw StandardException.newException( SQLState.LANG_INVALID_FUNCTION_ARGUMENT, 1320 ReuseFactory.getInteger( intervalType), 1321 "TIMESTAMPDIFF"); 1322 } 1323 if (ldiff > Integer.MAX_VALUE || ldiff < Integer.MIN_VALUE) 1324 throw StandardException.newException(SQLState.LANG_OUTSIDE_RANGE_FOR_DATATYPE, "INTEGER"); 1325 resultHolder.setValue( (int) ldiff); 1326 return resultHolder; 1327 } 1329 1338 static SQLTimestamp promote( DateTimeDataValue dateTime, java.sql.Date currentDate) throws StandardException 1339 { 1340 if( dateTime instanceof SQLTimestamp) 1341 return (SQLTimestamp) dateTime; 1342 else if( dateTime instanceof SQLTime) 1343 return new SQLTimestamp( SQLDate.computeEncodedDate( currentDate, (Calendar ) null), 1344 ((SQLTime) dateTime).getEncodedTime(), 1345 0 ); 1346 else if( dateTime instanceof SQLDate) 1347 return new SQLTimestamp( ((SQLDate) dateTime).getEncodedDate(), 0, 0); 1348 else 1349 return new SQLTimestamp( dateTime.getTimestamp( new GregorianCalendar ())); 1350 } } 1352 | Popular Tags |