1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_connectivity.hxx"
26 #include <connectivity/dbconversion.hxx>
27 #include <connectivity/dbcharset.hxx>
28 #include <osl/diagnose.h>
29 #ifndef _INC_STDIO
30 #include <stdio.h>
31 #endif
32 #include <com/sun/star/sdbc/SQLException.hpp>
33 #include <com/sun/star/util/Date.hpp>
34 #include <com/sun/star/util/Time.hpp>
35 #include <com/sun/star/util/DateTime.hpp>
36 #include <rtl/ustrbuf.hxx>
37 
38 #define MAX_DAYS    3636532
39 
40 //.........................................................................
41 namespace dbtools
42 {
43 //.........................................................................
44 
45 
46     using namespace ::comphelper;
47     using namespace ::com::sun::star::uno;
48     using namespace ::com::sun::star::util;
49     using namespace ::com::sun::star::sdb;
50     using namespace ::com::sun::star::sdbc;
51     using namespace ::com::sun::star::lang;
52     using namespace ::com::sun::star::beans;
53 
54 
55     //------------------------------------------------------------------------------
getStandardDate()56     ::com::sun::star::util::Date DBTypeConversion::getStandardDate()
57     {
58         static ::com::sun::star::util::Date STANDARD_DB_DATE(1,1,1900);
59         return STANDARD_DB_DATE;
60     }
61     //------------------------------------------------------------------------------
toDateString(const Date & rDate)62     ::rtl::OUString DBTypeConversion::toDateString(const Date& rDate)
63     {
64         sal_Char s[11];
65         snprintf(s,
66                 sizeof(s),
67                 "%04d-%02d-%02d",
68                 (int)rDate.Year,
69                 (int)rDate.Month,
70                 (int)rDate.Day);
71         s[10] = 0;
72         return ::rtl::OUString::createFromAscii(s);
73     }
74     //------------------------------------------------------------------
toTimeString(const Time & rTime)75     ::rtl::OUString DBTypeConversion::toTimeString(const Time& rTime)
76     {
77         sal_Char s[9];
78         snprintf(s,
79                 sizeof(s),
80                 "%02d:%02d:%02d",
81                 (int)rTime.Hours,
82                 (int)rTime.Minutes,
83                 (int)rTime.Seconds);
84         s[8] = 0;
85         return ::rtl::OUString::createFromAscii(s);
86     }
87 
88     //------------------------------------------------------------------
toDateTimeString(const DateTime & _rDateTime)89     ::rtl::OUString DBTypeConversion::toDateTimeString(const DateTime& _rDateTime)
90     {
91         Date aDate(_rDateTime.Day,_rDateTime.Month,_rDateTime.Year);
92         ::rtl::OUStringBuffer aTemp(toDateString(aDate));
93         aTemp.appendAscii(" ");
94         Time aTime(0,_rDateTime.Seconds,_rDateTime.Minutes,_rDateTime.Hours);
95         aTemp.append( toTimeString(aTime) );
96         aTemp.appendAscii(".");
97         aTemp.append( static_cast<sal_Int32>(_rDateTime.HundredthSeconds));
98         return  aTemp.makeStringAndClear();
99     }
100     //------------------------------------------------------------------------------
toDate(sal_Int32 _nVal)101     Date DBTypeConversion::toDate(sal_Int32 _nVal)
102     {
103         Date aReturn;
104         aReturn.Day = (sal_uInt16)(_nVal % 100);
105         aReturn.Month = (sal_uInt16)((_nVal  / 100) % 100);
106         aReturn.Year = (sal_uInt16)(_nVal  / 10000);
107         return aReturn;
108     }
109 
110     //------------------------------------------------------------------------------
toTime(sal_Int32 _nVal)111     Time DBTypeConversion::toTime(sal_Int32 _nVal)
112     {
113         Time aReturn;
114         aReturn.Hours = (sal_uInt16)(((sal_uInt32)(_nVal >= 0 ? _nVal : _nVal*-1)) / 1000000);
115         aReturn.Minutes = (sal_uInt16)((((sal_uInt32)(_nVal >= 0 ? _nVal : _nVal*-1)) / 10000) % 100);
116         aReturn.Seconds = (sal_uInt16)((((sal_uInt32)(_nVal >= 0 ? _nVal : _nVal*-1)) / 100) % 100);
117         aReturn.HundredthSeconds = (sal_uInt16)(((sal_uInt32)(_nVal >= 0 ? _nVal : _nVal*-1)) % 100);
118         return aReturn;
119     }
120 
121     const double fMilliSecondsPerDay = 86400000.0;
122     //------------------------------------------------------------------------------
toINT32(const Date & rVal)123     sal_Int32 DBTypeConversion::toINT32(const Date& rVal)
124     {
125         return ((sal_Int32)(rVal.Day%100)) +
126             (((sal_Int32)(rVal.Month%100))*100) +
127             (((sal_Int32) rVal.Year%10000)*10000);
128     }
129 
130     //------------------------------------------------------------------------------
toINT32(const Time & rVal)131     sal_Int32 DBTypeConversion::toINT32(const Time& rVal)
132     {
133         // Zeit normalisieren
134         sal_Int32 nSeconds          = rVal.Seconds + rVal.HundredthSeconds / 100;
135         sal_Int32 nHundredthSeconds = rVal.HundredthSeconds % 100;
136         sal_Int32 nMinutes          = rVal.Minutes + nSeconds / 60;
137         nSeconds                    = nSeconds % 60;
138         sal_Int32 nHours            = rVal.Hours + nMinutes / 60;
139         nMinutes                    = nMinutes % 60;
140 
141         // Zeit zusammenbauen
142         return (sal_Int32)(nHundredthSeconds + (nSeconds*100) + (nMinutes*10000) + (nHours*1000000));
143     }
144 
145     //------------------------------------------------------------------------------
toINT64(const DateTime & rVal)146     sal_Int64 DBTypeConversion::toINT64(const DateTime& rVal)
147     {
148         // Zeit normalisieren
149         sal_Int32 nSeconds          = rVal.Seconds + rVal.HundredthSeconds / 100;
150         sal_Int32 nHundredthSeconds = rVal.HundredthSeconds % 100;
151         sal_Int32 nMinutes          = rVal.Minutes + nSeconds / 60;
152         nSeconds                    = nSeconds % 60;
153         sal_Int32 nHours            = rVal.Hours + nMinutes / 60;
154         nMinutes                    = nMinutes % 60;
155 
156         // Zeit zusammenbauen
157         sal_Int32 nTime = (sal_Int32)(nHundredthSeconds + (nSeconds*100) + (nMinutes*10000) + (nHours*1000000));
158         sal_Int32 nDate = ((sal_Int32)(rVal.Day%100)) + (((sal_Int32)(rVal.Month%100))*100) + (((sal_Int32) rVal.Year%10000)*10000);
159         sal_Int64 nRet;
160 
161         nRet = (sal_Int64) nTime;
162         nRet <<= 32;
163         nRet += nDate;
164 
165         return nRet;
166     }
167 
168     //------------------------------------------------------------------------------
getMsFromTime(const Time & rVal)169     sal_Int32 DBTypeConversion::getMsFromTime(const Time& rVal)
170     {
171         sal_Int32   nHour     = rVal.Hours;
172         sal_Int32   nMin      = rVal.Minutes;
173         sal_Int32   nSec      = rVal.Seconds;
174         sal_Int32   n100Sec   = rVal.HundredthSeconds;
175 
176         return ((nHour*3600000)+(nMin*60000)+(nSec*1000)+(n100Sec*10));
177     }
178 
179     //------------------------------------------------------------------------------
180     static sal_Int32 aDaysInMonth[12] = {   31, 28, 31, 30, 31, 30,
181                                             31, 31, 30, 31, 30, 31 };
182 
183     //------------------------------------------------------------------------------
implIsLeapYear(sal_Int32 _nYear)184     static sal_Bool implIsLeapYear(sal_Int32 _nYear)
185     {
186         return  (   (   ((_nYear % 4) == 0)
187                     &&  ((_nYear % 100) != 0)
188                     )
189                 )
190                 ||  ((_nYear % 400) == 0)
191                 ;
192     }
193 
194     //------------------------------------------------------------------------------
implDaysInMonth(sal_Int32 _nMonth,sal_Int32 _nYear)195     static sal_Int32 implDaysInMonth(sal_Int32 _nMonth, sal_Int32 _nYear)
196     {
197         OSL_ENSURE(_nMonth > 0 && _nMonth < 13,"Month as invalid value!");
198         if (_nMonth != 2)
199             return aDaysInMonth[_nMonth-1];
200         else
201         {
202             if (implIsLeapYear(_nYear))
203                 return aDaysInMonth[_nMonth-1] + 1;
204             else
205                 return aDaysInMonth[_nMonth-1];
206         }
207     }
208 
209     //------------------------------------------------------------------------------
implRelativeToAbsoluteNull(const Date & _rDate)210     static sal_Int32 implRelativeToAbsoluteNull(const Date& _rDate)
211     {
212         sal_Int32 nDays = 0;
213 
214         // ripped this code from the implementation of tools::Date
215         sal_Int32 nNormalizedYear = _rDate.Year - 1;
216         nDays = nNormalizedYear * 365;
217         // leap years
218         nDays += (nNormalizedYear / 4) - (nNormalizedYear / 100) + (nNormalizedYear / 400);
219 
220         for (sal_Int32 i = 1; i < _rDate.Month; ++i)
221             nDays += implDaysInMonth(i, _rDate.Year);
222 
223         nDays += _rDate.Day;
224         return nDays;
225     }
226     //------------------------------------------------------------------------------
implBuildFromRelative(sal_Int32 nDays,sal_uInt16 & rDay,sal_uInt16 & rMonth,sal_uInt16 & rYear)227     static void implBuildFromRelative( sal_Int32 nDays, sal_uInt16& rDay, sal_uInt16& rMonth, sal_uInt16& rYear)
228     {
229         sal_Int32   nTempDays;
230         sal_Int32   i = 0;
231         sal_Bool    bCalc;
232 
233         do
234         {
235             nTempDays = nDays;
236             rYear = (sal_uInt16)((nTempDays / 365) - i);
237             nTempDays -= (rYear-1) * 365;
238             nTempDays -= ((rYear-1) / 4) - ((rYear-1) / 100) + ((rYear-1) / 400);
239             bCalc = sal_False;
240             if ( nTempDays < 1 )
241             {
242                 i++;
243                 bCalc = sal_True;
244             }
245             else
246             {
247                 if ( nTempDays > 365 )
248                 {
249                     if ( (nTempDays != 366) || !implIsLeapYear( rYear ) )
250                     {
251                         i--;
252                         bCalc = sal_True;
253                     }
254                 }
255             }
256         }
257         while ( bCalc );
258 
259         rMonth = 1;
260         while ( nTempDays > implDaysInMonth( rMonth, rYear ) )
261         {
262             nTempDays -= implDaysInMonth( rMonth, rYear );
263             rMonth++;
264         }
265         rDay = (sal_uInt16)nTempDays;
266     }
267     //------------------------------------------------------------------------------
toDays(const Date & _rVal,const Date & _rNullDate)268     sal_Int32 DBTypeConversion::toDays(const Date& _rVal, const Date& _rNullDate)
269     {
270         return implRelativeToAbsoluteNull(_rVal) - implRelativeToAbsoluteNull(_rNullDate);
271     }
272 
273     //------------------------------------------------------------------------------
toDouble(const Date & rVal,const Date & _rNullDate)274     double DBTypeConversion::toDouble(const Date& rVal, const Date& _rNullDate)
275     {
276         return (double)toDays(rVal, _rNullDate);
277     }
278 
279     //------------------------------------------------------------------------------
toDouble(const Time & rVal)280     double DBTypeConversion::toDouble(const Time& rVal)
281     {
282         return (double)getMsFromTime(rVal) / fMilliSecondsPerDay;
283     }
284 
285     //------------------------------------------------------------------------------
toDouble(const DateTime & _rVal,const Date & _rNullDate)286     double DBTypeConversion::toDouble(const DateTime& _rVal, const Date& _rNullDate)
287     {
288         sal_Int64   nTime     = toDays(Date(_rVal.Day, _rVal.Month, _rVal.Year), _rNullDate);
289         Time aTimePart;
290 
291         aTimePart.Hours             = _rVal.Hours;
292         aTimePart.Minutes           = _rVal.Minutes;
293         aTimePart.Seconds           = _rVal.Seconds;
294         aTimePart.HundredthSeconds  = _rVal.HundredthSeconds;
295 
296         return ((double)nTime) + toDouble(aTimePart);
297     }
298     // -------------------------------------------------------------------------
addDays(sal_Int32 nDays,Date & _rDate)299     static void addDays(sal_Int32 nDays, Date& _rDate)
300     {
301         sal_Int32   nTempDays = implRelativeToAbsoluteNull( _rDate );
302 
303         nTempDays += nDays;
304         if ( nTempDays > MAX_DAYS )
305         {
306             _rDate.Day      = 31;
307             _rDate.Month    = 12;
308             _rDate.Year     = 9999;
309         }
310         else if ( nTempDays <= 0 )
311         {
312             _rDate.Day      = 1;
313             _rDate.Month    = 1;
314             _rDate.Year     = 00;
315         }
316         else
317             implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
318     }
319     // -----------------------------------------------------------------------
subDays(sal_Int32 nDays,Date & _rDate)320     static void subDays( sal_Int32 nDays, Date& _rDate )
321     {
322         sal_Int32   nTempDays = implRelativeToAbsoluteNull( _rDate );
323 
324         nTempDays -= nDays;
325         if ( nTempDays > MAX_DAYS )
326         {
327             _rDate.Day      = 31;
328             _rDate.Month    = 12;
329             _rDate.Year     = 9999;
330         }
331         else if ( nTempDays <= 0 )
332         {
333             _rDate.Day      = 1;
334             _rDate.Month    = 1;
335             _rDate.Year     = 00;
336         }
337         else
338             implBuildFromRelative( nTempDays, _rDate.Day, _rDate.Month, _rDate.Year );
339     }
340     // -------------------------------------------------------------------------
toDate(double dVal,const Date & _rNullDate)341     Date DBTypeConversion::toDate(double dVal, const Date& _rNullDate)
342     {
343         Date aRet = _rNullDate;
344 
345         if (dVal >= 0)
346             addDays((sal_Int32)dVal,aRet);
347         else
348             subDays((sal_uInt32)(-dVal),aRet);
349             //  x -= (sal_uInt32)(-nDays);
350 
351         return aRet;
352     }
353     // -------------------------------------------------------------------------
toTime(double dVal)354     Time DBTypeConversion::toTime(double dVal)
355     {
356         sal_Int32 nDays     = (sal_Int32)dVal;
357         sal_Int32 nMS = sal_Int32((dVal - (double)nDays) * fMilliSecondsPerDay + 0.5);
358 
359         sal_Int16 nSign;
360         if ( nMS < 0 )
361         {
362             nMS *= -1;
363             nSign = -1;
364         }
365         else
366             nSign = 1;
367 
368         Time xRet;
369         // Zeit normalisieren
370         // we have to sal_Int32 here because otherwise we get an overflow
371         sal_Int32 nHundredthSeconds = nMS/10;
372         sal_Int32 nSeconds          = nHundredthSeconds / 100;
373         sal_Int32 nMinutes          = nSeconds / 60;
374 
375         xRet.HundredthSeconds       = (sal_uInt16)(nHundredthSeconds % 100);
376         xRet.Seconds                = (sal_uInt16)(nSeconds % 60);
377         xRet.Hours                  = (sal_uInt16)(nMinutes / 60);
378         xRet.Minutes                = (sal_uInt16)(nMinutes % 60);
379 
380         // Zeit zusammenbauen
381         sal_Int32 nTime = (sal_Int32)(xRet.HundredthSeconds + (xRet.Seconds*100) + (xRet.Minutes*10000) + (xRet.Hours*1000000)) * nSign;
382 
383         if(nTime < 0)
384         {
385             xRet.HundredthSeconds   = 99;
386             xRet.Minutes            = 59;
387             xRet.Seconds            = 59;
388             xRet.Hours              = 23;
389         }
390         return xRet;
391     }
392     //------------------------------------------------------------------------------
toDateTime(double dVal,const Date & _rNullDate)393     DateTime DBTypeConversion::toDateTime(double dVal, const Date& _rNullDate)
394     {
395         Date aDate = toDate(dVal, _rNullDate);
396         Time aTime = toTime(dVal);
397 
398         DateTime xRet;
399 
400         xRet.Day                = aDate.Day;
401         xRet.Month              = aDate.Month;
402         xRet.Year               = aDate.Year;
403 
404         xRet.HundredthSeconds   = aTime.HundredthSeconds;
405         xRet.Minutes            = aTime.Minutes;
406         xRet.Seconds            = aTime.Seconds;
407         xRet.Hours              = aTime.Hours;
408 
409 
410         return xRet;
411     }
412     //------------------------------------------------------------------------------
toDate(const::rtl::OUString & _sSQLString)413     Date DBTypeConversion::toDate(const ::rtl::OUString& _sSQLString)
414     {
415         // get the token out of a string
416         static sal_Unicode sDateSep = '-';
417 
418         sal_Int32 nIndex    = 0;
419         sal_uInt16  nYear   = 0,
420                     nMonth  = 0,
421                     nDay    = 0;
422         nYear   = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
423         if(nIndex != -1)
424         {
425             nMonth = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
426             if(nIndex != -1)
427                 nDay = (sal_uInt16)_sSQLString.getToken(0,sDateSep,nIndex).toInt32();
428         }
429 
430         return Date(nDay,nMonth,nYear);
431     }
432 
433     //-----------------------------------------------------------------------------
toDateTime(const::rtl::OUString & _sSQLString)434     DateTime DBTypeConversion::toDateTime(const ::rtl::OUString& _sSQLString)
435     {
436         //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Timestamp.html#valueOf(java.lang.String)
437         //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Date.html#valueOf(java.lang.String)
438         //@see http://java.sun.com/j2se/1.4.2/docs/api/java/sql/Time.html#valueOf(java.lang.String)
439 
440         // the date part
441         Date aDate = toDate(_sSQLString);
442         Time aTime;
443         sal_Int32 nSeparation = _sSQLString.indexOf( ' ' );
444         if ( -1 != nSeparation )
445             aTime = toTime( _sSQLString.copy( nSeparation ) );
446 
447         return DateTime(aTime.HundredthSeconds,aTime.Seconds,aTime.Minutes,aTime.Hours,aDate.Day,aDate.Month,aDate.Year);
448     }
449 
450     //-----------------------------------------------------------------------------
toTime(const::rtl::OUString & _sSQLString)451     Time DBTypeConversion::toTime(const ::rtl::OUString& _sSQLString)
452     {
453         static sal_Unicode sTimeSep = ':';
454 
455         sal_Int32 nIndex    = 0;
456         sal_uInt16  nHour   = 0,
457                     nMinute = 0,
458                     nSecond = 0,
459                     nHundredthSeconds   = 0;
460         nHour   = (sal_uInt16)_sSQLString.getToken(0,sTimeSep,nIndex).toInt32();
461         if(nIndex != -1)
462         {
463             nMinute = (sal_uInt16)_sSQLString.getToken(0,sTimeSep,nIndex).toInt32();
464             if(nIndex != -1)
465             {
466                 nSecond = (sal_uInt16)_sSQLString.getToken(0,sTimeSep,nIndex).toInt32();
467                 nIndex = 0;
468                 ::rtl::OUString sNano(_sSQLString.getToken(1,'.',nIndex));
469                 if ( sNano.getLength() )
470                 {
471                     // our time struct only supports hundredth seconds
472                     sNano = sNano.copy(0,::std::min<sal_Int32>(sNano.getLength(),2));
473                     const static ::rtl::OUString s_Zeros(RTL_CONSTASCII_USTRINGPARAM("00"));
474                     sNano += s_Zeros.copy(0,s_Zeros.getLength() - sNano.getLength());
475                     nHundredthSeconds = static_cast<sal_uInt16>(sNano.toInt32());
476                 }
477             }
478         }
479         return Time(nHundredthSeconds,nSecond,nMinute,nHour);
480     }
481 
482 //.........................................................................
483 }   // namespace dbtools
484 //.........................................................................
485 
486 
487