7a9f2b9d129c76315223fdf1c36e40bdaa97f684
[mono.git] / mcs / class / System.Data / System.Data.ProviderBase.jvm / AbstractDataReader.cs
1 //\r
2 // System.Data.Common.AbstractDataReader\r
3 //
4 // Authors:
5 //      Konstantin Triger <kostat@mainsoft.com>
6 //      Boris Kirzner <borisk@mainsoft.com>
7 //      
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
9 //
10
11 //
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
19 // 
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
22 // 
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 //\r
31 \r
32 \r
33 using System;\r
34 using System.Data;\r
35 using System.Collections;\r
36 using System.Data.ProviderBase;\r
37 \r
38 using java.io;\r
39 using java.sql;\r
40 \r
41 namespace System.Data.Common\r
42 {\r
43         public abstract class AbstractDataReader : DbDataReaderBase, ISafeDataRecord {\r
44 \r
45                 #region Fields\r
46 \r
47                 private ResultSetMetaData _resultsMetaData;\r
48                 protected AbstractDbCommand _command;\r
49                 private DataTable _schemaTable;\r
50                 private ReaderState _readerState = ReaderState.Uninitialized;\r
51 \r
52                 private IReaderCacheContainer[] _readerCache;\r
53                 private int _currentCacheFilledPosition; \r
54                 private Stack _resultSetStack = new Stack();\r
55                 private bool _isClosed = false;\r
56 \r
57                 [Flags]\r
58                 private enum ReaderState { Uninitialized = 0, Empty = 1, HasRows = 2, FirstRed = 4, Eof = 8, Fetching = 16 };\r
59 \r
60                 internal enum SCHEMA_TABLE { ColumnName,\r
61                         ColumnOrdinal,\r
62                         ColumnSize,\r
63                         NumericPrecision,\r
64                         NumericScale,\r
65                         IsUnique,\r
66                         IsKey,\r
67                         BaseServerName,\r
68                         BaseCatalogName,\r
69                         BaseColumnName,\r
70                         BaseSchemaName,\r
71                         BaseTableName,\r
72                         DataType,\r
73                         AllowDBNull,\r
74                         ProviderType,\r
75                         IsAliased,\r
76                         IsExpression,\r
77                         IsIdentity,\r
78                         IsAutoIncrement,\r
79                         IsRowVersion,\r
80                         IsHidden,\r
81                         IsLong,\r
82                         IsReadOnly};\r
83 \r
84                 #endregion // Fields\r
85 \r
86                 #region Constructors\r
87 \r
88                 protected AbstractDataReader() : base (CommandBehavior.Default) {\r
89                 }\r
90                 \r
91                 public AbstractDataReader(AbstractDbCommand command): base(command.Behavior) {\r
92                         _command = command;\r
93                         if (_command.Connection != null) {\r
94                                 ((AbstractDBConnection)_command.Connection).AddReference(this);\r
95                         }\r
96                 }\r
97 \r
98                 #endregion // Constructors\r
99 \r
100                 #region Properties\r
101 \r
102                 public override bool HasRows {\r
103                         get {\r
104                                 if (IsClosed) {\r
105                                         throw new InvalidOperationException("Invalid attempt to HasRows when reader is closed.");\r
106                                 }\r
107 \r
108                                 try {\r
109                                         if(null == Results)\r
110                                                 return false;\r
111                                 }\r
112                                 catch(SystemException) {\r
113                                         //suppress\r
114                                         return false;\r
115                                 }\r
116 \r
117                                 return (_readerState & ReaderState.HasRows) != 0;\r
118                         }\r
119                 }\r
120 \r
121                 public override int RecordsAffected\r
122                 {\r
123                         // MSDN : The RecordsAffected property is not set \r
124                         // until all rows are read and you close the reader.\r
125                         get { \r
126                                 return _command.RecordsAffected; \r
127                         }\r
128                 }\r
129 \r
130                 public override int FieldCount\r
131                 {\r
132                         get {\r
133                                 if (ResultsMetaData == null)\r
134                                         return 0;\r
135 \r
136                                 try {\r
137                                         return ResultsMetaData.getColumnCount();\r
138                                 }\r
139                                 catch (SQLException exp) {\r
140                                         throw CreateException(exp);\r
141                                 }\r
142 \r
143                         }\r
144                 }\r
145 \r
146                 protected internal CommandBehavior Behavior\r
147                 {\r
148                         get {\r
149                                 return _command.Behavior;\r
150                         }\r
151                 }\r
152 \r
153                 public override Object this[String columnName]\r
154                 {\r
155                         get {\r
156                                 try {\r
157                                         int columnIndex = Results.findColumn(columnName) - 1;\r
158                                         return this[columnIndex];\r
159                                 }\r
160                                 catch (SQLException exp) {\r
161                                         throw new IndexOutOfRangeException(exp.Message, exp);\r
162                                 }                               \r
163                         }\r
164                 }\r
165 \r
166                 public override Object this[int columnIndex]\r
167                 {\r
168                         get { return GetValue(columnIndex); }\r
169                 }\r
170 \r
171                 protected ResultSet Results\r
172                 {\r
173                         get {\r
174                                 if (_readerState == ReaderState.Uninitialized) {\r
175 \r
176                                         if (_resultSetStack.Count == 0) {\r
177                                                 ResultSet resultSet =  _command.CurrentResultSet;\r
178                                                 if (resultSet == null)\r
179                                                         return null;\r
180 \r
181                                                 _resultSetStack.Push(resultSet);\r
182                                         }\r
183 \r
184                                         _readerState = ReaderState.Fetching;\r
185                                         for (;;) {\r
186                                                 try {\r
187                                                         Configuration.BooleanSetting prefetchSchema = Configuration.Switches.PrefetchSchema;\r
188 \r
189                                                         if (prefetchSchema == Configuration.BooleanSetting.NotSet) {\r
190                                                                 AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);\r
191                                                                 string driverName = conn.JdbcConnection.getMetaData().getDriverName();\r
192                                                                 if (driverName.IndexOf("DB2") >= 0)\r
193                                                                         prefetchSchema = Configuration.BooleanSetting.True;\r
194                                                         }\r
195 \r
196                                                         if (prefetchSchema == Configuration.BooleanSetting.True)\r
197                                                                 GetSchemaTable();\r
198 \r
199                                                         ResultSet resultSet = (ResultSet)_resultSetStack.Peek();\r
200                                                         if (resultSet.next()) {\r
201                                                                 _readerState = (ReaderState.HasRows | ReaderState.FirstRed);\r
202                                                                 ResultSetMetaData rsMetaData = ResultsMetaData;\r
203                                                                 DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes)rsMetaData.getColumnType(1);\r
204                                                                 if (javaSqlType == DbTypes.JavaSqlTypes.OTHER) {\r
205                                                                         object value = GetValue(0);\r
206                                                                         if (value != null && value is ResultSet) {\r
207                                                                                 _resultsMetaData = null;\r
208                                                                                 _readerCache = null;\r
209                                                                                 SchemaTable = null;\r
210                                                                                 _readerState = ReaderState.Fetching;\r
211                                                                                 _resultSetStack.Push(value);\r
212                                                                                 continue;\r
213                                                                         }\r
214                                                                 }\r
215                                                         }\r
216                                                         else\r
217                                                                 _readerState = ReaderState.Empty;\r
218 \r
219                                                         break;\r
220                                                 }\r
221                                                 catch(SQLException e) {\r
222                                                         throw CreateException(e);\r
223                                                 }\r
224                                         }\r
225                                 }\r
226 \r
227                                 return (_resultSetStack.Count > 0) ? (ResultSet)_resultSetStack.Peek() : null;\r
228                         }\r
229                 }\r
230 \r
231                 protected ResultSetMetaData ResultsMetaData\r
232                 {\r
233                         get {\r
234                                 ResultSet results = Results;\r
235                                 if (results == null) {\r
236                                         return null;\r
237                                 }\r
238                                 if(_resultsMetaData == null) {\r
239                                         _resultsMetaData = results.getMetaData();\r
240                                 }\r
241                                 return _resultsMetaData;\r
242                         }                       \r
243                 }\r
244 \r
245                 protected DataTable SchemaTable\r
246                 {\r
247                         get {\r
248                                 if (_schemaTable == null) {\r
249                                         _schemaTable = ConstructSchemaTable();\r
250                                 }\r
251                                 return _schemaTable;\r
252                         }\r
253 \r
254                         set {_schemaTable = value; }\r
255                 }\r
256 \r
257                 internal protected IReaderCacheContainer[] ReaderCache\r
258                 {\r
259                         get {\r
260                                 if (_readerCache == null) {\r
261                                         _readerCache = CreateReaderCache();\r
262                                         _currentCacheFilledPosition = -1;\r
263                                 }\r
264                                 return _readerCache;\r
265                         }\r
266                 }\r
267
268                 public override bool IsClosed {\r
269                         get { return _isClosed; }\r
270                 }\r
271 \r
272                 #endregion // Properties\r
273 \r
274                 #region Methods\r
275 \r
276                 protected abstract int GetProviderType(int jdbcType);\r
277 \r
278                 protected abstract SystemException CreateException(string message, SQLException e);\r
279 \r
280                 protected abstract SystemException CreateException(IOException e);\r
281 \r
282                 protected SystemException CreateException(SQLException e)\r
283                 {\r
284                         return CreateException(e.Message,e);    \r
285                 }\r
286 \r
287                 private bool CloseCurrentResultSet() {\r
288                         if (_resultSetStack.Count > 0) {\r
289                                 try{\r
290                                         _resultsMetaData = null;\r
291                                         _readerCache = null;\r
292                                         _readerState = ReaderState.Uninitialized;\r
293                                         ResultSet rs = (ResultSet)_resultSetStack.Pop();\r
294                                         rs.close();\r
295                                         return true;\r
296                                 }\r
297                                 catch (SQLException exp) {\r
298                                         throw CreateException(exp);\r
299                                 }\r
300                         }\r
301 \r
302                         return false;\r
303                 }\r
304 \r
305                 // FIXME : add Close(bool readAllRecords) and pass this bool to skip looping over NextResult(), override AbstractDbCommand.ExecuteScalar\r
306                 public override void Close()\r
307                 {\r
308                         if (IsClosed)\r
309                                 return;\r
310 \r
311                         try {\r
312                                 CloseCurrentResultSet();\r
313                                 _command.OnReaderClosed(this);\r
314                         }\r
315                         finally {\r
316                                 CloseInternal();\r
317                         }\r
318                 }\r
319 \r
320                 internal void CloseInternal()\r
321                 {\r
322                         _resultsMetaData = null;\r
323                         _readerCache = null;\r
324                         _isClosed = true;\r
325                 }\r
326 \r
327                 public override bool NextResult()\r
328                 {\r
329                         CloseCurrentResultSet();\r
330 \r
331                         if ((_command.Behavior & CommandBehavior.SingleResult) != 0) {\r
332                                 while (CloseCurrentResultSet());\r
333                                 while (_command.NextResultSet());\r
334                                 return false;\r
335                         }\r
336 \r
337                         try {\r
338                                 while (_resultSetStack.Count > 0) {\r
339                                         ResultSet rs = (ResultSet)_resultSetStack.Peek();\r
340 \r
341                                         if(!rs.next()) {\r
342                                                 CloseCurrentResultSet();\r
343                                                 continue;\r
344                                         }\r
345 \r
346                                         // must be a ResultSet\r
347                                         object childRs = rs.getObject(1);\r
348                                         if (childRs != null) {\r
349                                                 SchemaTable = null;\r
350                                                 _resultSetStack.Push(childRs);\r
351                                                 return true;\r
352                                         }\r
353                                 }\r
354                         }\r
355                         catch (SQLException exp) {\r
356                                 throw CreateException(exp);\r
357                         }\r
358                                 \r
359                         if (_command.NextResultSet()) {\r
360                                 SchemaTable = null;     \r
361                                 return true;\r
362                         }\r
363                         return false;\r
364                 }\r
365 \r
366                 public override bool Read()\r
367                 {\r
368                         if(null == Results ||\r
369                                 (_readerState & (ReaderState.HasRows | ReaderState.Eof)) != ReaderState.HasRows)\r
370                                 return false;\r
371 \r
372                         bool firstRead = false;\r
373 \r
374                         try {\r
375                                 if ((_readerState & ReaderState.FirstRed) != 0) {\r
376                                         firstRead = true;\r
377                                         _readerState &= ~ReaderState.FirstRed;\r
378                                         return true;\r
379                                 }\r
380                                 else {\r
381                                         bool next = Results.next();\r
382 \r
383                                         if (!next)\r
384                                                 _readerState |= ReaderState.Eof;\r
385 \r
386                                         return next;\r
387                                 }\r
388                         }                       \r
389                         catch (SQLException exp) {\r
390                                 // suppress exception as .Net does\r
391                                 return false;\r
392                         }\r
393                         finally {\r
394                                 // in case of first read we could sampled the first value\r
395                                 // to see whether there is a resultset, so _currentCacheFilledPosition\r
396                                 // might be already inited\r
397                                 if (!firstRead)\r
398                                         _currentCacheFilledPosition = -1;\r
399                         }\r
400                 }\r
401 \r
402                 public override bool GetBoolean(int columnIndex)\r
403                 {\r
404                         FillReaderCache(columnIndex);\r
405                         return ((BooleanReaderCacheContainer)ReaderCache[columnIndex]).GetBoolean();\r
406                 }\r
407 \r
408                 public bool GetBooleanSafe(int columnIndex)\r
409                 {\r
410                         if (ReaderCache[columnIndex] is BooleanReaderCacheContainer) {\r
411                                 return GetBoolean(columnIndex);\r
412                         }\r
413                         else {\r
414                                 return Convert.ToBoolean(GetValue(columnIndex));\r
415                         }\r
416                 }\r
417 \r
418                 public override byte GetByte(int columnIndex)\r
419                 {\r
420                         FillReaderCache(columnIndex);\r
421                         return ((ByteReaderCacheContainer)ReaderCache[columnIndex]).GetByte();\r
422                 }\r
423 \r
424                 public byte GetByteSafe(int columnIndex)\r
425                 {\r
426                         if (ReaderCache[columnIndex] is ByteReaderCacheContainer) {\r
427                                 return GetByte(columnIndex);\r
428                         }\r
429                         else {\r
430                                 return Convert.ToByte(GetValue(columnIndex));\r
431                         }\r
432                 }\r
433 \r
434                 public override long GetBytes(\r
435                         int columnIndex,\r
436                         long dataIndex,\r
437                         byte[] buffer,\r
438                         int bufferIndex,\r
439                         int length)\r
440                 {\r
441                         FillReaderCache(columnIndex);\r
442                         byte[] byteArr = ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();\r
443                         long actualLength = ((dataIndex + length) >= byteArr.Length) ? (byteArr.Length - dataIndex) : length;\r
444                         Array.Copy(byteArr,dataIndex,buffer,bufferIndex,actualLength);\r
445                         return actualLength;\r
446                 }\r
447 \r
448                 public virtual byte[] GetBytes(int columnIndex)\r
449                 {\r
450                         FillReaderCache(columnIndex);\r
451                         return ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();\r
452                 }\r
453 \r
454                 public override char GetChar(int columnIndex)\r
455                 {\r
456                         FillReaderCache(columnIndex);\r
457                         string s = ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();\r
458                         if(s == null) {\r
459                                 return '\0';\r
460                         }\r
461                         return s[0];\r
462                 }\r
463 \r
464                 public char GetCharSafe(int columnIndex)\r
465                 {\r
466                         if (ReaderCache[columnIndex] is StringReaderCacheContainer) {\r
467                                 return GetChar(columnIndex);\r
468                         }\r
469                         else {\r
470                                 return Convert.ToChar(GetValue(columnIndex));\r
471                         }\r
472                 }\r
473 \r
474                 public override long GetChars(\r
475                         int columnIndex,\r
476                         long dataIndex,\r
477                         char[] buffer,\r
478                         int bufferIndex,\r
479                         int length)\r
480                 {\r
481                         FillReaderCache(columnIndex);\r
482                         char[] charArr = ((CharsReaderCacheContainer)ReaderCache[columnIndex]).GetChars();\r
483                         long actualLength = ((dataIndex + length) >= charArr.Length) ? (charArr.Length - dataIndex) : length;\r
484                         Array.Copy(charArr,dataIndex,buffer,bufferIndex,actualLength);\r
485                         return actualLength;\r
486                 }\r
487 \r
488                 public override string GetDataTypeName(int columnIndex)\r
489                 {\r
490                         try {\r
491                                 if (ResultsMetaData == null) {\r
492                                         return String.Empty;\r
493                                 }\r
494                                 return ResultsMetaData.getColumnTypeName(columnIndex + 1);\r
495                         }\r
496                         catch (SQLException exp) {\r
497                                 throw CreateException(exp);\r
498                         }\r
499                 }\r
500 \r
501                 public override DateTime GetDateTime(int columnIndex)\r
502                 {\r
503                         FillReaderCache(columnIndex);\r
504                         return ((DateTimeReaderCacheContainer)ReaderCache[columnIndex]).GetDateTime();\r
505                 }\r
506 \r
507                 public DateTime GetDateTimeSafe(int columnIndex)\r
508                 {\r
509                         if (ReaderCache[columnIndex] is DateTimeReaderCacheContainer) {\r
510                                 return GetDateTime(columnIndex);\r
511                         }\r
512                         else {\r
513                                 return Convert.ToDateTime(GetValue(columnIndex));\r
514                         }\r
515                 }\r
516 \r
517                 public virtual TimeSpan GetTimeSpan(int columnIndex)\r
518                 {\r
519                         FillReaderCache(columnIndex);\r
520                         return ((TimeSpanReaderCacheContainer)ReaderCache[columnIndex]).GetTimeSpan();\r
521                 }\r
522 \r
523                 public override Guid GetGuid(int columnIndex)\r
524                 {\r
525                         FillReaderCache(columnIndex);\r
526                         return ((GuidReaderCacheContainer)ReaderCache[columnIndex]).GetGuid();\r
527                 }\r
528 \r
529                 public override decimal GetDecimal(int columnIndex)\r
530                 {\r
531                         FillReaderCache(columnIndex);\r
532                         return ((DecimalReaderCacheContainer)ReaderCache[columnIndex]).GetDecimal();\r
533                 }\r
534 \r
535                 public decimal GetDecimalSafe(int columnIndex)\r
536                 {\r
537                         if (ReaderCache[columnIndex] is DecimalReaderCacheContainer) {\r
538                                 return GetDecimal(columnIndex);\r
539                         }\r
540                         else {\r
541                                 return Convert.ToDecimal(GetValue(columnIndex));\r
542                         }\r
543                 }\r
544 \r
545                 public override double GetDouble(int columnIndex)\r
546                 {\r
547                         FillReaderCache(columnIndex);\r
548                         return ((DoubleReaderCacheContainer)ReaderCache[columnIndex]).GetDouble();\r
549                 }\r
550 \r
551                 public double GetDoubleSafe(int columnIndex)\r
552                 {\r
553                         if (ReaderCache[columnIndex] is DoubleReaderCacheContainer) {\r
554                                 return GetDouble(columnIndex);\r
555                         }\r
556                         else {\r
557                                 return Convert.ToDouble(GetValue(columnIndex));\r
558                         }\r
559                 }\r
560 \r
561                 public override float GetFloat(int columnIndex)\r
562                 {\r
563                         FillReaderCache(columnIndex);\r
564                         return ((FloatReaderCacheContainer)ReaderCache[columnIndex]).GetFloat();\r
565                 }\r
566 \r
567                 public float GetFloatSafe(int columnIndex)\r
568                 {\r
569                         if (ReaderCache[columnIndex] is FloatReaderCacheContainer) {\r
570                                 return GetFloat(columnIndex);\r
571                         }\r
572                         else {\r
573                                 return Convert.ToSingle(GetValue(columnIndex));\r
574                         }\r
575                 }\r
576 \r
577                 public override short GetInt16(int columnIndex)\r
578                 {\r
579                         FillReaderCache(columnIndex);\r
580                         return ((Int16ReaderCacheContainer)ReaderCache[columnIndex]).GetInt16();\r
581                 }\r
582 \r
583                 public short GetInt16Safe(int columnIndex)\r
584                 {\r
585                         if (ReaderCache[columnIndex] is Int16ReaderCacheContainer) {\r
586                                 return GetInt16(columnIndex);\r
587                         }\r
588                         else {\r
589                                 return Convert.ToInt16(GetValue(columnIndex));\r
590                         }\r
591                 }\r
592 \r
593                 public override int GetInt32(int columnIndex)\r
594                 {\r
595                         FillReaderCache(columnIndex);\r
596                         return ((Int32ReaderCacheContainer)ReaderCache[columnIndex]).GetInt32();\r
597                 }\r
598 \r
599                 public int GetInt32Safe(int columnIndex)\r
600                 {\r
601                         if (ReaderCache[columnIndex] is Int32ReaderCacheContainer) {\r
602                                 return GetInt32(columnIndex);\r
603                         }\r
604                         else {\r
605                                 return Convert.ToInt32(GetValue(columnIndex));\r
606                         }\r
607                 }\r
608 \r
609                 public override long GetInt64(int columnIndex)\r
610                 {\r
611                         FillReaderCache(columnIndex);\r
612                         return ((Int64ReaderCacheContainer)ReaderCache[columnIndex]).GetInt64();\r
613                 }\r
614 \r
615                 public long GetInt64Safe(int columnIndex)\r
616                 {\r
617                         if (ReaderCache[columnIndex] is Int64ReaderCacheContainer) {\r
618                                 return GetInt64(columnIndex);\r
619                         }\r
620                         else {\r
621                                 return Convert.ToInt64(GetValue(columnIndex));\r
622                         }\r
623                 }\r
624 \r
625                 public override string GetName(int columnIndex)\r
626                 {\r
627                         try {\r
628                                 if (ResultsMetaData == null) {\r
629                                         return String.Empty;\r
630                                 }\r
631                                 return ResultsMetaData.getColumnName(columnIndex + 1);\r
632                         }\r
633                         catch (SQLException exp) {\r
634                                 throw new IndexOutOfRangeException(exp.Message, exp);\r
635                         }\r
636                 }\r
637 \r
638                 public override int GetOrdinal(String columnName)\r
639                 {\r
640                         try {\r
641                                 int retVal = Results.findColumn(columnName);\r
642                                 if(retVal != -1) {\r
643                                         retVal -= 1;\r
644                                 }\r
645                                 return  retVal;\r
646                         }\r
647                         catch (SQLException exp) {\r
648                                 throw new IndexOutOfRangeException(exp.Message, exp);\r
649                         }\r
650                 }\r
651 \r
652                 public override string GetString(int columnIndex)\r
653                 {\r
654                         FillReaderCache(columnIndex);\r
655                         return ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();\r
656                 }\r
657 \r
658                 public string GetStringSafe(int columnIndex) {\r
659                         if (ReaderCache[columnIndex] is StringReaderCacheContainer) {\r
660                                 return GetString(columnIndex);\r
661                         }\r
662                         else {\r
663                                 return Convert.ToString(GetValue(columnIndex));\r
664                         }\r
665                 }\r
666 \r
667                 public override object GetValue(int columnIndex)\r
668                 {\r
669                         FillReaderCache(columnIndex);\r
670                         if (ReaderCache[columnIndex].IsNull()) {\r
671                                 return DBNull.Value;\r
672                         }\r
673                         return ReaderCache[columnIndex].GetValue();\r
674                 }\r
675 \r
676                 public override int GetValues(Object[] values)\r
677                 {       \r
678                         int columnCount = FieldCount;\r
679                         int i = 0;\r
680                         for (; i < values.Length && i < columnCount; i++) {\r
681                                 values[i] = GetValue(i);\r
682                         }\r
683                         return i;\r
684                 }\r
685 \r
686                 private void FillReaderCache(int columnIndex)\r
687                 {\r
688                         try {\r
689                                 IReaderCacheContainer[] readerCache = ReaderCache;\r
690                                 if ((Behavior & CommandBehavior.SequentialAccess) == 0) {                                       \r
691                                         while (_currentCacheFilledPosition < columnIndex) {\r
692                                                 _currentCacheFilledPosition++;\r
693                                                 readerCache[_currentCacheFilledPosition].Fetch(Results,_currentCacheFilledPosition);\r
694                                         }                                       \r
695                                 }\r
696                                 else {\r
697                                         readerCache[columnIndex].Fetch(Results,columnIndex);\r
698                                 }\r
699                         }\r
700                         catch(SQLException e) {\r
701                                 _currentCacheFilledPosition = -1;\r
702                                 throw CreateException(e);\r
703                         }\r
704                         catch (IOException e) {\r
705                                 _currentCacheFilledPosition = -1;\r
706                                 throw CreateException(e);\r
707                         }\r
708                 }\r
709 \r
710                 private IReaderCacheContainer[] CreateReaderCache()\r
711                 {\r
712                         try {\r
713                                 IReaderCacheContainer[] readerCache = new IReaderCacheContainer[FieldCount];\r
714                                 for(int i=0; i < readerCache.Length; i++) {\r
715                                         DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes) ResultsMetaData.getColumnType(i + 1);\r
716                                         switch (javaSqlType) {\r
717                                                 case DbTypes.JavaSqlTypes.ARRAY :\r
718                                                         readerCache[i] = new ArrayReaderCacheContainer();\r
719                                                         break;\r
720                                                 case DbTypes.JavaSqlTypes.BIGINT :\r
721                                                         readerCache[i] = new Int64ReaderCacheContainer();\r
722                                                         break;\r
723                                                 case DbTypes.JavaSqlTypes.BINARY :\r
724                                                 case DbTypes.JavaSqlTypes.VARBINARY :\r
725                                                 case DbTypes.JavaSqlTypes.LONGVARBINARY :\r
726                                                         readerCache[i] = new BytesReaderCacheContainer();\r
727                                                         break;\r
728                                                 case DbTypes.JavaSqlTypes.BIT :\r
729                                                         readerCache[i] = new BooleanReaderCacheContainer();\r
730                                                         break;\r
731                                                 case DbTypes.JavaSqlTypes.BLOB :\r
732                                                         readerCache[i] = new BlobReaderCacheContainer();\r
733                                                         break;  \r
734                                                 case DbTypes.JavaSqlTypes.CHAR :                                                \r
735                                                         if ("uniqueidentifier".Equals(ResultsMetaData.getColumnTypeName(i + 1))) {\r
736                                                                 readerCache[i] = new GuidReaderCacheContainer();\r
737                                                         }\r
738                                                         else {\r
739                                                                 readerCache[i] = new StringReaderCacheContainer();\r
740                                                         }\r
741                                                         break;\r
742                                                 case DbTypes.JavaSqlTypes.CLOB :\r
743                                                         readerCache[i] = new ClobReaderCacheContainer();\r
744                                                         break;          \r
745                                                 case DbTypes.JavaSqlTypes.TIME :\r
746                                                         readerCache[i] = new TimeSpanReaderCacheContainer();\r
747                                                         break;  \r
748                                                 case DbTypes.JavaSqlTypes.DATE :\r
749                                                         AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);\r
750                                                         string driverName = conn.JdbcConnection.getMetaData().getDriverName();\r
751 \r
752                                                         if (driverName.StartsWith("PostgreSQL")) {\r
753                                                                 readerCache[i] = new DateTimeReaderCacheContainer();\r
754                                                                 break;\r
755                                                         }\r
756                                                         else\r
757                                                                 goto case DbTypes.JavaSqlTypes.TIMESTAMP;\r
758                                                 case DbTypes.JavaSqlTypes.TIMESTAMP :                           \r
759                                                         readerCache[i] = new TimestampReaderCacheContainer();\r
760                                                         break;          \r
761                                                 case DbTypes.JavaSqlTypes.DECIMAL :\r
762                                                 case DbTypes.JavaSqlTypes.NUMERIC :\r
763                                                         // jdbc driver for oracle identitfies both FLOAT and NUMBEr columns as \r
764                                                         // java.sql.Types.NUMERIC (2), columnTypeName NUMBER, columnClassName java.math.BigDecimal \r
765                                                         // therefore we relay on scale\r
766                                                         int scale = ResultsMetaData.getScale(i + 1);\r
767                                                         if (scale == -127) {\r
768                                                                 // Oracle db type FLOAT\r
769                                                                 readerCache[i] = new DoubleReaderCacheContainer();\r
770                                                         }\r
771                                                         else {\r
772                                                                 readerCache[i] = new DecimalReaderCacheContainer();\r
773                                                         }\r
774                                                         break;          \r
775                                                 case DbTypes.JavaSqlTypes.DOUBLE :\r
776                                                 case DbTypes.JavaSqlTypes.FLOAT :\r
777                                                         readerCache[i] = new DoubleReaderCacheContainer();\r
778                                                         break;\r
779                                                 case DbTypes.JavaSqlTypes.INTEGER :\r
780                                                         readerCache[i] = new Int32ReaderCacheContainer();\r
781                                                         break;\r
782                                                 case DbTypes.JavaSqlTypes.LONGVARCHAR :\r
783                                                 case DbTypes.JavaSqlTypes.VARCHAR :\r
784                                                         readerCache[i] = new StringReaderCacheContainer();\r
785                                                         break;\r
786                                                 case DbTypes.JavaSqlTypes.NULL :\r
787                                                         readerCache[i] = new NullReaderCacheContainer();\r
788                                                         break;\r
789                                                 case DbTypes.JavaSqlTypes.REAL :\r
790                                                         readerCache[i] = new FloatReaderCacheContainer();\r
791                                                         break;\r
792                                                 case DbTypes.JavaSqlTypes.REF :\r
793                                                         readerCache[i] = new RefReaderCacheContainer();\r
794                                                         break;\r
795                                                 case DbTypes.JavaSqlTypes.SMALLINT :\r
796                                                         readerCache[i] = new Int16ReaderCacheContainer();\r
797                                                         break;\r
798                                                 case DbTypes.JavaSqlTypes.TINYINT :\r
799                                                         readerCache[i] = new ByteReaderCacheContainer();\r
800                                                         break;\r
801                                                 case DbTypes.JavaSqlTypes.DISTINCT :\r
802                                                 case DbTypes.JavaSqlTypes.JAVA_OBJECT :\r
803                                                 case DbTypes.JavaSqlTypes.OTHER :\r
804                                                 case DbTypes.JavaSqlTypes.STRUCT :\r
805                                                 default :\r
806                                                         readerCache[i] = new ObjectReaderCacheContainer();\r
807                                                         break;\r
808                                         }\r
809                                         //                              ((ReaderCacheContainerBase)readerCache[i])._jdbcType = (int) javaSqlType;\r
810                                 }\r
811 \r
812                                 return readerCache;\r
813                         }\r
814                         catch(SQLException e) {\r
815                                 throw CreateException(e);\r
816                         }\r
817                 }\r
818 \r
819                 public override bool IsDBNull(int columnIndex)\r
820                 {\r
821                         FillReaderCache(columnIndex);\r
822                         return ReaderCache[columnIndex].IsNull();\r
823                 }\r
824 \r
825                 public override Type GetFieldType(int i)\r
826                 {\r
827                         try {\r
828                                 int javaSqlType = ResultsMetaData.getColumnType(i + 1);\r
829                                 return DbConvert.JavaSqlTypeToClrType(javaSqlType);\r
830                         }\r
831                         catch (SQLException exp) {\r
832                                 throw new IndexOutOfRangeException(exp.Message, exp);\r
833                         }\r
834                 }\r
835 \r
836                 public IDataReader GetData(int i)\r
837                 {\r
838                         throw new NotSupportedException();\r
839                 }\r
840 \r
841                 public override DataTable GetSchemaTable()\r
842                 {\r
843                         if (SchemaTable.Rows != null && SchemaTable.Rows.Count > 0) {\r
844                                 return SchemaTable;\r
845                         }\r
846             \r
847                         ResultSetMetaData metaData;                     \r
848                         if (Behavior == CommandBehavior.SchemaOnly) {\r
849                                 try {\r
850                                         metaData = ((PreparedStatement)_command.JdbcStatement).getMetaData();\r
851                                 }\r
852                                 catch(SQLException e) {\r
853                                         throw CreateException("CommandBehaviour.SchemaOnly is not supported by the JDBC driver.",e);\r
854                                 }\r
855                         }\r
856                         else {\r
857                                 metaData = ResultsMetaData;\r
858                         }\r
859 \r
860                         if (metaData == null) {\r
861                                 return SchemaTable;\r
862                         }\r
863 \r
864                         DatabaseMetaData dbMetaData = null;\r
865                         AbstractDBConnection clonedConnection = null;\r
866                         if ((_command.Behavior & CommandBehavior.KeyInfo) != 0) {\r
867                                 clonedConnection = (AbstractDBConnection)((ICloneable)_command.Connection).Clone();\r
868 \r
869                                 try {\r
870                                         clonedConnection.Open();\r
871                                         dbMetaData = clonedConnection.JdbcConnection.getMetaData();\r
872                                 }\r
873                                 catch {\r
874                                         //suppress\r
875                                         if (clonedConnection != null) {\r
876                                                 clonedConnection.Close();\r
877                                         }\r
878                                 }                       \r
879                         }\r
880                         \r
881                         try {\r
882                                 int tmp;                                \r
883                                 for(int i = 1; i <= metaData.getColumnCount(); i++) {\r
884                                         DataRow row = SchemaTable.NewRow ();\r
885                                         string columnName = metaData.getColumnLabel(i);\r
886                                         string baseColumnName = metaData.getColumnName(i);\r
887         \r
888                                         row [(int)SCHEMA_TABLE.ColumnName] = columnName; // maybe we should use metaData.getColumnLabel(i);\r
889                                         row [(int)SCHEMA_TABLE.ColumnSize] = metaData.getColumnDisplaySize(i);\r
890                                         row [(int)SCHEMA_TABLE.ColumnOrdinal]           = i - 1;\r
891                                         try {\r
892                                                 // FIXME : workaround for Oracle JDBC driver bug\r
893                                                 // getPrecision on BLOB, CLOB, NCLOB throws NumberFormatException\r
894                                                 tmp = metaData.getPrecision(i);\r
895                                         }\r
896                                         catch(java.lang.NumberFormatException e) {\r
897                                                 // supress exception\r
898                                                 tmp = 255;\r
899                                         }\r
900                                         row [(int)SCHEMA_TABLE.NumericPrecision] = Convert.ToInt16(tmp > 255 ? 255 : tmp);\r
901                                         tmp = metaData.getScale(i);\r
902                                         row [(int)SCHEMA_TABLE.NumericScale] = Convert.ToInt16(tmp > 255 ? 255 : tmp);\r
903 \r
904                                         row [(int)SCHEMA_TABLE.BaseServerName] = DBNull.Value;\r
905                                 \r
906                                         string catalog = null;\r
907                                         try {\r
908                                                 catalog = metaData.getCatalogName(i);\r
909                                         }\r
910                                         catch (Exception e) {\r
911                                                 // supress exception\r
912                                         }\r
913                                         if (catalog != null && catalog.Length == 0)\r
914                                                 catalog =  ((AbstractDBConnection)_command.Connection).JdbcConnection.getCatalog();\r
915                                         row [(int)SCHEMA_TABLE.BaseCatalogName] = catalog;\r
916                                         row [(int)SCHEMA_TABLE.BaseColumnName] = baseColumnName;\r
917 \r
918                                         string schemaName;\r
919                                         string tableName;\r
920 \r
921                                         try {\r
922                                                 tableName = metaData.getTableName(i);\r
923                                         }\r
924                                         catch {\r
925                                                 tableName = null;\r
926                                         }\r
927 \r
928                                         try {\r
929                                                 schemaName = metaData.getSchemaName(i);\r
930                                         }\r
931                                         catch {\r
932                                                 schemaName = null;\r
933                                         }\r
934 \r
935                                         if (tableName != null && tableName.Length == 0)\r
936                                                 tableName = null;\r
937                                         if (schemaName != null && schemaName.Length == 0)\r
938                                                 schemaName = null;\r
939 \r
940                                         row [(int)SCHEMA_TABLE.BaseSchemaName] = schemaName;\r
941                                         row [(int)SCHEMA_TABLE.BaseTableName] = tableName;\r
942 \r
943 \r
944                                         row [(int)SCHEMA_TABLE.AllowDBNull] = Convert.ToBoolean(metaData.isNullable(i));\r
945                                 \r
946                                         InitKeyInfo(row, dbMetaData, catalog, schemaName, tableName);\r
947                                 \r
948                                         row [(int)SCHEMA_TABLE.IsAliased] = columnName != baseColumnName;\r
949                                         row [(int)SCHEMA_TABLE.IsExpression] = false;\r
950 \r
951                                         row [(int)SCHEMA_TABLE.IsAutoIncrement] = metaData.isAutoIncrement(i);\r
952 \r
953                                         row [(int)SCHEMA_TABLE.IsHidden] = false;\r
954                                         row [(int)SCHEMA_TABLE.IsReadOnly] = metaData.isReadOnly(i);\r
955 \r
956                                         int columnType = metaData.getColumnType(i);\r
957                                         string columnTypeName = metaData.getColumnTypeName(i);\r
958                                         if(columnType == Types.ARRAY) {\r
959                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
960                                                 row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Array);\r
961                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
962                                         }\r
963                                         else if(columnType == Types.BIGINT) {\r
964                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
965                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt64;\r
966                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
967                                         }\r
968                                         else if(columnType == Types.BINARY) {\r
969                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
970                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;\r
971                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
972                                         }\r
973                                         else if(columnType == Types.BIT) {\r
974                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
975                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfBoolean;\r
976                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
977                                         }\r
978                                         else if(columnType == Types.BLOB) {\r
979                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
980                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;\r
981                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
982                                         }\r
983                                         else if(columnType == Types.CHAR) {\r
984                                                 // FIXME : specific for Microsoft SQl Server driver\r
985                                                 if (columnTypeName.Equals("uniqueidentifier")) {\r
986                                                         row [(int)SCHEMA_TABLE.ProviderType] = DbType.Guid;\r
987                                                         row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfGuid;\r
988                                                         row [(int)SCHEMA_TABLE.IsLong] = false;\r
989                                                 }\r
990                                                 else {\r
991                                                         row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
992                                                         row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;\r
993                                                         row [(int)SCHEMA_TABLE.IsLong] = false;\r
994                                                 }\r
995                                         }\r
996                                         else if(columnType == Types.CLOB) {\r
997                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
998                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString; // instead og .java.sql.Clob\r
999                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
1000                                         }\r
1001                                         else if(columnType == Types.DATE) {\r
1002                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1003                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;\r
1004                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1005                                         }\r
1006                                         else if(columnType == Types.DECIMAL) {\r
1007                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1008                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;\r
1009                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1010                                         }\r
1011                                                 //                else if(columnType == Types.DISTINCT)\r
1012                                                 //                {\r
1013                                                 //                    row ["ProviderType = (int)GetProviderType(columnType);\r
1014                                                 //                    row ["DataType = typeof (?);\r
1015                                                 //                    row ["IsLong = false;\r
1016                                                 //                }\r
1017                                         else if(columnType == Types.DOUBLE) {\r
1018                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1019                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble; // was typeof(float)\r
1020                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1021                                         }\r
1022                                         else if(columnType == Types.FLOAT) {\r
1023                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1024                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble;\r
1025                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1026                                         }\r
1027                                         else if(columnType == Types.REAL) {\r
1028                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1029                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfFloat;\r
1030                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1031                                         }\r
1032                                         else if(columnType == Types.INTEGER) {\r
1033                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1034                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt32;\r
1035                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1036                                         }\r
1037                                         else if(columnType == Types.JAVA_OBJECT) {\r
1038                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1039                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;\r
1040                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1041                                         }\r
1042                                         else if(columnType == Types.LONGVARBINARY) {\r
1043                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1044                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;\r
1045                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
1046                                         }\r
1047                                         else if(columnType == Types.LONGVARCHAR) {\r
1048                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1049                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;\r
1050                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
1051                                         }\r
1052                                         else if(columnType == Types.NUMERIC) {\r
1053                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1054                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;\r
1055                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1056                                         }\r
1057                                         else if(columnType == Types.REF) {\r
1058                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1059                                                 row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Ref);\r
1060                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
1061                                         }\r
1062                                         else if(columnType == Types.SMALLINT) {\r
1063                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1064                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt16;\r
1065                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1066                                         }\r
1067                                         else if(columnType == Types.STRUCT) {\r
1068                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1069                                                 row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Struct);\r
1070                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1071                                         }\r
1072                                         else if(columnType == Types.TIME) {\r
1073                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1074                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfTimespan;\r
1075                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1076                                         }\r
1077                                         else if(columnType == Types.TIMESTAMP) {\r
1078                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1079                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;\r
1080                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1081                                         }\r
1082                                         else if(columnType == Types.TINYINT) {\r
1083                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1084                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByte;\r
1085                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1086                                         }\r
1087                                         else if(columnType == Types.VARBINARY) {\r
1088                                                 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1089                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;\r
1090                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
1091                                         }\r
1092                                         else if(columnType == Types.VARCHAR) {\r
1093                                                 // FIXME : specific for Microsoft SQl Server driver\r
1094                                                 if (columnTypeName.Equals("sql_variant")) {\r
1095                                                         row [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;\r
1096                                                         row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;\r
1097                                                         row [(int)SCHEMA_TABLE.IsLong] = false;\r
1098                                                 }\r
1099                                                 else {\r
1100                                                         row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);\r
1101                                                         row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;// (char[]);\r
1102                                                         row [(int)SCHEMA_TABLE.IsLong] = false;//true;\r
1103                                                 }\r
1104                                         }\r
1105                                         else if(columnType == -8 && columnTypeName.Equals("ROWID")) {\r
1106                                                 // FIXME : specific for Oracle JDBC driver : OracleTypes.ROWID\r
1107                                                 row [(int)SCHEMA_TABLE.ProviderType] = DbType.String;\r
1108                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;\r
1109                                                 row [(int)SCHEMA_TABLE.IsLong] = false;\r
1110                                         }\r
1111                                         else {\r
1112                                                 row [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;\r
1113                                                 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;\r
1114                                                 row [(int)SCHEMA_TABLE.IsLong] = true;\r
1115                                         }\r
1116                                         SchemaTable.Rows.Add (row);\r
1117                                 }\r
1118                         }\r
1119                         catch (SQLException e) {                                \r
1120                                 throw CreateException(e);\r
1121                         }\r
1122                         finally {\r
1123                                 if (clonedConnection != null) {\r
1124                                         clonedConnection.Close();\r
1125                                 }\r
1126                         }                       \r
1127                         return SchemaTable;\r
1128                 }\r
1129 \r
1130                 private void InitKeyInfo(DataRow row, DatabaseMetaData dbMetaData, String catalog, String schema, String table) {\r
1131                         string column = (string)row [(int)SCHEMA_TABLE.BaseColumnName];\r
1132 \r
1133                         row [(int)SCHEMA_TABLE.IsUnique] = false;\r
1134                         row [(int)SCHEMA_TABLE.IsKey] = false;\r
1135                         row [(int)SCHEMA_TABLE.IsIdentity] = false;\r
1136                         row [(int)SCHEMA_TABLE.IsRowVersion] = false;\r
1137 \r
1138                         if ((_command.Behavior & CommandBehavior.KeyInfo) == 0)\r
1139                                 return;\r
1140 \r
1141                         if(table == null || column == null || dbMetaData == null)\r
1142                                 return;\r
1143 \r
1144                         ResultSet versionCol = dbMetaData.getVersionColumns(catalog, schema, table);\r
1145                         try {\r
1146                                 while(versionCol.next()) {\r
1147                                         if(versionCol.getString("COLUMN_NAME") == column) {\r
1148                                                 if (DatabaseMetaData__Finals.versionColumnPseudo == versionCol.getShort("PSEUDO_COLUMN")) {\r
1149                                                         row [(int)SCHEMA_TABLE.IsIdentity] = true;\r
1150                                                         row [(int)SCHEMA_TABLE.IsRowVersion] = true;\r
1151                                                 }\r
1152                                         }\r
1153                                 }\r
1154                         }\r
1155                         finally {\r
1156                                 versionCol.close();\r
1157                         }\r
1158 \r
1159                         ResultSet primaryKeys = dbMetaData.getPrimaryKeys(catalog,schema,table);\r
1160                         bool primaryKeyExists = false;\r
1161                         int columnCount = 0;\r
1162                         try {\r
1163                                 while(primaryKeys.next()) {\r
1164                                         columnCount++;\r
1165                                         if(primaryKeys.getString("COLUMN_NAME") == column) {\r
1166                                                 row [(int)SCHEMA_TABLE.IsKey] = true;\r
1167                                                 primaryKeyExists = true;\r
1168                                         }\r
1169                                 }\r
1170                                 // column constitutes a key by itself, so it should be marked as unique \r
1171                                 if ((columnCount == 1) && (((bool)row [(int)SCHEMA_TABLE.IsKey]) == true)) {\r
1172                                         row [(int)SCHEMA_TABLE.IsUnique] = true;\r
1173                                 }\r
1174                         }\r
1175                         finally {\r
1176                                 primaryKeys.close();\r
1177                         }\r
1178 \r
1179                         ResultSet indexInfoRes = dbMetaData.getIndexInfo(catalog,schema,table,true,false);\r
1180                         string currentIndexName = null;\r
1181                         columnCount = 0;\r
1182                         bool belongsToCurrentIndex = false;\r
1183                         bool atFirstIndex = true;\r
1184                         bool uniqueKeyExists = false;\r
1185                         try {\r
1186                                 while(indexInfoRes.next()) {\r
1187                                         if (indexInfoRes.getShort("TYPE") ==  DatabaseMetaData__Finals.tableIndexStatistic) {\r
1188                                                 // index of type tableIndexStatistic identifies table statistics - ignore it\r
1189                                                 continue;\r
1190                                         }\r
1191                                         \r
1192                                         uniqueKeyExists = true;\r
1193                                         string iname = indexInfoRes.getString("INDEX_NAME");\r
1194                                         if (currentIndexName == iname) {\r
1195                                                 // we're within the rows of the same index \r
1196                                                 columnCount++;\r
1197                                         }\r
1198                                         else {\r
1199                                                 // we jump to row of new index \r
1200                                                 if (belongsToCurrentIndex && columnCount == 1) {\r
1201                                                         // there is a constraint of type UNIQUE that applies only to this column\r
1202                                                         row [(int)SCHEMA_TABLE.IsUnique] = true;\r
1203                                                 }\r
1204 \r
1205                                                 if (currentIndexName != null) {\r
1206                                                         atFirstIndex = false;\r
1207                                                 }\r
1208                                                 currentIndexName = iname;\r
1209                                                 columnCount = 1;\r
1210                                                 belongsToCurrentIndex = false;\r
1211                                         }\r
1212 \r
1213                                         if(indexInfoRes.getString("COLUMN_NAME") == column) {\r
1214                                                 // FIXME : this will cause "spare" columns marked as IsKey. Needs future investigation.\r
1215                                                 // only the first index we met should be marked as a key\r
1216                                                 //if (atFirstIndex) {\r
1217                                                         row [(int)SCHEMA_TABLE.IsKey] = true;\r
1218                                                 //}\r
1219                                                 belongsToCurrentIndex = true;                                           \r
1220                                         }\r
1221                                 }\r
1222                                 // the column appears in the last index, which is single-column\r
1223                                 if (belongsToCurrentIndex && columnCount == 1) {\r
1224                                         // there is a constraint of type UNIQUE that applies only to this column\r
1225                                         row [(int)SCHEMA_TABLE.IsUnique] = true;\r
1226                                 }\r
1227                         }\r
1228                         finally {\r
1229                                 indexInfoRes.close();\r
1230                         }                       \r
1231 \r
1232                         if(!primaryKeyExists && !uniqueKeyExists) {\r
1233                                 ResultSet bestRowId = dbMetaData.getBestRowIdentifier(catalog, schema, table, DatabaseMetaData__Finals.bestRowTemporary, false);\r
1234                                 try {\r
1235                                         while(bestRowId.next()) {\r
1236                                                 if(bestRowId.getString("COLUMN_NAME") == column)\r
1237                                                         row [(int)SCHEMA_TABLE.IsKey] = true;\r
1238                                         }\r
1239                                 }\r
1240                                 finally {\r
1241                                         bestRowId.close();\r
1242                                 }\r
1243                         }\r
1244                 }\r
1245 \r
1246                 protected static DataTable ConstructSchemaTable ()\r
1247                 {\r
1248                         Type booleanType = DbTypes.TypeOfBoolean;\r
1249                         Type stringType = DbTypes.TypeOfString;\r
1250                         Type intType = DbTypes.TypeOfInt32;\r
1251                         Type typeType = DbTypes.TypeOfType;\r
1252                         Type shortType = DbTypes.TypeOfInt16;\r
1253 \r
1254                         DataTable schemaTable = new DataTable ("SchemaTable");\r
1255                         schemaTable.Columns.Add ("ColumnName", stringType);\r
1256                         schemaTable.Columns.Add ("ColumnOrdinal", intType);\r
1257                         schemaTable.Columns.Add ("ColumnSize", intType);\r
1258                         schemaTable.Columns.Add ("NumericPrecision", shortType);\r
1259                         schemaTable.Columns.Add ("NumericScale", shortType);\r
1260                         schemaTable.Columns.Add ("IsUnique", booleanType);\r
1261                         schemaTable.Columns.Add ("IsKey", booleanType);\r
1262                         schemaTable.Columns.Add ("BaseServerName", stringType);\r
1263                         schemaTable.Columns.Add ("BaseCatalogName", stringType);\r
1264                         schemaTable.Columns.Add ("BaseColumnName", stringType);\r
1265                         schemaTable.Columns.Add ("BaseSchemaName", stringType);\r
1266                         schemaTable.Columns.Add ("BaseTableName", stringType);\r
1267                         schemaTable.Columns.Add ("DataType", typeType);\r
1268                         schemaTable.Columns.Add ("AllowDBNull", booleanType);\r
1269                         schemaTable.Columns.Add ("ProviderType", intType);\r
1270                         schemaTable.Columns.Add ("IsAliased", booleanType);\r
1271                         schemaTable.Columns.Add ("IsExpression", booleanType);\r
1272                         schemaTable.Columns.Add ("IsIdentity", booleanType);\r
1273                         schemaTable.Columns.Add ("IsAutoIncrement", booleanType);\r
1274                         schemaTable.Columns.Add ("IsRowVersion", booleanType);\r
1275                         schemaTable.Columns.Add ("IsHidden", booleanType);\r
1276                         schemaTable.Columns.Add ("IsLong", booleanType);\r
1277                         schemaTable.Columns.Add ("IsReadOnly", booleanType);\r
1278                         return schemaTable;\r
1279                 }\r
1280 \r
1281                 #endregion // Methods\r
1282         }\r
1283 }