2 // System.Data.Common.AbstractDataReader
\r
5 // Konstantin Triger <kostat@mainsoft.com>
6 // Boris Kirzner <borisk@mainsoft.com>
8 // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com)
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:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
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.
35 using System.Collections;
\r
36 using System.Data.ProviderBase;
\r
41 namespace System.Data.Common
\r
43 public abstract class AbstractDataReader : DbDataReaderBase, ISafeDataRecord {
\r
47 private ResultSetMetaData _resultsMetaData;
\r
48 protected AbstractDbCommand _command;
\r
49 private DataTable _schemaTable;
\r
50 private ReaderState _readerState = ReaderState.Uninitialized;
\r
52 private IReaderCacheContainer[] _readerCache;
\r
53 private int _currentCacheFilledPosition;
\r
54 private Stack _resultSetStack = new Stack();
\r
55 private bool _isClosed = false;
\r
58 private enum ReaderState { Uninitialized = 0, Empty = 1, HasRows = 2, FirstRed = 4, Eof = 8, Fetching = 16 };
\r
60 internal enum SCHEMA_TABLE { ColumnName,
\r
84 #endregion // Fields
\r
86 #region Constructors
\r
88 protected AbstractDataReader() : base (CommandBehavior.Default) {
\r
91 public AbstractDataReader(AbstractDbCommand command): base(command.Behavior) {
\r
93 if (_command.Connection != null) {
\r
94 ((AbstractDBConnection)_command.Connection).AddReference(this);
\r
98 #endregion // Constructors
\r
102 public override bool HasRows {
\r
105 throw new InvalidOperationException("Invalid attempt to HasRows when reader is closed.");
\r
109 if(null == Results)
\r
112 catch(SystemException) {
\r
117 return (_readerState & ReaderState.HasRows) != 0;
\r
121 public override int RecordsAffected
\r
123 // MSDN : The RecordsAffected property is not set
\r
124 // until all rows are read and you close the reader.
\r
126 return _command.RecordsAffected;
\r
130 public override int FieldCount
\r
133 if (ResultsMetaData == null)
\r
137 return ResultsMetaData.getColumnCount();
\r
139 catch (SQLException exp) {
\r
140 throw CreateException(exp);
\r
146 protected internal CommandBehavior Behavior
\r
149 return _command.Behavior;
\r
153 public override Object this[String columnName]
\r
157 int columnIndex = Results.findColumn(columnName) - 1;
\r
158 return this[columnIndex];
\r
160 catch (SQLException exp) {
\r
161 throw new IndexOutOfRangeException(exp.Message, exp);
\r
166 public override Object this[int columnIndex]
\r
168 get { return GetValue(columnIndex); }
\r
171 protected ResultSet Results
\r
174 if (_readerState == ReaderState.Uninitialized) {
\r
176 if (_resultSetStack.Count == 0) {
\r
177 ResultSet resultSet = _command.CurrentResultSet;
\r
178 if (resultSet == null)
\r
181 _resultSetStack.Push(resultSet);
\r
184 _readerState = ReaderState.Fetching;
\r
187 Configuration.BooleanSetting prefetchSchema = Configuration.Switches.PrefetchSchema;
\r
189 if (prefetchSchema == Configuration.BooleanSetting.NotSet) {
\r
190 AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);
\r
191 string driverName = conn.JdbcConnection.getMetaData().getDriverName();
\r
192 if (driverName.IndexOf("DB2") >= 0)
\r
193 prefetchSchema = Configuration.BooleanSetting.True;
\r
196 if (prefetchSchema == Configuration.BooleanSetting.True)
\r
199 ResultSet resultSet = (ResultSet)_resultSetStack.Peek();
\r
200 if (resultSet.next()) {
\r
201 _readerState = (ReaderState.HasRows | ReaderState.FirstRed);
\r
202 ResultSetMetaData rsMetaData = ResultsMetaData;
\r
203 DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes)rsMetaData.getColumnType(1);
\r
204 if (javaSqlType == DbTypes.JavaSqlTypes.OTHER) {
\r
205 object value = GetValue(0);
\r
206 if (value != null && value is ResultSet) {
\r
207 _resultsMetaData = null;
\r
208 _readerCache = null;
\r
209 SchemaTable = null;
\r
210 _readerState = ReaderState.Fetching;
\r
211 _resultSetStack.Push(value);
\r
217 _readerState = ReaderState.Empty;
\r
221 catch(SQLException e) {
\r
222 throw CreateException(e);
\r
227 return (_resultSetStack.Count > 0) ? (ResultSet)_resultSetStack.Peek() : null;
\r
231 protected ResultSetMetaData ResultsMetaData
\r
234 ResultSet results = Results;
\r
235 if (results == null) {
\r
238 if(_resultsMetaData == null) {
\r
239 _resultsMetaData = results.getMetaData();
\r
241 return _resultsMetaData;
\r
245 protected DataTable SchemaTable
\r
248 if (_schemaTable == null) {
\r
249 _schemaTable = ConstructSchemaTable();
\r
251 return _schemaTable;
\r
254 set {_schemaTable = value; }
\r
257 internal protected IReaderCacheContainer[] ReaderCache
\r
260 if (_readerCache == null) {
\r
261 _readerCache = CreateReaderCache();
\r
262 _currentCacheFilledPosition = -1;
\r
264 return _readerCache;
\r
268 public override bool IsClosed {
\r
269 get { return _isClosed; }
\r
272 #endregion // Properties
\r
276 protected abstract int GetProviderType(int jdbcType);
\r
278 protected abstract SystemException CreateException(string message, SQLException e);
\r
280 protected abstract SystemException CreateException(IOException e);
\r
282 protected SystemException CreateException(SQLException e)
\r
284 return CreateException(e.Message,e);
\r
287 private bool CloseCurrentResultSet() {
\r
288 if (_resultSetStack.Count > 0) {
\r
290 _resultsMetaData = null;
\r
291 _readerCache = null;
\r
292 _readerState = ReaderState.Uninitialized;
\r
293 ResultSet rs = (ResultSet)_resultSetStack.Pop();
\r
297 catch (SQLException exp) {
\r
298 throw CreateException(exp);
\r
305 // FIXME : add Close(bool readAllRecords) and pass this bool to skip looping over NextResult(), override AbstractDbCommand.ExecuteScalar
\r
306 public override void Close()
\r
312 CloseCurrentResultSet();
\r
313 _command.OnReaderClosed(this);
\r
320 internal void CloseInternal()
\r
322 _resultsMetaData = null;
\r
323 _readerCache = null;
\r
327 public override bool NextResult()
\r
329 CloseCurrentResultSet();
\r
331 if ((_command.Behavior & CommandBehavior.SingleResult) != 0) {
\r
332 while (CloseCurrentResultSet());
\r
333 while (_command.NextResultSet());
\r
338 while (_resultSetStack.Count > 0) {
\r
339 ResultSet rs = (ResultSet)_resultSetStack.Peek();
\r
342 CloseCurrentResultSet();
\r
346 // must be a ResultSet
\r
347 object childRs = rs.getObject(1);
\r
348 if (childRs != null) {
\r
349 SchemaTable = null;
\r
350 _resultSetStack.Push(childRs);
\r
355 catch (SQLException exp) {
\r
356 throw CreateException(exp);
\r
359 if (_command.NextResultSet()) {
\r
360 SchemaTable = null;
\r
366 public override bool Read()
\r
368 if(null == Results ||
\r
369 (_readerState & (ReaderState.HasRows | ReaderState.Eof)) != ReaderState.HasRows)
\r
372 bool firstRead = false;
\r
375 if ((_readerState & ReaderState.FirstRed) != 0) {
\r
377 _readerState &= ~ReaderState.FirstRed;
\r
381 bool next = Results.next();
\r
384 _readerState |= ReaderState.Eof;
\r
389 catch (SQLException exp) {
\r
390 // suppress exception as .Net does
\r
394 // in case of first read we could sampled the first value
\r
395 // to see whether there is a resultset, so _currentCacheFilledPosition
\r
396 // might be already inited
\r
398 _currentCacheFilledPosition = -1;
\r
402 public override bool GetBoolean(int columnIndex)
\r
404 FillReaderCache(columnIndex);
\r
405 return ((BooleanReaderCacheContainer)ReaderCache[columnIndex]).GetBoolean();
\r
408 public bool GetBooleanSafe(int columnIndex)
\r
410 if (ReaderCache[columnIndex] is BooleanReaderCacheContainer) {
\r
411 return GetBoolean(columnIndex);
\r
414 return Convert.ToBoolean(GetValue(columnIndex));
\r
418 public override byte GetByte(int columnIndex)
\r
420 FillReaderCache(columnIndex);
\r
421 return ((ByteReaderCacheContainer)ReaderCache[columnIndex]).GetByte();
\r
424 public byte GetByteSafe(int columnIndex)
\r
426 if (ReaderCache[columnIndex] is ByteReaderCacheContainer) {
\r
427 return GetByte(columnIndex);
\r
430 return Convert.ToByte(GetValue(columnIndex));
\r
434 public override long GetBytes(
\r
441 FillReaderCache(columnIndex);
\r
442 byte[] byteArr = ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();
\r
443 if (byteArr == null)
\r
445 if (buffer == null)
\r
446 return byteArr.LongLength;
\r
447 long actualLength = ((dataIndex + length) >= byteArr.Length) ? (byteArr.Length - dataIndex) : length;
\r
448 Array.Copy(byteArr,dataIndex,buffer,bufferIndex,actualLength);
\r
449 return actualLength;
\r
452 public virtual byte[] GetBytes(int columnIndex)
\r
454 FillReaderCache(columnIndex);
\r
455 return ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();
\r
458 public override char GetChar(int columnIndex)
\r
460 FillReaderCache(columnIndex);
\r
461 string s = ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();
\r
468 public char GetCharSafe(int columnIndex)
\r
470 if (ReaderCache[columnIndex] is StringReaderCacheContainer) {
\r
471 return GetChar(columnIndex);
\r
474 return Convert.ToChar(GetValue(columnIndex));
\r
478 public override long GetChars(
\r
485 FillReaderCache(columnIndex);
\r
486 char[] charArr = ((CharsReaderCacheContainer)ReaderCache[columnIndex]).GetChars();
\r
487 long actualLength = ((dataIndex + length) >= charArr.Length) ? (charArr.Length - dataIndex) : length;
\r
488 Array.Copy(charArr,dataIndex,buffer,bufferIndex,actualLength);
\r
489 return actualLength;
\r
492 public override string GetDataTypeName(int columnIndex)
\r
495 if (ResultsMetaData == null) {
\r
496 return String.Empty;
\r
498 return ResultsMetaData.getColumnTypeName(columnIndex + 1);
\r
500 catch (SQLException exp) {
\r
501 throw CreateException(exp);
\r
505 public override DateTime GetDateTime(int columnIndex)
\r
507 FillReaderCache(columnIndex);
\r
508 return ((DateTimeReaderCacheContainer)ReaderCache[columnIndex]).GetDateTime();
\r
511 public DateTime GetDateTimeSafe(int columnIndex)
\r
513 if (ReaderCache[columnIndex] is DateTimeReaderCacheContainer) {
\r
514 return GetDateTime(columnIndex);
\r
517 return Convert.ToDateTime(GetValue(columnIndex));
\r
521 public virtual TimeSpan GetTimeSpan(int columnIndex)
\r
523 FillReaderCache(columnIndex);
\r
524 return ((TimeSpanReaderCacheContainer)ReaderCache[columnIndex]).GetTimeSpan();
\r
527 public override Guid GetGuid(int columnIndex)
\r
529 FillReaderCache(columnIndex);
\r
530 return ((GuidReaderCacheContainer)ReaderCache[columnIndex]).GetGuid();
\r
533 public override decimal GetDecimal(int columnIndex)
\r
535 FillReaderCache(columnIndex);
\r
536 return ((DecimalReaderCacheContainer)ReaderCache[columnIndex]).GetDecimal();
\r
539 public decimal GetDecimalSafe(int columnIndex)
\r
541 if (ReaderCache[columnIndex] is DecimalReaderCacheContainer) {
\r
542 return GetDecimal(columnIndex);
\r
545 return Convert.ToDecimal(GetValue(columnIndex));
\r
549 public override double GetDouble(int columnIndex)
\r
551 FillReaderCache(columnIndex);
\r
552 return ((DoubleReaderCacheContainer)ReaderCache[columnIndex]).GetDouble();
\r
555 public double GetDoubleSafe(int columnIndex)
\r
557 if (ReaderCache[columnIndex] is DoubleReaderCacheContainer) {
\r
558 return GetDouble(columnIndex);
\r
561 return Convert.ToDouble(GetValue(columnIndex));
\r
565 public override float GetFloat(int columnIndex)
\r
567 FillReaderCache(columnIndex);
\r
568 return ((FloatReaderCacheContainer)ReaderCache[columnIndex]).GetFloat();
\r
571 public float GetFloatSafe(int columnIndex)
\r
573 if (ReaderCache[columnIndex] is FloatReaderCacheContainer) {
\r
574 return GetFloat(columnIndex);
\r
577 return Convert.ToSingle(GetValue(columnIndex));
\r
581 public override short GetInt16(int columnIndex)
\r
583 FillReaderCache(columnIndex);
\r
584 return ((Int16ReaderCacheContainer)ReaderCache[columnIndex]).GetInt16();
\r
587 public short GetInt16Safe(int columnIndex)
\r
589 if (ReaderCache[columnIndex] is Int16ReaderCacheContainer) {
\r
590 return GetInt16(columnIndex);
\r
593 return Convert.ToInt16(GetValue(columnIndex));
\r
597 public override int GetInt32(int columnIndex)
\r
599 FillReaderCache(columnIndex);
\r
600 return ((Int32ReaderCacheContainer)ReaderCache[columnIndex]).GetInt32();
\r
603 public int GetInt32Safe(int columnIndex)
\r
605 if (ReaderCache[columnIndex] is Int32ReaderCacheContainer) {
\r
606 return GetInt32(columnIndex);
\r
609 return Convert.ToInt32(GetValue(columnIndex));
\r
613 public override long GetInt64(int columnIndex)
\r
615 FillReaderCache(columnIndex);
\r
616 return ((Int64ReaderCacheContainer)ReaderCache[columnIndex]).GetInt64();
\r
619 public long GetInt64Safe(int columnIndex)
\r
621 if (ReaderCache[columnIndex] is Int64ReaderCacheContainer) {
\r
622 return GetInt64(columnIndex);
\r
625 return Convert.ToInt64(GetValue(columnIndex));
\r
629 public override string GetName(int columnIndex)
\r
632 if (ResultsMetaData == null) {
\r
633 return String.Empty;
\r
635 return ResultsMetaData.getColumnName(columnIndex + 1);
\r
637 catch (SQLException exp) {
\r
638 throw new IndexOutOfRangeException(exp.Message, exp);
\r
642 public override int GetOrdinal(String columnName)
\r
645 int retVal = Results.findColumn(columnName);
\r
651 catch (SQLException exp) {
\r
652 throw new IndexOutOfRangeException(exp.Message, exp);
\r
656 public override string GetString(int columnIndex)
\r
658 FillReaderCache(columnIndex);
\r
659 return ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();
\r
662 public string GetStringSafe(int columnIndex) {
\r
663 if (ReaderCache[columnIndex] is StringReaderCacheContainer) {
\r
664 return GetString(columnIndex);
\r
667 return Convert.ToString(GetValue(columnIndex));
\r
671 public override object GetValue(int columnIndex)
\r
673 FillReaderCache(columnIndex);
\r
674 if (ReaderCache[columnIndex].IsNull()) {
\r
675 return DBNull.Value;
\r
677 return ReaderCache[columnIndex].GetValue();
\r
680 public override int GetValues(Object[] values)
\r
682 int columnCount = FieldCount;
\r
684 for (; i < values.Length && i < columnCount; i++) {
\r
685 values[i] = GetValue(i);
\r
690 private void FillReaderCache(int columnIndex)
\r
693 IReaderCacheContainer[] readerCache = ReaderCache;
\r
694 if ((Behavior & CommandBehavior.SequentialAccess) == 0) {
\r
695 while (_currentCacheFilledPosition < columnIndex) {
\r
696 _currentCacheFilledPosition++;
\r
697 readerCache[_currentCacheFilledPosition].Fetch(Results,_currentCacheFilledPosition);
\r
701 readerCache[columnIndex].Fetch(Results,columnIndex);
\r
704 catch(SQLException e) {
\r
705 _currentCacheFilledPosition = -1;
\r
706 throw CreateException(e);
\r
708 catch (IOException e) {
\r
709 _currentCacheFilledPosition = -1;
\r
710 throw CreateException(e);
\r
714 private IReaderCacheContainer[] CreateReaderCache()
\r
717 IReaderCacheContainer[] readerCache = new IReaderCacheContainer[FieldCount];
\r
718 for(int i=0; i < readerCache.Length; i++) {
\r
719 DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes) ResultsMetaData.getColumnType(i + 1);
\r
720 switch (javaSqlType) {
\r
721 case DbTypes.JavaSqlTypes.ARRAY :
\r
722 readerCache[i] = new ArrayReaderCacheContainer();
\r
724 case DbTypes.JavaSqlTypes.BIGINT :
\r
725 readerCache[i] = new Int64ReaderCacheContainer();
\r
727 case DbTypes.JavaSqlTypes.BINARY :
\r
728 case DbTypes.JavaSqlTypes.VARBINARY :
\r
729 case DbTypes.JavaSqlTypes.LONGVARBINARY :
\r
730 readerCache[i] = new BytesReaderCacheContainer();
\r
732 case DbTypes.JavaSqlTypes.BIT :
\r
733 readerCache[i] = new BooleanReaderCacheContainer();
\r
735 case DbTypes.JavaSqlTypes.BLOB :
\r
736 readerCache[i] = new BlobReaderCacheContainer();
\r
738 case DbTypes.JavaSqlTypes.CHAR :
\r
739 if ("uniqueidentifier".Equals(ResultsMetaData.getColumnTypeName(i + 1))) {
\r
740 readerCache[i] = new GuidReaderCacheContainer();
\r
743 readerCache[i] = new StringReaderCacheContainer();
\r
746 case DbTypes.JavaSqlTypes.CLOB :
\r
747 readerCache[i] = new ClobReaderCacheContainer();
\r
749 case DbTypes.JavaSqlTypes.TIME :
\r
750 readerCache[i] = new TimeSpanReaderCacheContainer();
\r
752 case DbTypes.JavaSqlTypes.DATE :
\r
753 AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);
\r
754 string driverName = conn.JdbcConnection.getMetaData().getDriverName();
\r
756 if (driverName.StartsWith("PostgreSQL")) {
\r
757 readerCache[i] = new DateTimeReaderCacheContainer();
\r
761 goto case DbTypes.JavaSqlTypes.TIMESTAMP;
\r
762 case DbTypes.JavaSqlTypes.TIMESTAMP :
\r
763 readerCache[i] = new TimestampReaderCacheContainer();
\r
765 case DbTypes.JavaSqlTypes.DECIMAL :
\r
766 case DbTypes.JavaSqlTypes.NUMERIC :
\r
767 // jdbc driver for oracle identitfies both FLOAT and NUMBEr columns as
\r
768 // java.sql.Types.NUMERIC (2), columnTypeName NUMBER, columnClassName java.math.BigDecimal
\r
769 // therefore we relay on scale
\r
770 int scale = ResultsMetaData.getScale(i + 1);
\r
771 if (scale == -127) {
\r
772 // Oracle db type FLOAT
\r
773 readerCache[i] = new DoubleReaderCacheContainer();
\r
776 readerCache[i] = new DecimalReaderCacheContainer();
\r
779 case DbTypes.JavaSqlTypes.DOUBLE :
\r
780 case DbTypes.JavaSqlTypes.FLOAT :
\r
781 readerCache[i] = new DoubleReaderCacheContainer();
\r
783 case DbTypes.JavaSqlTypes.INTEGER :
\r
784 readerCache[i] = new Int32ReaderCacheContainer();
\r
786 case DbTypes.JavaSqlTypes.LONGVARCHAR :
\r
787 case DbTypes.JavaSqlTypes.VARCHAR :
\r
788 readerCache[i] = new StringReaderCacheContainer();
\r
790 case DbTypes.JavaSqlTypes.NULL :
\r
791 readerCache[i] = new NullReaderCacheContainer();
\r
793 case DbTypes.JavaSqlTypes.REAL :
\r
794 readerCache[i] = new FloatReaderCacheContainer();
\r
796 case DbTypes.JavaSqlTypes.REF :
\r
797 readerCache[i] = new RefReaderCacheContainer();
\r
799 case DbTypes.JavaSqlTypes.SMALLINT :
\r
800 readerCache[i] = new Int16ReaderCacheContainer();
\r
802 case DbTypes.JavaSqlTypes.TINYINT :
\r
803 readerCache[i] = new ByteReaderCacheContainer();
\r
805 case DbTypes.JavaSqlTypes.DISTINCT :
\r
806 case DbTypes.JavaSqlTypes.JAVA_OBJECT :
\r
807 case DbTypes.JavaSqlTypes.OTHER :
\r
808 case DbTypes.JavaSqlTypes.STRUCT :
\r
810 readerCache[i] = new ObjectReaderCacheContainer();
\r
813 // ((ReaderCacheContainerBase)readerCache[i])._jdbcType = (int) javaSqlType;
\r
816 return readerCache;
\r
818 catch(SQLException e) {
\r
819 throw CreateException(e);
\r
823 public override bool IsDBNull(int columnIndex)
\r
825 FillReaderCache(columnIndex);
\r
826 return ReaderCache[columnIndex].IsNull();
\r
829 public override Type GetFieldType(int i)
\r
832 int javaSqlType = ResultsMetaData.getColumnType(i + 1);
\r
833 return DbConvert.JavaSqlTypeToClrType(javaSqlType);
\r
835 catch (SQLException exp) {
\r
836 throw new IndexOutOfRangeException(exp.Message, exp);
\r
840 public IDataReader GetData(int i)
\r
842 throw new NotSupportedException();
\r
845 public override DataTable GetSchemaTable()
\r
847 if (SchemaTable.Rows != null && SchemaTable.Rows.Count > 0) {
\r
848 return SchemaTable;
\r
851 ResultSetMetaData metaData;
\r
852 if (Behavior == CommandBehavior.SchemaOnly) {
\r
854 metaData = ((PreparedStatement)_command.JdbcStatement).getMetaData();
\r
856 catch(SQLException e) {
\r
857 throw CreateException("CommandBehaviour.SchemaOnly is not supported by the JDBC driver.",e);
\r
861 metaData = ResultsMetaData;
\r
864 if (metaData == null) {
\r
865 return SchemaTable;
\r
868 DatabaseMetaData dbMetaData = null;
\r
869 AbstractDBConnection clonedConnection = null;
\r
870 if ((_command.Behavior & CommandBehavior.KeyInfo) != 0) {
\r
871 clonedConnection = (AbstractDBConnection)((ICloneable)_command.Connection).Clone();
\r
874 clonedConnection.Open();
\r
875 dbMetaData = clonedConnection.JdbcConnection.getMetaData();
\r
879 if (clonedConnection != null) {
\r
880 clonedConnection.Close();
\r
887 for(int i = 1; i <= metaData.getColumnCount(); i++) {
\r
888 DataRow row = SchemaTable.NewRow ();
\r
889 string columnName = metaData.getColumnLabel(i);
\r
890 string baseColumnName = metaData.getColumnName(i);
\r
892 row [(int)SCHEMA_TABLE.ColumnName] = columnName; // maybe we should use metaData.getColumnLabel(i);
\r
893 row [(int)SCHEMA_TABLE.ColumnSize] = metaData.getColumnDisplaySize(i);
\r
894 row [(int)SCHEMA_TABLE.ColumnOrdinal] = i - 1;
\r
896 // FIXME : workaround for Oracle JDBC driver bug
\r
897 // getPrecision on BLOB, CLOB, NCLOB throws NumberFormatException
\r
898 tmp = metaData.getPrecision(i);
\r
900 catch(java.lang.NumberFormatException e) {
\r
901 // supress exception
\r
904 row [(int)SCHEMA_TABLE.NumericPrecision] = Convert.ToInt16(tmp > 255 ? 255 : tmp);
\r
905 tmp = metaData.getScale(i);
\r
906 row [(int)SCHEMA_TABLE.NumericScale] = Convert.ToInt16(tmp > 255 ? 255 : tmp);
\r
908 row [(int)SCHEMA_TABLE.BaseServerName] = DBNull.Value;
\r
910 string catalog = null;
\r
912 catalog = metaData.getCatalogName(i);
\r
914 catch (Exception e) {
\r
915 // supress exception
\r
917 if (catalog != null && catalog.Length == 0)
\r
918 catalog = ((AbstractDBConnection)_command.Connection).JdbcConnection.getCatalog();
\r
919 row [(int)SCHEMA_TABLE.BaseCatalogName] = catalog;
\r
920 row [(int)SCHEMA_TABLE.BaseColumnName] = baseColumnName;
\r
926 tableName = metaData.getTableName(i);
\r
933 schemaName = metaData.getSchemaName(i);
\r
939 if (tableName != null && tableName.Length == 0)
\r
941 if (schemaName != null && schemaName.Length == 0)
\r
944 row [(int)SCHEMA_TABLE.BaseSchemaName] = schemaName;
\r
945 row [(int)SCHEMA_TABLE.BaseTableName] = tableName;
\r
948 row [(int)SCHEMA_TABLE.AllowDBNull] = Convert.ToBoolean(metaData.isNullable(i));
\r
950 InitKeyInfo(row, dbMetaData, catalog, schemaName, tableName);
\r
952 row [(int)SCHEMA_TABLE.IsAliased] = columnName != baseColumnName;
\r
953 row [(int)SCHEMA_TABLE.IsExpression] = false;
\r
955 row [(int)SCHEMA_TABLE.IsAutoIncrement] = metaData.isAutoIncrement(i);
\r
957 row [(int)SCHEMA_TABLE.IsHidden] = false;
\r
958 row [(int)SCHEMA_TABLE.IsReadOnly] = metaData.isReadOnly(i);
\r
960 int columnType = metaData.getColumnType(i);
\r
961 string columnTypeName = metaData.getColumnTypeName(i);
\r
962 if(columnType == Types.ARRAY) {
\r
963 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
964 row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Array);
\r
965 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
967 else if(columnType == Types.BIGINT) {
\r
968 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
969 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt64;
\r
970 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
972 else if(columnType == Types.BINARY) {
\r
973 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
974 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
\r
975 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
977 else if(columnType == Types.BIT) {
\r
978 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
979 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfBoolean;
\r
980 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
982 else if(columnType == Types.BLOB) {
\r
983 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
984 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
\r
985 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
987 else if(columnType == Types.CHAR) {
\r
988 // FIXME : specific for Microsoft SQl Server driver
\r
989 if (columnTypeName.Equals("uniqueidentifier")) {
\r
990 row [(int)SCHEMA_TABLE.ProviderType] = DbType.Guid;
\r
991 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfGuid;
\r
992 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
995 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
996 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
\r
997 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1000 else if(columnType == Types.CLOB) {
\r
1001 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1002 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString; // instead og .java.sql.Clob
\r
1003 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
1005 else if(columnType == Types.DATE) {
\r
1006 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1007 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;
\r
1008 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1010 else if(columnType == Types.DECIMAL) {
\r
1011 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1012 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;
\r
1013 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1015 // else if(columnType == Types.DISTINCT)
\r
1017 // row ["ProviderType = (int)GetProviderType(columnType);
\r
1018 // row ["DataType = typeof (?);
\r
1019 // row ["IsLong = false;
\r
1021 else if(columnType == Types.DOUBLE) {
\r
1022 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1023 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble; // was typeof(float)
\r
1024 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1026 else if(columnType == Types.FLOAT) {
\r
1027 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1028 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble;
\r
1029 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1031 else if(columnType == Types.REAL) {
\r
1032 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1033 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfFloat;
\r
1034 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1036 else if(columnType == Types.INTEGER) {
\r
1037 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1038 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt32;
\r
1039 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1041 else if(columnType == Types.JAVA_OBJECT) {
\r
1042 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1043 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
\r
1044 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1046 else if(columnType == Types.LONGVARBINARY) {
\r
1047 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1048 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
\r
1049 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
1051 else if(columnType == Types.LONGVARCHAR) {
\r
1052 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1053 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
\r
1054 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
1056 else if(columnType == Types.NUMERIC) {
\r
1057 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1058 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;
\r
1059 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1061 else if(columnType == Types.REF) {
\r
1062 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1063 row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Ref);
\r
1064 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
1066 else if(columnType == Types.SMALLINT) {
\r
1067 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1068 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt16;
\r
1069 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1071 else if(columnType == Types.STRUCT) {
\r
1072 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1073 row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Struct);
\r
1074 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1076 else if(columnType == Types.TIME) {
\r
1077 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1078 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfTimespan;
\r
1079 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1081 else if(columnType == Types.TIMESTAMP) {
\r
1082 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1083 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;
\r
1084 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1086 else if(columnType == Types.TINYINT) {
\r
1087 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1088 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByte;
\r
1089 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1091 else if(columnType == Types.VARBINARY) {
\r
1092 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1093 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
\r
1094 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
1096 else if(columnType == Types.VARCHAR) {
\r
1097 // FIXME : specific for Microsoft SQl Server driver
\r
1098 if (columnTypeName.Equals("sql_variant")) {
\r
1099 row [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;
\r
1100 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
\r
1101 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1104 row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
\r
1105 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;// (char[]);
\r
1106 row [(int)SCHEMA_TABLE.IsLong] = false;//true;
\r
1109 else if(columnType == -8 && columnTypeName.Equals("ROWID")) {
\r
1110 // FIXME : specific for Oracle JDBC driver : OracleTypes.ROWID
\r
1111 row [(int)SCHEMA_TABLE.ProviderType] = DbType.String;
\r
1112 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
\r
1113 row [(int)SCHEMA_TABLE.IsLong] = false;
\r
1116 row [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;
\r
1117 row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
\r
1118 row [(int)SCHEMA_TABLE.IsLong] = true;
\r
1120 SchemaTable.Rows.Add (row);
\r
1123 catch (SQLException e) {
\r
1124 throw CreateException(e);
\r
1127 if (clonedConnection != null) {
\r
1128 clonedConnection.Close();
\r
1131 return SchemaTable;
\r
1134 private void InitKeyInfo(DataRow row, DatabaseMetaData dbMetaData, String catalog, String schema, String table) {
\r
1135 string column = (string)row [(int)SCHEMA_TABLE.BaseColumnName];
\r
1137 row [(int)SCHEMA_TABLE.IsUnique] = false;
\r
1138 row [(int)SCHEMA_TABLE.IsKey] = false;
\r
1139 row [(int)SCHEMA_TABLE.IsIdentity] = false;
\r
1140 row [(int)SCHEMA_TABLE.IsRowVersion] = false;
\r
1142 if ((_command.Behavior & CommandBehavior.KeyInfo) == 0)
\r
1145 if(table == null || column == null || dbMetaData == null)
\r
1148 ResultSet versionCol = dbMetaData.getVersionColumns(catalog, schema, table);
\r
1150 while(versionCol.next()) {
\r
1151 if(versionCol.getString("COLUMN_NAME") == column) {
\r
1152 if (DatabaseMetaData__Finals.versionColumnPseudo == versionCol.getShort("PSEUDO_COLUMN")) {
\r
1153 row [(int)SCHEMA_TABLE.IsIdentity] = true;
\r
1154 row [(int)SCHEMA_TABLE.IsRowVersion] = true;
\r
1160 versionCol.close();
\r
1163 ResultSet primaryKeys = dbMetaData.getPrimaryKeys(catalog,schema,table);
\r
1164 bool primaryKeyExists = false;
\r
1165 int columnCount = 0;
\r
1167 while(primaryKeys.next()) {
\r
1169 if(primaryKeys.getString("COLUMN_NAME") == column) {
\r
1170 row [(int)SCHEMA_TABLE.IsKey] = true;
\r
1171 primaryKeyExists = true;
\r
1174 // column constitutes a key by itself, so it should be marked as unique
\r
1175 if ((columnCount == 1) && (((bool)row [(int)SCHEMA_TABLE.IsKey]) == true)) {
\r
1176 row [(int)SCHEMA_TABLE.IsUnique] = true;
\r
1180 primaryKeys.close();
\r
1183 ResultSet indexInfoRes = dbMetaData.getIndexInfo(catalog,schema,table,true,false);
\r
1184 string currentIndexName = null;
\r
1186 bool belongsToCurrentIndex = false;
\r
1187 bool atFirstIndex = true;
\r
1188 bool uniqueKeyExists = false;
\r
1190 while(indexInfoRes.next()) {
\r
1191 if (indexInfoRes.getShort("TYPE") == DatabaseMetaData__Finals.tableIndexStatistic) {
\r
1192 // index of type tableIndexStatistic identifies table statistics - ignore it
\r
1196 uniqueKeyExists = true;
\r
1197 string iname = indexInfoRes.getString("INDEX_NAME");
\r
1198 if (currentIndexName == iname) {
\r
1199 // we're within the rows of the same index
\r
1203 // we jump to row of new index
\r
1204 if (belongsToCurrentIndex && columnCount == 1) {
\r
1205 // there is a constraint of type UNIQUE that applies only to this column
\r
1206 row [(int)SCHEMA_TABLE.IsUnique] = true;
\r
1209 if (currentIndexName != null) {
\r
1210 atFirstIndex = false;
\r
1212 currentIndexName = iname;
\r
1214 belongsToCurrentIndex = false;
\r
1217 if(indexInfoRes.getString("COLUMN_NAME") == column) {
\r
1218 // FIXME : this will cause "spare" columns marked as IsKey. Needs future investigation.
\r
1219 // only the first index we met should be marked as a key
\r
1220 //if (atFirstIndex) {
\r
1221 row [(int)SCHEMA_TABLE.IsKey] = true;
\r
1223 belongsToCurrentIndex = true;
\r
1226 // the column appears in the last index, which is single-column
\r
1227 if (belongsToCurrentIndex && columnCount == 1) {
\r
1228 // there is a constraint of type UNIQUE that applies only to this column
\r
1229 row [(int)SCHEMA_TABLE.IsUnique] = true;
\r
1233 indexInfoRes.close();
\r
1236 if(!primaryKeyExists && !uniqueKeyExists) {
\r
1237 ResultSet bestRowId = dbMetaData.getBestRowIdentifier(catalog, schema, table, DatabaseMetaData__Finals.bestRowTemporary, false);
\r
1239 while(bestRowId.next()) {
\r
1240 if(bestRowId.getString("COLUMN_NAME") == column)
\r
1241 row [(int)SCHEMA_TABLE.IsKey] = true;
\r
1245 bestRowId.close();
\r
1250 protected static DataTable ConstructSchemaTable ()
\r
1252 Type booleanType = DbTypes.TypeOfBoolean;
\r
1253 Type stringType = DbTypes.TypeOfString;
\r
1254 Type intType = DbTypes.TypeOfInt32;
\r
1255 Type typeType = DbTypes.TypeOfType;
\r
1256 Type shortType = DbTypes.TypeOfInt16;
\r
1258 DataTable schemaTable = new DataTable ("SchemaTable");
\r
1259 schemaTable.Columns.Add ("ColumnName", stringType);
\r
1260 schemaTable.Columns.Add ("ColumnOrdinal", intType);
\r
1261 schemaTable.Columns.Add ("ColumnSize", intType);
\r
1262 schemaTable.Columns.Add ("NumericPrecision", shortType);
\r
1263 schemaTable.Columns.Add ("NumericScale", shortType);
\r
1264 schemaTable.Columns.Add ("IsUnique", booleanType);
\r
1265 schemaTable.Columns.Add ("IsKey", booleanType);
\r
1266 schemaTable.Columns.Add ("BaseServerName", stringType);
\r
1267 schemaTable.Columns.Add ("BaseCatalogName", stringType);
\r
1268 schemaTable.Columns.Add ("BaseColumnName", stringType);
\r
1269 schemaTable.Columns.Add ("BaseSchemaName", stringType);
\r
1270 schemaTable.Columns.Add ("BaseTableName", stringType);
\r
1271 schemaTable.Columns.Add ("DataType", typeType);
\r
1272 schemaTable.Columns.Add ("AllowDBNull", booleanType);
\r
1273 schemaTable.Columns.Add ("ProviderType", intType);
\r
1274 schemaTable.Columns.Add ("IsAliased", booleanType);
\r
1275 schemaTable.Columns.Add ("IsExpression", booleanType);
\r
1276 schemaTable.Columns.Add ("IsIdentity", booleanType);
\r
1277 schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
\r
1278 schemaTable.Columns.Add ("IsRowVersion", booleanType);
\r
1279 schemaTable.Columns.Add ("IsHidden", booleanType);
\r
1280 schemaTable.Columns.Add ("IsLong", booleanType);
\r
1281 schemaTable.Columns.Add ("IsReadOnly", booleanType);
\r
1282 return schemaTable;
\r
1285 #endregion // Methods
\r