[Cleanup] Removed JavaEE csproj and sln files
[mono-project.git] / mcs / class / System.Data / System.Data.ProviderBase.jvm / AbstractDataReader.cs
blob6b6978280a8a1f3b332052cf18d56b92f0cbeb66
1 //
2 // System.Data.Common.AbstractDataReader
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 //
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.
33 using System;
34 using System.Data;
35 using System.Collections;
36 using System.Data.Common;
38 using java.io;
39 using java.sql;
41 namespace System.Data.ProviderBase
43 public abstract class AbstractDataReader : DbDataReader, ISafeDataRecord {
45 #region Fields
47 private ResultSetMetaData _resultsMetaData;
48 protected AbstractDbCommand _command;
49 private DataTable _schemaTable;
50 private ReaderState _readerState = ReaderState.Uninitialized;
52 private IReaderCacheContainer[] _readerCache;
53 private int _currentCacheFilledPosition;
54 private Stack _resultSetStack = new Stack();
55 private bool _isClosed = false;
57 [Flags]
58 private enum ReaderState { Uninitialized = 0, Empty = 1, HasRows = 2, FirstRed = 4, Eof = 8, Fetching = 16 };
60 protected internal enum SCHEMA_TABLE { ColumnName,
61 ColumnOrdinal,
62 ColumnSize,
63 NumericPrecision,
64 NumericScale,
65 IsUnique,
66 IsKey,
67 BaseServerName,
68 BaseCatalogName,
69 BaseColumnName,
70 BaseSchemaName,
71 BaseTableName,
72 DataType,
73 AllowDBNull,
74 ProviderType,
75 IsAliased,
76 IsExpression,
77 IsIdentity,
78 IsAutoIncrement,
79 IsRowVersion,
80 IsHidden,
81 IsLong,
82 IsReadOnly};
84 #endregion // Fields
86 #region Constructors
88 protected AbstractDataReader(AbstractDbCommand command) {
89 _command = command;
90 if (_command.Connection != null) {
91 ((AbstractDBConnection)_command.Connection).AddReference(this);
95 #endregion // Constructors
97 #region Properties
99 public override int Depth {
100 get { return 0; }
103 public override bool HasRows {
104 get {
105 if (IsClosed) {
106 throw new InvalidOperationException("Invalid attempt to HasRows when reader is closed.");
109 try {
110 if(null == Results)
111 return false;
113 catch(SystemException) {
114 //suppress
115 return false;
118 return (_readerState & ReaderState.HasRows) != 0;
122 public override int RecordsAffected
124 // MSDN : The RecordsAffected property is not set
125 // until all rows are read and you close the reader.
126 get {
127 return _command.RecordsAffected;
131 public override int FieldCount
133 get {
134 if (ResultsMetaData == null)
135 return 0;
137 try {
138 return ResultsMetaData.getColumnCount();
140 catch (SQLException exp) {
141 throw CreateException(exp);
147 protected internal CommandBehavior Behavior
149 get {
150 return _command.Behavior;
154 public override Object this[String columnName]
156 get {
157 try {
158 int columnIndex = Results.findColumn(columnName) - 1;
159 return this[columnIndex];
161 catch (SQLException exp) {
162 throw new IndexOutOfRangeException(exp.Message, exp);
167 public override Object this[int columnIndex]
169 get { return GetValue(columnIndex); }
172 protected ResultSet Results
174 get {
175 if (_readerState == ReaderState.Uninitialized) {
177 if (_resultSetStack.Count == 0) {
178 ResultSet resultSet = _command.CurrentResultSet;
179 if (resultSet == null)
180 return null;
182 _resultSetStack.Push(resultSet);
185 _readerState = ReaderState.Fetching;
186 for (;;) {
187 try {
188 Configuration.BooleanSetting prefetchSchema = Configuration.Switches.PrefetchSchema;
190 if (prefetchSchema == Configuration.BooleanSetting.NotSet) {
191 AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);
192 string driverName = conn.JdbcConnection.getMetaData().getDriverName();
193 if (driverName.IndexOf("DB2", StringComparison.Ordinal) >= 0)
194 prefetchSchema = Configuration.BooleanSetting.True;
197 if (prefetchSchema == Configuration.BooleanSetting.True)
198 GetSchemaTable();
200 ResultSet resultSet = (ResultSet)_resultSetStack.Peek();
201 if (resultSet.next()) {
202 _readerState = (ReaderState.HasRows | ReaderState.FirstRed);
203 ResultSetMetaData rsMetaData = ResultsMetaData;
204 DbConvert.JavaSqlTypes javaSqlType = (DbConvert.JavaSqlTypes)rsMetaData.getColumnType(1);
205 if (javaSqlType == DbConvert.JavaSqlTypes.OTHER) {
206 object value = GetValue(0);
207 if (value != null && value is ResultSet) {
208 _resultsMetaData = null;
209 _readerCache = null;
210 SchemaTable = null;
211 _readerState = ReaderState.Fetching;
212 _resultSetStack.Push(value);
213 continue;
217 else
218 _readerState = ReaderState.Empty;
220 break;
222 catch(SQLException e) {
223 throw CreateException(e);
228 return (_resultSetStack.Count > 0) ? (ResultSet)_resultSetStack.Peek() : null;
232 protected ResultSetMetaData ResultsMetaData
234 get {
235 ResultSet results = Results;
236 if (results == null) {
237 return null;
239 if(_resultsMetaData == null) {
240 _resultsMetaData = results.getMetaData();
242 return _resultsMetaData;
246 protected DataTable SchemaTable
248 get {
249 if (_schemaTable == null) {
250 _schemaTable = ConstructSchemaTable();
252 return _schemaTable;
255 set {_schemaTable = value; }
258 internal protected IReaderCacheContainer[] ReaderCache
260 get {
261 if (_readerCache == null) {
262 _readerCache = CreateReaderCache();
263 _currentCacheFilledPosition = -1;
265 return _readerCache;
269 public override bool IsClosed {
270 get { return _isClosed; }
273 #endregion // Properties
275 #region Methods
277 protected abstract int GetProviderType(int jdbcType);
279 protected abstract SystemException CreateException(string message, SQLException e);
281 protected abstract SystemException CreateException(IOException e);
283 protected SystemException CreateException(SQLException e)
285 return CreateException(e.Message,e);
288 private bool CloseCurrentResultSet() {
289 if (_resultSetStack.Count > 0) {
290 try{
291 _resultsMetaData = null;
292 _readerCache = null;
293 _readerState = ReaderState.Uninitialized;
294 ResultSet rs = (ResultSet)_resultSetStack.Pop();
295 rs.close();
296 return true;
298 catch (SQLException exp) {
299 throw CreateException(exp);
303 return false;
306 // FIXME : add Close(bool readAllRecords) and pass this bool to skip looping over NextResult(), override AbstractDbCommand.ExecuteScalar
307 public override void Close()
309 if (IsClosed)
310 return;
312 try {
313 CloseCurrentResultSet();
314 _command.OnReaderClosed(this);
316 finally {
317 CloseInternal();
321 internal void CloseInternal()
323 _resultsMetaData = null;
324 _readerCache = null;
325 _isClosed = true;
328 public override IEnumerator GetEnumerator ()
330 bool closeReader = (Behavior & CommandBehavior.CloseConnection) != 0;
331 return new DbEnumerator (this , closeReader);
334 public override bool NextResult()
336 CloseCurrentResultSet();
338 if ((_command.Behavior & CommandBehavior.SingleResult) != 0) {
339 while (CloseCurrentResultSet());
340 while (_command.NextResultSet());
341 return false;
344 try {
345 while (_resultSetStack.Count > 0) {
346 ResultSet rs = (ResultSet)_resultSetStack.Peek();
348 if(!rs.next()) {
349 CloseCurrentResultSet();
350 continue;
353 // must be a ResultSet
354 object childRs = rs.getObject(1);
355 if (childRs != null) {
356 SchemaTable = null;
357 _resultSetStack.Push(childRs);
358 return true;
362 catch (SQLException exp) {
363 throw CreateException(exp);
366 if (_command.NextResultSet()) {
367 SchemaTable = null;
368 return true;
370 return false;
373 public override bool Read()
375 if(null == Results ||
376 (_readerState & (ReaderState.HasRows | ReaderState.Eof)) != ReaderState.HasRows)
377 return false;
379 bool firstRead = false;
381 try {
382 if ((_readerState & ReaderState.FirstRed) != 0) {
383 firstRead = true;
384 _readerState &= ~ReaderState.FirstRed;
385 return true;
387 else {
388 bool next = Results.next();
390 if (!next)
391 _readerState |= ReaderState.Eof;
393 return next;
396 catch (SQLException exp) {
397 // suppress exception as .Net does
398 return false;
400 finally {
401 // in case of first read we could sampled the first value
402 // to see whether there is a resultset, so _currentCacheFilledPosition
403 // might be already inited
404 if (!firstRead)
405 _currentCacheFilledPosition = -1;
409 public override bool GetBoolean(int columnIndex)
411 FillReaderCache(columnIndex);
412 return ((BooleanReaderCacheContainer)ReaderCache[columnIndex]).GetBoolean();
415 public bool GetBooleanSafe(int columnIndex)
417 if (ReaderCache[columnIndex] is BooleanReaderCacheContainer) {
418 return GetBoolean(columnIndex);
420 else {
421 return Convert.ToBoolean(GetValue(columnIndex));
425 public override byte GetByte(int columnIndex)
427 FillReaderCache(columnIndex);
428 return ((ByteReaderCacheContainer)ReaderCache[columnIndex]).GetByte();
431 public byte GetByteSafe(int columnIndex)
433 if (ReaderCache[columnIndex] is ByteReaderCacheContainer) {
434 return GetByte(columnIndex);
436 else {
437 return Convert.ToByte(GetValue(columnIndex));
441 public override long GetBytes(
442 int columnIndex,
443 long dataIndex,
444 byte[] buffer,
445 int bufferIndex,
446 int length)
448 FillReaderCache(columnIndex);
449 return ((BytesReaderCacheContainer)ReaderCache[columnIndex])
450 .GetBytes(dataIndex, buffer, bufferIndex, length);
453 public virtual byte[] GetBytes(int columnIndex)
455 FillReaderCache(columnIndex);
456 return ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();
459 public override char GetChar(int columnIndex)
461 FillReaderCache(columnIndex);
462 string s = ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();
463 if(s == null) {
464 return '\0';
466 return s[0];
469 public char GetCharSafe(int columnIndex)
471 if (ReaderCache[columnIndex] is StringReaderCacheContainer) {
472 return GetChar(columnIndex);
474 else {
475 return Convert.ToChar(GetValue(columnIndex));
479 public override long GetChars(
480 int columnIndex,
481 long dataIndex,
482 char[] buffer,
483 int bufferIndex,
484 int length)
486 FillReaderCache(columnIndex);
487 return ((CharsReaderCacheContainer)ReaderCache[columnIndex])
488 .GetChars(dataIndex, buffer, bufferIndex, length);
491 public override string GetDataTypeName(int columnIndex)
493 try {
494 if (ResultsMetaData == null) {
495 return String.Empty;
497 return ResultsMetaData.getColumnTypeName(columnIndex + 1);
499 catch (SQLException exp) {
500 throw CreateException(exp);
504 public override DateTime GetDateTime(int columnIndex)
506 return GetDateTimeUnsafe(columnIndex);
509 DateTime GetDateTimeUnsafe(int columnIndex)
511 FillReaderCache(columnIndex);
512 return ((DateTimeReaderCacheContainer)ReaderCache[columnIndex]).GetDateTime();
515 public DateTime GetDateTimeSafe(int columnIndex)
517 if (ReaderCache[columnIndex] is DateTimeReaderCacheContainer) {
518 return GetDateTimeUnsafe(columnIndex);
520 else {
521 return Convert.ToDateTime(GetValue(columnIndex));
525 public virtual TimeSpan GetTimeSpan(int columnIndex)
527 FillReaderCache(columnIndex);
528 return ((TimeSpanReaderCacheContainer)ReaderCache[columnIndex]).GetTimeSpan();
531 public override Guid GetGuid(int columnIndex)
533 FillReaderCache(columnIndex);
534 return ((GuidReaderCacheContainer)ReaderCache[columnIndex]).GetGuid();
537 public override decimal GetDecimal(int columnIndex)
539 return GetDecimalUnsafe(columnIndex);
542 decimal GetDecimalUnsafe(int columnIndex)
544 FillReaderCache(columnIndex);
545 return ((DecimalReaderCacheContainer)ReaderCache[columnIndex]).GetDecimal();
548 public decimal GetDecimalSafe(int columnIndex)
550 if (ReaderCache[columnIndex] is DecimalReaderCacheContainer) {
551 return GetDecimalUnsafe(columnIndex);
553 else {
554 return Convert.ToDecimal(GetValue(columnIndex));
558 public override double GetDouble(int columnIndex)
560 return GetDoubleUnsafe(columnIndex);
563 double GetDoubleUnsafe(int columnIndex)
565 FillReaderCache(columnIndex);
566 return ((DoubleReaderCacheContainer)ReaderCache[columnIndex]).GetDouble();
569 public double GetDoubleSafe(int columnIndex)
571 if (ReaderCache[columnIndex] is DoubleReaderCacheContainer) {
572 return GetDoubleUnsafe(columnIndex);
574 else {
575 return Convert.ToDouble(GetValue(columnIndex));
579 public override float GetFloat(int columnIndex)
581 return GetFloatUnsafe(columnIndex);
584 float GetFloatUnsafe(int columnIndex)
586 FillReaderCache(columnIndex);
587 return ((FloatReaderCacheContainer)ReaderCache[columnIndex]).GetFloat();
590 public float GetFloatSafe(int columnIndex)
592 if (ReaderCache[columnIndex] is FloatReaderCacheContainer) {
593 return GetFloatUnsafe(columnIndex);
595 else {
596 return Convert.ToSingle(GetValue(columnIndex));
600 public override short GetInt16(int columnIndex)
602 return GetInt16Unsafe(columnIndex);
605 short GetInt16Unsafe(int columnIndex)
607 FillReaderCache(columnIndex);
608 return ((Int16ReaderCacheContainer)ReaderCache[columnIndex]).GetInt16();
611 public short GetInt16Safe(int columnIndex)
613 if (ReaderCache[columnIndex] is Int16ReaderCacheContainer) {
614 return GetInt16Unsafe(columnIndex);
616 else {
617 return Convert.ToInt16(GetValue(columnIndex));
621 public override int GetInt32(int columnIndex)
623 return GetInt32Unsafe(columnIndex);
626 int GetInt32Unsafe(int columnIndex)
628 FillReaderCache(columnIndex);
629 return ((Int32ReaderCacheContainer)ReaderCache[columnIndex]).GetInt32();
632 public int GetInt32Safe(int columnIndex)
634 if (ReaderCache[columnIndex] is Int32ReaderCacheContainer) {
635 return GetInt32Unsafe(columnIndex);
637 else {
638 return Convert.ToInt32(GetValue(columnIndex));
642 public override long GetInt64(int columnIndex)
644 return GetInt64Unsafe(columnIndex);
647 long GetInt64Unsafe(int columnIndex)
649 FillReaderCache(columnIndex);
650 return ((Int64ReaderCacheContainer)ReaderCache[columnIndex]).GetInt64();
653 public long GetInt64Safe(int columnIndex)
655 if (ReaderCache[columnIndex] is Int64ReaderCacheContainer) {
656 return GetInt64Unsafe(columnIndex);
658 else {
659 return Convert.ToInt64(GetValue(columnIndex));
663 public override string GetName(int columnIndex)
665 try {
666 if (ResultsMetaData == null) {
667 return String.Empty;
669 return ResultsMetaData.getColumnName(columnIndex + 1);
671 catch (SQLException exp) {
672 throw new IndexOutOfRangeException(exp.Message, exp);
676 public override int GetOrdinal(String columnName)
678 try {
679 int retVal = Results.findColumn(columnName);
680 if(retVal != -1) {
681 retVal -= 1;
683 return retVal;
685 catch (SQLException exp) {
686 throw new IndexOutOfRangeException(exp.Message, exp);
690 public override string GetString(int columnIndex)
692 return GetStringUnsafe(columnIndex);
695 string GetStringUnsafe(int columnIndex)
697 FillReaderCache(columnIndex);
698 return ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();
701 public string GetStringSafe(int columnIndex) {
702 if (ReaderCache[columnIndex] is StringReaderCacheContainer) {
703 return GetStringUnsafe(columnIndex);
705 else {
706 return Convert.ToString(GetValue(columnIndex));
710 public override object GetValue(int columnIndex)
712 FillReaderCache(columnIndex);
713 if (ReaderCache[columnIndex].IsNull()) {
714 return DBNull.Value;
716 return ReaderCache[columnIndex].GetValue();
719 public override int GetValues(Object[] values)
721 int columnCount = FieldCount;
722 int i = 0;
723 for (; i < values.Length && i < columnCount; i++) {
724 values[i] = GetValue(i);
726 return i;
729 private void FillReaderCache(int columnIndex)
731 try {
732 IReaderCacheContainer[] readerCache = ReaderCache;
733 if ((Behavior & CommandBehavior.SequentialAccess) == 0) {
734 while (_currentCacheFilledPosition < columnIndex) {
735 _currentCacheFilledPosition++;
736 readerCache[_currentCacheFilledPosition].Fetch(Results,_currentCacheFilledPosition, false);
739 else {
740 readerCache[columnIndex].Fetch(Results,columnIndex, true);
743 catch(SQLException e) {
744 _currentCacheFilledPosition = -1;
745 throw CreateException(e);
747 catch (IOException e) {
748 _currentCacheFilledPosition = -1;
749 throw CreateException(e);
753 protected virtual IReaderCacheContainer CreateReaderCacheContainer(int jdbcType, int columnIndex) {
754 switch ((DbConvert.JavaSqlTypes)jdbcType) {
755 case DbConvert.JavaSqlTypes.ARRAY :
756 return new ArrayReaderCacheContainer();
757 case DbConvert.JavaSqlTypes.BIGINT :
758 return new Int64ReaderCacheContainer();
759 case DbConvert.JavaSqlTypes.BINARY :
760 case DbConvert.JavaSqlTypes.VARBINARY :
761 case DbConvert.JavaSqlTypes.LONGVARBINARY :
762 return new BytesReaderCacheContainer();
763 case DbConvert.JavaSqlTypes.BIT :
764 return new BooleanReaderCacheContainer();
765 case DbConvert.JavaSqlTypes.BLOB :
766 return new BlobReaderCacheContainer();
767 case DbConvert.JavaSqlTypes.VARCHAR:
768 case DbConvert.JavaSqlTypes.CHAR :
769 if (String.CompareOrdinal("uniqueidentifier", ResultsMetaData.getColumnTypeName(columnIndex)) == 0) {
770 return new GuidReaderCacheContainer();
772 else {
773 return new StringReaderCacheContainer();
775 case DbConvert.JavaSqlTypes.CLOB :
776 return new ClobReaderCacheContainer();
777 case DbConvert.JavaSqlTypes.TIME :
778 return new TimeSpanReaderCacheContainer();
779 case DbConvert.JavaSqlTypes.DATE :
780 AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);
781 string driverName = conn.JdbcConnection.getMetaData().getDriverName();
783 if (driverName.StartsWith("PostgreSQL")) {
784 return new DateTimeReaderCacheContainer();
786 else
787 goto case DbConvert.JavaSqlTypes.TIMESTAMP;
788 case DbConvert.JavaSqlTypes.TIMESTAMP :
789 return new TimestampReaderCacheContainer();
790 case DbConvert.JavaSqlTypes.DECIMAL :
791 case DbConvert.JavaSqlTypes.NUMERIC :
792 // jdbc driver for oracle identitfies both FLOAT and NUMBEr columns as
793 // java.sql.Types.NUMERIC (2), columnTypeName NUMBER, columnClassName java.math.BigDecimal
794 // therefore we relay on scale
795 int scale = ResultsMetaData.getScale(columnIndex);
796 if (scale == -127) {
797 // Oracle db type FLOAT
798 return new DoubleReaderCacheContainer();
800 else {
801 return new DecimalReaderCacheContainer();
803 case DbConvert.JavaSqlTypes.DOUBLE :
804 case DbConvert.JavaSqlTypes.FLOAT :
805 return new DoubleReaderCacheContainer();
806 case DbConvert.JavaSqlTypes.INTEGER :
807 return new Int32ReaderCacheContainer();
808 case DbConvert.JavaSqlTypes.LONGVARCHAR :
809 return new StringReaderCacheContainer();
810 case DbConvert.JavaSqlTypes.NULL :
811 return new NullReaderCacheContainer();
812 case DbConvert.JavaSqlTypes.REAL :
813 return new FloatReaderCacheContainer();
814 case DbConvert.JavaSqlTypes.REF :
815 return new RefReaderCacheContainer();
816 case DbConvert.JavaSqlTypes.SMALLINT :
817 return new Int16ReaderCacheContainer();
818 case DbConvert.JavaSqlTypes.TINYINT :
819 return new ByteReaderCacheContainer();
820 case DbConvert.JavaSqlTypes.DISTINCT :
821 case DbConvert.JavaSqlTypes.JAVA_OBJECT :
822 case DbConvert.JavaSqlTypes.OTHER :
823 case DbConvert.JavaSqlTypes.STRUCT :
824 default :
825 return new ObjectReaderCacheContainer();
829 private IReaderCacheContainer[] CreateReaderCache()
831 try {
832 IReaderCacheContainer[] readerCache = new IReaderCacheContainer[FieldCount];
833 for(int i=1; i <= readerCache.Length; i++)
834 readerCache[i-1] = CreateReaderCacheContainer(ResultsMetaData.getColumnType(i), i);
836 return readerCache;
838 catch(SQLException e) {
839 throw CreateException(e);
843 protected bool IsNumeric(int columnIndex)
845 return ReaderCache[columnIndex].IsNumeric();
848 public override bool IsDBNull(int columnIndex)
850 FillReaderCache(columnIndex);
851 return ReaderCache[columnIndex].IsNull();
854 public override Type GetFieldType(int i)
856 try {
857 int javaSqlType = ResultsMetaData.getColumnType(i + 1);
858 return DbConvert.JavaSqlTypeToClrType(javaSqlType);
860 catch (SQLException exp) {
861 throw new IndexOutOfRangeException(exp.Message, exp);
865 public IDataReader GetData(int i)
867 throw new NotSupportedException();
870 protected virtual void SetSchemaType(DataRow schemaRow, ResultSetMetaData metaData, int columnIndex) {
871 DbConvert.JavaSqlTypes columnType = (DbConvert.JavaSqlTypes)metaData.getColumnType(columnIndex);
873 switch (columnType) {
874 case DbConvert.JavaSqlTypes.ARRAY: {
875 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
876 schemaRow [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Array);
877 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
878 break;
880 case DbConvert.JavaSqlTypes.BIGINT: {
881 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
882 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt64;
883 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
884 break;
886 case DbConvert.JavaSqlTypes.BINARY: {
887 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
888 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
889 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
890 break;
892 case DbConvert.JavaSqlTypes.BIT: {
893 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
894 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfBoolean;
895 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
896 break;
898 case DbConvert.JavaSqlTypes.BLOB: {
899 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
900 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
901 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
902 break;
904 case DbConvert.JavaSqlTypes.VARCHAR:
905 case DbConvert.JavaSqlTypes.CHAR: {
906 // FIXME : specific for Microsoft SQl Server driver
907 if (String.CompareOrdinal(metaData.getColumnTypeName(columnIndex), "uniqueidentifier") == 0) {
908 schemaRow [(int)SCHEMA_TABLE.ProviderType] = DbType.Guid;
909 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfGuid;
910 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
912 else
913 if (String.CompareOrdinal(metaData.getColumnTypeName(columnIndex), "sql_variant") == 0) {
914 schemaRow [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;
915 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
916 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
918 else {
919 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
920 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
921 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
923 break;
925 case DbConvert.JavaSqlTypes.CLOB: {
926 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
927 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString; // instead og .java.sql.Clob
928 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
929 break;
931 case DbConvert.JavaSqlTypes.DATE: {
932 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
933 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;
934 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
935 break;
937 // else if(DbConvert.JavaSqlTypes.DISTINCT)
938 // {
939 // schemaRow ["ProviderType = (int)GetProviderType((int)columnType);
940 // schemaRow ["DataType = typeof (?);
941 // schemaRow ["IsLong = false;
942 // }
943 case DbConvert.JavaSqlTypes.DOUBLE: {
944 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
945 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble; // was typeof(float)
946 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
947 break;
949 case DbConvert.JavaSqlTypes.FLOAT: {
950 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
951 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble;
952 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
953 break;
955 case DbConvert.JavaSqlTypes.REAL: {
956 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
957 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfFloat;
958 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
959 break;
961 case DbConvert.JavaSqlTypes.INTEGER: {
962 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
963 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt32;
964 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
965 break;
967 case DbConvert.JavaSqlTypes.JAVA_OBJECT: {
968 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
969 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
970 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
971 break;
973 case DbConvert.JavaSqlTypes.LONGVARBINARY: {
974 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
975 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
976 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
977 break;
979 case DbConvert.JavaSqlTypes.LONGVARCHAR: {
980 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
981 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
982 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
983 break;
985 case DbConvert.JavaSqlTypes.DECIMAL:
986 case DbConvert.JavaSqlTypes.NUMERIC: {
987 int scale = ResultsMetaData.getScale(columnIndex);
988 if (scale == -127) {
989 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
990 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble;
991 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
993 else {
994 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
995 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;
996 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
998 break;
1000 case DbConvert.JavaSqlTypes.REF: {
1001 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1002 schemaRow [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Ref);
1003 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
1004 break;
1006 case DbConvert.JavaSqlTypes.SMALLINT: {
1007 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1008 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt16;
1009 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
1010 break;
1012 case DbConvert.JavaSqlTypes.STRUCT: {
1013 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1014 schemaRow [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Struct);
1015 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
1016 break;
1018 case DbConvert.JavaSqlTypes.TIME: {
1019 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1020 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfTimespan;
1021 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
1022 break;
1024 case DbConvert.JavaSqlTypes.TIMESTAMP: {
1025 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1026 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;
1027 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
1028 break;
1030 case DbConvert.JavaSqlTypes.TINYINT: {
1031 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1032 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByte;
1033 schemaRow [(int)SCHEMA_TABLE.IsLong] = false;
1034 break;
1036 case DbConvert.JavaSqlTypes.VARBINARY: {
1037 schemaRow [(int)SCHEMA_TABLE.ProviderType] = GetProviderType((int)columnType);
1038 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
1039 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
1040 break;
1042 default: {
1043 schemaRow [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;
1044 schemaRow [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
1045 schemaRow [(int)SCHEMA_TABLE.IsLong] = true;
1046 break;
1051 public override DataTable GetSchemaTable()
1053 if (SchemaTable.Rows != null && SchemaTable.Rows.Count > 0) {
1054 return SchemaTable;
1057 ResultSetMetaData metaData;
1058 if (Behavior == CommandBehavior.SchemaOnly) {
1059 try {
1060 metaData = ((PreparedStatement)_command.Statement).getMetaData();
1062 catch(SQLException e) {
1063 throw CreateException("CommandBehaviour.SchemaOnly is not supported by the JDBC driver.",e);
1066 else {
1067 metaData = ResultsMetaData;
1070 if (metaData == null) {
1071 return SchemaTable;
1074 DatabaseMetaData dbMetaData = null;
1075 AbstractDBConnection clonedConnection = null;
1076 if ((_command.Behavior & CommandBehavior.KeyInfo) != 0) {
1077 clonedConnection = (AbstractDBConnection)((ICloneable)_command.Connection).Clone();
1079 try {
1080 clonedConnection.Open();
1081 dbMetaData = clonedConnection.JdbcConnection.getMetaData();
1083 catch {
1084 //suppress
1085 if (clonedConnection != null) {
1086 clonedConnection.Close();
1091 try {
1092 int tmp;
1093 for(int i = 1; i <= metaData.getColumnCount(); i++) {
1094 DataRow row = SchemaTable.NewRow ();
1095 string columnName = metaData.getColumnLabel(i);
1096 string baseColumnName = metaData.getColumnName(i);
1098 row [(int)SCHEMA_TABLE.ColumnName] = columnName; // maybe we should use metaData.getColumnLabel(i);
1099 row [(int)SCHEMA_TABLE.ColumnSize] = metaData.getColumnDisplaySize(i);
1100 row [(int)SCHEMA_TABLE.ColumnOrdinal] = i - 1;
1101 try {
1102 // FIXME : workaround for Oracle JDBC driver bug
1103 // getPrecision on BLOB, CLOB, NCLOB throws NumberFormatException
1104 tmp = metaData.getPrecision(i);
1106 catch(java.lang.NumberFormatException e) {
1107 // supress exception
1108 tmp = 255;
1110 row [(int)SCHEMA_TABLE.NumericPrecision] = Convert.ToInt16(tmp > 255 ? 255 : tmp);
1111 tmp = metaData.getScale(i);
1112 row [(int)SCHEMA_TABLE.NumericScale] = Convert.ToInt16(tmp > 255 ? 255 : tmp);
1114 row [(int)SCHEMA_TABLE.BaseServerName] = DBNull.Value;
1116 string catalog = null;
1117 try {
1118 catalog = metaData.getCatalogName(i);
1120 catch (Exception e) {
1121 // supress exception
1123 if (catalog != null && catalog.Length == 0)
1124 catalog = ((AbstractDBConnection)_command.Connection).JdbcConnection.getCatalog();
1125 row [(int)SCHEMA_TABLE.BaseCatalogName] = catalog;
1126 row [(int)SCHEMA_TABLE.BaseColumnName] = baseColumnName;
1128 string schemaName;
1129 string tableName;
1131 try {
1132 tableName = metaData.getTableName(i);
1134 catch {
1135 tableName = null;
1138 try {
1139 schemaName = metaData.getSchemaName(i);
1141 catch {
1142 schemaName = null;
1145 if (tableName != null && tableName.Length == 0)
1146 tableName = null;
1147 if (schemaName != null && schemaName.Length == 0)
1148 schemaName = null;
1150 row [(int)SCHEMA_TABLE.BaseSchemaName] = schemaName;
1151 row [(int)SCHEMA_TABLE.BaseTableName] = tableName;
1154 row [(int)SCHEMA_TABLE.AllowDBNull] = Convert.ToBoolean(metaData.isNullable(i));
1156 InitKeyInfo(row, dbMetaData, catalog, schemaName, tableName);
1158 row [(int)SCHEMA_TABLE.IsAliased] = columnName != baseColumnName;
1159 row [(int)SCHEMA_TABLE.IsExpression] = false;
1161 row [(int)SCHEMA_TABLE.IsAutoIncrement] = metaData.isAutoIncrement(i);
1163 row [(int)SCHEMA_TABLE.IsHidden] = false;
1164 row [(int)SCHEMA_TABLE.IsReadOnly] = metaData.isReadOnly(i);
1166 SetSchemaType(row, metaData, i);
1168 SchemaTable.Rows.Add (row);
1171 catch (SQLException e) {
1172 throw CreateException(e);
1174 finally {
1175 if (clonedConnection != null) {
1176 clonedConnection.Close();
1179 return SchemaTable;
1182 private void InitKeyInfo(DataRow row, DatabaseMetaData dbMetaData, String catalog, String schema, String table) {
1183 string column = (string)row [(int)SCHEMA_TABLE.BaseColumnName];
1185 row [(int)SCHEMA_TABLE.IsUnique] = false;
1186 row [(int)SCHEMA_TABLE.IsKey] = false;
1187 row [(int)SCHEMA_TABLE.IsIdentity] = false;
1188 row [(int)SCHEMA_TABLE.IsRowVersion] = false;
1190 if ((_command.Behavior & CommandBehavior.KeyInfo) == 0)
1191 return;
1193 if(table == null || column == null || dbMetaData == null)
1194 return;
1196 ResultSet versionCol = dbMetaData.getVersionColumns(catalog, schema, table);
1197 try {
1198 while(versionCol.next()) {
1199 if(versionCol.getString("COLUMN_NAME") == column) {
1200 if (DatabaseMetaData__Finals.versionColumnPseudo == versionCol.getShort("PSEUDO_COLUMN")) {
1201 row [(int)SCHEMA_TABLE.IsIdentity] = true;
1202 row [(int)SCHEMA_TABLE.IsRowVersion] = true;
1207 finally {
1208 versionCol.close();
1211 ResultSet primaryKeys = dbMetaData.getPrimaryKeys(catalog,schema,table);
1212 bool primaryKeyExists = false;
1213 int columnCount = 0;
1214 try {
1215 while(primaryKeys.next()) {
1216 columnCount++;
1217 if(primaryKeys.getString("COLUMN_NAME") == column) {
1218 row [(int)SCHEMA_TABLE.IsKey] = true;
1219 primaryKeyExists = true;
1222 // column constitutes a key by itself, so it should be marked as unique
1223 if ((columnCount == 1) && (((bool)row [(int)SCHEMA_TABLE.IsKey]) == true)) {
1224 row [(int)SCHEMA_TABLE.IsUnique] = true;
1227 finally {
1228 primaryKeys.close();
1231 ResultSet indexInfoRes = dbMetaData.getIndexInfo(catalog,schema,table,true,false);
1232 string currentIndexName = null;
1233 columnCount = 0;
1234 bool belongsToCurrentIndex = false;
1235 bool atFirstIndex = true;
1236 bool uniqueKeyExists = false;
1237 try {
1238 while(indexInfoRes.next()) {
1239 if (indexInfoRes.getShort("TYPE") == DatabaseMetaData__Finals.tableIndexStatistic) {
1240 // index of type tableIndexStatistic identifies table statistics - ignore it
1241 continue;
1244 uniqueKeyExists = true;
1245 string iname = indexInfoRes.getString("INDEX_NAME");
1246 if (currentIndexName == iname) {
1247 // we're within the rows of the same index
1248 columnCount++;
1250 else {
1251 // we jump to row of new index
1252 if (belongsToCurrentIndex && columnCount == 1) {
1253 // there is a constraint of type UNIQUE that applies only to this column
1254 row [(int)SCHEMA_TABLE.IsUnique] = true;
1257 if (currentIndexName != null) {
1258 atFirstIndex = false;
1260 currentIndexName = iname;
1261 columnCount = 1;
1262 belongsToCurrentIndex = false;
1265 if(indexInfoRes.getString("COLUMN_NAME") == column) {
1266 // FIXME : this will cause "spare" columns marked as IsKey. Needs future investigation.
1267 // only the first index we met should be marked as a key
1268 //if (atFirstIndex) {
1269 row [(int)SCHEMA_TABLE.IsKey] = true;
1271 belongsToCurrentIndex = true;
1274 // the column appears in the last index, which is single-column
1275 if (belongsToCurrentIndex && columnCount == 1) {
1276 // there is a constraint of type UNIQUE that applies only to this column
1277 row [(int)SCHEMA_TABLE.IsUnique] = true;
1280 finally {
1281 indexInfoRes.close();
1284 if(!primaryKeyExists && !uniqueKeyExists) {
1285 ResultSet bestRowId = dbMetaData.getBestRowIdentifier(catalog, schema, table, DatabaseMetaData__Finals.bestRowTemporary, false);
1286 try {
1287 while(bestRowId.next()) {
1288 if(bestRowId.getString("COLUMN_NAME") == column)
1289 row [(int)SCHEMA_TABLE.IsKey] = true;
1292 finally {
1293 bestRowId.close();
1298 protected static DataTable ConstructSchemaTable ()
1300 Type booleanType = DbTypes.TypeOfBoolean;
1301 Type stringType = DbTypes.TypeOfString;
1302 Type intType = DbTypes.TypeOfInt32;
1303 Type typeType = DbTypes.TypeOfType;
1304 Type shortType = DbTypes.TypeOfInt16;
1306 DataTable schemaTable = new DataTable ("SchemaTable");
1307 schemaTable.Columns.Add ("ColumnName", stringType);
1308 schemaTable.Columns.Add ("ColumnOrdinal", intType);
1309 schemaTable.Columns.Add ("ColumnSize", intType);
1310 schemaTable.Columns.Add ("NumericPrecision", shortType);
1311 schemaTable.Columns.Add ("NumericScale", shortType);
1312 schemaTable.Columns.Add ("IsUnique", booleanType);
1313 schemaTable.Columns.Add ("IsKey", booleanType);
1314 schemaTable.Columns.Add ("BaseServerName", stringType);
1315 schemaTable.Columns.Add ("BaseCatalogName", stringType);
1316 schemaTable.Columns.Add ("BaseColumnName", stringType);
1317 schemaTable.Columns.Add ("BaseSchemaName", stringType);
1318 schemaTable.Columns.Add ("BaseTableName", stringType);
1319 schemaTable.Columns.Add ("DataType", typeType);
1320 schemaTable.Columns.Add ("AllowDBNull", booleanType);
1321 schemaTable.Columns.Add ("ProviderType", intType);
1322 schemaTable.Columns.Add ("IsAliased", booleanType);
1323 schemaTable.Columns.Add ("IsExpression", booleanType);
1324 schemaTable.Columns.Add ("IsIdentity", booleanType);
1325 schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
1326 schemaTable.Columns.Add ("IsRowVersion", booleanType);
1327 schemaTable.Columns.Add ("IsHidden", booleanType);
1328 schemaTable.Columns.Add ("IsLong", booleanType);
1329 schemaTable.Columns.Add ("IsReadOnly", booleanType);
1330 return schemaTable;
1333 #endregion // Methods