// // System.Data.ProviderBase.ReaderCache.cs // // Authors: // Konstantin Triger // Boris Kirzner // // (C) 2005 Mainsoft Corporation (http://www.mainsoft.com) // // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using java.sql; namespace System.Data.ProviderBase { public interface IReaderCacheContainer { void Fetch(ResultSet rs, int columnIndex, bool isSequential); bool IsNull(); bool IsNumeric(); object GetValue(); } public abstract class ReaderCacheContainerBase : IReaderCacheContainer { #region Fields bool _isNull; #endregion // Fields #region Methods protected abstract void FetchInternal(ResultSet rs, int columnIndex); protected virtual void FetchInternal(ResultSet rs, int columnIndex, bool isSequential) { FetchInternal(rs, columnIndex); } public virtual bool IsNumeric() { return false; } public abstract object GetValue(); public void Fetch(ResultSet rs, int columnIndex, bool isSequential) { FetchInternal(rs, columnIndex + 1, isSequential); _isNull = rs.wasNull(); } public bool IsNull() { return _isNull; } #endregion // Methods } internal sealed class ArrayReaderCacheContainer : ReaderCacheContainerBase // Types.ARRAY { #region Fields object _a; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _a = rs.getArray(columnIndex).getArray(); } public override object GetValue() { return _a; } #endregion // Methods } internal sealed class Int64ReaderCacheContainer : ReaderCacheContainerBase // Types.BIGINT { #region Fields long _l; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _l = rs.getLong(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _l; } internal long GetInt64() { return _l; } #endregion // Methods } internal class BytesReaderCacheContainer : ReaderCacheContainerBase // Types.BINARY, Types.VARBINARY, Types.LONGVARBINARY { #region Fields protected byte[] _b; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { sbyte[] sbyteArray = rs.getBytes(columnIndex); if (sbyteArray != null) { _b = (byte[])vmw.common.TypeUtils.ToByteArray(sbyteArray); } } public override object GetValue() { return _b; } internal byte[] GetBytes() { return (byte[])GetValue(); } internal virtual long GetBytes( long dataIndex, byte[] buffer, int bufferIndex, int length) { if (_b == null) return 0; if (buffer == null) return _b.LongLength; long actualLength = ((dataIndex + length) >= _b.LongLength) ? (_b.LongLength - dataIndex) : length; Array.Copy(_b,dataIndex,buffer,bufferIndex,actualLength); return actualLength; } #endregion // Methods } internal sealed class BooleanReaderCacheContainer : ReaderCacheContainerBase // Types.BIT { #region Fields bool _b; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _b = rs.getBoolean(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _b; } internal bool GetBoolean() { return _b; } #endregion // Methods } internal sealed class BlobReaderCacheContainer : BytesReaderCacheContainer // Types.BLOB { #region Fields static readonly byte[] _emptyByteArr = new byte[0]; java.sql.Blob _blob; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { throw new NotImplementedException("Should not be called"); } protected override void FetchInternal(ResultSet rs, int columnIndex, bool isSequential) { _blob = rs.getBlob(columnIndex); if (!isSequential) ReadAll(); } void ReadAll() { if (_blob != null) { long length = _blob.length(); if (length == 0) { _b = _emptyByteArr; } else { java.io.InputStream input = _blob.getBinaryStream(); byte[] byteValue = new byte[length]; sbyte[] sbyteValue = vmw.common.TypeUtils.ToSByteArray(byteValue); input.read(sbyteValue); _b = byteValue; } } } public override object GetValue() { if (_b == null) ReadAll(); return base.GetValue(); } internal override long GetBytes(long dataIndex, byte[] buffer, int bufferIndex, int length) { if (_b != null) return base.GetBytes (dataIndex, buffer, bufferIndex, length); if (_blob == null) return 0; if (buffer == null) return _blob.length(); java.io.InputStream input = _blob.getBinaryStream(); input.skip(dataIndex); return input.read(vmw.common.TypeUtils.ToSByteArray(buffer), bufferIndex, length); } #endregion // Methods } internal abstract class CharsReaderCacheContainer : ReaderCacheContainerBase // { #region Fields #endregion // Fields #region Methods internal abstract long GetChars( long dataIndex, char[] buffer, int bufferIndex, int length); #endregion // Methods } internal sealed class GuidReaderCacheContainer : ReaderCacheContainerBase // Types.CHAR { #region Fields Guid _g; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { string s = rs.getString(columnIndex); if (s != null) _g = new Guid(s); } public override object GetValue() { return _g; } internal Guid GetGuid() { return _g; } #endregion // Methods } internal sealed class ClobReaderCacheContainer : StringReaderCacheContainer // Types.CLOB { #region Fields java.sql.Clob _clob; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex, bool isSequential) { _clob = rs.getClob(columnIndex); if (!isSequential) ReadAll(); } void ReadAll() { if (_clob != null) { long length = _clob.length(); if (length == 0) { _s = String.Empty; } else { java.io.Reader reader = _clob.getCharacterStream(); char[] charValue = new char[length]; reader.read(charValue); if (charValue != null) _s = new String(charValue); } } } public override object GetValue() { if (_s == null) ReadAll(); return base.GetValue(); } internal override long GetChars(long dataIndex, char[] buffer, int bufferIndex, int length) { if (_s != null) return base.GetChars (dataIndex, buffer, bufferIndex, length); if (_clob == null) return 0; if (buffer == null) return _clob.length(); java.io.Reader reader = _clob.getCharacterStream(); reader.skip(dataIndex); return reader.read(buffer, bufferIndex, length); } #endregion // Methods } internal sealed class TimeSpanReaderCacheContainer : ReaderCacheContainerBase // Types.TIME { #region Fields TimeSpan _t; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { Time t = rs.getTime(columnIndex); if (t != null) { _t = new TimeSpan(DbConvert.JavaTimeToClrTicks(t)); } } public override object GetValue() { return _t; } internal TimeSpan GetTimeSpan() { return _t; } #endregion // Methods } internal class DateTimeReaderCacheContainer : ReaderCacheContainerBase // Types.TIMESTAMP { #region Fields protected DateTime _d; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { Date d = rs.getDate(columnIndex); if (d != null) { _d = new DateTime(DbConvert.JavaDateToClrTicks(d)); } } public override object GetValue() { return _d; } internal DateTime GetDateTime() { return _d; } #endregion // Methods } internal sealed class TimestampReaderCacheContainer : DateTimeReaderCacheContainer // Types.DATE { protected override void FetchInternal(ResultSet rs, int columnIndex) { Timestamp ts = rs.getTimestamp(columnIndex); if (ts != null) { _d = new DateTime(DbConvert.JavaTimestampToClrTicks(ts)); } } } internal sealed class DecimalReaderCacheContainer : ReaderCacheContainerBase // Types.DECIMAL, Types.NUMERIC { #region Fields decimal _d; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { java.math.BigDecimal bigDecimal = rs.getBigDecimal(columnIndex); if (bigDecimal != null) { _d = (decimal)vmw.common.PrimitiveTypeUtils.BigDecimalToDecimal(bigDecimal); } } public override bool IsNumeric() { return true; } public override object GetValue() { return _d; } internal decimal GetDecimal() { return _d; } #endregion // Methods } internal sealed class DoubleReaderCacheContainer : ReaderCacheContainerBase // Types.DOUBLE, Types.Float, Types.NUMERIC for Oracle with scale = -127 { #region Fields double _d; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _d = rs.getDouble(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _d; } internal double GetDouble() { return _d; } #endregion // Methods } internal sealed class Int32ReaderCacheContainer : ReaderCacheContainerBase // Types.INTEGER { #region Fields int _i; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _i = rs.getInt(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _i; } internal int GetInt32() { return _i; } #endregion // Methods } internal class StringReaderCacheContainer : CharsReaderCacheContainer // Types.LONGVARCHAR, Types.VARCHAR, Types.CHAR { #region Fields protected string _s; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _s = rs.getString(columnIndex); // Oracle Jdbc driver returns extra trailing 0 chars for NCHAR columns // if ((_s != null) && (_jdbcType == 1)) { // Console.WriteLine(_jdbcType); // int zeroIndex = ((string)_s).IndexOf((char)0); // if (zeroIndex > 0) { // Console.WriteLine("zero-padded"); // _s = ((string)_s).Substring(0,zeroIndex); // } // else { // // Oracle sometimes pads with blanks (32) // int blankIndex = ((string)_s).IndexOf((char)32); // if (blankIndex > 0) { // Console.WriteLine("blank-padded"); // _s = ((string)_s).Substring(0,blankIndex); // } // } // } } public override object GetValue() { return _s; } internal string GetString() { return _s; } internal override long GetChars(long dataIndex, char[] buffer, int bufferIndex, int length) { if (_s == null) return 0; if (buffer == null) return _s.Length; int actualLength = ((dataIndex + length) >= _s.Length) ? (_s.Length - (int)dataIndex) : length; _s.CopyTo((int)dataIndex, buffer, bufferIndex, actualLength); return actualLength; } #endregion // Methods } internal sealed class NullReaderCacheContainer : ReaderCacheContainerBase // Types.NULL { #region Fields #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { } public override object GetValue() { return DBNull.Value; } #endregion // Methods } internal sealed class FloatReaderCacheContainer : ReaderCacheContainerBase // Types.REAL { #region Fields float _f; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _f = rs.getFloat(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _f; } internal float GetFloat() { return _f; } #endregion // Methods } internal sealed class RefReaderCacheContainer : ReaderCacheContainerBase // Types.REF { #region Fields java.sql.Ref _r; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _r = rs.getRef(columnIndex); } public override object GetValue() { return _r; } #endregion // Methods } internal sealed class Int16ReaderCacheContainer : ReaderCacheContainerBase // Types.SMALLINT { #region Fields short _s; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _s = rs.getShort(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _s; } internal short GetInt16() { return _s; } #endregion // Methods } internal sealed class ByteReaderCacheContainer : ReaderCacheContainerBase // Types.TINYINT { #region Fields byte _b; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { _b = (byte)rs.getByte(columnIndex); } public override bool IsNumeric() { return true; } public override object GetValue() { return _b; } internal byte GetByte() { return _b; } #endregion // Methods } internal sealed class ObjectReaderCacheContainer : ReaderCacheContainerBase // Types.Distinct, Types.JAVA_OBJECT, Types.OTHER, Types.STRUCT { #region Fields object o; #endregion // Fields #region Methods protected override void FetchInternal(ResultSet rs, int columnIndex) { o = rs.getObject(columnIndex); } public override object GetValue() { return o; } #endregion // Methods } }