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