KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > derby > iapi > types > SQLDate


1 /*
2
3    Derby - Class org.apache.derby.iapi.types.SQLDate
4
5    Licensed to the Apache Software Foundation (ASF) under one or more
6    contributor license agreements. See the NOTICE file distributed with
7    this work for additional information regarding copyright ownership.
8    The ASF licenses this file to you under the Apache License, Version 2.0
9    (the "License"); you may not use this file except in compliance with
10    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, software
15    distributed under the License is distributed on an "AS IS" BASIS,
16    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17    See the License for the specific language governing permissions and
18    limitations under the License.
19
20  */

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 JavaDoc;
52 import java.sql.Time JavaDoc;
53 import java.sql.Timestamp JavaDoc;
54 import java.sql.Types JavaDoc;
55 import java.sql.PreparedStatement JavaDoc;
56
57 import java.util.Calendar JavaDoc;
58 import java.util.GregorianCalendar JavaDoc;
59
60 import java.io.ObjectOutput JavaDoc;
61 import java.io.ObjectInput JavaDoc;
62 import java.io.IOException JavaDoc;
63
64 import java.sql.ResultSet JavaDoc;
65 import java.sql.SQLException JavaDoc;
66
67 import java.text.DateFormat JavaDoc;
68 import java.text.ParseException JavaDoc;
69
70 /**
71  * This contains an instance of a SQL Date.
72  * <p>
73  * The date is stored as int (year << 16 + month << 8 + day)
74  * Null is represented by an encodedDate value of 0.
75  * Some of the static methods in this class are also used by SQLTime and SQLTimestamp
76  * so check those classes if you change the date encoding
77  *
78  * PERFORMANCE OPTIMIZATION:
79  * The java.sql.Date object is only instantiated when needed
80  * do to the overhead of Date.valueOf(), etc. methods.
81  */

82
83 public final class SQLDate extends DataType
84                         implements DateTimeDataValue
85 {
86
87     private int encodedDate; //year << 16 + month << 8 + day
88

89     // The cached value.toString()
90
private String JavaDoc 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     } // end of estimateMemoryUsage
98

99     int getEncodedDate()
100     {
101         return encodedDate;
102     }
103     
104     /*
105     ** DataValueDescriptor interface
106     ** (mostly implemented in DataType)
107     */

