2005-11-24 Chris Toshok <toshok@ximian.com>
[mono.git] / mcs / class / System.Data / System.Data.Common / DbConvert.cs
1 //\r
2 // System.Data.Common.DbConvert\r
3 //\r
4 // Author:\r
5 //   Boris Kirzner (borisk@mainsoft.com)\r
6 //\r
7 \r
8 using System;\r
9 \r
10 using java.io;\r
11 using java.sql;\r
12 \r
13 namespace System.Data.Common\r
14 {\r
15         internal class DbConvert\r
16         {\r
17                 #region Fields\r
18 \r
19                 const long JAVA_MIN_MILLIS_UTC = -62135769600000L; // java.sql.Timestamp.valueOf("0001-01-01 00:00:00.000000000").getTime() at Greenwich time zone.\r
20                 static readonly long TIMEZONE_RAW_OFFSET;\r
21                 // .NET milliseconds value of DateTime(1582,1,1,0,0,0,0).Ticks/TimeSpan.TicksPerMillisecond                     \r
22                 const long CLR_MILLIS_1582 = 49891507200000L;\r
23                 const long MILLIS_PER_TWO_DAYS = 2 * TimeSpan.TicksPerDay / TimeSpan.TicksPerMillisecond; // 172800000L;\r
24                 internal static readonly java.util.TimeZone DEFAULT_TIME_ZONE;\r
25 \r
26                 #endregion // Fields\r
27 \r
28                 #region Methods\r
29 \r
30                 static DbConvert()\r
31                 {\r
32                         DEFAULT_TIME_ZONE = java.util.SimpleTimeZone.getDefault();                      \r
33                         TIMEZONE_RAW_OFFSET = (long)DEFAULT_TIME_ZONE.getRawOffset();                                           \r
34                 }\r
35 \r
36                 // The diff between .Net and Java goes as the following:\r
37                 //  * at 1582: java has 10 days less than .net\r
38                 //  * below 1500 (exept 1200,800,400) : each 100'th year java adds 1 day over .net. \r
39                 // Current implementation compatible with .net in 1-99 and since 1582. In 100-1582 we're not compatible with .Ner nor with Java\r
40 \r
41                 internal static long JavaMillisToClrMillis(long javaMillis)\r
42                 {\r
43                         return JavaMillisToClrMillisUTC(javaMillis) + TIMEZONE_RAW_OFFSET;\r
44                 }\r
45 \r
46                 internal static long JavaMillisToClrMillisUTC(long javaMillis) {\r
47                         long clrMillis = javaMillis - JAVA_MIN_MILLIS_UTC;\r
48                         if (clrMillis > CLR_MILLIS_1582) {\r
49                                 clrMillis -= MILLIS_PER_TWO_DAYS;\r
50                         }\r
51                         return clrMillis;\r
52                 }\r
53 \r
54                 internal static long ClrMillisToJavaMillis(long clrMillis)\r
55                 {\r
56                         return ClrMillisToJavaMillisUTC(clrMillis) - TIMEZONE_RAW_OFFSET;\r
57                 }\r
58 \r
59                 internal static long ClrMillisToJavaMillisUTC(long clrMillis) {\r
60                         long javaMillis = clrMillis + JAVA_MIN_MILLIS_UTC;\r
61                         if (clrMillis > CLR_MILLIS_1582) {\r
62                                 javaMillis += MILLIS_PER_TWO_DAYS;\r
63                         }\r
64                         return javaMillis;\r
65                 }\r
66 \r
67                 internal static java.sql.Time ClrTicksToJavaTime(long ticks) {\r
68                         return new Time((ticks / TimeSpan.TicksPerMillisecond)\r
69                                 - DEFAULT_TIME_ZONE.getRawOffset());\r
70                 }\r
71 \r
72                 internal static java.sql.Date ClrTicksToJavaDate(long ticks) {\r
73                         java.sql.Date d = new java.sql.Date(0);\r
74                         ClrTicksToJavaDate(d, ticks);\r
75                         return d;\r
76                 }\r
77 \r
78                 internal static java.sql.Timestamp ClrTicksToJavaTimestamp(long ticks)\r
79                 {\r
80                         java.sql.Timestamp ts = new java.sql.Timestamp(0);\r
81                         ClrTicksToJavaDate(ts, ticks);\r
82 \r
83 //                      int nanos = (int)(ticks % TimeSpan.TicksPerMillisecond) * 100;\r
84 //                      ts.setNanos(javaTimestamp.getNanos() + nanos);\r
85 \r
86                         return ts;\r
87                 }\r
88 \r
89                 internal static void ClrTicksToJavaDate(java.util.Date d, long ticks) {\r
90                         long millis = ClrMillisToJavaMillis(ticks / TimeSpan.TicksPerMillisecond);\r
91 \r
92                         d.setTime(millis);\r
93                         if (DEFAULT_TIME_ZONE.inDaylightTime(d)) {\r
94                                 millis -= DEFAULT_TIME_ZONE.getDSTSavings();\r
95                                 d.setTime(millis);\r
96                         }\r
97                 }\r
98                 \r
99                 internal static long JavaTimestampToClrTicks(java.sql.Timestamp ts)\r
100                 {\r
101                         long ticks = JavaDateToClrTicks(ts);\r
102                         // Extra ticks, for dbs that can save them. \r
103                         // We do not use it, since .net does not saves ticks for fractial milliseconds\r
104                         // long ticksLessThanMilliseconds = (ts.getNanos()*100) % TimeSpan.TicksPerMillisecond;\r
105                         // ticks += ticksLessThanMilliseconds;\r
106                         \r
107                         return ticks;\r
108                 }\r
109 \r
110                 internal static long JavaDateToClrTicks(java.util.Date d) {\r
111                         long millis = JavaMillisToClrMillis(d.getTime());\r
112                         if (DEFAULT_TIME_ZONE.inDaylightTime(d)) {\r
113                                 millis += DEFAULT_TIME_ZONE.getDSTSavings();\r
114                         }\r
115                         return millis * TimeSpan.TicksPerMillisecond;\r
116                 }\r
117 \r
118                 internal static long JavaTimeToClrTicks(java.sql.Time t) {\r
119                         return (t.getTime() + DEFAULT_TIME_ZONE.getRawOffset())\r
120                                 * TimeSpan.TicksPerMillisecond;\r
121                 }\r
122 \r
123                 internal protected static Type JavaSqlTypeToClrType(int sqlTypeValue)\r
124                 {\r
125                         DbTypes.JavaSqlTypes sqlType = (DbTypes.JavaSqlTypes)sqlTypeValue;\r
126 \r
127                         switch (sqlType) {\r
128                                 case DbTypes.JavaSqlTypes.ARRAY : return typeof (java.sql.Array);\r
129                                 case DbTypes.JavaSqlTypes.BIGINT : return DbTypes.TypeOfInt64;\r
130                                 case DbTypes.JavaSqlTypes.BINARY : return DbTypes.TypeOfByteArray;\r
131                                 case DbTypes.JavaSqlTypes.BIT : return DbTypes.TypeOfBoolean;\r
132                                 case DbTypes.JavaSqlTypes.BLOB : return DbTypes.TypeOfByteArray;\r
133                                 case DbTypes.JavaSqlTypes.BOOLEAN : return DbTypes.TypeOfBoolean;\r
134                                 case DbTypes.JavaSqlTypes.CHAR : return DbTypes.TypeOfString;\r
135                                 case DbTypes.JavaSqlTypes.CLOB : return DbTypes.TypeOfString;\r
136 //                              case DbTypes.JavaSqlTypes.DATALINK :\r
137                                 case DbTypes.JavaSqlTypes.DATE : return DbTypes.TypeOfDateTime;\r
138                                 case DbTypes.JavaSqlTypes.DECIMAL : return DbTypes.TypeOfDecimal;\r
139 //                              case DbTypes.JavaSqlTypes.DISTINCT :\r
140                                 case DbTypes.JavaSqlTypes.DOUBLE : return DbTypes.TypeOfDouble;\r
141                                 case DbTypes.JavaSqlTypes.FLOAT : return DbTypes.TypeOfDouble;\r
142                                 case DbTypes.JavaSqlTypes.INTEGER : return DbTypes.TypeOfInt32;\r
143 //                              case DbTypes.JavaSqlTypes.JAVA_OBJECT :\r
144                                 case DbTypes.JavaSqlTypes.LONGVARBINARY : return DbTypes.TypeOfByteArray;\r
145                                 case DbTypes.JavaSqlTypes.LONGVARCHAR : return DbTypes.TypeOfString;\r
146                                 case DbTypes.JavaSqlTypes.NULL : return null;\r
147                                 case DbTypes.JavaSqlTypes.NUMERIC : return DbTypes.TypeOfDecimal;\r
148 //                              case DbTypes.JavaSqlTypes.OTHER :\r
149                                 case DbTypes.JavaSqlTypes.REAL : return DbTypes.TypeOfSingle;\r
150                                 case DbTypes.JavaSqlTypes.REF : return typeof (java.sql.Ref);\r
151                                 case DbTypes.JavaSqlTypes.SMALLINT : return DbTypes.TypeOfInt16;\r
152                                 case DbTypes.JavaSqlTypes.STRUCT : return typeof (java.sql.Struct);\r
153                                 case DbTypes.JavaSqlTypes.TIME : return DbTypes.TypeOfTimespan;\r
154                                 case DbTypes.JavaSqlTypes.TIMESTAMP : return DbTypes.TypeOfDateTime;\r
155                                 case DbTypes.JavaSqlTypes.TINYINT : return DbTypes.TypeOfByte;\r
156                                 case DbTypes.JavaSqlTypes.VARBINARY : return DbTypes.TypeOfByteArray;\r
157                                 case DbTypes.JavaSqlTypes.VARCHAR : return DbTypes.TypeOfString;\r
158                                 default : return DbTypes.TypeOfObject;\r
159                         }\r
160 \r
161                 }\r
162 \r
163 \r
164                 internal protected static object JavaResultSetToClrWrapper(CallableStatement results,int columnIndex,DbTypes.JavaSqlTypes javaSqlType,int maxLength ,ResultSetMetaData resultsMetaData)\r
165                 {\r
166                         object returnValue = null;      \r
167                         sbyte[] sbyteArray;\r
168                         long milliseconds;\r
169                         long ticks;\r
170                         string s;\r
171                         columnIndex++; //jdbc style\r
172                         switch (javaSqlType) {\r
173                                 case DbTypes.JavaSqlTypes.ARRAY :\r
174                                         returnValue = results.getArray(columnIndex);\r
175                                         break;\r
176                                 case DbTypes.JavaSqlTypes.BIGINT :\r
177                                         returnValue = results.getLong(columnIndex);\r
178                                         break;\r
179                                 case DbTypes.JavaSqlTypes.BINARY :\r
180                                 case DbTypes.JavaSqlTypes.VARBINARY :\r
181                                 case DbTypes.JavaSqlTypes.LONGVARBINARY :\r
182                                         // FIXME : comsider using maxLength\r
183                                         sbyteArray = results.getBytes(columnIndex);\r
184                                         if (sbyteArray != null) {\r
185                                                 returnValue = vmw.common.TypeUtils.ToByteArray(sbyteArray);\r
186                                         }\r
187                                         break;\r
188                                 case DbTypes.JavaSqlTypes.BIT :\r
189                                         returnValue = results.getBoolean(columnIndex);\r
190                                         break;\r
191                                 case DbTypes.JavaSqlTypes.BLOB :\r
192                                         // FIXME : comsider using maxLength\r
193                                         java.sql.Blob blob = results.getBlob(columnIndex);\r
194                                         if (blob != null) {\r
195                                                 InputStream input = blob.getBinaryStream();                                     \r
196                                                 if (input == null) {\r
197                                                         returnValue = new byte[0];\r
198                                                 }\r
199                                                 else {\r
200                                                         long length = blob.length();\r
201                                                         byte[] byteValue = new byte[length];\r
202                                                         sbyte[] sbyteValue = vmw.common.TypeUtils.ToSByteArray(byteValue);\r
203                                                         input.read(sbyteValue);\r
204                                                         returnValue = byteValue;\r
205                                                 }\r
206                                         }\r
207                                         break;  \r
208                                 case DbTypes.JavaSqlTypes.CHAR :                                                \r
209                                         if (resultsMetaData != null && "uniqueidentifier".Equals(resultsMetaData.getColumnTypeName(columnIndex))) {\r
210                                                 returnValue = new Guid(results.getString(columnIndex));\r
211                                         }\r
212                                         else {\r
213                                                 // Oracle Jdbc driver returns extra trailing 0 chars for NCHAR columns, so we threat this at parameter.Size level\r
214                                                 s = results.getString(columnIndex);\r
215                                                 if ((s != null) && (maxLength < s.Length)) {\r
216                                                         s = s.Substring(0,maxLength);\r
217                                                 }\r
218                                                 returnValue = s;\r
219                                         }\r
220                                         break;\r
221                                 case DbTypes.JavaSqlTypes.CLOB :\r
222                                         // FIXME : comsider using maxLength\r
223                                         java.sql.Clob clob = results.getClob(columnIndex);\r
224                                         if (clob != null) {\r
225                                                 java.io.Reader reader = clob.getCharacterStream();                                      \r
226                                                 if (reader == null) {\r
227                                                         returnValue = String.Empty;\r
228                                                 }\r
229                                                 else {\r
230                                                         long length = clob.length();\r
231                                                         char[] charValue = new char[length];\r
232                                                         reader.read(charValue);\r
233                                                         returnValue = new string(charValue);\r
234                                                 }\r
235                                         }\r
236                                         break;          \r
237                                 case DbTypes.JavaSqlTypes.TIME :\r
238                                         Time t = results.getTime(columnIndex);\r
239                                         if (t != null) {\r
240                                                 returnValue = new TimeSpan(JavaTimeToClrTicks(t));\r
241                                         }\r
242                                         break;  \r
243                                 case DbTypes.JavaSqlTypes.DATE :\r
244                                         Date d = results.getDate(columnIndex);\r
245                                         if (d != null) {\r
246                                                 returnValue = new DateTime(JavaDateToClrTicks(d));\r
247                                         }\r
248                                         break;\r
249                                 case DbTypes.JavaSqlTypes.TIMESTAMP :                           \r
250                                         Timestamp ts = results.getTimestamp(columnIndex);\r
251                                         if (ts != null) {\r
252                                                 returnValue = new DateTime(JavaTimestampToClrTicks(ts));\r
253                                         }\r
254                                         break;          \r
255                                 case DbTypes.JavaSqlTypes.DECIMAL :\r
256                                 case DbTypes.JavaSqlTypes.NUMERIC :\r
257                                         // java.sql.Types.NUMERIC (2), columnTypeName NUMBER, columnClassName java.math.BigDecimal \r
258                                         // therefore we rely on scale\r
259                                         if (resultsMetaData != null &&  resultsMetaData.getScale(columnIndex) == -127) {\r
260                                                 // Oracle db type FLOAT\r
261                                                 returnValue = results.getDouble(columnIndex);\r
262                                         }\r
263                                         else {\r
264                                                 java.math.BigDecimal bigDecimal = results.getBigDecimal(columnIndex);\r
265                                                 if (bigDecimal != null) {\r
266                                                         returnValue = vmw.common.PrimitiveTypeUtils.BigDecimalToDecimal(bigDecimal);\r
267                                                 }\r
268                                         }\r
269                                         break;          \r
270                                 case DbTypes.JavaSqlTypes.DISTINCT :\r
271                                         returnValue = results.getObject(columnIndex);\r
272                                         break;\r
273                                 case DbTypes.JavaSqlTypes.DOUBLE :\r
274                                         returnValue = results.getDouble(columnIndex);\r
275                                         break;\r
276                                 case DbTypes.JavaSqlTypes.FLOAT :\r
277                                         //float f = results.getFloat(columnIndex);\r
278                                         returnValue = results.getDouble(columnIndex);\r
279                                         break;\r
280                                 case DbTypes.JavaSqlTypes.INTEGER :\r
281                                         returnValue = results.getInt(columnIndex);\r
282                                         break;\r
283                                 case DbTypes.JavaSqlTypes.JAVA_OBJECT :\r
284                                         returnValue = results.getObject(columnIndex);\r
285                                         break;\r
286                                 case DbTypes.JavaSqlTypes.LONGVARCHAR :\r
287                                         returnValue = results.getString(columnIndex);\r
288                                         break;\r
289                                 case DbTypes.JavaSqlTypes.NULL :\r
290                                         returnValue = DBNull.Value;\r
291                                         break;\r
292                                 case DbTypes.JavaSqlTypes.OTHER :\r
293                                         returnValue = results.getObject(columnIndex);\r
294                                         break;\r
295                                 case DbTypes.JavaSqlTypes.REAL :\r
296                                         returnValue = results.getFloat(columnIndex);\r
297                                         break;\r
298                                 case DbTypes.JavaSqlTypes.REF :\r
299                                         returnValue = results.getRef(columnIndex);\r
300                                         break;\r
301                                 case DbTypes.JavaSqlTypes.SMALLINT :\r
302                                         returnValue = results.getShort(columnIndex);\r
303                                         break;\r
304                                 case DbTypes.JavaSqlTypes.STRUCT :\r
305                                         returnValue = results.getObject(columnIndex);\r
306                                         break;\r
307                                 case DbTypes.JavaSqlTypes.TINYINT :\r
308                                         returnValue = Convert.ToByte(results.getByte(columnIndex));\r
309                                         break;\r
310                                 case DbTypes.JavaSqlTypes.VARCHAR :\r
311                                         s = results.getString(columnIndex);\r
312                                         if ((s != null) && (maxLength < s.Length)) {\r
313                                                 s = s.Substring(0,maxLength);\r
314                                         }\r
315                                         returnValue = s;\r
316                                         break;\r
317                                 default :\r
318                                         returnValue = results.getObject(columnIndex);\r
319                                         break;\r
320                         }\r
321                                 \r
322                         if (results.wasNull() || results == null) {\r
323                                 return DBNull.Value;\r
324                         }                \r
325                         return  returnValue;\r
326                 }\r
327 \r
328                 #endregion // Methods\r
329         }\r
330 }\r