108
109     public String JavaDoc getString()
110     {
111         //format is [yyy]y-mm-dd e.g. 1-01-01, 9999-99-99
112
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     /**
136         getTimestamp returns a timestamp with the date value
137         time is set to 00:00:00.0
138     */

139     public Timestamp JavaDoc getTimestamp( Calendar JavaDoc cal)
140     {
141         if (isNull())
142         {
143             return null;
144         }
145         else
146             // date is converted to a timestamp filling the time in with 00:00:00
147
return newTimestamp(cal);
148     }
149
150     private long getTimeInMillis( Calendar JavaDoc cal)
151     {
152         if( cal == null)
153             cal = new GregorianCalendar JavaDoc();
154         cal.clear();
155         cal.set( getYear( encodedDate), getMonth( encodedDate)-1, getDay( encodedDate));
156         return cal.getTime().getTime();
157     }
158     
159     private Timestamp JavaDoc newTimestamp(java.util.Calendar JavaDoc cal)
160     {
161         return new Timestamp JavaDoc(getTimeInMillis( cal));
162     }
163
164     /**
165         getObject returns the date value
166
167      */

168     public Object JavaDoc getObject()
169     {
170         return getDate( (Calendar JavaDoc) null);
171     }
172         
173     public int getLength()
174     {
175         return 4;
176     }
177
178     /* this is for DataType's error generator */
179     public String JavaDoc getTypeName()
180     {
181         return "DATE";
182     }
183
184     /*
185      * Storable interface, implies Externalizable, TypedFormat
186      */

187
188     /**
189         Return my format identifier.
190
191         @see org.apache.derby.iapi.services.io.TypedFormat#getTypeFormatId
192     */

193     public int getTypeFormatId() {
194         return StoredFormatIds.SQL_DATE_ID;
195     }
196
197     /**
198         @exception IOException error writing data
199
200     */

201     public void writeExternal(ObjectOutput JavaDoc out) throws IOException JavaDoc {
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     /**
210      * @see java.io.Externalizable#readExternal
211      *
212      * @exception IOException Thrown on error reading the object
213      */

214     public void readExternal(ObjectInput JavaDoc in) throws IOException JavaDoc
215     {
216         encodedDate = in.readInt();
217
218         // reset cached string values
219
valueString = null;
220     }
221     public void readExternalFromArray(ArrayInputStream in) throws IOException JavaDoc
222     {
223         encodedDate = in.readInt();
224
225         // reset cached string values
226
valueString = null;
227     }
228
229     /*
230      * DataValueDescriptor interface
231      */

232
233     /** @see DataValueDescriptor#getClone */
234     public DataValueDescriptor getClone()
235     {
236         // Call constructor with all of our info
237
return new SQLDate(encodedDate);
238     }
239
240     /**
241      * @see DataValueDescriptor#getNewNull
242      */

243     public DataValueDescriptor getNewNull()
244     {
245         return new SQLDate();
246     }
247     /**
248      * @see org.apache.derby.iapi.services.io.Storable#restoreToNull
249      *
250      */

251
252     public void restoreToNull()
253     {
254         // clear encodedDate
255
encodedDate = 0;
256
257         // clear cached valueString
258
valueString = null;
259     }
260
261     /*
262      * DataValueDescriptor interface
263      */

264
265     /**
266      * @see DataValueDescriptor#setValueFromResultSet
267      *
268      * @exception SQLException Thrown on error
269      */

270     public void setValueFromResultSet(ResultSet JavaDoc resultSet, int colNumber,
271                                       boolean isNullable)
272         throws SQLException JavaDoc, StandardException
273     {
274         setValue(resultSet.getDate(colNumber), (Calendar JavaDoc) null);
275     }
276
277     /**
278      * Orderable interface
279      *
280      *
281      * @see org.apache.derby.iapi.types.Orderable
282      *
283      * @exception StandardException thrown on failure
284      */

285     public int compare(DataValueDescriptor other)
286         throws StandardException
287     {
288         /* Use compare method from dominant type, negating result
289          * to reflect flipping of sides.
290          */

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         /*
303          * thisNull otherNull return
304          * T T 0 (this == other)
305          * F T -1 (this < other)
306          * T F 1 (this > other)
307          */

308         if (thisNull || otherNull)
309         {
310             if (!thisNull) // otherNull must be true
311
return -1;
312             if (!otherNull) // thisNull must be true
313
return 1;
314             return 0;
315         }
316
317         /*
318             Neither are null compare them
319          */

320
321         int comparison;
322         /* get the comparison date values */
323         int otherVal = 0;
324
325         /* if the argument is another SQLDate
326          * get the encodedDate
327          */

328         if (other instanceof SQLDate)
329         {
330             otherVal = ((SQLDate)other).encodedDate;
331         }
332         else
333         {
334             /* O.K. have to do it the hard way and calculate the numeric value
335              * from the value
336              */

337             otherVal = SQLDate.computeEncodedDate(other.getDate(new GregorianCalendar JavaDoc()));
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     /**
350         @exception StandardException thrown on error
351      */

352     public boolean compare(int op,
353                            DataValueDescriptor other,
354                            boolean orderedNulls,
355                            boolean unknownRV)
356         throws StandardException
357     {
358         if (!orderedNulls) // nulls are unordered
359
{
360             if (this.isNull() || other.isNull())
361                 return unknownRV;
362         }
363
364         /* Do the comparison */
365         return super.compare(op, other, orderedNulls, unknownRV);
366     }
367
368     /*
369     ** Class interface
370     */

371
372     /*
373     ** Constructors
374     */

375
376     /** no-arg constructor required by Formattable */
377     public SQLDate() {
378     }
379
380     public SQLDate(Date JavaDoc value) throws StandardException
381     {
382         parseDate(value);
383     }
384     
385     private void parseDate( java.util.Date JavaDoc value) throws StandardException
386     {
387         encodedDate = computeEncodedDate(value);
388     }
389
390     private SQLDate(int encodedDate) {
391         this.encodedDate = encodedDate;
392     }
393
394     /**
395      * Construct a date from a string. The allowed date formats are:
396      *<ol>
397      *<li>ISO: yyyy-mm-dd
398      *<li>IBM USA standard: mm/dd/yyyy
399      *<li>IBM European standard: dd.mm.yyyy
400      *</ol>
401      * Trailing blanks may be included; leading zeros may be omitted from the month and day portions.
402      *
403      * @param dateStr
404      * @param isJdbcEscape if true then only the JDBC date escape syntax is allowed
405      * @param localeFinder
406      *
407      * @exception Standard exception if the syntax is invalid or the value is out of range.
408      */

409     public SQLDate( String JavaDoc dateStr, boolean isJdbcEscape, LocaleFinder localeFinder)
410         throws StandardException
411     {
412         parseDate( dateStr, isJdbcEscape, localeFinder, (Calendar JavaDoc) null);
413     }
414
415     /**
416      * Construct a date from a string. The allowed date formats are:
417      *<ol>
418      *<li>ISO: yyyy-mm-dd
419      *<li>IBM USA standard: mm/dd/yyyy
420      *<li>IBM European standard: dd.mm.yyyy
421      *</ol>
422      * Trailing blanks may be included; leading zeros may be omitted from the month and day portions.
423      *
424      * @param dateStr
425      * @param isJdbcEscape if true then only the JDBC date escape syntax is allowed
426      * @param localeFinder
427      *
428      * @exception Standard exception if the syntax is invalid or the value is out of range.
429      */

430     public SQLDate( String JavaDoc dateStr, boolean isJdbcEscape, LocaleFinder localeFinder, Calendar JavaDoc 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 JavaDoc dateStr, boolean isJdbcEscape, LocaleFinder localeFinder, Calendar JavaDoc 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             // See if it is a localized date or timestamp.
502
dateStr = StringUtil.trimTrailing( dateStr);
503             DateFormat JavaDoc dateFormat = null;
504             if( localeFinder == null)
505                 dateFormat = DateFormat.getDateInstance();
506             else if( cal == null)
507                 dateFormat = localeFinder.getDateFormat();
508             else
509                 dateFormat = (DateFormat JavaDoc) 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 JavaDoc pe)
517             {
518                 // Maybe it is a localized timestamp
519
try
520                 {
521                     encodedDate = SQLTimestamp.parseLocalTimestamp( dateStr, localeFinder, cal)[0];
522                 }
523                 catch( ParseException JavaDoc 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     } // end of parseDate
533

534     /**
535      * Set the value from a correctly typed Date object.
536      * @throws StandardException
537      */

538     void setObject(Object JavaDoc theValue) throws StandardException
539     {
540         setValue((Date JavaDoc) theValue);
541     }
542
543     protected void setFrom(DataValueDescriptor theValue) throws StandardException {
544
545         // Same format means same type SQLDate
546
if (theValue instanceof SQLDate) {
547             restoreToNull();
548             encodedDate = ((SQLDate) theValue).encodedDate;
549         }
550         else
551         {
552             Calendar JavaDoc cal = new GregorianCalendar JavaDoc();
553             setValue(theValue.getDate( cal), cal);
554         }
555     }
556
557     /**
558         @see DateTimeDataValue#setValue
559
560      */

561     public void setValue(Date JavaDoc value, Calendar JavaDoc cal) throws StandardException
562     {
563         restoreToNull();
564         encodedDate = computeEncodedDate((java.util.Date JavaDoc) value, cal);
565     }
566
567     /**
568         @see DateTimeDataValue#setValue
569
570      */

571     public void setValue(Timestamp JavaDoc value, Calendar JavaDoc cal) throws StandardException
572     {
573         restoreToNull();
574         encodedDate = computeEncodedDate((java.util.Date JavaDoc) value, cal);
575     }
576
577
578     public void setValue(String JavaDoc 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 JavaDoc) null);
590         }
591     }
592
593     /*
594     ** SQL Operators
595     */

596
597     /**
598      * @see DateTimeDataValue#getYear
599      *
600      * @exception StandardException Thrown on error
601      */

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     /**
613      * @see DateTimeDataValue#getMonth
614      *
615      * @exception StandardException Thrown on error
616      */

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     /**
628      * @see DateTimeDataValue#getDate
629      *
630      * @exception StandardException Thrown on error
631      */

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     /**
643      * @see DateTimeDataValue#getHours
644      *
645      * @exception StandardException Thrown on error
646      */

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     /**
659      * @see DateTimeDataValue#getMinutes
660      *
661      * @exception StandardException Thrown on error
662      */

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     /**
675      * @see DateTimeDataValue#getSeconds
676      *
677      * @exception StandardException Thrown on error
678      */

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     /*
691     ** String display of value
692     */

693
694     public String JavaDoc toString()
695     {
696         if (isNull())
697         {
698             return "NULL";
699         }
700         else
701         {
702             return getDate( (Calendar JavaDoc) null).toString();
703         }
704     }
705
706     /*
707      * Hash code
708      */

709     public int hashCode()
710     {
711         return encodedDate;
712     }
713
714     /** @see DataValueDescriptor#typePrecedence */
715     public int typePrecedence()
716     {
717         return TypeId.DATE_PRECEDENCE;
718     }
719
720     /**
721      * Check if the value is null.
722      * encodedDate is 0 if the value is null
723      *
724      * @return Whether or not value is logically null.
725      */

726     public final boolean isNull()
727     {
728         return (encodedDate == 0);
729     }
730
731     /**
732      * Get the value field. We instantiate the field
733      * on demand.
734      *
735      * @return The value field.
736      */

737     public Date JavaDoc getDate( Calendar JavaDoc cal)
738     {
739         if (encodedDate != 0)
740             return new Date JavaDoc( getTimeInMillis( cal));
741
742         return null;
743     }
744
745     /**
746      * Get the year from the encodedDate.
747      *
748      * @param encodedDate the encoded date
749      * @return year value.
750      */

751     static int getYear(int encodedDate)
752     {
753         return (encodedDate >>> 16);
754     }
755
756     /**
757      * Get the month from the encodedDate.
758      *
759      * @param encodedDate the encoded date
760      * @return month value.
761      */

762     static int getMonth(int encodedDate)
763     {
764         return ((encodedDate >>> 8) & 0x00ff);
765     }
766
767     /**
768      * Get the day from the encodedDate.
769      *
770      * @param encodedDate the encoded date
771      * @return day value.
772      */

773     static int getDay(int encodedDate)
774     {
775         return (encodedDate & 0x00ff);
776     }
777     /**
778      * computeEncodedDate extracts the year, month and date from
779      * a Calendar value and encodes them as
780      * year << 16 + month << 8 + date
781      * Use this function will help to remember to add 1 to month
782      * which is 0 based in the Calendar class
783      * @param cal the Calendar
784      * @return the encodedDate
785      *
786      * @exception StandardException if the value is out of the DB2 date range
787      */

788     static int computeEncodedDate(Calendar JavaDoc 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             // leap years are every 4 years except for century years not divisble by 400.
809
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     /**
820      * Convert a date to the JDBC representation and append it to a string buffer.
821      *
822      * @param year
823      * @param month 1 based (January == 1)
824      * @param day
825      * @param sb The string representation is appended to this StringBuffer
826      */

827     static void dateToString( int year, int month, int day, StringBuffer JavaDoc sb)
828     {
829         String JavaDoc 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 JavaDoc monthStr = Integer.toString( month);
836         String JavaDoc 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     } // end of dateToString
845

846     /**
847      * Get the String version from the encodedDate.
848      *
849      * @return string value.
850      */

851     static String JavaDoc encodedDateToString(int encodedDate)
852     {
853         StringBuffer JavaDoc vstr = new StringBuffer JavaDoc();
854         dateToString( getYear(encodedDate), getMonth(encodedDate), getDay(encodedDate), vstr);
855         return vstr.toString();
856     }
857
858     // International Support
859

860     /**
861      * International version of getString(). Overrides getNationalString
862      * in DataType for date, time, and timestamp.
863      *
864      * @exception StandardException Thrown on error
865      */

866     protected String JavaDoc getNationalString(LocaleFinder localeFinder) throws StandardException
867     {
868         if (isNull())
869         {
870             return getString();
871         }
872
873         return localeFinder.getDateFormat().format(getDate(new GregorianCalendar JavaDoc()));
874     }
875
876     /**
877         This helper routine tests the nullability of various parameters
878         and sets up the result appropriately.
879
880         If source is null, a new NumberDataValue is built.
881
882         @exception StandardException Thrown on error
883      */

884     static NumberDataValue setSource(int value,
885                                         NumberDataValue source)
886                                     throws StandardException {
887         /*
888         ** NOTE: Most extract operations return int, so the generation of
889         ** a SQLInteger is here. Those extract operations that return
890         ** something other than int must allocate the source NumberDataValue
891         ** themselves, so that we do not allocate a SQLInteger here.
892         */

893         if (source == null)
894             source = new SQLInteger();
895
896         source.setValue(value);
897
898         return source;
899     }
900     /**
901      * Compute the encoded date given a date
902      *
903      */

904     private static int computeEncodedDate(java.util.Date JavaDoc value) throws StandardException
905     {
906         return computeEncodedDate( value, null);
907     }
908
909     static int computeEncodedDate(java.util.Date JavaDoc value, Calendar JavaDoc currentCal) throws StandardException
910     {
911         if (value == null)
912             return 0; //encoded dates have a 0 value for null
913
if( currentCal == null)
914             currentCal = new GregorianCalendar JavaDoc();
915         currentCal.setTime(value);
916         return SQLDate.computeEncodedDate(currentCal);
917     }
918
919
920         /**
921          * Implement the date SQL function: construct a SQL date from a string, number, or timestamp.
922          *
923          * @param operand Must be a date or a string convertible to a date.
924          * @param dvf the DataValueFactory
925          *
926          * @exception StandardException standard error policy
927          */

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 JavaDoc cal = new GregorianCalendar JavaDoc( 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 JavaDoc str = operand.getString();
957             if( str.length() == 7)
958             {
959                 // yyyyddd where ddd is the day of the year
960
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 JavaDoc cal = new GregorianCalendar JavaDoc( 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             // Else use the standard cast.
976
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     } // end of computeDateFunction
986

987     /** Adding this method to ensure that super class' setInto method doesn't get called
988       * that leads to the violation of JDBC spec( untyped nulls ) when batching is turned on.
989       */

990     public void setInto(PreparedStatement JavaDoc ps, int position) throws SQLException JavaDoc, StandardException {
991
992                   ps.setDate(position, getDate((Calendar JavaDoc) null));
993      }
994
995
996     /**
997      * Add a number of intervals to a datetime value. Implements the JDBC escape TIMESTAMPADD function.
998      *
999      * @param intervalType One of FRAC_SECOND_INTERVAL, SECOND_INTERVAL, MINUTE_INTERVAL, HOUR_INTERVAL,
1000     * DAY_INTERVAL, WEEK_INTERVAL, MONTH_INTERVAL, QUARTER_INTERVAL, or YEAR_INTERVAL
1001     * @param intervalCount The number of intervals to add
1002     * @param currentDate Used to convert time to timestamp
1003     * @param resultHolder If non-null a DateTimeDataValue that can be used to hold the result. If null then
1004     * generate a new holder
1005     *
1006     * @return startTime + intervalCount intervals, as a timestamp
1007     *
1008     * @exception StandardException
1009     */

1010    public DateTimeDataValue timestampAdd( int intervalType,
1011                                           NumberDataValue intervalCount,
1012                                           java.sql.Date JavaDoc 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    /**
1025     * Finds the difference between two datetime values as a number of intervals. Implements the JDBC
1026     * TIMESTAMPDIFF escape function.
1027     *
1028     * @param intervalType One of FRAC_SECOND_INTERVAL, SECOND_INTERVAL, MINUTE_INTERVAL, HOUR_INTERVAL,
1029     * DAY_INTERVAL, WEEK_INTERVAL, MONTH_INTERVAL, QUARTER_INTERVAL, or YEAR_INTERVAL
1030     * @param time1
1031     * @param currentDate Used to convert time to timestamp
1032     * @param resultHolder If non-null a NumberDataValue that can be used to hold the result. If null then
1033     * generate a new holder
1034     *
1035     * @return the number of intervals by which this datetime is greater than time1
1036     *
1037     * @exception StandardException
1038     */

1039    public NumberDataValue timestampDiff( int intervalType,
1040                                          DateTimeDataValue time1,
1041                                          java.sql.Date JavaDoc currentDate,
1042                                          NumberDataValue resultHolder)
1043        throws StandardException
1044    {
1045        return toTimestamp().timestampDiff( intervalType, time1, currentDate, resultHolder);
1046    }
1047}
1048
Popular Tags