Przeglądaj źródła

Drop of Mainsoft.System.Data

svn path=/branches/Mainsoft.System.Data/mcs/; revision=43607
Boris Kirzner 20 lat temu
rodzic
commit
cc4891c52c

+ 751 - 0
mcs/class/System.Data/System.Data.Common/AbstractDBCommand.cs

@@ -0,0 +1,751 @@
+//namespace System.Data.Common
+//{
+//
+//	using java.sql;
+//	using java.util;
+//
+//	using System;
+//	using System.Collections;
+//	using System.Data;
+//	using System.Data.ProviderBase;
+//
+//	/**
+//	 * @author erand
+//	 */
+//	public abstract class AbstractDBCommand : DbCommandBase
+//	{
+//		protected String _cmdText, _javaCmdText;
+//		protected AbstractDBConnection _connection;
+//		protected IDbTransaction _transaction;
+//		protected int _cmdTimeout = 30;
+//		protected CommandType _cmdType = CommandType.Text;
+//		protected UpdateRowSource _updateRowSource = UpdateRowSource.Both;
+//		protected Statement _statement;
+//		protected IDataParameterCollection _paramCollection;
+//		protected IDataReader _reader;
+//		private bool _isCommandTextChanged;
+//		private CommandBehavior _behvior = CommandBehavior.Default;
+//
+//		private static readonly int _oracleRefCursor;
+//		protected const int oracleTypeRefCursor = 1111; // Types.OTHER
+//        
+//        
+//		static AbstractDBCommand()
+//		{
+//			try {
+//				java.lang.Class OracleTypesClass = java.lang.Class.forName("oracle.jdbc.OracleTypes");
+//				_oracleRefCursor = OracleTypesClass.getField("CURSOR").getInt(null);
+//			}
+//			catch(java.lang.ClassNotFoundException e) {
+//				// oracle driver is not in classpath - just continue
+//			}
+//		}
+//
+//		public AbstractDBCommand(
+//			String cmdText,
+//			AbstractDBConnection connection,
+//			IDbTransaction transaction)
+//		{
+//			_connection = connection;
+//			_cmdText = cmdText;
+//			_transaction = transaction;
+//			_isCommandTextChanged = true;
+//		}
+//    
+//		public java.sql.Statement Statement
+//		{
+//			get
+//			{
+//				return _statement;
+//			}
+//			set
+//			{
+//				_statement = value;
+//			}
+//		}
+//
+//		public virtual String JavaCommandText
+//		{
+//			get
+//			{
+//				return _javaCmdText;
+//			}
+//			set
+//			{
+//				_javaCmdText = value;
+//			}
+//		}
+//
+//		protected bool getCommandTextChanged()
+//		{
+//			return _isCommandTextChanged;
+//		}
+//    
+//		internal void setCommandTextChanged(bool value)
+//		{
+//			_isCommandTextChanged = value;
+//		}
+//    
+//		public Statement getStatement()
+//		{
+//			return _statement;
+//		}
+//		/**
+//		 * @see System.Data.IDbCommand#Cancel()
+//		 */
+//		public override void Cancel()
+//		{
+//			try
+//			{
+//				if (_statement != null)
+//					_statement.cancel();
+//			}
+//			catch (SQLException exp)
+//			{
+//				Console.WriteLine(exp);
+//			}
+//		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#ExecuteScalar()
+////		 */
+////		public virtual Object ExecuteScalar()
+////		{
+////			Object result = null;
+////			IDataReader reader = ((IDbCommand)this).ExecuteReader();
+////
+////			if (reader != null && reader.Read())
+////			{
+////				result = ((IDataRecord) reader).GetValue(0);
+////			}
+////			reader.Close();
+////
+////			return result;
+////		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#CommandTimeout
+////		 */
+////		public virtual int CommandTimeout
+////		{
+////			get
+////			{
+////				return _cmdTimeout;
+////			}
+////			set
+////			{
+////				_cmdTimeout = value;
+////			}
+////		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#CommandType
+////		 */
+////		public virtual CommandType CommandType
+////		{
+////			get
+////			{
+////				return _cmdType;
+////			}
+////			set
+////			{
+////				_cmdType = value;
+////			}
+////		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#Connection
+////		 */
+////		public virtual IDbConnection Connection
+////		{
+////			get
+////			{
+////				return (IDbConnection)_connection;
+////			}
+////			set
+////			{
+////				_connection = (AbstractDBConnection) value;
+////			}
+////		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#Transaction
+////		 */
+////		public virtual IDbTransaction Transaction
+////		{
+////			get
+////			{
+////				return _transaction;
+////			}
+////			set
+////			{
+////				_transaction = value;
+////			}
+////		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#UpdatedRowSource
+////		 */
+////		public virtual UpdateRowSource UpdatedRowSource
+////		{
+////			get
+////			{
+////				return _updateRowSource;
+////			}
+////			set
+////			{
+////				_updateRowSource = value;
+////			}
+////		}
+//
+////		/**
+////		 * @see System.Data.IDbCommand#CommandText
+////		 */
+////		public virtual String CommandText
+////		{
+////			get
+////			{
+////				return _cmdText;
+////			}
+////			set
+////			{
+////				if (_cmdText == null || String.Compare(_cmdText, value,  true) != 0)
+////				{
+////					_cmdText = value;
+////					_isCommandTextChanged = true;
+////				}
+////			}
+////		}
+//
+//		protected virtual void setInputForStatement(
+//			PreparedStatement stm,
+//			int javaType,
+//			int place,
+//			Object value)
+//			//throws SQLException
+//		{
+//			// by the type of the the parameter we know wich method of
+//			// the statement to use
+//
+//			if (value is DBNull)
+//				stm.setNull(place, javaType);
+//
+//			else if (javaType == Types.BINARY)
+//				stm.setBytes(place, vmw.common.TypeUtils.ToSByteArray((byte[]) value));
+//
+//			else if (javaType == Types.BLOB)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.CLOB)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.DISTINCT)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.ARRAY)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.JAVA_OBJECT)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.REF)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.STRUCT)
+//				stm.setObject(place, value);
+//
+//			else if (javaType == Types.VARBINARY)
+//				stm.setBytes(place, vmw.common.TypeUtils.ToSByteArray((byte[]) value));
+//
+//			else if (javaType == Types.BIGINT)
+//				stm.setLong(place, ((java.lang.Long) value).longValue());
+//
+//			else if (javaType == Types.BIT)
+//				stm.setBoolean(place, ((java.lang.Boolean) value).booleanValue());
+//
+//			else if (javaType == Types.CHAR)
+//				stm.setString(place, ((java.lang.Character) value).toString());
+//
+//			else if (javaType == Types.DATE)
+//			{
+//				DateTime tmp = (DateTime) value;
+//				Calendar c = vmw.common.DateTimeUtils.DateTimeToCalendar(tmp);
+//				stm.setDate(
+//					place, new java.sql.Date(c.getTime().getTime()));
+//			}
+//			else if (javaType == Types.DECIMAL || javaType == Types.NUMERIC)
+//				stm.setBigDecimal(place, vmw.common.PrimitiveTypeUtils.DecimalToBigDecimal((Decimal) value));
+//
+//			else if (javaType == Types.DOUBLE)
+//				stm.setDouble(place, ((java.lang.Double) value).doubleValue());
+//
+//			else if (javaType == Types.FLOAT)
+//				stm.setFloat(place, ((java.lang.Float) value).floatValue());
+//
+//			else if (javaType == Types.INTEGER)
+//				stm.setInt(place, ((java.lang.Integer) value).intValue());
+//
+//			else if (javaType == Types.LONGVARCHAR)
+//				stm.setString(place, (String) value);
+//
+//			else if (javaType == Types.LONGVARBINARY)
+//				stm.setBytes(place, vmw.common.TypeUtils.ToSByteArray((byte[]) value));
+//
+//			else if (javaType == Types.REAL)
+//				stm.setFloat(place, ((java.lang.Float) value).floatValue());
+//
+//			else if (javaType == Types.SMALLINT)
+//				stm.setShort(place, ((java.lang.Short) value).shortValue());
+//
+//			else if (javaType == Types.TIME)
+//			{
+//				Calendar c = vmw.common.DateTimeUtils.DateTimeToCalendar(value);
+//				stm.setTime(
+//					place,
+//					new java.sql.Time(c.getTime().getTime()));
+//			}
+//			else if (javaType == Types.TIMESTAMP)
+//			{
+//				DateTime tmp = (DateTime) value;
+//				Calendar c = vmw.common.DateTimeUtils.DateTimeToCalendar(value);
+//				stm.setTimestamp(
+//					place,
+//					new java.sql.Timestamp(c.getTime().getTime()));
+//			}
+//
+//			else if (javaType == Types.TINYINT)
+//				stm.setByte(place, ((java.lang.Byte) value).byteValue());
+//
+//			else if (javaType == Types.VARCHAR)
+//				stm.setString(place, (String) value);
+//
+//			else
+//				stm.setObject(place, value, javaType);
+//
+//		}
+//
+//		// create the _javaCmdText from the _cmdText (the .NET text)
+//		protected String createCommandForStoreProcedure(String text)
+//		{
+//			IDbDataParameter param;
+//			bool isFirst = true;
+//			IList paramCollection = (IList) ((IDbCommand)this).Parameters;
+//        
+//			//in .Net the name of sore procedure can be wraped by '[' and ']'
+//			// so we remove them.
+//			int indx1 = text.IndexOf('[');
+//			if (indx1 != -1)
+//			{
+//				int indx2 = text.IndexOf(']', indx1);
+//				if (indx2 != -1)
+//					text = text.Substring(indx1 + 1, indx2 - (indx1 + 1));
+//			}
+//
+//			java.lang.StringBuffer sb = new java.lang.StringBuffer(text);
+//			sb.insert(0, "{call ");
+//
+//			for (int i = 0; i < paramCollection.Count; i++)
+//			{
+//				param = (IDbDataParameter) paramCollection[i];
+//
+//				if (param.Direction == ParameterDirection.ReturnValue)
+//					sb = sb.insert(1, "? =");
+//				else if (isFirst)
+//				{
+//					sb = sb.append("(?");
+//					isFirst = false;
+//				}
+//				else
+//					sb = sb.append(",?");
+//			}
+//
+//			String retVal = sb.toString();
+//
+//			if (retVal.IndexOf("(") != -1)
+//				retVal = retVal + ")";
+//
+//			retVal += "}";
+//
+//			_javaCmdText = retVal;
+//
+//			return retVal;
+//
+//		}
+//
+//		// prepare the input and output parameters for the jdbc prepared statement
+//		// from the SqlParameters of this instance
+//		internal virtual void prepareStatementForStoreProcedure()// throws SQLException
+//		{
+//			CallableStatement stm = (CallableStatement) _statement;
+//			AbstractDBParameter param;
+//			IList paramCollection = (IList) ((IDbCommand)this).Parameters;
+//			ParameterDirection direction;
+//			//int place;
+//
+//			// NOTE - we add 1 to the index because in .NET it is zero base
+//			// and in jdbc it is one base
+//			for (int i = 0; i < paramCollection.Count; i++)
+//			{
+//				param = (AbstractDBParameter) paramCollection[i];
+//				direction = param.Direction;
+//
+//				if (direction == ParameterDirection.Input)
+//					setInput(stm, i + 1, param);
+//				else if (direction == ParameterDirection.Output)
+//				{
+//					setOutput(stm, i + 1, param);
+//					param.setParameterPlace(i + 1);
+//				}
+//				else if (direction == ParameterDirection.InputOutput)
+//				{
+//					setInput(stm, i + 1, param);
+//					setOutput(stm, i + 1, param);
+//					param.setParameterPlace(i + 1);
+//				}
+//				else if (direction == ParameterDirection.ReturnValue)
+//				{
+//					setOutput(stm, 1, param);
+//					param.setParameterPlace(1);
+//				}
+//			}
+//
+//		}
+//
+//		// set input parameter for the statement
+//		protected void setInput(
+//			PreparedStatement stm,
+//			int place,
+//			AbstractDbParameter param)
+//			//throws SQLException
+//		{
+//			int javaType = param.JdbcType;
+//			Object value = param.Value;
+//
+//			value = getJavaWrapperFromCSharp(value);
+//
+//			setInputForStatement(stm, javaType, place, value);
+//		}
+//        
+//		public static Object getJavaWrapperFromCSharp(Object obj)
+//		{
+//			if (obj is bool)
+//				return new java.lang.Boolean((bool)obj);
+//			else if (obj is byte)
+//				return new java.lang.Byte((sbyte)obj);
+//			else if (obj is char)
+//				return new java.lang.Character((char) obj);
+//			else if (obj is short)
+//				return new java.lang.Short((short)obj);
+//			else if (obj is int)
+//				return new java.lang.Integer((int)obj);
+//			else if (obj is long)
+//				return new java.lang.Long((long)obj);
+//			else if (obj is float)
+//				return new java.lang.Float((float)obj);
+//			else if (obj is double)
+//				return new java.lang.Double((double)obj);
+//
+//			return obj;
+//
+//		}
+//
+//		// set an output parameter to the statement.
+//		protected void setOutput(
+//			CallableStatement stm,
+//			int place,
+//			AbstractDbParameter param)
+//			//throws SQLException
+//		{
+//			int javaType = param.JdbcType;
+//
+//			// the scale has a meening only in DECIMAL parameters
+//			if (javaType == Types.DECIMAL || javaType == Types.NUMERIC)
+//			{
+//				if(param.DbType == DbType.Currency)
+//					stm.registerOutParameter(place, javaType, 4);
+//				else
+//					stm.registerOutParameter(place, javaType, param.Scale);
+//			}
+//			else if (javaType == oracleTypeRefCursor) {
+//				stm.registerOutParameter(place, _oracleRefCursor);
+//			}
+//			else {
+//				stm.registerOutParameter(place, javaType);
+//			}
+//
+//		}
+//
+//		// get the the output parameter for a specific statement at a specific place
+//		// returns the value of the output parameter
+//		protected Object getOutputValue(
+//			AbstractDbParameter param,
+//			CallableStatement stm)
+//			//throws SQLException
+//		{
+//			Object retVal = null;
+//
+//			int place = param.getParameterPlace();
+//
+//			// by the type of the parameter we know wich method to use
+//			// on the statement
+//			int type = param.JdbcType;
+//
+//			if (type == Types.ARRAY)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.BIGINT)
+//				retVal = stm.getLong(place);
+//			else if (type == Types.BINARY)
+//				retVal = stm.getBytes(place);
+//			else if (type == Types.BIT)
+//				retVal = stm.getBoolean(place);
+//			else if (type == Types.BLOB)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.CHAR)
+//				retVal = stm.getString(place);
+//			else if (type == Types.CLOB)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.DATE)
+//			{
+//				java.sql.Date date = stm.getDate(place);
+//				if(date != null)
+//				{
+//					// convertirn sql.Date to DateTime
+//					Calendar c = Calendar.getInstance();
+//					c.setTime(date);
+//
+//					retVal = vmw.common.DateTimeUtils.CalendarToDateTime(c);
+//				}
+//				
+//			}
+//			else if (type == Types.DECIMAL)
+//			{
+//				java.math.BigDecimal bd = stm.getBigDecimal(place);
+//				if(bd != null)
+//					retVal = vmw.common.PrimitiveTypeUtils.BigDecimalToDecimal(bd);
+//			}
+//			else if (type == Types.DISTINCT)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.DOUBLE)
+//				retVal = stm.getDouble(place);
+//			else if (type == Types.FLOAT)
+//				retVal = stm.getFloat(place);
+//			else if (type == Types.INTEGER)
+//				retVal = stm.getInt(place);
+//			else if (type == Types.JAVA_OBJECT)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.LONGVARBINARY)
+//				retVal = stm.getBytes(place);
+//			else if (type == Types.LONGVARCHAR)
+//				retVal = stm.getString(place);
+//			else if (type == Types.NULL)
+//				retVal = DBNull.Value;
+//			else if (type == Types.NUMERIC)
+//				retVal = stm.getBigDecimal(place);
+//			else if (type == Types.OTHER)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.REAL)
+//				retVal = stm.getFloat(place);
+//			else if (type == Types.REF)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.SMALLINT)
+//				retVal = stm.getShort(place);
+//			else if (type == Types.STRUCT)
+//				retVal = stm.getObject(place);
+//			else if (type == Types.TIME)
+//			{
+//				Time t = stm.getTime(place);
+//				if(t != null)
+//				{
+//					java.util.Date d = new java.util.Date(t.getTime());
+//					// convertirn sql.Date to DateTime
+//					Calendar c = Calendar.getInstance();
+//					c.setTime(d);
+//
+//					retVal = vmw.common.DateTimeUtils.CalendarToDateTime(c);
+//				}
+//				
+//			}
+//			else if (type == Types.TIMESTAMP)
+//			{
+//				Timestamp ts = stm.getTimestamp(place);
+//				if(ts != null)
+//				{
+//					java.util.Calendar cal = java.util.Calendar.getInstance();
+//					cal.setTime(new java.util.Date(ts.getTime() + ts.getNanos()/1000000));
+//					retVal = (DateTime)vmw.common.DateTimeUtils.CalendarToDateTime(cal);
+//				}
+//			}
+//			else if (type == Types.TINYINT)
+//				retVal = stm.getByte(place);
+//			else if (type == Types.VARBINARY)
+//				retVal = stm.getBytes(place);
+//			else if (type == Types.VARCHAR)
+//				retVal = stm.getString(place);
+//        
+//			if(stm.wasNull())
+//				retVal = DBNull.Value;
+//            
+//			return retVal;
+//		}
+//
+//    
+////		IDbDataParameter IDbCommand.CreateParameter()
+////		{
+////			return null;
+////		}
+//    
+////		IDataReader IDbCommand.ExecuteReader(CommandBehavior behavior)
+////		{
+////			return null;
+////		}
+////
+////		IDataReader IDbCommand.ExecuteReader()
+////		{
+////			return null;
+////		}
+////
+////		int IDbCommand.ExecuteNonQuery()
+////		{
+////			return -1;
+////		}
+////
+////		void IDbCommand.Prepare()
+////		{
+////		}
+//
+//        
+////		public IDataParameterCollection Parameters
+////		{
+////			get
+////			{
+////				return _paramCollection;
+////			}
+////		}
+//
+//		~AbstractDBCommand()
+//		{
+//			Dispose();
+//		}
+//
+//		public new void Dispose()
+//		{
+//			if (_paramCollection != null)
+//				_paramCollection.Clear();
+//
+//			_connection = null;
+//			_transaction = null;
+//
+//			if (_statement != null)
+//			{
+//				_statement.close();
+//				_statement = null;
+//			}
+//			base.Dispose();
+//		}
+//
+//		protected void CheckTrasactionContext()
+//		{
+//			if (_connection.Transaction != null && 
+//				(Transaction == null || Transaction != _connection.Transaction)) {
+//				throw new InvalidOperationException("Execute requires the command to have a transaction object" + 
+//							" when the connection assigned to the command is in a pending local transaction." +
+//							" The Transaction property of the command has not been initialized.");
+//			}
+//		}
+//
+//		protected String buildJavaCommand(String command)
+//		{
+//			IDataParameterCollection parameters = Parameters;
+//			
+//			if (parameters != null && parameters.Count > 0) {
+//				string tokens = command;
+//				System.Text.StringBuilder sb = new System.Text.StringBuilder(tokens.Length);
+//
+//				int currParameter = 0;
+//				int currStart = 0;
+//				int curr = 0;
+//				char curSeparator = (char)0;
+//				bool foundSeparator = false;
+//
+//				for(;curr<tokens.Length;curr++) {
+//					switch(tokens[curr]) {
+//						case '"':
+//						case '\'':
+//							if (foundSeparator) {
+//								if (curSeparator == tokens[curr]) {
+//									foundSeparator = false;
+//								}
+//							}
+//							else {
+//								// start inner string
+//								foundSeparator = true;
+//								curSeparator = tokens[curr];
+//							}
+//							break;
+//						case '?':
+//							if (!foundSeparator) {
+//								if (curr > currStart) { 
+//									// copy collected 
+//									sb.Append(tokens,currStart,curr - currStart);
+//								}
+//								// append parameter value
+//								AbstractDBParameter param = (AbstractDBParameter)parameters[currParameter++];
+//								sb.Append(param.formatParameter());
+//								currStart = curr+1;
+//							}
+//							break;
+//					}
+//				}
+//
+//				if (curr > currStart) { // end of the stirng
+//					sb.Append(tokens,currStart,curr - currStart);
+//				}
+//
+//				command = sb.ToString();
+//			}
+//			return command;
+//		}
+//
+//		internal void fillParameters()
+//		{
+//			if(CommandType == CommandType.StoredProcedure)
+//			{
+//				AbstractDBParameter param;
+//				CallableStatement stm = (CallableStatement)_statement;
+//				// get the output parameters from the statement
+//				// and put their values into the SqlParameter
+//				for (int i = 0; i < _paramCollection.Count; i++)
+//				{
+//					param = (AbstractDBParameter)_paramCollection[i];
+//
+//					if (param.IsOracleRefCursor)
+//						continue;
+//
+//					ParameterDirection direction = param.Direction;
+//					if (direction == ParameterDirection.InputOutput
+//						|| direction == ParameterDirection.Output
+//						|| direction == ParameterDirection.ReturnValue)
+//						param.Value = getOutputValue(param, stm);
+//				}
+//			}
+//		}
+//
+//		protected void setCommandBehabior(CommandBehavior cmdBehavior)
+//		{
+//			_behvior = cmdBehavior;
+//		}
+//
+//		internal CommandBehavior getCommandBehavior()
+//		{
+//			return _behvior;
+//		}
+//
+//		protected static String GetProcedureName(string cmdText)
+//		{
+//			if(cmdText[0] == '[' && cmdText[cmdText.Length - 1] == ']')
+//				return cmdText.Substring(1, cmdText.Length - 2);
+//			return cmdText;
+//		}
+//        
+//	}
+//}

+ 1158 - 0
mcs/class/System.Data/System.Data.Common/AbstractDBConnection.cs

@@ -0,0 +1,1158 @@
+//
+// System.Data.Common.AbstractDBConnection
+//
+// Author:
+//   Boris Kirzner ([email protected])
+//
+
+using System.Data;
+using System.Data.ProviderBase;
+using System.Data.Configuration;
+using System.Configuration;
+using System.Collections;
+using System.Collections.Specialized;
+using System.Text;
+using System.Text.RegularExpressions;
+
+using java.sql;
+using javax.sql;
+using javax.naming;
+// can not use java.util here - it manes ArrayList an ambiguous reference
+
+namespace System.Data.Common
+{
+	public abstract class AbstractDBConnection : DbConnection
+	{
+		#region ObjectNamesHelper
+
+		private sealed class ObjectNamesHelper
+		{
+			//static readonly Regex NameOrder = new Regex(@"^\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			static readonly Regex NameOrder = new Regex(@"^((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+
+			//static readonly Regex SchemaNameOrder = new Regex(@"^\s*((\[(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			static readonly Regex SchemaNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			//static readonly Regex CatalogSchemaNameOrder = new Regex(@"^\s*((\[\s*(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			//static readonly Regex CatalogSchemaNameOrder = new Regex(@"^\s*((\[\s*(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<SCHEMA>(\s*[^\]\s])+)\s*\])|(?<SCHEMA>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			static readonly Regex CatalogSchemaNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+
+			//static readonly Regex CatalogNameOrder = new Regex(@"^\s*((\[(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			//static readonly Regex CatalogNameOrder = new Regex(@"^\s*((\[(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			static readonly Regex CatalogNameOrder = new Regex(@"^((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			//static readonly Regex SchemaCatalogNameOrder = new Regex(@"^\s*((\[\s*(?<SCHEMA>(\s*[^\[\]\s])+)\s*\])|(?<SCHEMA>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<CATALOG>(\s*[^\[\]\s])+)\s*\])|(?<CATALOG>(\w|!|\#|\$)*(\s*(\w|!|\#|\$)+)*))\s*\.\s*((\[(?<NAME>(\s*[^\[\]\s])+)\s*\])|(?<NAME>(\w|!|\#|\$)+(\s*(\w|!|\#|\$)+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			//static readonly Regex SchemaCatalogNameOrder = new Regex(@"^\s*((\[\s*(?<SCHEMA>(\s*[^\]\s])+)\s*\])|(?<SCHEMA>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<CATALOG>(\s*[^\]\s])+)\s*\])|(?<CATALOG>([^\.\s])*(\s*([^\.\s])+)*))\s*\.\s*((\[(?<NAME>(\s*[^\]\s])+)\s*\])|(?<NAME>([^\.\s])+(\s*([^\.\s])+)*))\s*$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+			static readonly Regex SchemaCatalogNameOrder = new Regex(@"^((\[(?<SCHEMA>[^\]]+)\])|(?<SCHEMA>[^\.\[\]]+))\s*\.\s*((\[(?<CATALOG>[^\]]+)\])|(?<CATALOG>[^\.\[\]]+))\s*\.\s*((\[(?<NAME>[^\]]+)\])|(?<NAME>[^\.\[\]]+))$", RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
+
+			internal static ObjectNameResolver[] GetSyntaxPatterns(AbstractDBConnection connection)
+			{
+				ArrayList collection = new ArrayList();
+				collection.Add(new ObjectNameResolver(NameOrder));
+
+				ObjectNameResolversCollection basic = (ObjectNameResolversCollection)ConfigurationSettings.GetConfig("system.data/objectnameresolution");
+				
+				DatabaseMetaData metaData = connection.JdbcConnection.getMetaData();
+				string productName = metaData.getDatabaseProductName();
+
+				foreach(ObjectNameResolver nameResolver in basic) {
+					if (productName.IndexOf(nameResolver.DbName) != -1) {
+						collection.Add(nameResolver);
+					}
+				}
+
+				//defaults
+				if (metaData.isCatalogAtStart()) {
+					collection.Add(new ObjectNameResolver(SchemaNameOrder));
+					collection.Add(new ObjectNameResolver(CatalogNameOrder));
+					collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
+					collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
+				}
+				else {
+					collection.Add(new ObjectNameResolver(CatalogNameOrder));
+					collection.Add(new ObjectNameResolver(SchemaNameOrder));
+					collection.Add(new ObjectNameResolver(SchemaCatalogNameOrder));
+					collection.Add(new ObjectNameResolver(CatalogSchemaNameOrder));
+				}
+
+				return (ObjectNameResolver[])collection.ToArray(typeof(ObjectNameResolver));				
+			}
+		}
+
+		#endregion // ObjectNamesHelper
+
+		#region ConnectionStringHelper
+
+		internal sealed class ConnectionStringHelper
+		{
+			internal static string FindValue(NameValueCollection collection, string[] keys)
+			{
+				if (collection == null || keys == null || keys.Length == 0) {
+					return String.Empty;
+				}
+
+				for(int i=0; i < keys.Length; i++) {
+					string value = FindValue(collection,keys[i]);
+					if (!String.Empty.Equals(value)) {
+						return value;
+					}
+				}
+				return String.Empty;
+			}
+
+			internal static string FindValue(NameValueCollection collection, string key)
+			{
+				if (collection == null) {
+					return String.Empty;
+				}
+
+				string value = collection[key];
+				return (value != null) ? value : String.Empty;
+			}
+
+			internal static void UpdateValue(NameValueCollection collection,string[] keys,string value)
+			{
+				for(int i=0; i < keys.Length; i++) {
+					if (collection[keys[i]] != null) {
+						collection[keys[i]] = value;
+					}
+				}
+			}
+
+			internal static void AddValue(NameValueCollection collection,string[] keys,string value)
+			{
+				for(int i=0; i < keys.Length; i++) {
+					collection[keys[i]] = value;
+				}
+			}
+
+			/**
+			* Parses connection string and builds NameValueCollection 
+			* for all keys.
+			*/ 
+			internal static NameValueCollection BuildUserParameters (string connectionString)
+			{
+				NameValueCollection userParameters = new NameValueCollection();
+
+				if (connectionString == null || connectionString.Length == 0) {
+					return userParameters;
+				}
+				connectionString += ";";
+
+				bool inQuote = false;
+				bool inDQuote = false;
+				bool inName = true;
+
+				string name = String.Empty;
+				string value = String.Empty;
+				StringBuilder sb = new StringBuilder ();
+
+				for (int i = 0; i < connectionString.Length; i += 1) {
+					char c = connectionString [i];
+					char peek;
+					if (i == connectionString.Length - 1)
+						peek = '\0';
+					else
+						peek = connectionString [i + 1];
+
+					switch (c) {
+						case '\'':
+							if (inDQuote)
+								sb.Append (c);
+							else if (peek.Equals(c)) {
+								sb.Append(c);
+								i += 1;
+							}
+							else
+								inQuote = !inQuote;
+							break;
+						case '"':
+							if (inQuote)
+								sb.Append(c);
+							else if (peek.Equals(c)) {
+								sb.Append(c);
+								i += 1;
+							}
+							else
+								inDQuote = !inDQuote;
+							break;
+						case ';':
+							if (inDQuote || inQuote)
+								sb.Append(c);
+							else {
+								if (name != String.Empty && name != null) {
+									value = sb.ToString();
+									userParameters [name.Trim()] = value.Trim();
+								}
+								inName = true;
+								name = String.Empty;
+								value = String.Empty;
+								sb = new StringBuilder();
+							}
+							break;
+						case '=':
+							if (inDQuote || inQuote || !inName)
+								sb.Append (c);
+							else if (peek.Equals(c)) {
+								sb.Append (c);
+								i += 1;
+							}
+							else {
+								name = sb.ToString();
+								sb = new StringBuilder();
+								inName = false;
+							}
+							break;
+						case ' ':
+							if (inQuote || inDQuote)
+								sb.Append(c);
+							else if (sb.Length > 0 && !peek.Equals(';'))
+								sb.Append(c);
+							break;
+						default:
+							sb.Append(c);
+							break;
+					}
+				}
+				return userParameters;
+			}
+		}
+
+		#endregion // ConnectionStringHelper
+
+		#region DataSourceCache
+
+		private sealed class DataSourceCache : AbstractDbMetaDataCache
+		{
+			internal DataSource GetDataSource(string dataSourceName,string namingProviderUrl,string namingFactoryInitial)
+			{
+				Hashtable cache = Cache;
+
+				DataSource ds = cache[dataSourceName] as DataSource;
+
+				if (ds != null) {
+					return ds;
+				}
+
+				Context ctx = null;
+				
+				java.util.Properties properties = new java.util.Properties();
+
+				if ((namingProviderUrl != null) && (namingProviderUrl.Length > 0)) {
+					properties.put("java.naming.provider.url",namingProviderUrl);
+				}
+				
+				if ((namingFactoryInitial != null) && (namingFactoryInitial.Length > 0)) {
+					properties.put("java.naming.factory.initial",namingFactoryInitial);
+				}
+
+				ctx = new InitialContext(properties);
+ 
+				try {
+					ds = (DataSource)ctx.lookup(dataSourceName);
+				}
+				catch(javax.naming.NameNotFoundException e) {
+					// possible that is a Tomcat bug,
+					// so try to lookup for jndi datasource with "java:comp/env/" appended
+					ds = (DataSource)ctx.lookup("java:comp/env/" + dataSourceName);
+				}
+
+				cache[dataSourceName] = ds;
+				return ds;
+			}
+		}
+
+		#endregion // DatasourceCache
+
+		#region Declarations
+
+		protected internal enum JDBC_MODE { NONE, DATA_SOURCE_MODE, JDBC_DRIVER_MODE, PROVIDER_MODE }
+		protected internal enum PROVIDER_TYPE { NONE, SQLOLEDB, MSDAORA, IBMDADB2 }
+
+		#endregion // Declarations
+		
+		#region Fields
+
+		private static DataSourceCache _dataSourceCache = new DataSourceCache();
+		private const int DEFAULT_TIMEOUT = 15;
+
+		private Connection _jdbcConnnection;
+		private ConnectionState _internalState;
+		private object _internalStateSync = new object();
+
+		private NameValueCollection _userParameters;
+
+		protected string _connectionString = String.Empty;
+		protected string _jdbcUrl;		
+
+		private ArrayList _referencedObjects = new ArrayList();	
+		private ObjectNameResolver[] _syntaxPatterns;
+
+		#endregion // Fields
+
+		#region Constructors
+
+		public AbstractDBConnection(string connectionString)
+		{
+			_connectionString = connectionString;
+			InitializeSkippedUserParameters();
+		}
+
+		#endregion // Constructors
+
+		#region Properties
+
+		public override String ConnectionString
+		{
+			get { return _connectionString; }
+			set {
+				if (IsOpened) {
+					throw ExceptionHelper.NotAllowedWhileConnectionOpen("ConnectionString",_internalState);
+				}					
+				_connectionString = value;
+				_userParameters = null;
+				_jdbcUrl = null;
+			}
+		}
+
+		public override int ConnectionTimeout
+		{
+			get {
+				string timeoutStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_TIMEOUT"));
+				if (!String.Empty.Equals(timeoutStr)) {
+					try {
+						return Convert.ToInt32(timeoutStr);
+					}
+					catch(FormatException e) {
+						throw ExceptionHelper.InvalidValueForKey("connect timeout");
+					}
+					catch (OverflowException e) {
+						throw ExceptionHelper.InvalidValueForKey("connect timeout");
+					}
+				}
+				return DEFAULT_TIMEOUT;
+			}
+		}
+
+		public override String Database
+		{
+			get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATABASE")); }
+		}
+
+		public override ConnectionState State
+		{
+			get {
+				try {
+					if ((JdbcConnection == null) || JdbcConnection.isClosed()) {
+						// jdbc connection not initialized or closed
+						if (_internalState == ConnectionState.Closed ) {
+							return ConnectionState.Closed;
+						}
+					}
+					else {
+						// jdbc connection is opened
+						if ((_internalState & ConnectionState.Open) != 0) {
+							return ConnectionState.Open;
+						}
+					}
+					return ConnectionState.Broken;										
+				}	
+				catch (SQLException) {
+					return ConnectionState.Broken;
+				}				
+			}
+		}
+
+		internal bool IsExecuting
+		{
+			get { 
+				return ((_internalState & ConnectionState.Executing) != 0);
+			}
+
+			set {
+				lock(_internalStateSync) {
+					// to switch to executing, the connection must be in opened
+					if (value) {
+						if (_internalState != ConnectionState.Open) {
+							if (IsFetching) {
+								throw ExceptionHelper.OpenedReaderExists();
+							}
+							throw ExceptionHelper.OpenConnectionRequired("",_internalState);
+						}
+						_internalState |= ConnectionState.Executing;
+					}
+					else { 
+						if (!IsExecuting) {
+							throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Executing.ToString() + " while in state " + _internalState.ToString());
+						}
+						_internalState &= ~ConnectionState.Executing;
+					}
+				}
+			}
+		}
+
+		internal bool IsFetching
+		{
+			get {
+				return ((_internalState & ConnectionState.Fetching) != 0);
+			}
+
+			set {
+				lock(_internalStateSync) {
+					if (value) {
+						// to switch to fetching connection must be in opened, executing
+						if (((_internalState & ConnectionState.Open) == 0) || ((_internalState & ConnectionState.Executing) == 0)) {
+							throw ExceptionHelper.OpenConnectionRequired("",_internalState);
+						}
+						_internalState |= ConnectionState.Fetching;
+					}
+					else {
+						if (!IsFetching) {
+							throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Fetching.ToString() + " while in state " + _internalState.ToString());
+						}
+						_internalState &= ~ConnectionState.Fetching;
+					}
+				}
+			}
+		}
+
+		internal bool IsOpened
+		{
+			get {
+				return ((_internalState & ConnectionState.Open) != 0);
+			}
+
+			set {
+				lock(_internalStateSync) {			
+					if (value) {
+						// only connecting connection can be opened
+						if ((_internalState != ConnectionState.Connecting)) {
+							throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
+						}
+						_internalState |= ConnectionState.Open;
+					}
+					else {
+						if (!IsOpened) {
+							throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Open.ToString() + " while in state " + _internalState.ToString());
+						}
+						_internalState &= ~ConnectionState.Open;
+					}
+				}
+			}
+		}
+
+		internal bool IsConnecting
+		{
+			get {
+				return ((_internalState & ConnectionState.Connecting) != 0);
+			}
+
+			set {
+				lock(_internalStateSync) {			
+					if (value) {
+						// to switch to connecting conection must be in closed or in opened
+						if ((_internalState != ConnectionState.Closed) && (_internalState != ConnectionState.Open)) {
+							throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
+						}
+						_internalState |= ConnectionState.Connecting;
+					}
+					else {
+						if (!IsConnecting) {
+							throw new InvalidOperationException("Connection : Impossible to tear down from state " + ConnectionState.Connecting.ToString() + " while in state " + _internalState.ToString());
+						}
+						_internalState &= ~ConnectionState.Connecting;
+					}
+				}
+			}
+		}
+
+		protected virtual PROVIDER_TYPE ProviderType
+		{
+			get {
+				if (JdbcMode != JDBC_MODE.PROVIDER_MODE) {
+					return PROVIDER_TYPE.NONE;
+				}
+				
+				string providerStr = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PROVIDER"));
+				if (providerStr.StartsWith("SQLOLEDB")) {
+					return PROVIDER_TYPE.SQLOLEDB;
+				}
+				else if (providerStr.StartsWith("MSDAORA")) {
+					return PROVIDER_TYPE.MSDAORA;
+				}
+				else if (providerStr.StartsWith("IBMDADB2")) {
+					return PROVIDER_TYPE.IBMDADB2;
+				}
+				return PROVIDER_TYPE.NONE;
+			}
+		}
+
+		protected internal virtual JDBC_MODE JdbcMode
+		{
+			get { 
+				string[] conJndiNameStr = StringManager.GetStringArray("CON_JNDI_NAME");
+				if ( !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,conJndiNameStr))) {
+					return JDBC_MODE.DATA_SOURCE_MODE;
+				}
+
+				string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
+				string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
+				bool jdbcDriverSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr));
+				bool jdbcUrlSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr));
+
+				if (jdbcDriverSpecified && jdbcUrlSpecified) {
+					return JDBC_MODE.JDBC_DRIVER_MODE;
+				}
+
+				string[] providerStr = StringManager.GetStringArray("CON_PROVIDER");
+				if (!String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,providerStr))) {
+					return JDBC_MODE.PROVIDER_MODE;
+				}
+				
+				return JDBC_MODE.NONE;
+			}
+		}
+
+		protected virtual string JdbcDriverName
+		{
+			get { return String.Empty; }
+		}
+
+		protected abstract DbStringManager StringManager
+		{
+			get;
+		}
+
+		protected virtual string ServerName
+		{
+			get { return DataSource; }
+		}
+
+		protected virtual string CatalogName
+		{
+			get { return Database; }
+		}
+
+		protected virtual string Port
+		{
+			get {
+				string port = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_PORT"));
+				switch (ProviderType) {
+					case PROVIDER_TYPE.SQLOLEDB : 
+						if (String.Empty.Equals(port)) {
+							// if needed - resolve MSSQL port
+							// FIXME : decide about behaviour in the case all the timeout spent on port resolution
+							//long start = DateTime.Now.Ticks;
+							port = DbPortResolver.getMSSqlPort(DataSource,InstanceName,ConnectionTimeout).ToString();
+							//long end = DateTime.Now.Ticks;													
+							//if( (end - start) < ConnectionTimeout*1000000) {								
+								//timeout -= (int)(end - start)/1000000;
+							//}
+						}
+						// todo : what should we do if all the timeout spent on port resolution ?
+						if ("-1".Equals(port)) {
+							port = StringManager.GetString("SQL_CON_PORT", "1433"); //default port of MSSql Server 3167.
+						}
+						ConnectionStringHelper.AddValue(UserParameters,StringManager.GetStringArray("CON_PORT"),port);
+						break;
+				}
+				return port;
+			}
+		}
+
+		public override string DataSource
+		{
+			get {
+				string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));
+
+				if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {
+					int instanceIdx;
+					if ((instanceIdx = dataSource.IndexOf("\\")) != -1) {
+						// throw out named instance name
+						dataSource = dataSource.Substring(0,instanceIdx);
+					}
+
+					if (dataSource != null && dataSource.StartsWith("(") && dataSource.EndsWith(")")) {						
+						dataSource = dataSource.Substring(1,dataSource.Length - 2);
+					}
+
+					if(String.Empty.Equals(dataSource) || (String.Compare("local",dataSource,true) == 0)) {
+						dataSource = "localhost";
+					}
+				}
+				return dataSource;
+			}
+		}
+
+		protected virtual string InstanceName
+		{
+			get {
+				string dataSource = ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_DATA_SOURCE"));
+				string instanceName = String.Empty;
+				if (ProviderType == PROVIDER_TYPE.SQLOLEDB) {
+					int instanceIdx;
+					if ((instanceIdx = dataSource.IndexOf("\\")) == -1) {
+						// no named instance specified - use a default name
+						instanceName = StringManager.GetString("SQL_DEFAULT_INSTANCE_NAME");
+					}
+					else {
+						// get named instance name
+						instanceName = dataSource.Substring(instanceIdx + 1);
+					}
+				}
+				return instanceName;
+			}
+		}
+
+		protected virtual string User
+		{
+			get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_USER_ID")); }
+		}
+
+		protected virtual string Password
+		{
+			get { return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("CON_PASSWORD")); }
+		}
+
+		protected NameValueCollection UserParameters
+		{
+			get {
+				if (_userParameters == null) {
+					_userParameters = ConnectionStringHelper.BuildUserParameters(ConnectionString);
+				}
+				return _userParameters;
+			}
+		}
+
+		internal String JdbcUrl 
+		{
+			get { 
+				if ( UserParameters == null) {
+					return String.Empty;
+				}
+
+				if (_jdbcUrl == null) {
+					_jdbcUrl = BuildJdbcUrl();
+				}
+				return _jdbcUrl;
+			}
+		}
+
+		internal ConnectionState InternalState
+		{
+			get	{ return _internalState; }
+		}
+
+
+		protected internal Connection JdbcConnection
+		{
+			get { return _jdbcConnnection; }
+			set { _jdbcConnnection = value; }
+		}
+
+		protected virtual string[] ResourceIgnoredKeys
+		{
+			get { return new string[0]; }
+		}
+
+		protected virtual Hashtable SkippedUserParameters
+		{
+			get { return new Hashtable(new CaseInsensitiveHashCodeProvider(),new CaseInsensitiveComparer()); }
+		}
+
+		internal ObjectNameResolver[] SyntaxPatterns
+		{
+			get {
+				if (_syntaxPatterns == null) {
+					_syntaxPatterns = ObjectNamesHelper.GetSyntaxPatterns(this);
+				}
+				return _syntaxPatterns;
+			}
+		}
+
+		#endregion // Properties
+
+		#region Methods
+			// since WS also does not permits dynamically change of login timeout and tomcat does no implements - do not do it at all
+			//ds.setLoginTimeout(ConnectionTimeout);
+
+		internal abstract void OnSqlWarning(SQLWarning warning);
+
+		internal abstract void OnStateChanged(ConnectionState orig, ConnectionState current);
+
+		protected abstract SystemException CreateException(SQLException e);
+
+		public override void Close()
+		{
+			try {
+				ClearReferences();
+				if (JdbcConnection != null && !JdbcConnection.isClosed()) {
+					JdbcConnection.close();
+				}
+			}
+			catch (SQLException e) {
+				// suppress exception
+				JdbcConnection = null;
+#if DEBUG
+				Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
+#endif
+			}
+			catch (Exception e) {
+				// suppress exception
+				JdbcConnection = null;
+#if DEBUG
+				Console.WriteLine("Exception catched at Conection.Close() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
+#endif
+			}
+			finally {
+				lock(_internalStateSync) {
+					_internalState = ConnectionState.Closed;
+				}
+			}
+		}
+
+		protected internal virtual void CopyTo(AbstractDBConnection target)
+		{
+			target._connectionString = _connectionString;
+		}
+
+		internal protected virtual void OnSqlException(SQLException exp)
+		{
+			throw CreateException(exp);
+		}
+
+		internal void AddReference(object referencedObject)
+		{	lock(_referencedObjects.SyncRoot) {
+				_referencedObjects.Add(new WeakReference(referencedObject));
+			}
+		}
+
+		internal void RemoveReference(object referencedObject)
+		{
+			lock(_referencedObjects.SyncRoot) {
+				for(int i = 0; i < _referencedObjects.Count; i++) {
+					WeakReference wr = (WeakReference) _referencedObjects[i];
+					if (wr.IsAlive && (wr.Target == referencedObject)) {
+						_referencedObjects.RemoveAt(i);
+					}
+				}
+			}
+		}
+
+		private void ClearReferences()
+		{
+			ArrayList oldList = _referencedObjects;
+			_referencedObjects = new ArrayList();
+
+			for(int i = 0; i < oldList.Count; i++) {
+				WeakReference wr = (WeakReference) oldList[i];
+				if (wr.IsAlive) {
+					ClearReference(wr.Target);
+				}
+			}
+		}
+
+		private void ClearReference(object referencedObject)
+		{
+			try {
+				if (referencedObject is AbstractDbCommand) {
+					((AbstractDbCommand)referencedObject).CloseInternal();
+				}
+				else if (referencedObject is AbstractDataReader) {
+					((AbstractDataReader)referencedObject).CloseInternal();
+				}
+			}
+			catch (SQLException) {
+				// suppress exception since it's possible that command or reader are in inconsistent state
+			}
+		}
+
+		public override void Open()
+		{
+			if (_connectionString == null || _connectionString.Length == 0) {
+				throw ExceptionHelper.ConnectionStringNotInitialized();
+			}
+
+			IsConnecting = true;
+			try {			
+				if (JdbcConnection != null && !JdbcConnection.isClosed()) {
+					throw ExceptionHelper.ConnectionAlreadyOpen(_internalState);
+				}
+	
+				switch(JdbcMode) {
+					case JDBC_MODE.DATA_SOURCE_MODE :
+						JdbcConnection = GetConnectionFromDataSource();
+						break;
+
+					case JDBC_MODE.JDBC_DRIVER_MODE:
+						JdbcConnection = GetConnectionFromJdbcDriver();
+						break;
+
+					case JDBC_MODE.PROVIDER_MODE : 					
+						JdbcConnection = GetConnectionFromProvider();
+						break;
+				}
+				IsOpened = true;
+
+				OnStateChanged(ConnectionState.Closed, ConnectionState.Open);
+			}
+			catch (SQLWarning warning) {
+				OnSqlWarning(warning);
+			}
+			catch (SQLException exp) {
+				OnSqlException(exp);
+			}
+			finally {
+				IsConnecting = false;
+			}
+		}
+
+		public override void ChangeDatabase(String database)
+		{
+			IsConnecting = true;
+			try {
+				ClearReferences();
+				Connection con = JdbcConnection;				
+				con.setCatalog(database);
+				ConnectionStringHelper.UpdateValue(UserParameters,StringManager.GetStringArray("CON_DATABASE"),database);
+			}
+			catch (SQLWarning warning) {
+				OnSqlWarning(warning);
+			}
+			catch (SQLException exp) {
+				throw CreateException(exp);
+			}
+			finally {
+				IsConnecting = false;
+			}
+		}
+
+		public override string ServerVersion {
+			get {
+				// only if the driver support this methods
+				try {
+					if (JdbcConnection == null)
+						return String.Empty;
+
+					DatabaseMetaData metaData = JdbcConnection.getMetaData();
+					return metaData.getDatabaseProductVersion();
+				}
+				catch (SQLException exp) {
+					throw CreateException(exp);
+				}
+			}
+		}
+
+		internal string JdbcProvider {
+			get {
+				// only if the driver support this methods
+				try {
+					if (JdbcConnection == null)
+						return String.Empty;
+
+					DatabaseMetaData metaData = JdbcConnection.getMetaData();
+					return metaData.getDriverName() + " " + metaData.getDriverVersion();
+				}
+				catch (SQLException exp) {
+					return String.Empty; //suppress
+				}
+			}
+		}
+
+		protected override void Dispose(bool disposing)
+		{
+			if (disposing) {
+				try {
+					if (JdbcConnection != null && !JdbcConnection.isClosed()) {
+						JdbcConnection.close();
+					}	                
+					JdbcConnection = null;
+				}
+				catch (java.sql.SQLException exp) {
+					throw CreateException(exp);
+				}
+			}
+			base.Dispose(disposing);
+		}
+
+		protected internal virtual void ValidateConnectionString(string connectionString)
+		{
+			JDBC_MODE currentJdbcMode = JdbcMode;
+			
+			if (currentJdbcMode == JDBC_MODE.NONE) {
+				string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
+				string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
+				bool jdbcDriverSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr));
+				bool jdbcUrlSpecified = !String.Empty.Equals(ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr));
+
+				if (jdbcDriverSpecified ^ jdbcUrlSpecified) {
+					throw new ArgumentException("Invalid format of connection string. If you want to use third-party JDBC driver, the format is: \"JdbcDriverClassName=<jdbc driver class name>;JdbcURL=<jdbc url>\"");
+				}				
+			}
+		}
+
+		protected virtual string BuildJdbcUrl()
+		{
+			switch (JdbcMode) {
+				case JDBC_MODE.JDBC_DRIVER_MODE :
+					return ConnectionStringHelper.FindValue(UserParameters,StringManager.GetStringArray("JDBC_URL"));
+				default :
+					return String.Empty;
+			}
+		}
+
+		protected java.util.Properties BuildProperties()
+		{
+			java.util.Properties properties = new java.util.Properties();
+
+			string user = User;
+			if (user != null && user.Length > 0)
+				properties.put("user", user);
+			string password = Password;
+			if (user != null && user.Length > 0)
+				properties.put("password", password);
+
+			string[] userKeys = UserParameters.AllKeys;
+
+			for(int i=0; i < userKeys.Length; i++) {
+				string userKey = userKeys[i];
+				string userParameter = UserParameters[userKey];
+				if (!SkipUserParameter(userKey)) {
+					properties.put(userKey,userParameter);
+				}
+			}
+			return properties;
+		}
+
+		protected virtual bool SkipUserParameter(string parameterName)
+		{
+			if (SkippedUserParameters.Count == 0) {
+				// skipped parameters not initialized - skip all
+				return true;
+			}
+
+			return SkippedUserParameters.Contains(parameterName);
+		}
+
+		protected virtual void InitializeSkippedUserParameters()
+		{
+			if (SkippedUserParameters.Count > 0) {
+				return;
+			}
+
+			for(int i=0; i < ResourceIgnoredKeys.Length; i++) {
+				string[] userKeys = StringManager.GetStringArray(ResourceIgnoredKeys[i]);
+				for(int j=0; j < userKeys.Length; j++) {
+					SkippedUserParameters.Add(userKeys[j],userKeys[j]);
+				}
+			}
+		}
+ 
+		internal void ValidateBeginTransaction()
+		{
+			if (State != ConnectionState.Open) {
+				throw new InvalidOperationException(Res.GetString("ADP_OpenConnectionRequired_BeginTransaction", new object[] {"BeginTransaction", State}));
+			}
+
+			if (!JdbcConnection.getAutoCommit()) {
+				throw new System.InvalidOperationException("Parallel transactions are not supported.");
+			}
+		}
+
+		internal virtual Connection GetConnectionFromProvider()
+		{
+			ActivateJdbcDriver(JdbcDriverName);
+			DriverManager.setLoginTimeout(ConnectionTimeout);
+			java.util.Properties properties = BuildProperties();
+			return DriverManager.getConnection (JdbcUrl, properties);
+		}
+
+		internal Connection GetConnectionFromDataSource()
+		{
+			string dataSourceJndi = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_NAME"));
+			string namingProviderUrl = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_PROVIDER"));
+			string namingFactoryInitial = ConnectionStringHelper.FindValue(UserParameters, StringManager.GetStringArray("CON_JNDI_FACTORY"));
+			DataSource ds = _dataSourceCache.GetDataSource(dataSourceJndi,namingProviderUrl,namingFactoryInitial);
+			try {
+				ds.setLoginTimeout(ConnectionTimeout);
+			}
+			catch (java.lang.Exception) {
+				// WebSphere does not allows dynamicall change of login timeout
+				// setLoginTimeout is not supported yet
+				// in Tomcat data source.
+				// In this case we work wthout timeout.
+			}
+			return ds.getConnection();
+		}
+
+		internal virtual Connection GetConnectionFromJdbcDriver()
+		{
+			string[] jdbcDriverStr = StringManager.GetStringArray("JDBC_DRIVER");
+			string[] jdbcUrlStr = StringManager.GetStringArray("JDBC_URL");
+		
+			string jdbcDriverName = ConnectionStringHelper.FindValue(UserParameters,jdbcDriverStr);
+			string jdbcUrl = ConnectionStringHelper.FindValue(UserParameters,jdbcUrlStr);
+
+			ActivateJdbcDriver(jdbcDriverName);
+			DriverManager.setLoginTimeout(ConnectionTimeout);
+
+			java.util.Properties properties = BuildProperties();
+
+			return DriverManager.getConnection(jdbcUrl,properties);
+		}
+
+		internal ArrayList GetProcedureColumns(String procedureString, AbstractDbCommand command)
+		{
+			ArrayList col = new ArrayList();
+			try {
+				ObjectNameResolver[] nameResolvers = SyntaxPatterns;
+				ResultSet res = null;
+				string catalog = null;
+				string schema = null;
+				string spname = null;
+						
+				DatabaseMetaData metadata = JdbcConnection.getMetaData();	
+				bool storesUpperCaseIdentifiers = false;
+				bool storesLowerCaseIdentifiers = false;
+				try {
+					storesUpperCaseIdentifiers = metadata.storesUpperCaseIdentifiers();
+					storesLowerCaseIdentifiers = metadata.storesLowerCaseIdentifiers();
+				}
+				catch (SQLException e) {
+					// suppress
+				}
+
+				for(int i=0; i < nameResolvers.Length; i++) {
+					ObjectNameResolver nameResolver = nameResolvers[i];
+					Match match = nameResolver.Match(procedureString);
+
+					if (match.Success) {
+						spname = ObjectNameResolver.GetName(match);				
+						schema = ObjectNameResolver.GetSchema(match);						
+						catalog = ObjectNameResolver.GetCatalog(match);						
+
+						// make all identifiers uppercase or lowercase according to database metadata
+						if (storesUpperCaseIdentifiers) {
+							spname = (spname.Length > 0) ? spname.ToUpper() : null;
+							schema = (schema.Length > 0) ? schema.ToUpper() : null;
+							catalog = (catalog.Length > 0) ? catalog.ToUpper() : null;
+						}
+						else if (storesLowerCaseIdentifiers) {
+							spname = (spname.Length > 0) ? spname.ToLower() : null;
+							schema = (schema.Length > 0) ? schema.ToLower() : null;
+							catalog = (catalog.Length > 0) ? catalog.ToLower() : null;
+						}
+						else {
+							spname = (spname.Length > 0) ? spname : null;
+							schema = (schema.Length > 0) ? schema : null;
+							catalog = (catalog.Length > 0) ? catalog : null;
+						}
+
+						// catalog from db is always in correct caps
+						if (catalog == null) {
+							catalog = JdbcConnection.getCatalog();
+						}
+
+						try {
+							// always get the first procedure that db returns
+							res = metadata.getProcedures(catalog, schema, spname);												
+							if (res.next()) {
+								catalog = res.getString(1);
+								schema = res.getString(2);
+								spname = res.getString(3);
+								break;
+							}
+
+							spname = null;
+						}
+						catch { // suppress exception
+							return null;
+						}
+						finally {
+							if (res != null) {
+								res.close();
+							}
+						}
+					}
+				}	
+		
+				if (spname == null || spname.Length == 0) {
+					return null;
+				}
+				
+				try {
+					// get procedure columns based o  procedure metadata
+					res = metadata.getProcedureColumns(catalog, schema, spname, null);				
+					while (res.next()) {
+						// since there is still a possibility that some of the parameters to getProcedureColumn were nulls, 
+						// we need to filter the results with strict matching
+						if ((res.getString(1) != catalog ) || (res.getString(2) != schema) || (res.getString(3) != spname)) {
+							continue;
+						}
+
+						AbstractDbParameter parameter = (AbstractDbParameter)command.CreateParameter();
+						
+						parameter.SetParameterName(res);
+						parameter.SetParameterDbType(res);
+						parameter.SetSpecialFeatures(res);
+
+						//get parameter direction
+						short direction = res.getShort("COLUMN_TYPE");
+						if(direction == 1) //DatabaseMetaData.procedureColumnIn
+							parameter.Direction = ParameterDirection.Input;
+						else if(direction == 2) //DatabaseMetaData.procedureColumnInOut
+							parameter.Direction = ParameterDirection.InputOutput;
+						else if(direction == 4) //DatabaseMetaData.procedureColumnOut
+							parameter.Direction = ParameterDirection.Output;
+						else if(direction == 5) //DatabaseMetaData.procedureColumnReturn
+							parameter.Direction = ParameterDirection.ReturnValue;
+					
+						//get parameter precision and scale
+						parameter.SetParameterPrecisionAndScale(res);
+
+						parameter.SetParameterSize(res);
+						parameter.SetParameterIsNullable(res);
+
+						col.Add(parameter);
+					}
+				}
+				finally {
+					if (res != null) {
+						res.close();
+					}
+				}				
+			}
+			catch(Exception e) {
+				//supress
+#if DEBUG
+				Console.WriteLine("Exception catched at AbstractDBConnection.GetProcedureColumns() : {0}\n{1}\n{2}",e.GetType().FullName,e.Message,e.StackTrace);
+#endif
+			}
+			return col;
+		}
+
+		protected static void ActivateJdbcDriver(string driver)
+		{
+			if(driver != null) {
+				try {
+					java.lang.Class.forName(driver).newInstance();
+				}
+				catch (java.lang.ClassNotFoundException e) {
+					throw new TypeLoadException(e.Message);
+				}
+				catch (java.lang.InstantiationException e) {
+					throw new MemberAccessException(e.Message);
+				}
+                catch (java.lang.IllegalAccessException e) {
+					throw new MissingMethodException(e.Message);
+				}
+			}
+		}
+
+		protected String BuildMsSqlUrl()
+		{
+			return StringManager.GetString("SQL_JDBC_URL") //"jdbc:microsoft:sqlserver://"
+				+ ServerName + ":" + Port + ";DatabaseName=" + CatalogName;
+		}
+
+		#endregion // Methods	
+	}
+}

+ 259 - 0
mcs/class/System.Data/System.Data.Common/AbstractDBParameter.cs

@@ -0,0 +1,259 @@
+//namespace System.Data.Common
+//{
+//
+//    //using clr.System;
+//    //using clr.compiler.BitConstants;
+//
+//    using System.Data;
+//	using System.Data.ProviderBase;
+//	using System.Text;
+//
+//    /**
+//     * @author erand
+//     */
+//    public abstract class AbstractDBParameter : DbParameterBase, System.ICloneable
+//    {
+//        /* Properties from IDataParameter */
+////        protected ParameterDirection _direction = ParameterDirection.Input;
+////        protected bool _isNullable = false;
+////        protected String _name = null;
+////        protected String _sourceColumn = null;
+//        protected DataRowVersion _version = DataRowVersion.Current;
+////        protected Object _value = null;
+//
+//        /* Properties from IDbDataParameter */
+////        protected byte _precision;
+////        protected byte _scale;
+////        protected int _size = -1;
+//
+//        private int _place;
+//		private int _jdbcType;
+//    
+////        /**
+////         * @see System.Data.IDbDataParameter#Precision
+////         */
+////        public virtual byte Precision
+////        {
+////            get
+////            {
+////                return _precision;
+////            }
+////            set
+////            {
+////                _precision = value;
+////            }
+////        }
+//
+//        
+////        /**
+////         * @see System.Data.IDbDataParameter#Scale
+////         */
+////        public virtual byte Scale
+////        {
+////            get
+////            {
+////                return _scale;
+////            }
+////            set
+////            {
+////                _scale = value;
+////            }
+////        }
+//
+//        
+//
+////        /**
+////         * @see System.Data.IDbDataParameter#Size
+////         */
+////        public virtual int Size
+////        {
+////            get
+////            {
+////                return _size;
+////            }
+////            set
+////            {
+////                _size = value;
+////            }
+////        }
+//
+//        
+////        /**
+////         * @see System.Data.IDataParameter#Direction
+////         */
+////        public virtual ParameterDirection Direction
+////        {
+////            get
+////            {
+////                return _direction;
+////            }
+////            set
+////            {
+////                _direction = value;
+////            }
+////        }
+//
+//        
+////        /**
+////         * @see System.Data.IDataParameter#IsNullable
+////         */
+////        public virtual bool IsNullable
+////        {
+////            get
+////            {
+////                return _isNullable;
+////            }
+////            set
+////            {
+////                _isNullable = value;
+////            }
+////        }
+//
+//        
+////        /**
+////         * @see System.Data.IDataParameter#ParameterName
+////         */
+////        public virtual String ParameterName
+////        {
+////            get
+////            {
+////                /**@todo What's the value of the Empty string ?*/
+////                /*Where to define our Empty String ?*/
+////                if (_name == null)
+////                    return String.Empty;
+////                else
+////                    return _name;
+////            }
+////            set
+////            {
+////                if ((value != null) && value.Equals(_name))
+////                    return;
+////                //if ((value != null) && (value.length() > Constants.MAXIMAL_PARAMETER_LENGTH))
+////                /**@todo Implement Exception::-->*/
+////                //    throw InvalidParameterLength(value);
+////
+////                _name = value;
+////            }
+////        }
+//
+//        
+////        /**
+////         * @see System.Data.IDataParameter#SourceColumn
+////         */
+////        public virtual String SourceColumn
+////        {
+////            get
+////            {
+////                if (_sourceColumn != null)
+////                    return _sourceColumn;
+////                else
+////                    return String.Empty;
+////            }
+////            set
+////            {
+////                _sourceColumn = value;
+////            }
+////        }
+//
+//        
+//
+////        /**
+////         * @see System.Data.IDataParameter#SourceVersion
+////         */
+////        public virtual DataRowVersion SourceVersion
+////        {
+////            get
+////            {
+////                return _version;
+////            }
+////            set
+////            {
+////                _version = value;
+////            }
+////        }
+//
+//        
+////        /**
+////         * @see System.Data.IDataParameter#Value
+////         */
+////        public virtual Object Value
+////        {
+////            get
+////            {
+////                return _value;
+////            }
+////            set
+////            {
+////                _value = value;
+////            }
+////        }
+//
+//        
+//
+//        public virtual void setParameterPlace(int place)
+//        {
+//            _place = place;
+//        }
+//
+//        public virtual int getParameterPlace()
+//        {
+//            return _place;
+//        }
+//
+//        abstract internal int getJDBCType(DbType dbType);
+//
+//		internal int JdbcType
+//		{
+//			get {
+//				return _jdbcType;
+//			}
+//
+//			set {
+//				_jdbcType = value;
+//			}
+//		}
+//
+//        public abstract DbType DbType
+//        {
+//            get;
+//            set;
+//        }
+//
+//        public abstract Object Clone();
+//
+//		internal virtual bool IsOracleRefCursor
+//		{
+//			get
+//			{
+//				return false;
+//			}
+//		}
+//        
+//        internal virtual String formatParameter()
+//        {
+//			if (Value == null || Value == DBNull.Value)
+//				return "NULL";
+//	            
+//			switch(DbType) {
+//				case DbType.Byte:
+//				case DbType.Currency:
+//				case DbType.Decimal:
+//				case DbType.Double:
+//				case DbType.Int16:
+//				case DbType.Int32:
+//				case DbType.Int64:
+//				case DbType.SByte:
+//				case DbType.Single:
+//				case DbType.UInt16:
+//				case DbType.UInt32:
+//				case DbType.UInt64:
+//					return Value.ToString();
+//				case DbType.Boolean:
+//					return (bool)Value ? "0x1" : "0x0";
+//				case DbType.Binary:
+//				default:
+//					return String.Concat("\'", Value.ToString().Replace("\'", "\'\'"),"\'");
+//			}
+//        }
+//    }
+//}

+ 1179 - 0
mcs/class/System.Data/System.Data.Common/AbstractDataReader.cs

@@ -0,0 +1,1179 @@
+//
+// System.Data.Common.AbstractDataReader
+//
+// Author:
+//   Boris Kirzner ([email protected])
+//   Konstantin Triger ([email protected])
+//
+
+using System;
+using System.Data;
+using System.Collections;
+using System.Data.ProviderBase;
+
+using java.io;
+using java.sql;
+
+namespace System.Data.Common
+{
+	public abstract class AbstractDataReader : DbDataReaderBase, ISafeDataRecord {
+		#region Fields
+
+		private ResultSetMetaData _resultsMetaData;
+		protected AbstractDbCommand _command;
+		private DataTable _schemaTable;
+		private ReaderState _readerState = ReaderState.Uninitialized;
+
+		private IReaderCacheContainer[] _readerCache;
+		private int _currentCacheFilledPosition; 
+		private Stack _resultSetStack = new Stack();
+
+		[Flags]
+		private enum ReaderState { Uninitialized = 0, Empty = 1, HasRows = 2, FirstRed = 4, Eof = 8, Fetching = 16 };
+
+		internal enum SCHEMA_TABLE { ColumnName,
+			ColumnOrdinal,
+			ColumnSize,
+			NumericPrecision,
+			NumericScale,
+			IsUnique,
+			IsKey,
+			BaseServerName,
+			BaseCatalogName,
+			BaseColumnName,
+			BaseSchemaName,
+			BaseTableName,
+			DataType,
+			AllowDBNull,
+			ProviderType,
+			IsAliased,
+			IsExpression,
+			IsIdentity,
+			IsAutoIncrement,
+			IsRowVersion,
+			IsHidden,
+			IsLong,
+			IsReadOnly};
+
+		#endregion // Fields
+
+		#region Constructors
+
+		protected AbstractDataReader() : base (CommandBehavior.Default) {
+		}
+		
+		public AbstractDataReader(AbstractDbCommand command): base(command.Behavior) {
+			_command = command;
+			if (_command.Connection != null) {
+				((AbstractDBConnection)_command.Connection).AddReference(this);
+			}
+		}
+
+		#endregion // Constructors
+
+		#region Properties
+
+		public override bool HasRows {
+			get {
+				if (IsClosed) {
+					throw new InvalidOperationException("Invalid attempt to HasRows when reader is closed.");
+				}
+
+				try {
+					if(null == Results)
+						return false;
+				}
+				catch(SystemException) {
+					//suppress
+					return false;
+				}
+
+				return (_readerState & ReaderState.HasRows) != 0;
+			}
+		}
+
+		public override int RecordsAffected
+		{
+			// MSDN : The RecordsAffected property is not set 
+			// until all rows are read and you close the reader.
+			get { 
+				return _command.RecordsAffected; 
+			}
+		}
+
+		public override int FieldCount
+		{
+			get {
+				if (ResultsMetaData == null)
+					return 0;
+
+				try {
+					return ResultsMetaData.getColumnCount();
+				}
+				catch (SQLException exp) {
+					throw CreateException(exp);
+				}
+
+			}
+		}
+
+		protected internal CommandBehavior Behavior
+		{
+			get {
+				return _command.Behavior;
+			}
+		}
+
+		public override Object this[String columnName]
+		{
+			get {
+				try {
+					int columnIndex = Results.findColumn(columnName) - 1;
+					return this[columnIndex];
+				}
+				catch (SQLException exp) {
+					throw new IndexOutOfRangeException(exp.Message, exp);
+				}				
+			}
+		}
+
+		public override Object this[int columnIndex]
+		{
+			get { return GetValue(columnIndex); }
+		}
+
+		protected ResultSet Results
+		{
+			get {
+				if (_readerState == ReaderState.Uninitialized) {
+
+					if (_resultSetStack.Count == 0) {
+						ResultSet resultSet =  _command.CurrentResultSet;
+						if (resultSet == null)
+							return null;
+
+						_resultSetStack.Push(resultSet);
+					}
+
+					_readerState = ReaderState.Fetching;
+					for (;;) {
+						try {
+							Configuration.BooleanSetting prefetchSchema = Configuration.Switches.PrefetchSchema;
+
+							if (prefetchSchema == Configuration.BooleanSetting.NotSet) {
+								AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);
+								string driverName = conn.JdbcConnection.getMetaData().getDriverName();
+								if (driverName.IndexOf("DB2") >= 0)
+									prefetchSchema = Configuration.BooleanSetting.True;
+							}
+
+							if (prefetchSchema == Configuration.BooleanSetting.True)
+								GetSchemaTable();
+
+							ResultSet resultSet = (ResultSet)_resultSetStack.Peek();
+							if (resultSet.next()) {
+								_readerState = (ReaderState.HasRows | ReaderState.FirstRed);
+								ResultSetMetaData rsMetaData = ResultsMetaData;
+								DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes)rsMetaData.getColumnType(1);
+								if (javaSqlType == DbTypes.JavaSqlTypes.OTHER) {
+									object value = GetValue(0);
+									if (value != null && value is ResultSet) {
+										_resultsMetaData = null;
+										_readerCache = null;
+										SchemaTable = null;
+										_readerState = ReaderState.Fetching;
+										_resultSetStack.Push(value);
+										continue;
+									}
+								}
+							}
+							else
+								_readerState = ReaderState.Empty;
+
+							break;
+						}
+						catch(SQLException e) {
+							throw CreateException(e);
+						}
+					}
+				}
+
+				return (_resultSetStack.Count > 0) ? (ResultSet)_resultSetStack.Peek() : null;
+			}
+		}
+
+		protected ResultSetMetaData ResultsMetaData
+		{
+			get {
+				ResultSet results = Results;
+				if (results == null) {
+					return null;
+				}
+				if(_resultsMetaData == null) {
+					_resultsMetaData = results.getMetaData();
+				}
+				return _resultsMetaData;
+			}			
+		}
+
+		protected DataTable SchemaTable
+		{
+			get {
+				if (_schemaTable == null) {
+					_schemaTable = ConstructSchemaTable();
+				}
+				return _schemaTable;
+			}
+
+			set {_schemaTable = value; }
+		}
+
+		internal protected IReaderCacheContainer[] ReaderCache
+		{
+			get {
+				if (_readerCache == null) {
+					_readerCache = CreateReaderCache();
+					_currentCacheFilledPosition = -1;
+				}
+				return _readerCache;
+			}
+		}
+
+		#endregion // Properties
+
+		#region Methods
+
+		protected abstract int GetProviderType(int jdbcType);
+
+		protected abstract SystemException CreateException(string message, SQLException e);
+
+		protected abstract SystemException CreateException(IOException e);
+
+		protected SystemException CreateException(SQLException e)
+		{
+			return CreateException(e.Message,e);	
+		}
+
+		private bool CloseCurrentResultSet() {
+			if (_resultSetStack.Count > 0) {
+				try{
+					_resultsMetaData = null;
+					_readerCache = null;
+					_readerState = ReaderState.Uninitialized;
+					ResultSet rs = (ResultSet)_resultSetStack.Pop();
+					rs.close();
+					return true;
+				}
+				catch (SQLException exp) {
+					throw CreateException(exp);
+				}
+			}
+
+			return false;
+		}
+
+		// FIXME : add Close(bool readAllRecords) and pass this bool to skip looping over NextResult(), override AbstractDbCommand.ExecuteScalar
+		public override void Close()
+		{
+			if (IsClosed)
+				return;
+
+			try {
+				CloseCurrentResultSet();
+				_command.OnReaderClosed(this);
+			}
+			finally {
+				CloseInternal();
+			}
+		}
+
+		internal void CloseInternal()
+		{
+			_resultsMetaData = null;
+			_readerCache = null;
+			_isClosed = true;
+		}
+
+		public override bool NextResult()
+		{
+			CloseCurrentResultSet();
+
+			if ((_command.Behavior & CommandBehavior.SingleResult) != 0) {
+				while (CloseCurrentResultSet());
+				while (_command.NextResultSet());
+				return false;
+			}
+
+			try {
+				while (_resultSetStack.Count > 0) {
+					ResultSet rs = (ResultSet)_resultSetStack.Peek();
+
+					if(!rs.next()) {
+						CloseCurrentResultSet();
+						continue;
+					}
+
+					// must be a ResultSet
+					object childRs = rs.getObject(1);
+					if (childRs != null) {
+						SchemaTable = null;
+						_resultSetStack.Push(childRs);
+						return true;
+					}
+				}
+			}
+			catch (SQLException exp) {
+				throw CreateException(exp);
+			}
+				
+			if (_command.NextResultSet()) {
+				SchemaTable = null;	
+				return true;
+			}
+			return false;
+		}
+
+		public override bool Read()
+		{
+			if(null == Results ||
+				(_readerState & (ReaderState.HasRows | ReaderState.Eof)) != ReaderState.HasRows)
+				return false;
+
+			bool firstRead = false;
+
+			try {
+				if ((_readerState & ReaderState.FirstRed) != 0) {
+					firstRead = true;
+					_readerState &= ~ReaderState.FirstRed;
+					return true;
+				}
+				else {
+					bool next = Results.next();
+
+					if (!next)
+						_readerState |= ReaderState.Eof;
+
+					return next;
+				}
+			}			
+			catch (SQLException exp) {
+				// suppress exception as .Net does
+				return false;
+			}
+			finally {
+				// in case of first read we could sampled the first value
+				// to see whether there is a resultset, so _currentCacheFilledPosition
+				// might be already inited
+				if (!firstRead)
+					_currentCacheFilledPosition = -1;
+			}
+		}
+
+		public override bool GetBoolean(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((BooleanReaderCacheContainer)ReaderCache[columnIndex]).GetBoolean();
+		}
+
+		public bool GetBooleanSafe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is BooleanReaderCacheContainer) {
+				return GetBoolean(columnIndex);
+			}
+			else {
+				return Convert.ToBoolean(GetValue(columnIndex));
+			}
+		}
+
+		public override byte GetByte(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((ByteReaderCacheContainer)ReaderCache[columnIndex]).GetByte();
+		}
+
+		public byte GetByteSafe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is ByteReaderCacheContainer) {
+				return GetByte(columnIndex);
+			}
+			else {
+				return Convert.ToByte(GetValue(columnIndex));
+			}
+		}
+
+		public override long GetBytes(
+			int columnIndex,
+			long dataIndex,
+			byte[] buffer,
+			int bufferIndex,
+			int length)
+		{
+			FillReaderCache(columnIndex);
+			byte[] byteArr = ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();
+			long actualLength = ((dataIndex + length) >= byteArr.Length) ? (byteArr.Length - dataIndex) : length;
+			Array.Copy(byteArr,dataIndex,buffer,bufferIndex,actualLength);
+			return actualLength;
+		}
+
+		public virtual byte[] GetBytes(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((BytesReaderCacheContainer)ReaderCache[columnIndex]).GetBytes();
+		}
+
+		public override char GetChar(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			string s = ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();
+			if(s == null) {
+				return '\0';
+			}
+			return s[0];
+		}
+
+		public char GetCharSafe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is StringReaderCacheContainer) {
+				return GetChar(columnIndex);
+			}
+			else {
+				return Convert.ToChar(GetValue(columnIndex));
+			}
+		}
+
+		public override long GetChars(
+			int columnIndex,
+			long dataIndex,
+			char[] buffer,
+			int bufferIndex,
+			int length)
+		{
+			FillReaderCache(columnIndex);
+			char[] charArr = ((CharsReaderCacheContainer)ReaderCache[columnIndex]).GetChars();
+			long actualLength = ((dataIndex + length) >= charArr.Length) ? (charArr.Length - dataIndex) : length;
+			Array.Copy(charArr,dataIndex,buffer,bufferIndex,actualLength);
+			return actualLength;
+		}
+
+		public override string GetDataTypeName(int columnIndex)
+		{
+			try {
+				if (ResultsMetaData == null) {
+					return String.Empty;
+				}
+				return ResultsMetaData.getColumnTypeName(columnIndex + 1);
+			}
+			catch (SQLException exp) {
+				throw CreateException(exp);
+			}
+		}
+
+		public override DateTime GetDateTime(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((DateTimeReaderCacheContainer)ReaderCache[columnIndex]).GetDateTime();
+		}
+
+		public virtual TimeSpan GetTimeSpan(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((TimeSpanReaderCacheContainer)ReaderCache[columnIndex]).GetTimeSpan();
+		}
+
+		public override Guid GetGuid(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((GuidReaderCacheContainer)ReaderCache[columnIndex]).GetGuid();
+		}
+
+		public override decimal GetDecimal(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((DecimalReaderCacheContainer)ReaderCache[columnIndex]).GetDecimal();
+		}
+
+		public decimal GetDecimalSafe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is DecimalReaderCacheContainer) {
+				return GetDecimal(columnIndex);
+			}
+			else {
+				return Convert.ToDecimal(GetValue(columnIndex));
+			}
+		}
+
+		public override double GetDouble(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((DoubleReaderCacheContainer)ReaderCache[columnIndex]).GetDouble();
+		}
+
+		public double GetDoubleSafe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is DoubleReaderCacheContainer) {
+				return GetDouble(columnIndex);
+			}
+			else {
+				return Convert.ToDouble(GetValue(columnIndex));
+			}
+		}
+
+		public override float GetFloat(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((FloatReaderCacheContainer)ReaderCache[columnIndex]).GetFloat();
+		}
+
+		public float GetFloatSafe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is FloatReaderCacheContainer) {
+				return GetFloat(columnIndex);
+			}
+			else {
+				return Convert.ToSingle(GetValue(columnIndex));
+			}
+		}
+
+		public override short GetInt16(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((Int16ReaderCacheContainer)ReaderCache[columnIndex]).GetInt16();
+		}
+
+		public short GetInt16Safe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is Int16ReaderCacheContainer) {
+				return GetInt16(columnIndex);
+			}
+			else {
+				return Convert.ToInt16(GetValue(columnIndex));
+			}
+		}
+
+		public override int GetInt32(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((Int32ReaderCacheContainer)ReaderCache[columnIndex]).GetInt32();
+		}
+
+		public int GetInt32Safe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is Int32ReaderCacheContainer) {
+				return GetInt32(columnIndex);
+			}
+			else {
+				return Convert.ToInt32(GetValue(columnIndex));
+			}
+		}
+
+		public override long GetInt64(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((Int64ReaderCacheContainer)ReaderCache[columnIndex]).GetInt64();
+		}
+
+		public long GetInt64Safe(int columnIndex)
+		{
+			if (ReaderCache[columnIndex] is Int64ReaderCacheContainer) {
+				return GetInt64(columnIndex);
+			}
+			else {
+				return Convert.ToInt64(GetValue(columnIndex));
+			}
+		}
+
+		public override string GetName(int columnIndex)
+		{
+			try {
+				if (ResultsMetaData == null) {
+					return String.Empty;
+				}
+				return ResultsMetaData.getColumnName(columnIndex + 1);
+			}
+			catch (SQLException exp) {
+				throw new IndexOutOfRangeException(exp.Message, exp);
+			}
+		}
+
+		public override int GetOrdinal(String columnName)
+		{
+			try {
+				int retVal = Results.findColumn(columnName);
+				if(retVal != -1) {
+					retVal -= 1;
+				}
+				return  retVal;
+			}
+			catch (SQLException exp) {
+				throw new IndexOutOfRangeException(exp.Message, exp);
+			}
+		}
+
+		public override string GetString(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ((StringReaderCacheContainer)ReaderCache[columnIndex]).GetString();
+		}
+
+		public string GetStringSafe(int columnIndex) {
+			if (ReaderCache[columnIndex] is StringReaderCacheContainer) {
+				return GetString(columnIndex);
+			}
+			else {
+				return Convert.ToString(GetValue(columnIndex));
+			}
+		}
+
+		public override object GetValue(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			if (ReaderCache[columnIndex].IsNull()) {
+				return DBNull.Value;
+			}
+			return ReaderCache[columnIndex].GetValue();
+		}
+
+		public override int GetValues(Object[] values)
+		{	
+			int columnCount = FieldCount;
+			int i = 0;
+			for (; i < values.Length && i < columnCount; i++) {
+				values[i] = GetValue(i);
+			}
+			return i;
+		}
+
+		private void FillReaderCache(int columnIndex)
+		{
+			try {
+				IReaderCacheContainer[] readerCache = ReaderCache;
+				if ((Behavior & CommandBehavior.SequentialAccess) == 0) {					
+					while (_currentCacheFilledPosition < columnIndex) {
+						_currentCacheFilledPosition++;
+						readerCache[_currentCacheFilledPosition].Fetch(Results,_currentCacheFilledPosition);
+					}					
+				}
+				else {
+					readerCache[columnIndex].Fetch(Results,columnIndex);
+				}
+			}
+			catch(SQLException e) {
+				_currentCacheFilledPosition = -1;
+				throw CreateException(e);
+			}
+			catch (IOException e) {
+				_currentCacheFilledPosition = -1;
+				throw CreateException(e);
+			}
+		}
+
+		private IReaderCacheContainer[] CreateReaderCache()
+		{
+			try {
+				IReaderCacheContainer[] readerCache = new IReaderCacheContainer[FieldCount];
+				for(int i=0; i < readerCache.Length; i++) {
+					DbTypes.JavaSqlTypes javaSqlType = (DbTypes.JavaSqlTypes) ResultsMetaData.getColumnType(i + 1);
+					switch (javaSqlType) {
+						case DbTypes.JavaSqlTypes.ARRAY :
+							readerCache[i] = new ArrayReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.BIGINT :
+							readerCache[i] = new Int64ReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.BINARY :
+						case DbTypes.JavaSqlTypes.VARBINARY :
+						case DbTypes.JavaSqlTypes.LONGVARBINARY :
+							readerCache[i] = new BytesReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.BIT :
+							readerCache[i] = new BooleanReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.BLOB :
+							readerCache[i] = new BlobReaderCacheContainer();
+							break;	
+						case DbTypes.JavaSqlTypes.CHAR :						
+							if ("uniqueidentifier".Equals(ResultsMetaData.getColumnTypeName(i + 1))) {
+								readerCache[i] = new GuidReaderCacheContainer();
+							}
+							else {
+								readerCache[i] = new StringReaderCacheContainer();
+							}
+							break;
+						case DbTypes.JavaSqlTypes.CLOB :
+							readerCache[i] = new ClobReaderCacheContainer();
+							break;		
+						case DbTypes.JavaSqlTypes.TIME :
+							readerCache[i] = new TimeSpanReaderCacheContainer();
+							break;	
+						case DbTypes.JavaSqlTypes.DATE :
+							AbstractDBConnection conn = (AbstractDBConnection)((ICloneable)_command.Connection);
+							string driverName = conn.JdbcConnection.getMetaData().getDriverName();
+
+							if (driverName.StartsWith("PostgreSQL")) {
+								readerCache[i] = new DateTimeReaderCacheContainer();
+								break;
+							}
+							else
+								goto case DbTypes.JavaSqlTypes.TIMESTAMP;
+						case DbTypes.JavaSqlTypes.TIMESTAMP :				
+							readerCache[i] = new TimestampReaderCacheContainer();
+							break;		
+						case DbTypes.JavaSqlTypes.DECIMAL :
+						case DbTypes.JavaSqlTypes.NUMERIC :
+							// jdbc driver for oracle identitfies both FLOAT and NUMBEr columns as 
+							// java.sql.Types.NUMERIC (2), columnTypeName NUMBER, columnClassName java.math.BigDecimal 
+							// therefore we relay on scale
+							int scale = ResultsMetaData.getScale(i + 1);
+							if (scale == -127) {
+								// Oracle db type FLOAT
+								readerCache[i] = new DoubleReaderCacheContainer();
+							}
+							else {
+								readerCache[i] = new DecimalReaderCacheContainer();
+							}
+							break;		
+						case DbTypes.JavaSqlTypes.DOUBLE :
+						case DbTypes.JavaSqlTypes.FLOAT :
+							readerCache[i] = new DoubleReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.INTEGER :
+							readerCache[i] = new Int32ReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.LONGVARCHAR :
+						case DbTypes.JavaSqlTypes.VARCHAR :
+							readerCache[i] = new StringReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.NULL :
+							readerCache[i] = new NullReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.REAL :
+							readerCache[i] = new FloatReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.REF :
+							readerCache[i] = new RefReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.SMALLINT :
+							readerCache[i] = new Int16ReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.TINYINT :
+							readerCache[i] = new ByteReaderCacheContainer();
+							break;
+						case DbTypes.JavaSqlTypes.DISTINCT :
+						case DbTypes.JavaSqlTypes.JAVA_OBJECT :
+						case DbTypes.JavaSqlTypes.OTHER :
+						case DbTypes.JavaSqlTypes.STRUCT :
+						default :
+							readerCache[i] = new ObjectReaderCacheContainer();
+							break;
+					}
+					//				((ReaderCacheContainerBase)readerCache[i])._jdbcType = (int) javaSqlType;
+				}
+
+				return readerCache;
+			}
+			catch(SQLException e) {
+				throw CreateException(e);
+			}
+		}
+
+		public override bool IsDBNull(int columnIndex)
+		{
+			FillReaderCache(columnIndex);
+			return ReaderCache[columnIndex].IsNull();
+		}
+
+		public override Type GetFieldType(int i)
+		{
+			try {
+				int javaSqlType = ResultsMetaData.getColumnType(i + 1);
+				return DbConvert.JavaSqlTypeToClrType(javaSqlType);
+			}
+			catch (SQLException exp) {
+				throw new IndexOutOfRangeException(exp.Message, exp);
+			}
+		}
+
+		public IDataReader GetData(int i)
+		{
+			throw new NotSupportedException();
+		}
+
+		public override DataTable GetSchemaTable()
+		{
+			if (SchemaTable.Rows != null && SchemaTable.Rows.Count > 0) {
+				return SchemaTable;
+			}
+            
+			ResultSetMetaData metaData;			
+			if (Behavior == CommandBehavior.SchemaOnly) {
+				try {
+					metaData = ((PreparedStatement)_command.JdbcStatement).getMetaData();
+				}
+				catch(SQLException e) {
+					throw CreateException("CommandBehaviour.SchemaOnly is not supported by the JDBC driver.",e);
+				}
+			}
+			else {
+				metaData = ResultsMetaData;
+			}
+
+			if (metaData == null) {
+				return SchemaTable;
+			}
+
+			DatabaseMetaData dbMetaData = null;
+			AbstractDBConnection clonedConnection = null;
+			if ((_command.Behavior & CommandBehavior.KeyInfo) != 0) {
+				clonedConnection = (AbstractDBConnection)((ICloneable)_command.Connection).Clone();
+
+				try {
+					clonedConnection.Open();
+					dbMetaData = clonedConnection.JdbcConnection.getMetaData();
+				}
+				catch {
+					//suppress
+					if (clonedConnection != null) {
+						clonedConnection.Close();
+					}
+				}			
+			}
+			
+			try {
+				int tmp;				
+				for(int i = 1; i <= metaData.getColumnCount(); i++) {
+					DataRow row = SchemaTable.NewRow ();
+					string columnName = metaData.getColumnLabel(i);
+					string baseColumnName = metaData.getColumnName(i);
+	
+					row [(int)SCHEMA_TABLE.ColumnName] = columnName; // maybe we should use metaData.getColumnLabel(i);
+					row [(int)SCHEMA_TABLE.ColumnSize] = metaData.getColumnDisplaySize(i);
+					row [(int)SCHEMA_TABLE.ColumnOrdinal]		= i - 1;
+					try {
+						// FIXME : workaround for Oracle JDBC driver bug
+						// getPrecision on BLOB, CLOB, NCLOB throws NumberFormatException
+						tmp = metaData.getPrecision(i);
+					}
+					catch(java.lang.NumberFormatException e) {
+						// supress exception
+						tmp = 255;
+					}
+					row [(int)SCHEMA_TABLE.NumericPrecision] = Convert.ToInt16(tmp > 255 ? 255 : tmp);
+					tmp = metaData.getScale(i);
+					row [(int)SCHEMA_TABLE.NumericScale] = Convert.ToInt16(tmp > 255 ? 255 : tmp);
+
+					row [(int)SCHEMA_TABLE.BaseServerName] = DBNull.Value;
+				
+					string catalog = null;
+					try {
+						catalog = metaData.getCatalogName(i);
+					}
+					catch (Exception e) {
+						// supress exception
+					}
+					if (catalog != null && catalog.Length == 0)
+						catalog =  ((AbstractDBConnection)_command.Connection).JdbcConnection.getCatalog();
+					row [(int)SCHEMA_TABLE.BaseCatalogName] = catalog;
+					row [(int)SCHEMA_TABLE.BaseColumnName] = baseColumnName;
+
+					string schemaName;
+					string tableName;
+
+					try {
+						tableName = metaData.getTableName(i);
+					}
+					catch {
+						tableName = null;
+					}
+
+					try {
+						schemaName = metaData.getSchemaName(i);
+					}
+					catch {
+						schemaName = null;
+					}
+
+					if (tableName != null && tableName.Length == 0)
+						tableName = null;
+					if (schemaName != null && schemaName.Length == 0)
+						schemaName = null;
+
+					row [(int)SCHEMA_TABLE.BaseSchemaName] = schemaName;
+					row [(int)SCHEMA_TABLE.BaseTableName] = tableName;
+
+
+					row [(int)SCHEMA_TABLE.AllowDBNull] = Convert.ToBoolean(metaData.isNullable(i));
+				
+					InitKeyInfo(row, dbMetaData, catalog, schemaName, tableName);
+				
+					row [(int)SCHEMA_TABLE.IsAliased] = columnName != baseColumnName;
+					row [(int)SCHEMA_TABLE.IsExpression] = false;
+
+					row [(int)SCHEMA_TABLE.IsAutoIncrement] = metaData.isAutoIncrement(i);
+
+					row [(int)SCHEMA_TABLE.IsHidden] = false;
+					row [(int)SCHEMA_TABLE.IsReadOnly] = metaData.isReadOnly(i);
+
+					int columnType = metaData.getColumnType(i);
+					string columnTypeName = metaData.getColumnTypeName(i);
+					if(columnType == Types.ARRAY) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Array);
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.BIGINT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt64;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.BINARY) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.BIT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfBoolean;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.BLOB) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.CHAR) {
+						// FIXME : specific for Microsoft SQl Server driver
+						if (columnTypeName.Equals("uniqueidentifier")) {
+							row [(int)SCHEMA_TABLE.ProviderType] = DbType.Guid;
+							row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfGuid;
+							row [(int)SCHEMA_TABLE.IsLong] = false;
+						}
+						else {
+							row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+							row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
+							row [(int)SCHEMA_TABLE.IsLong] = false;
+						}
+					}
+					else if(columnType == Types.CLOB) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString; // instead og .java.sql.Clob
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.DATE) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.DECIMAL) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+						//                else if(columnType == Types.DISTINCT)
+						//                {
+						//                    row ["ProviderType = (int)GetProviderType(columnType);
+						//                    row ["DataType = typeof (?);
+						//                    row ["IsLong = false;
+						//                }
+					else if(columnType == Types.DOUBLE) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble; // was typeof(float)
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.FLOAT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDouble;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.REAL) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfFloat;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.INTEGER) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt32;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.JAVA_OBJECT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.LONGVARBINARY) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.LONGVARCHAR) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.NUMERIC) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDecimal;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.REF) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Ref);
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.SMALLINT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfInt16;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.STRUCT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = typeof (java.sql.Struct);
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.TIME) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfTimespan;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.TIMESTAMP) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfDateTime;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.TINYINT) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByte;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else if(columnType == Types.VARBINARY) {
+						row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfByteArray;
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					else if(columnType == Types.VARCHAR) {
+						// FIXME : specific for Microsoft SQl Server driver
+						if (columnTypeName.Equals("sql_variant")) {
+							row [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;
+							row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
+							row [(int)SCHEMA_TABLE.IsLong] = false;
+						}
+						else {
+							row [(int)SCHEMA_TABLE.ProviderType] = GetProviderType(columnType);
+							row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;// (char[]);
+							row [(int)SCHEMA_TABLE.IsLong] = false;//true;
+						}
+					}
+					else if(columnType == -8 && columnTypeName.Equals("ROWID")) {
+						// FIXME : specific for Oracle JDBC driver : OracleTypes.ROWID
+						row [(int)SCHEMA_TABLE.ProviderType] = DbType.String;
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfString;
+						row [(int)SCHEMA_TABLE.IsLong] = false;
+					}
+					else {
+						row [(int)SCHEMA_TABLE.ProviderType] = DbType.Object;
+						row [(int)SCHEMA_TABLE.DataType] = DbTypes.TypeOfObject;
+						row [(int)SCHEMA_TABLE.IsLong] = true;
+					}
+					SchemaTable.Rows.Add (row);
+				}
+			}
+			catch (SQLException e) {				
+				throw CreateException(e);
+			}
+			finally {
+				if (clonedConnection != null) {
+					clonedConnection.Close();
+				}
+			}			
+			return SchemaTable;
+		}
+
+		private void InitKeyInfo(DataRow row, DatabaseMetaData dbMetaData, String catalog, String schema, String table) {
+			string column = (string)row [(int)SCHEMA_TABLE.BaseColumnName];
+
+			row [(int)SCHEMA_TABLE.IsUnique] = false;
+			row [(int)SCHEMA_TABLE.IsKey] = false;
+			row [(int)SCHEMA_TABLE.IsIdentity] = false;
+			row [(int)SCHEMA_TABLE.IsRowVersion] = false;
+
+			if ((_command.Behavior & CommandBehavior.KeyInfo) == 0)
+				return;
+
+			if(table == null || column == null || dbMetaData == null)
+				return;
+
+			ResultSet indexInfoRes = dbMetaData.getIndexInfo(catalog,schema,table,true,false);
+			try {
+				while(indexInfoRes.next()) {
+					if(indexInfoRes.getString("COLUMN_NAME") == column)
+						row [(int)SCHEMA_TABLE.IsUnique] = true;
+				}
+			}
+			finally {
+				indexInfoRes.close();
+			}
+
+			ResultSet versionCol = dbMetaData.getVersionColumns(catalog, schema, table);
+			try {
+				while(versionCol.next()) {
+					if(versionCol.getString("COLUMN_NAME") == column) {
+						if (DatabaseMetaData__Finals.versionColumnPseudo == versionCol.getShort("PSEUDO_COLUMN")) {
+							row [(int)SCHEMA_TABLE.IsIdentity] = true;
+							row [(int)SCHEMA_TABLE.IsRowVersion] = true;
+						}
+					}
+				}
+			}
+			finally {
+				versionCol.close();
+			}
+
+			ResultSet bestRowId = dbMetaData.getBestRowIdentifier(catalog, schema, table, DatabaseMetaData__Finals.bestRowTemporary, false);
+			try {
+				while(bestRowId.next()) {
+					if(bestRowId.getString("COLUMN_NAME") == column)
+						row [(int)SCHEMA_TABLE.IsKey] = true;
+				}
+			}
+			finally {
+				bestRowId.close();
+			}
+		}
+
+		protected static DataTable ConstructSchemaTable ()
+		{
+			Type booleanType = DbTypes.TypeOfBoolean;
+			Type stringType = DbTypes.TypeOfString;
+			Type intType = DbTypes.TypeOfInt32;
+			Type typeType = DbTypes.TypeOfType;
+			Type shortType = DbTypes.TypeOfInt16;
+
+			DataTable schemaTable = new DataTable ("SchemaTable");
+			schemaTable.Columns.Add ("ColumnName", stringType);
+			schemaTable.Columns.Add ("ColumnOrdinal", intType);
+			schemaTable.Columns.Add ("ColumnSize", intType);
+			schemaTable.Columns.Add ("NumericPrecision", shortType);
+			schemaTable.Columns.Add ("NumericScale", shortType);
+			schemaTable.Columns.Add ("IsUnique", booleanType);
+			schemaTable.Columns.Add ("IsKey", booleanType);
+			schemaTable.Columns.Add ("BaseServerName", stringType);
+			schemaTable.Columns.Add ("BaseCatalogName", stringType);
+			schemaTable.Columns.Add ("BaseColumnName", stringType);
+			schemaTable.Columns.Add ("BaseSchemaName", stringType);
+			schemaTable.Columns.Add ("BaseTableName", stringType);
+			schemaTable.Columns.Add ("DataType", typeType);
+			schemaTable.Columns.Add ("AllowDBNull", booleanType);
+			schemaTable.Columns.Add ("ProviderType", intType);
+			schemaTable.Columns.Add ("IsAliased", booleanType);
+			schemaTable.Columns.Add ("IsExpression", booleanType);
+			schemaTable.Columns.Add ("IsIdentity", booleanType);
+			schemaTable.Columns.Add ("IsAutoIncrement", booleanType);
+			schemaTable.Columns.Add ("IsRowVersion", booleanType);
+			schemaTable.Columns.Add ("IsHidden", booleanType);
+			schemaTable.Columns.Add ("IsLong", booleanType);
+			schemaTable.Columns.Add ("IsReadOnly", booleanType);
+			return schemaTable;
+		}
+
+		#endregion // Methods
+	}
+}

+ 152 - 0
mcs/class/System.Data/System.Data.Common/AbstractTransaction.cs

@@ -0,0 +1,152 @@
+/*
+  * Copyright (c) 2002-2004 Mainsoft Corporation.
+  *
+  * 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.
+  */
+
+namespace System.Data.Common
+{
+
+    using java.sql;
+
+    using System.Data;
+    /**
+     * @author erand
+     */
+    public abstract class AbstractTransaction : DbTransaction
+    {
+
+        protected String _transactionName;
+        protected AbstractDBConnection _connection;
+
+        protected IsolationLevel _isolationLevel;
+
+        public AbstractTransaction(
+            IsolationLevel isolationLevel,
+            AbstractDBConnection connection,
+            String transactionName)
+        {
+			connection.ValidateBeginTransaction();
+            _transactionName = transactionName;
+            _connection = connection;
+            _isolationLevel = isolationLevel;
+            try
+            {
+                _connection.JdbcConnection.setAutoCommit(false);
+                _connection.JdbcConnection.setTransactionIsolation(
+                convertIsolationLevel(isolationLevel));
+            }
+            catch (SQLException exp)
+            {
+                throw new System.InvalidOperationException(exp.Message);
+            }
+        }
+
+        
+        /**
+         * @see System.Data.IDbTransaction#Connection
+         */
+        protected override DbConnection DbConnection
+        {
+            get
+            {
+                return _connection;
+            }
+        }
+
+        /**
+         * @see System.Data.IDbTransaction#IsolationLevel
+         */
+        public override IsolationLevel IsolationLevel
+        {
+            get
+            {
+                return _isolationLevel;
+            }
+        }
+
+        /**
+         * @see System.Data.IDbTransaction#Commit()
+         */
+        public override void Commit()
+        {
+			if (_connection == null)
+				return;
+
+            try
+            {
+                _connection.JdbcConnection.commit();
+				_connection.JdbcConnection.setAutoCommit(true);
+				_connection = null;
+            }
+            catch (SQLException exp)
+            {
+                throw new SystemException(exp.Message);
+            }
+        }
+
+        /**
+         * @see System.Data.IDbTransaction#Rollback()
+         */
+        public override void Rollback()
+        {
+			if (_connection == null)
+				return;
+
+            try
+            {
+                _connection.JdbcConnection.rollback();
+				_connection = null;
+            }
+            catch (SQLException exp)
+            {
+                throw new SystemException(exp.Message);
+            }
+        }
+
+        public override void Dispose()
+        {
+            Rollback();
+        }
+
+		internal AbstractTransaction ActiveTransaction {
+			get {
+				// recoursively return parent transaction when nesting will
+				// be implemented
+				return _connection != null ? this : null;
+			}
+		}
+
+        private int convertIsolationLevel(IsolationLevel isolationLevel)
+        {
+            if (isolationLevel == IsolationLevel.Unspecified)
+                return [email protected]__Finals.TRANSACTION_NONE;
+            if (isolationLevel == IsolationLevel.ReadCommitted)
+                return [email protected]__Finals.TRANSACTION_READ_COMMITTED;
+            if (isolationLevel == IsolationLevel.ReadUncommitted)
+                return [email protected]__Finals.TRANSACTION_READ_UNCOMMITTED;
+            if (isolationLevel == IsolationLevel.RepeatableRead)
+                return [email protected]__Finals.TRANSACTION_REPEATABLE_READ;
+            if (isolationLevel == IsolationLevel.Serializable)
+                return [email protected]__Finals.TRANSACTION_SERIALIZABLE;
+
+            throw new NotSupportedException("The Isolation level '" + isolationLevel + "' is not supported");
+        }
+    }
+}

+ 320 - 0
mcs/class/System.Data/System.Data.Common/CallableStatementWrapper.cs

@@ -0,0 +1,320 @@
+using System;
+
+using java.sql;
+using java.util;
+
+namespace System.Data.Common
+{
+	public class CallableStatementWrapper : ResultSet
+	{
+		#region Fields
+
+		CallableStatement _callableStatement;
+
+		#endregion // Fields
+
+		#region Constructors
+
+		public CallableStatementWrapper(CallableStatement callableStatement)
+		{
+			_callableStatement = callableStatement;
+		}
+
+		#endregion // constructors
+
+		#region Methods
+
+		public int getConcurrency() { throw new NotImplementedException(); }
+
+		public int getFetchDirection() { throw new NotImplementedException(); }
+
+		public int getFetchSize()  { throw new NotImplementedException(); }
+
+		public int getRow()  { throw new NotImplementedException(); }
+
+		public int getType()  { throw new NotImplementedException(); }
+
+		public void afterLast()  { throw new NotImplementedException(); }
+
+		public void beforeFirst()  { throw new NotImplementedException(); }
+
+		public void cancelRowUpdates()  { throw new NotImplementedException(); }
+
+		public void clearWarnings()  { throw new NotImplementedException(); }
+
+		public void close()  { throw new NotImplementedException(); }
+
+		public void deleteRow()  { throw new NotImplementedException(); }
+
+		public void insertRow()  { throw new NotImplementedException(); }
+
+		public void moveToCurrentRow()  { throw new NotImplementedException(); }
+
+		public void moveToInsertRow()  { throw new NotImplementedException(); }
+
+		public void refreshRow()  { throw new NotImplementedException(); }
+
+		public void updateRow()  { throw new NotImplementedException(); }
+
+		public bool first()  { throw new NotImplementedException(); }
+
+		public bool isAfterLast()  { throw new NotImplementedException(); }
+
+		public bool isBeforeFirst()  { throw new NotImplementedException(); }
+
+		public bool isFirst()  { throw new NotImplementedException(); }
+
+		public bool isLast()  { throw new NotImplementedException(); }
+
+		public bool last()  { throw new NotImplementedException(); }
+
+		public bool next()  { throw new NotImplementedException(); }
+
+		public bool previous()  { throw new NotImplementedException(); }
+
+		public bool rowDeleted()  { throw new NotImplementedException(); }
+
+		public bool rowInserted()  { throw new NotImplementedException(); }
+
+		public bool rowUpdated()  { throw new NotImplementedException(); }
+
+		public bool wasNull()  { return _callableStatement.wasNull(); }
+
+		public sbyte getByte(int i) { return _callableStatement.getByte(i); } 
+
+		public double getDouble(int i)  { return _callableStatement.getDouble(i); } 
+
+		public float getFloat(int i)  { return _callableStatement.getFloat(i); } 
+
+		public int getInt(int i)  { return _callableStatement.getInt(i); }
+
+		public long getLong(int i)  { return _callableStatement.getLong(i); }
+
+		public short getShort(int i)  { return _callableStatement.getShort(i); }
+
+		public void setFetchDirection(int i)  { throw new NotImplementedException(); }
+
+		public void setFetchSize(int i)  { throw new NotImplementedException(); }
+
+		public void updateNull(int i)  { throw new NotImplementedException(); }
+
+		public bool absolute(int i)  { throw new NotImplementedException(); }
+
+		public bool getBoolean(int i)  { return _callableStatement.getBoolean(i); }
+
+		public bool relative(int i)  { throw new NotImplementedException(); }
+
+		public sbyte[] getBytes(int i)  { return _callableStatement.getBytes(i); }
+
+		public void updateByte(int i, sbyte b)  { throw new NotImplementedException(); }
+
+		public void updateDouble(int i, double v)  { throw new NotImplementedException(); }
+
+		public void updateFloat(int i, float v)  { throw new NotImplementedException(); }
+
+		public void updateInt(int i, int i1)  { throw new NotImplementedException(); }
+
+		public void updateLong(int i, long l)  { throw new NotImplementedException(); }
+
+		public void updateShort(int i, short i1)  { throw new NotImplementedException(); }
+
+		public void updateBoolean(int i, bool b)  { throw new NotImplementedException(); }
+
+		public void updateBytes(int i, sbyte[] bytes)  { throw new NotImplementedException(); }
+
+		public java.io.InputStream getAsciiStream(int i) { throw new NotImplementedException(); }
+
+		public java.io.InputStream getBinaryStream(int i)  { throw new NotImplementedException(); }
+
+		/**
+		* @deprecated
+		*/
+		public java.io.InputStream getUnicodeStream(int i)  { throw new NotImplementedException(); }
+
+		public void updateAsciiStream(int i, java.io.InputStream inputStream, int i1)  { throw new NotImplementedException(); }
+
+		public void updateBinaryStream(int i, java.io.InputStream inputStream, int i1)  { throw new NotImplementedException(); }
+
+		public java.io.Reader getCharacterStream(int i)  { throw new NotImplementedException(); }
+
+		public void updateCharacterStream(int i, java.io.Reader reader, int i1)  { throw new NotImplementedException(); }
+
+		public Object getObject(int i)  { return _callableStatement.getObject(i); }
+
+		public void updateObject(int i, Object o)  { throw new NotImplementedException(); }
+
+		public void updateObject(int i, Object o, int i1)  { throw new NotImplementedException(); }
+
+		public String getCursorName()  { throw new NotImplementedException(); }
+
+		public String getString(int i)  { return _callableStatement.getString(i); }
+
+		public void updateString(int i, String s)  { throw new NotImplementedException(); }
+
+		public sbyte getByte(String s)  { return _callableStatement.getByte(s); }
+
+		public double getDouble(String s)  { return _callableStatement.getDouble(s); }
+
+		public float getFloat(String s)  { return _callableStatement.getFloat(s); }
+
+		public int findColumn(String s)  { throw new NotImplementedException(); }
+
+		public int getInt(String s)  { return _callableStatement.getInt(s); }
+
+		public long getLong(String s)  { return _callableStatement.getLong(s); }
+
+		public short getShort(String s) { return _callableStatement.getShort(s); } 
+
+		public void updateNull(String s)  { throw new NotImplementedException(); }
+
+		public bool getBoolean(String s)  { return _callableStatement.getBoolean(s); }
+
+		public sbyte[] getBytes(String s)  { return _callableStatement.getBytes(s); }
+
+		public void updateByte(String s, sbyte b)  { throw new NotImplementedException(); }
+
+		public void updateDouble(String s, double v)  { throw new NotImplementedException(); }
+
+		public void updateFloat(String s, float v)  { throw new NotImplementedException(); }
+
+		public void updateInt(String s, int i)  { throw new NotImplementedException(); }
+
+		public void updateLong(String s, long l)  { throw new NotImplementedException(); }
+
+		public void updateShort(String s, short i)  { throw new NotImplementedException(); }
+
+		public void updateBoolean(String s, bool b)  { throw new NotImplementedException(); }
+
+		public void updateBytes(String s, sbyte[] bytes)  { throw new NotImplementedException(); }
+
+		public java.math.BigDecimal getBigDecimal(int i)  { return _callableStatement.getBigDecimal(i); }
+
+		/**
+		* @deprecated
+		*/
+		public java.math.BigDecimal getBigDecimal(int i, int i1)  { throw new NotImplementedException(); }
+
+		public void updateBigDecimal(int i, java.math.BigDecimal bigDecimal)  { throw new NotImplementedException(); }
+
+		public java.net.URL getURL(int i)  { throw new NotImplementedException(); }
+
+		public java.sql.Array getArray(int i)  { return _callableStatement.getArray(i); }
+
+		public void updateArray(int i, java.sql.Array array)  { throw new NotImplementedException(); }
+
+		public Blob getBlob(int i)  { return _callableStatement.getBlob(i); }
+
+		public void updateBlob(int i, Blob blob)  { throw new NotImplementedException(); }
+
+		public Clob getClob(int i)  { return _callableStatement.getClob(i); }
+
+		public void updateClob(int i, Clob clob)  { throw new NotImplementedException(); }
+
+		public java.sql.Date getDate(int i)  { return _callableStatement.getDate(i); }
+
+		public void updateDate(int i, java.sql.Date date)  { throw new NotImplementedException(); }
+
+		public Ref getRef(int i)  { return _callableStatement.getRef(i); }
+
+		public void updateRef(int i, Ref rf)  { throw new NotImplementedException(); }
+
+		public ResultSetMetaData getMetaData()  { throw new NotImplementedException(); }
+
+		public SQLWarning getWarnings()  { throw new NotImplementedException(); }
+
+		public Statement getStatement()  { throw new NotImplementedException(); }
+
+		public Time getTime(int i)  { return _callableStatement.getTime(i); }
+
+		public void updateTime(int i, Time time)  { throw new NotImplementedException(); }
+
+		public Timestamp getTimestamp(int i)  { return _callableStatement.getTimestamp(i); }
+
+		public void updateTimestamp(int i, Timestamp timestamp)  { throw new NotImplementedException(); }
+
+		public java.io.InputStream getAsciiStream(String s)  { throw new NotImplementedException(); }
+
+		public java.io.InputStream getBinaryStream(String s)  { throw new NotImplementedException(); }
+
+		/**
+		* @deprecated
+		*/
+		public java.io.InputStream getUnicodeStream(String s)  { throw new NotImplementedException(); }
+
+		public void updateAsciiStream(String s, java.io.InputStream inputStream, int i) { throw new NotImplementedException(); } 
+
+		public void updateBinaryStream(String s, java.io.InputStream inputStream, int i)  { throw new NotImplementedException(); }
+
+		public java.io.Reader getCharacterStream(String s)  { throw new NotImplementedException(); }
+
+		public void updateCharacterStream(String s, java.io.Reader reader, int i)  { throw new NotImplementedException(); }
+
+		public Object getObject(String s)  { return _callableStatement.getObject(s); }
+
+		public void updateObject(String s, Object o)  { throw new NotImplementedException(); }
+
+		public void updateObject(String s, Object o, int i)  { throw new NotImplementedException(); }
+
+		public Object getObject(int i, Map map)  { throw new NotImplementedException(); }
+
+		public String getString(String s)  { return _callableStatement.getString(s); }
+
+		public void updateString(String s, String s1)  { throw new NotImplementedException(); }
+
+		public java.math.BigDecimal getBigDecimal(String s)  { return _callableStatement.getBigDecimal(s); }
+
+		/**
+		* @deprecated
+		*/
+		public java.math.BigDecimal getBigDecimal(String s, int i)  { throw new NotImplementedException(); }
+
+		public void updateBigDecimal(String s, java.math.BigDecimal bigDecimal)  { throw new NotImplementedException(); }
+
+		public java.net.URL getURL(String s)  { throw new NotImplementedException(); }
+
+		public java.sql.Array getArray(String s)  { return _callableStatement.getArray(s); }
+
+		public void updateArray(String s, java.sql.Array array)  { throw new NotImplementedException(); }
+
+		public Blob getBlob(String s)  { return _callableStatement.getBlob(s); }
+
+		public void updateBlob(String s, Blob blob)  { throw new NotImplementedException(); }
+
+		public Clob getClob(String s)  { return _callableStatement.getClob(s); }
+
+		public void updateClob(String s, Clob clob)  { throw new NotImplementedException(); }
+
+		public java.sql.Date getDate(String s)  { return _callableStatement.getDate(s); }
+
+		public void updateDate(String s, java.sql.Date date)  { throw new NotImplementedException(); }
+
+		public java.sql.Date getDate(int i, Calendar calendar)  { throw new NotImplementedException(); }
+
+		public Ref getRef(String s)  { return _callableStatement.getRef(s); }
+
+		public void updateRef(String s, Ref rf)  { throw new NotImplementedException(); }
+
+		public Time getTime(String s)  { return _callableStatement.getTime(s); }
+
+		public void updateTime(String s, Time time)  { throw new NotImplementedException(); }
+
+		public Time getTime(int i, Calendar calendar)  { throw new NotImplementedException(); }
+
+		public Timestamp getTimestamp(String s)  { return _callableStatement.getTimestamp(s); }
+
+		public void updateTimestamp(String s, Timestamp timestamp)  { throw new NotImplementedException(); }
+
+		public Timestamp getTimestamp(int i, Calendar calendar)  { throw new NotImplementedException(); }
+
+		public Object getObject(String s, Map map)  { throw new NotImplementedException(); }
+
+		public java.sql.Date getDate(String s, Calendar calendar)  { throw new NotImplementedException(); }
+
+		public Time getTime(String s, Calendar calendar)  { throw new NotImplementedException(); }
+
+		public Timestamp getTimestamp(String s, Calendar calendar)  { throw new NotImplementedException(); }
+
+		#endregion // Methods
+		
+	}
+}

+ 330 - 0
mcs/class/System.Data/System.Data.Common/DbConvert.cs

@@ -0,0 +1,330 @@
+//
+// System.Data.Common.DbConvert
+//
+// Author:
+//   Boris Kirzner ([email protected])
+//
+
+using System;
+
+using java.io;
+using java.sql;
+
+namespace System.Data.Common
+{
+	internal class DbConvert
+	{
+		#region Fields
+
+		const long JAVA_MIN_MILLIS_UTC = -62135769600000L; // java.sql.Timestamp.valueOf("0001-01-01 00:00:00.000000000").getTime() at Greenwich time zone.
+		static readonly long TIMEZONE_RAW_OFFSET;
+		// .NET milliseconds value of DateTime(1582,1,1,0,0,0,0).Ticks/TimeSpan.TicksPerMillisecond			
+		const long CLR_MILLIS_1582 = 49891507200000L;
+		const long MILLIS_PER_TWO_DAYS = 2 * TimeSpan.TicksPerDay / TimeSpan.TicksPerMillisecond; // 172800000L;
+		internal static readonly java.util.TimeZone DEFAULT_TIME_ZONE;
+
+		#endregion // Fields
+
+		#region Methods
+
+		static DbConvert()
+		{
+			DEFAULT_TIME_ZONE = java.util.SimpleTimeZone.getDefault();			
+			TIMEZONE_RAW_OFFSET = (long)DEFAULT_TIME_ZONE.getRawOffset();						
+		}
+
+		// The diff between .Net and Java goes as the following:
+		//  * at 1582: java has 10 days less than .net
+		//  * below 1500 (exept 1200,800,400) : each 100'th year java adds 1 day over .net. 
+		// Current implementation compatible with .net in 1-99 and since 1582. In 100-1582 we're not compatible with .Ner nor with Java
+
+		internal static long JavaMillisToClrMillis(long javaMillis)
+		{
+			return JavaMillisToClrMillisUTC(javaMillis) + TIMEZONE_RAW_OFFSET;
+		}
+
+		internal static long JavaMillisToClrMillisUTC(long javaMillis) {
+			long clrMillis = javaMillis - JAVA_MIN_MILLIS_UTC;
+			if (clrMillis > CLR_MILLIS_1582) {
+				clrMillis -= MILLIS_PER_TWO_DAYS;
+			}
+			return clrMillis;
+		}
+
+		internal static long ClrMillisToJavaMillis(long clrMillis)
+		{
+			return ClrMillisToJavaMillisUTC(clrMillis) - TIMEZONE_RAW_OFFSET;
+		}
+
+		internal static long ClrMillisToJavaMillisUTC(long clrMillis) {
+			long javaMillis = clrMillis + JAVA_MIN_MILLIS_UTC;
+			if (clrMillis > CLR_MILLIS_1582) {
+				javaMillis += MILLIS_PER_TWO_DAYS;
+			}
+			return javaMillis;
+		}
+
+		internal static java.sql.Time ClrTicksToJavaTime(long ticks) {
+			return new Time((ticks / TimeSpan.TicksPerMillisecond)
+				- DEFAULT_TIME_ZONE.getRawOffset());
+		}
+
+		internal static java.sql.Date ClrTicksToJavaDate(long ticks) {
+			java.sql.Date d = new java.sql.Date(0);
+			ClrTicksToJavaDate(d, ticks);
+			return d;
+		}
+
+		internal static java.sql.Timestamp ClrTicksToJavaTimestamp(long ticks)
+		{
+			java.sql.Timestamp ts = new java.sql.Timestamp(0);
+			ClrTicksToJavaDate(ts, ticks);
+
+//			int nanos = (int)(ticks % TimeSpan.TicksPerMillisecond) * 100;
+//			ts.setNanos(javaTimestamp.getNanos() + nanos);
+
+			return ts;
+		}
+
+		internal static void ClrTicksToJavaDate(java.util.Date d, long ticks) {
+			long millis = ClrMillisToJavaMillis(ticks / TimeSpan.TicksPerMillisecond);
+
+			d.setTime(millis);
+			if (DEFAULT_TIME_ZONE.inDaylightTime(d)) {
+				millis -= DEFAULT_TIME_ZONE.getDSTSavings();
+				d.setTime(millis);
+			}
+		}
+		
+		internal static long JavaTimestampToClrTicks(java.sql.Timestamp ts)
+		{
+			long ticks = JavaDateToClrTicks(ts);
+			// Extra ticks, for dbs that can save them. 
+			// We do not use it, since .net does not saves ticks for fractial milliseconds
+			// long ticksLessThanMilliseconds = (ts.getNanos()*100) % TimeSpan.TicksPerMillisecond;
+			// ticks += ticksLessThanMilliseconds;
+			
+			return ticks;
+		}
+
+		internal static long JavaDateToClrTicks(java.util.Date d) {
+			long millis = JavaMillisToClrMillis(d.getTime());
+			if (DEFAULT_TIME_ZONE.inDaylightTime(d)) {
+				millis += DEFAULT_TIME_ZONE.getDSTSavings();
+			}
+			return millis * TimeSpan.TicksPerMillisecond;
+		}
+
+		internal static long JavaTimeToClrTicks(java.sql.Time t) {
+			return (t.getTime() + DEFAULT_TIME_ZONE.getRawOffset())
+				* TimeSpan.TicksPerMillisecond;
+		}
+
+		internal protected static Type JavaSqlTypeToClrType(int sqlTypeValue)
+		{
+			DbTypes.JavaSqlTypes sqlType = (DbTypes.JavaSqlTypes)sqlTypeValue;
+
+			switch (sqlType) {
+				case DbTypes.JavaSqlTypes.ARRAY : return typeof (java.sql.Array);
+				case DbTypes.JavaSqlTypes.BIGINT : return DbTypes.TypeOfInt64;
+				case DbTypes.JavaSqlTypes.BINARY : return DbTypes.TypeOfByteArray;
+				case DbTypes.JavaSqlTypes.BIT : return DbTypes.TypeOfBoolean;
+				case DbTypes.JavaSqlTypes.BLOB : return DbTypes.TypeOfByteArray;
+				case DbTypes.JavaSqlTypes.BOOLEAN : return DbTypes.TypeOfBoolean;
+				case DbTypes.JavaSqlTypes.CHAR : return DbTypes.TypeOfString;
+				case DbTypes.JavaSqlTypes.CLOB : return DbTypes.TypeOfString;
+//				case DbTypes.JavaSqlTypes.DATALINK :
+				case DbTypes.JavaSqlTypes.DATE : return DbTypes.TypeOfDateTime;
+				case DbTypes.JavaSqlTypes.DECIMAL : return DbTypes.TypeOfDecimal;
+//				case DbTypes.JavaSqlTypes.DISTINCT :
+				case DbTypes.JavaSqlTypes.DOUBLE : return DbTypes.TypeOfDouble;
+				case DbTypes.JavaSqlTypes.FLOAT : return DbTypes.TypeOfDouble;
+				case DbTypes.JavaSqlTypes.INTEGER : return DbTypes.TypeOfInt32;
+//				case DbTypes.JavaSqlTypes.JAVA_OBJECT :
+				case DbTypes.JavaSqlTypes.LONGVARBINARY : return DbTypes.TypeOfByteArray;
+				case DbTypes.JavaSqlTypes.LONGVARCHAR : return DbTypes.TypeOfString;
+				case DbTypes.JavaSqlTypes.NULL : return null;
+				case DbTypes.JavaSqlTypes.NUMERIC : return DbTypes.TypeOfDecimal;
+//				case DbTypes.JavaSqlTypes.OTHER :
+				case DbTypes.JavaSqlTypes.REAL : return DbTypes.TypeOfSingle;
+				case DbTypes.JavaSqlTypes.REF : return typeof (java.sql.Ref);
+				case DbTypes.JavaSqlTypes.SMALLINT : return DbTypes.TypeOfInt16;
+				case DbTypes.JavaSqlTypes.STRUCT : return typeof (java.sql.Struct);
+				case DbTypes.JavaSqlTypes.TIME : return DbTypes.TypeOfTimespan;
+				case DbTypes.JavaSqlTypes.TIMESTAMP : return DbTypes.TypeOfDateTime;
+				case DbTypes.JavaSqlTypes.TINYINT : return DbTypes.TypeOfByte;
+				case DbTypes.JavaSqlTypes.VARBINARY : return DbTypes.TypeOfByteArray;
+				case DbTypes.JavaSqlTypes.VARCHAR : return DbTypes.TypeOfString;
+				default : return DbTypes.TypeOfObject;
+			}
+
+		}
+
+
+		internal protected static object JavaResultSetToClrWrapper(CallableStatement results,int columnIndex,DbTypes.JavaSqlTypes javaSqlType,int maxLength ,ResultSetMetaData resultsMetaData)
+		{
+			object returnValue = null;	
+			sbyte[] sbyteArray;
+			long milliseconds;
+			long ticks;
+			string s;
+			columnIndex++; //jdbc style
+			switch (javaSqlType) {
+				case DbTypes.JavaSqlTypes.ARRAY :
+					returnValue = results.getArray(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.BIGINT :
+					returnValue = results.getLong(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.BINARY :
+				case DbTypes.JavaSqlTypes.VARBINARY :
+				case DbTypes.JavaSqlTypes.LONGVARBINARY :
+					// FIXME : comsider using maxLength
+					sbyteArray = results.getBytes(columnIndex);
+					if (sbyteArray != null) {
+						returnValue = vmw.common.TypeUtils.ToByteArray(sbyteArray);
+					}
+					break;
+				case DbTypes.JavaSqlTypes.BIT :
+					returnValue = results.getBoolean(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.BLOB :
+					// FIXME : comsider using maxLength
+					java.sql.Blob blob = results.getBlob(columnIndex);
+					if (blob != null) {
+						InputStream input = blob.getBinaryStream();					
+						if (input == null) {
+							returnValue = new byte[0];
+						}
+						else {
+							long length = blob.length();
+							byte[] byteValue = new byte[length];
+							sbyte[] sbyteValue = vmw.common.TypeUtils.ToSByteArray(byteValue);
+							input.read(sbyteValue);
+							returnValue = byteValue;
+						}
+					}
+					break;	
+				case DbTypes.JavaSqlTypes.CHAR :						
+					if (resultsMetaData != null && "uniqueidentifier".Equals(resultsMetaData.getColumnTypeName(columnIndex))) {
+						returnValue = new Guid(results.getString(columnIndex));
+					}
+					else {
+						// Oracle Jdbc driver returns extra trailing 0 chars for NCHAR columns, so we threat this at parameter.Size level
+						s = results.getString(columnIndex);
+						if ((s != null) && (maxLength < s.Length)) {
+							s = s.Substring(0,maxLength);
+						}
+						returnValue = s;
+					}
+					break;
+				case DbTypes.JavaSqlTypes.CLOB :
+					// FIXME : comsider using maxLength
+					java.sql.Clob clob = results.getClob(columnIndex);
+					if (clob != null) {
+						java.io.Reader reader = clob.getCharacterStream();					
+						if (reader == null) {
+							returnValue = String.Empty;
+						}
+						else {
+							long length = clob.length();
+							char[] charValue = new char[length];
+							reader.read(charValue);
+							returnValue = new string(charValue);
+						}
+					}
+					break;		
+				case DbTypes.JavaSqlTypes.TIME :
+					Time t = results.getTime(columnIndex);
+					if (t != null) {
+						returnValue = new TimeSpan(JavaTimeToClrTicks(t));
+					}
+					break;	
+				case DbTypes.JavaSqlTypes.DATE :
+					Date d = results.getDate(columnIndex);
+					if (d != null) {
+						returnValue = new DateTime(JavaDateToClrTicks(d));
+					}
+					break;
+				case DbTypes.JavaSqlTypes.TIMESTAMP :				
+					Timestamp ts = results.getTimestamp(columnIndex);
+					if (ts != null) {
+						returnValue = new DateTime(JavaTimestampToClrTicks(ts));
+					}
+					break;		
+				case DbTypes.JavaSqlTypes.DECIMAL :
+				case DbTypes.JavaSqlTypes.NUMERIC :
+					// java.sql.Types.NUMERIC (2), columnTypeName NUMBER, columnClassName java.math.BigDecimal 
+					// therefore we rely on scale
+					if (resultsMetaData != null &&  resultsMetaData.getScale(columnIndex) == -127) {
+						// Oracle db type FLOAT
+						returnValue = results.getDouble(columnIndex);
+					}
+					else {
+						java.math.BigDecimal bigDecimal = results.getBigDecimal(columnIndex);
+						if (bigDecimal != null) {
+							returnValue = vmw.common.PrimitiveTypeUtils.BigDecimalToDecimal(bigDecimal);
+						}
+					}
+					break;		
+				case DbTypes.JavaSqlTypes.DISTINCT :
+					returnValue = results.getObject(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.DOUBLE :
+					returnValue = results.getDouble(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.FLOAT :
+					//float f = results.getFloat(columnIndex);
+					returnValue = results.getDouble(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.INTEGER :
+					returnValue = results.getInt(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.JAVA_OBJECT :
+					returnValue = results.getObject(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.LONGVARCHAR :
+					returnValue = results.getString(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.NULL :
+					returnValue = DBNull.Value;
+					break;
+				case DbTypes.JavaSqlTypes.OTHER :
+					returnValue = results.getObject(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.REAL :
+					returnValue = results.getFloat(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.REF :
+					returnValue = results.getRef(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.SMALLINT :
+					returnValue = results.getShort(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.STRUCT :
+					returnValue = results.getObject(columnIndex);
+					break;
+				case DbTypes.JavaSqlTypes.TINYINT :
+					returnValue = Convert.ToByte(results.getByte(columnIndex));
+					break;
+				case DbTypes.JavaSqlTypes.VARCHAR :
+					s = results.getString(columnIndex);
+					if ((s != null) && (maxLength < s.Length)) {
+						s = s.Substring(0,maxLength);
+					}
+					returnValue = s;
+					break;
+				default :
+					returnValue = results.getObject(columnIndex);
+					break;
+			}
+				
+			if (results.wasNull() || results == null) {
+				return DBNull.Value;
+			}                
+			return  returnValue;
+		}
+
+		#endregion // Methods
+	}
+}

+ 60 - 0
mcs/class/System.Data/System.Data.Common/DbMetaDataCache.cs

@@ -0,0 +1,60 @@
+/*
+  * Copyright (c) 2002-2004 Mainsoft Corporation.
+  *
+  * 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 System.Collections;
+
+using java.sql;
+
+namespace System.Data.Common
+{
+	#region AbstractDbMetaDataCache
+
+	internal abstract class AbstractDbMetaDataCache
+	{
+		Hashtable _cache;
+		const int MINUTES_TIMEOUT = 10;
+		private long _timestamp;
+
+		protected AbstractDbMetaDataCache()
+		{
+			_cache = Hashtable.Synchronized(new Hashtable());
+		}
+
+		protected Hashtable Cache 
+		{
+			get
+			{
+				long now = DateTime.Now.Ticks;
+				if (now - _timestamp > MINUTES_TIMEOUT * TimeSpan.TicksPerMinute)
+				{
+					_timestamp = now;
+					_cache.Clear();
+				}
+
+				return _cache;
+			}
+		}
+	}
+
+	#endregion
+}

+ 107 - 0
mcs/class/System.Data/System.Data.Common/DbPortResolver.cs

@@ -0,0 +1,107 @@
+/*
+  * Copyright (c) 2002-2004 Mainsoft Corporation.
+  *
+  * 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.net;
+
+namespace System.Data.Common
+{
+	public class DbPortResolver
+	{
+		public static int getMSSqlPort(String sqlName, String instanceName,int timeout)
+		{
+			int port = -1;
+			try
+			{
+				DatagramSocket socket = new DatagramSocket();
+
+				// send request
+				sbyte[] buf = new sbyte[] {2};
+				InetAddress address = InetAddress.getByName(sqlName);
+				DatagramPacket packet = new DatagramPacket(buf, buf.Length, address, 1434);
+				socket.send(packet);
+				sbyte[] recbuf = new sbyte[1024];
+				packet = new DatagramPacket(recbuf, recbuf.Length, packet.getAddress(), packet.getPort());
+
+				// try to receive from socket while increasing timeouts in geometric progression
+				int iterationTimeout = 1;
+				int totalTimeout = 0;
+				while (totalTimeout < timeout*1000)
+				{
+					socket.setSoTimeout(iterationTimeout);
+					try
+					{
+						socket.receive(packet);
+						break;
+					}
+					catch (SocketTimeoutException e)
+					{
+						totalTimeout += iterationTimeout;
+						iterationTimeout *= 2;
+					}
+				}
+				sbyte[] rcvdSbytes = packet.getData();
+				char[] rcvdChars = new char[rcvdSbytes.Length];
+				for(int i=0; i < rcvdSbytes.Length; i++)
+				{
+					rcvdChars[i] = (char)rcvdSbytes[i];
+				}
+				String received = new String(rcvdChars);
+
+				java.util.StringTokenizer st = new java.util.StringTokenizer(received, ";");
+				String prev = "";
+				bool instanceReached = false;
+				while (st.hasMoreTokens())
+				{
+					if (!instanceReached)
+					{
+						if (prev.Trim().Equals("InstanceName"))
+						{
+							if (String.Compare(instanceName,st.nextToken().Trim(),true) == 0)
+							{
+								instanceReached = true;
+							}
+						}
+					}
+					else
+					{
+						if (prev.Trim().Equals("tcp"))
+						{
+							port = java.lang.Integer.parseInt(st.nextToken().Trim());
+							break;
+						}
+					}
+					prev = st.nextToken();
+				}
+				socket.close();
+				return port;
+
+			}
+			catch (java.lang.Exception e)
+			{
+				return port;
+			}
+		}
+	    
+	}
+}

+ 56 - 0
mcs/class/System.Data/System.Data.Common/DbStringManager.cs

@@ -0,0 +1,56 @@
+using java.util;
+
+namespace System.Data.Common
+{
+	public class DbStringManager
+	{
+		public DbStringManager(string bundleName)
+		{
+			_bundleName = bundleName;
+			_resourceBundle = ResourceBundle.getBundle(_bundleName);
+		}
+
+        private readonly string _bundleName;
+
+        private readonly ResourceBundle _resourceBundle;
+
+        public string GetString(string key)
+        {
+            try {
+                return _resourceBundle.getString(key);
+            }
+            catch (MissingResourceException) {
+                return null;
+            }
+        }
+	
+        public string GetString(string key, string defaultValue)
+        {
+            try {
+                return _resourceBundle.getString(key);
+            }
+            catch (MissingResourceException) {
+                return defaultValue;
+            }
+        }
+	
+	
+        public string[] GetStringArray(String key)
+        {
+            try {
+                string tmp = _resourceBundle.getString(key);
+                java.util.StringTokenizer st = new java.util.StringTokenizer(tmp, ",");
+			
+                String[] strArr = new String[st.countTokens()];
+			
+                for (int i = 0; i < strArr.Length; i++) {
+                    strArr[i] = st.nextToken();
+                }				
+                return strArr;			
+            }
+            catch (MissingResourceException) {
+                return null;
+            }
+        }
+    }
+}

+ 74 - 0
mcs/class/System.Data/System.Data.Common/DbTypes.cs

@@ -0,0 +1,74 @@
+using System;
+
+namespace System.Data.Common
+{
+	public class DbTypes
+	{
+		#region java.sql.Types constants
+
+		internal enum JavaSqlTypes {
+			ARRAY = 2003 ,
+			BIGINT = -5, 
+			BINARY = -2 ,
+			BIT = -7 ,
+			BLOB = 2004, 
+			BOOLEAN = 16, 
+			CHAR = 1, 
+			CLOB = 2005, 
+			DATALINK = 70, 
+			DATE = 91, 
+			DECIMAL = 3, 
+			DISTINCT = 2001, 
+			DOUBLE = 8, 
+			FLOAT = 6, 
+			INTEGER = 4, 
+			JAVA_OBJECT = 2000, 
+			LONGVARBINARY = -4,
+			LONGVARCHAR = -1, 
+			NULL = 0, 
+			NUMERIC = 2 ,
+			OTHER = 1111 ,
+			REAL = 7 ,
+			REF = 2006 ,
+			SMALLINT = 5,
+			STRUCT = 2002, 
+			TIME = 92, 
+			TIMESTAMP = 93, 
+			TINYINT = -6, 
+			VARBINARY = -3, 
+			VARCHAR = 12,
+//			NOTSET = int.MinValue
+		}
+
+
+		#endregion // java.sql.Types constants
+
+		#region .Net types constants
+
+		internal static readonly Type TypeOfBoolean = typeof(Boolean);
+		internal static readonly Type TypeOfSByte = typeof(SByte);
+		internal static readonly Type TypeOfChar = typeof(Char);
+		internal static readonly Type TypeOfInt16 = typeof(Int16);
+		internal static readonly Type TypeOfInt32 = typeof(Int32);
+		internal static readonly Type TypeOfInt64 = typeof(Int64);
+		internal static readonly Type TypeOfByte = typeof(Byte);
+		internal static readonly Type TypeOfUInt16 = typeof(UInt16);
+		internal static readonly Type TypeOfUInt32 = typeof(UInt32);
+		internal static readonly Type TypeOfUInt64 = typeof(UInt64);
+		internal static readonly Type TypeOfDouble = typeof(Double);
+		internal static readonly Type TypeOfSingle = typeof(Single);
+		internal static readonly Type TypeOfDecimal = typeof(Decimal);
+		internal static readonly Type TypeOfString = typeof(String);
+		internal static readonly Type TypeOfDateTime = typeof(DateTime);		
+		internal static readonly Type TypeOfObject = typeof(object);
+		internal static readonly Type TypeOfGuid = typeof(Guid);
+		internal static readonly Type TypeOfType = typeof(Type);
+
+		// additional types
+		internal static readonly Type TypeOfByteArray = typeof(Byte[]);
+		internal static readonly Type TypeOfFloat = typeof (float);
+		internal static readonly Type TypeOfTimespan = typeof (TimeSpan);
+
+		#endregion // .Net types constants
+	}
+}

+ 224 - 0
mcs/class/System.Data/System.Data.Common/ExceptionHelper.cs

@@ -0,0 +1,224 @@
+//
+// System.Data.Common.ExceptionHelper
+//
+// Author:
+//   Boris Kirzner ([email protected])
+//
+
+using System;
+
+using java.util;
+
+namespace System.Data.Common
+{
+	internal sealed class ExceptionHelper
+	{
+		sealed class ResourceManager
+		{
+			private static readonly ResourceBundle _resourceBundle = ResourceBundle.getBundle("SystemData");
+			
+			internal ResourceManager()
+			{				
+			}
+			
+			internal string GetString(string key)
+			{
+				return _resourceBundle.getString(key);
+			}
+		}
+
+		static ResourceManager _resourceManager = new ResourceManager();
+		
+		internal static ArgumentException InvalidSizeValue(int value)
+		{
+			string[] args = new string[] {value.ToString()};
+			return new ArgumentException(GetExceptionMessage("ADP_InvalidSizeValue",args));
+		}
+
+		internal static ArgumentOutOfRangeException InvalidDataRowVersion(DataRowVersion value)
+		{
+			return InvalidEnumerationValue(typeof(DataRowVersion), (int) value);
+		}
+		 
+		internal static ArgumentOutOfRangeException InvalidEnumerationValue(Type type, int value)
+		{
+			object[] args = new object[] { type.Name, value.ToString() } ;
+			return new ArgumentOutOfRangeException(GetExceptionMessage("ADP_InvalidEnumerationValue",args));
+		}
+ 
+		internal static ArgumentException InvalidOffsetValue(int value)
+		{
+			string[] args = new string[] {value.ToString()};
+			return new ArgumentException(GetExceptionMessage("ADP_InvalidOffsetValue",args));
+		}
+
+		internal static ArgumentOutOfRangeException InvalidParameterDirection(ParameterDirection value)
+		{
+			return InvalidEnumerationValue(typeof(ParameterDirection), (int) value);
+		}
+
+		internal static InvalidOperationException NoStoredProcedureExists(string procedureName) {
+			object[] args = new object[1] { procedureName } ;
+			return new InvalidOperationException(GetExceptionMessage("ADP_NoStoredProcedureExists", args));
+		}
+
+		internal static ArgumentNullException ArgumentNull(string parameter)
+		{
+			return new ArgumentNullException(parameter);
+		}
+
+		internal static InvalidOperationException TransactionRequired()
+		{
+			return new InvalidOperationException(GetExceptionMessage("ADP_TransactionRequired_Execute"));
+		}
+
+		internal static ArgumentOutOfRangeException InvalidOleDbType(int value)
+		{
+			string[] args = new string[] {value.ToString()};
+			return new ArgumentOutOfRangeException(GetExceptionMessage("OleDb_InvalidOleDbType",args));
+		}
+ 
+		internal static ArgumentException InvalidDbType(int value)
+		{
+			string[] args = new string[] {value.ToString()};
+			return new ArgumentException(GetExceptionMessage("ADP_UnknownDataType",args));
+		}
+
+		internal static InvalidOperationException DeriveParametersNotSupported(Type type,CommandType commandType)
+		{
+			string[] args = new string[] {type.ToString(),commandType.ToString()};
+			return new InvalidOperationException(GetExceptionMessage("ADP_DeriveParametersNotSupported",args));
+		}
+
+		internal static InvalidOperationException ReaderClosed(string mehodName)
+		{
+			string[] args = new string[] {mehodName};
+			return new InvalidOperationException(GetExceptionMessage("ADP_DataReaderClosed",args));
+		}
+
+		internal static ArgumentOutOfRangeException InvalidSqlDbType(int value)
+		{
+			string[] args = new string[] {value.ToString()};
+			return new ArgumentOutOfRangeException(GetExceptionMessage("SQL_InvalidSqlDbType",args));
+		}
+
+		internal static ArgumentException UnknownDataType(string type1, string type2)
+		{
+			string[] args = new string[] {type1, type2};
+			return new ArgumentException(GetExceptionMessage("ADP_UnknownDataType",args));
+		}
+
+		internal static InvalidOperationException TransactionNotInitialized()
+		{
+			return new InvalidOperationException(GetExceptionMessage("ADP_TransactionRequired_Execute"));
+		}
+
+		internal static InvalidOperationException ParametersNotInitialized(int parameterPosition,string parameterName,string parameterType)
+		{
+			object[] args = new object[] {parameterPosition,parameterName,parameterType};
+			return new InvalidOperationException(GetExceptionMessage("OleDb_UninitializedParameters",args));
+		}
+
+		internal static InvalidOperationException WrongParameterSize(string provider)
+		{
+			string[] args = new string[] {provider};
+			return new InvalidOperationException(GetExceptionMessage("ADP_PrepareParameterSize",args));
+		}
+
+		internal static InvalidOperationException ConnectionNotOpened(string operationName, string connectionState)
+		{
+			object[] args = new object[] {operationName,connectionState};
+			return new InvalidOperationException(GetExceptionMessage("ADP_OpenConnectionRequired_PropertySet",args));
+		}
+
+		internal static InvalidOperationException ConnectionNotInitialized(string methodName)
+		{
+			object[] args = new object[] {methodName};
+			return new InvalidOperationException(GetExceptionMessage("ADP_ConnectionRequired_ExecuteReader",args));
+		}
+
+		internal static InvalidOperationException OpenConnectionRequired(string methodName, object connectionState)
+		{
+			object[] args = new object[] {methodName, connectionState};
+			return new InvalidOperationException(GetExceptionMessage("ADP_OpenConnectionRequired_Fill",args));
+		}
+
+		internal static InvalidOperationException OpenedReaderExists()
+		{
+			return new InvalidOperationException(GetExceptionMessage("ADP_OpenReaderExists"));
+		}
+
+		internal static InvalidOperationException ConnectionAlreadyOpen(object connectionState)
+		{
+			object[] args = new object[] {connectionState};
+			return new InvalidOperationException(GetExceptionMessage("ADP_ConnectionAlreadyOpen",args));
+		}
+
+		internal static InvalidOperationException ConnectionStringNotInitialized()
+		{
+			return new InvalidOperationException(GetExceptionMessage("ADP_NoConnectionString"));
+		}
+
+		internal static InvalidOperationException ConnectionIsBusy(object commandType,object connectionState)
+		{
+			object[] args = new object[] {commandType.ToString(), connectionState.ToString()};
+			return new InvalidOperationException(GetExceptionMessage("ADP_CommandIsActive",args));
+		}
+
+		internal static InvalidOperationException NotAllowedWhileConnectionOpen(string propertyName, object connectionState)
+		{
+			object[] args = new object[] {propertyName,connectionState};
+			return new InvalidOperationException(GetExceptionMessage("ADP_OpenConnectionPropertySet",args));
+		}
+
+		internal static ArgumentException OleDbNoProviderSpecified()
+		{
+			return new ArgumentException(GetExceptionMessage("OleDb_NoProviderSpecified"));
+		}
+
+		internal static ArgumentException InvalidValueForKey(string key)
+		{
+			string[] args = new string[] { key };
+			return new ArgumentException(String.Format("Invalid value for key {0}",args));
+		}
+
+		internal static InvalidOperationException ParameterSizeNotInitialized(int parameterIndex, string parameterName,string parameterType,int parameterSize)
+		{
+			object[] args = new object[] { parameterIndex.ToString(),parameterName,parameterType,parameterSize.ToString()};
+			return new InvalidOperationException(GetExceptionMessage("ADP_UninitializedParameterSize",args));
+		}
+
+		internal static ArgumentException InvalidUpdateStatus(UpdateStatus status)
+		{
+			object[] args = new object[] { status };
+			return new ArgumentException(GetExceptionMessage("ADP_InvalidUpdateStatus",args));
+		}
+
+		internal static InvalidOperationException UpdateRequiresCommand(string command)
+		{
+			return new InvalidOperationException(GetExceptionMessage("ADP_UpdateRequiresCommand" + command));
+		}
+
+		internal static DataException RowUpdatedError()
+		{
+			return new DataException(GetExceptionMessage("ADP_RowUpdatedErrors"));
+		}
+
+		internal static string GetExceptionMessage(string key,object[] args)
+		{
+			string exceptionMessage = _resourceManager.GetString(key);
+
+			if ((args == null) || (args.Length == 0)) {
+				return exceptionMessage;
+			}
+			else {
+				return String.Format(exceptionMessage,args);
+			}
+		}
+
+		internal static string GetExceptionMessage(string key)
+		{
+			return GetExceptionMessage(key,null);
+		}
+	}
+}

+ 653 - 0
mcs/class/System.Data/System.Data.Common/Index.cs

@@ -0,0 +1,653 @@
+//
+// System.Data.Common.Key.cs
+//
+// Author:
+//   Boris Kirzner  <[email protected]>
+//   Konstantin Triger ([email protected])
+//
+
+/*
+  * Copyright (c) 2002-2004 Mainsoft Corporation.
+  *
+  * 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 System.Collections;
+
+using System.Text;
+
+namespace System.Data.Common
+{
+	enum IndexDuplicatesState { Unknown, True, False }; 
+	/// <summary>
+	/// Summary description for Index.
+	/// </summary>
+	internal class Index
+	{
+		#region Fields
+
+		int[] _array;
+		int _size;
+		Key _key;
+		int _refCount = 0;
+		IndexDuplicatesState _hasDuplicates;
+
+		#endregion // Fields
+
+		#region Constructors
+
+		internal Index(Key key)
+		{
+			_key = key;
+			Reset();
+		}
+
+		#endregion // Constructors
+
+		#region Properties
+
+		internal Key Key 
+		{
+			get {
+				return _key;
+			}
+		}
+
+		internal int Size
+		{
+			get {
+				EnsureArray();
+				return _size;
+			}
+		}
+
+		internal int RefCount
+		{
+			get {
+				return _refCount;
+			}
+		}
+
+		internal int IndexToRecord(int index){
+			return index < 0 ? index : Array[index];
+		}
+
+		private int[] Array
+		{
+			get {
+				EnsureArray();
+				return _array;
+			}
+		}
+
+		internal bool HasDuplicates
+		{
+			get {
+				if (_array == null || _hasDuplicates == IndexDuplicatesState.Unknown) {
+					EnsureArray();
+					if (_hasDuplicates == IndexDuplicatesState.Unknown) {
+						// check for duplicates
+						_hasDuplicates = IndexDuplicatesState.False;
+						for(int i = 0; i < Size - 1; i++) {
+							if (Key.CompareRecords(Array[i],Array[i+1]) == 0) {
+								_hasDuplicates = IndexDuplicatesState.True;
+								break;
+							}
+						}
+					}
+				}
+				return (_hasDuplicates == IndexDuplicatesState.True);
+			}
+		}
+
+		#endregion // Properties
+
+		#region Methods
+
+		internal int[] Duplicates {
+			get {
+				if (!HasDuplicates)
+					return null;
+
+				ArrayList dups = new ArrayList();
+
+				bool inRange = false;
+				for(int i = 0; i < Size - 1; i++) {
+					if (Key.CompareRecords(Array[i],Array[i+1]) == 0){
+						if (!inRange) {
+							dups.Add(Array[i]);
+							inRange = true;
+						}
+
+						dups.Add(Array[i+1]);
+					}
+					else
+						inRange = false;
+				}
+
+				return (int[])dups.ToArray(typeof(int));
+			}
+		}
+
+		private void EnsureArray()
+		{
+			if (_array == null) {
+				RebuildIndex();
+			}
+		}
+
+		internal int[] GetAll()
+		{
+			return Array;
+		}
+
+		internal void Reset()
+		{
+			_array = null;
+		}
+
+		private void RebuildIndex()
+		{
+			// consider better capacity approximation
+			_array = new int[Key.Table.RecordCache.CurrentCapacity];
+			_size = 0;
+			foreach(DataRow row in Key.Table.Rows) {
+				int record = Key.GetRecord(row);
+				if (record != -1) {
+					_array[_size++] = record;
+				}
+			}
+			_hasDuplicates = IndexDuplicatesState.False;
+			// Note : MergeSort may update hasDuplicates to True
+			Sort();
+		}
+
+		private void Sort()
+		{
+			//QuickSort(Array,0,Size-1);
+			MergeSort(Array,Size);
+		}
+		
+		/*
+		 * Returns record number of the record equal to the key values supplied 
+		 * in the meaning of index key, or -1 if no equal record found.
+		 */
+		internal int Find(object[] keys)
+		{
+			int index = FindIndex(keys);
+			return IndexToRecord(index);
+		}
+
+		/*
+		 * Returns record index (location) of the record equal to the key values supplied 
+		 * in the meaning of index key, or -1 if no equal record found.
+		 */
+		internal int FindIndex(object[] keys)
+		{
+			if (keys == null || keys.Length != Key.Columns.Length) {
+				throw new ArgumentException("Expecting " + Key.Columns.Length + " value(s) for the key being indexed, " +
+					"but received " + ((keys == null) ? 0 : keys.Length) + " value(s).");
+			}
+
+			int tmp = Key.Table.RecordCache.NewRecord();
+			try {
+				// init key values for temporal record
+				for(int i = 0; i < Key.Columns.Length; i++) {
+					Key.Columns[i].DataContainer[tmp] = keys[i];
+				}
+				return FindIndex(tmp);
+			}
+//			catch(FormatException) {
+//				return -1;
+//			}
+//			catch(InvalidCastException) {
+//				return -1;
+//			}
+			finally {
+				Key.Table.RecordCache.DisposeRecord(tmp);
+			}
+		}
+
+		/*
+		 * Returns record number of the record equal to the record supplied 
+		 * in the meaning of index key, or -1 if no equal record found.
+		 */
+		internal int Find(int record)
+		{
+			int index = FindIndex(record);
+			return IndexToRecord(index);
+		}
+
+		/*
+		 * Returns array of record numbers of the records equal equal to the key values supplied 
+		 * in the meaning of index key, or -1 if no equal record found.
+		 */
+		internal int[] FindAll(object[] keys)
+		{
+			int[] indexes = FindAllIndexes(keys);
+			IndexesToRecords(indexes);
+			return indexes;
+		}
+
+		/*
+		 * Returns array of indexes of the records inside the index equal equal to the key values supplied 
+		 * in the meaning of index key, or -1 if no equal record found.
+		 */
+		internal int[] FindAllIndexes(object[] keys)
+		{
+			if (keys == null || keys.Length != Key.Columns.Length) {
+				throw new ArgumentException("Expecting " + Key.Columns.Length + " value(s) for the key being indexed," +
+					"but received " + ((keys == null) ? 0 : keys.Length) + " value(s).");
+			}
+
+			int tmp = Key.Table.RecordCache.NewRecord();
+			try {
+				// init key values for temporal record
+				for(int i = 0; i < Key.Columns.Length; i++) {
+					Key.Columns[i].DataContainer[tmp] = keys[i];
+				}
+				return FindAllIndexes(tmp);
+			}
+			catch(FormatException) {
+				return new int[0];
+			}
+			catch(InvalidCastException) {
+				return new int[0];
+			}
+			finally {
+				Key.Table.RecordCache.DisposeRecord(tmp);
+			}
+		}
+
+		/*
+		 * Returns array of record numbers of the records equal to the record supplied 
+		 * in the meaning of index key, or empty list if no equal records found.
+		 */
+		internal int[] FindAll(int record)
+		{
+			int[] indexes = FindAllIndexes(record);
+            IndexesToRecords(indexes);
+			return indexes;
+		}
+
+		/*
+		 * Returns array of indexes of the records inside the index that equal to the record supplied 
+		 * in the meaning of index key, or empty list if no equal records found.
+		 */
+		internal int[] FindAllIndexes(int record)
+		{
+			int index = FindIndex(record);
+
+			if (index == -1) {
+				return new int[0];
+			}
+
+			int startIndex = index++;
+			int endIndex = index;
+			
+			for(;startIndex >= 0 && Key.CompareRecords(Array[startIndex],record) == 0;startIndex--);
+			for(;endIndex < Size && Key.CompareRecords(Array[endIndex],record) == 0;endIndex++);
+			
+			int length = endIndex - startIndex - 1;
+			int[] indexes = new int[length];
+			
+			for(int i = 0; i < length; i++) {
+				indexes[i] = ++startIndex;
+			}
+			
+			return indexes;
+		}
+
+		/*
+		 * Returns index inside the array where record number of the record equal to the record supplied 
+		 * in the meaning of index key is sored, or -1 if no equal record found.
+		 */
+		private int FindIndex(int record)
+		{
+			if (Size == 0) {
+				return -1;
+			}
+			return BinarySearch(Array,0,Size - 1,record);
+		}
+
+		/*
+		 * Finds exact location of the record specified
+		 */ 
+		private int FindIndexExact(int record)
+		{
+			int index = System.Array.BinarySearch(Array,record);
+			return (index > 0) ? index : -1;
+		}
+
+		/*
+		 * Returns array of records from the indexes (locations) inside the index
+		 */
+		private void IndexesToRecords(int[] indexes)
+		{
+			for(int i = 0; i < indexes.Length; i++) {
+				indexes[i] = Array[indexes[i]];
+			}
+		}
+
+		internal void Delete(DataRow row)
+		{
+			int oldRecord = Key.GetRecord(row);
+
+			Delete(oldRecord);
+		}
+
+		internal void Delete(int oldRecord)
+		{
+			int index = FindIndex(oldRecord);
+			if (index != -1) {
+				if ((_hasDuplicates == IndexDuplicatesState.True)) {
+					int c1 = 1;
+					int c2 = 1;
+
+					if (index > 0) {
+						c1 = Key.CompareRecords(Array[index - 1],oldRecord);
+					}
+					if (index < Size - 1) {
+						c2 = Key.CompareRecords(Array[index + 1],oldRecord);
+					}
+
+					if (c1 == 0 ^ c2 == 0) {
+						_hasDuplicates = IndexDuplicatesState.Unknown;
+					}
+				}
+				Remove(index);
+			}
+		}
+
+		private void Remove(int index)
+		{
+			if (Size > 1) {
+				System.Array.Copy(Array,index+1,Array,index,Size - index);
+			}
+			_size--;
+		}
+
+		internal void Update(DataRow row,int newRecord)
+		{
+			int oldRecord = Key.GetRecord(row);
+
+			if (oldRecord == -1 || Size == 0) {
+				Add(row,newRecord);
+				return;
+			}
+
+			int oldIdx = FindIndex(oldRecord);
+
+			if( oldIdx == -1) {
+				Add(row,newRecord);
+				return;
+			}
+				
+			int newIdx = -1;
+			int compare = Key.CompareRecords(Array[oldIdx],newRecord);
+			int start,end;
+
+			int c1 = 1;
+			int c2 = 1;
+
+			if (compare == 0) {
+				if (Array[oldIdx] == newRecord) {
+					// we deal with the same record that didn't change
+					// in the context of current index.
+					// so , do nothing.
+					return;
+				}
+			}
+			else {
+				if ((_hasDuplicates == IndexDuplicatesState.True)) {
+					if (oldIdx > 0) {
+						c1 = Key.CompareRecords(Array[oldIdx - 1],newRecord);
+					}
+					if (oldIdx < Size - 1) {
+						c2 = Key.CompareRecords(Array[oldIdx + 1],newRecord);
+					}
+
+					if ((c1 == 0 ^ c2 == 0) && compare != 0) {
+						_hasDuplicates = IndexDuplicatesState.Unknown;
+					}
+				}
+			}
+			
+			if ((oldIdx == 0 && compare > 0) || (oldIdx == (Size - 1) && compare < 0) || (compare == 0)) {
+				// no need to switch cells
+				newIdx = oldIdx;
+			}
+			else {
+				if (compare < 0) {
+					// search after the old place
+					start = oldIdx + 1;
+					end = Size - 1;
+				}
+				else {
+					// search before the old palce
+					start = 0;
+					end = oldIdx - 1;
+				}
+
+				newIdx = LazyBinarySearch(Array,start,end,newRecord);					
+
+				if (oldIdx < newIdx) {
+					System.Array.Copy(Array,oldIdx + 1,Array,oldIdx,newIdx - oldIdx);
+				}
+				else if (oldIdx > newIdx){
+					System.Array.Copy(Array,newIdx,Array,newIdx + 1,oldIdx - newIdx);
+				}
+			}			
+			Array[newIdx] = newRecord;
+
+			if (compare != 0) {
+				if (!(_hasDuplicates == IndexDuplicatesState.True)) {
+					if (newIdx > 0) {
+						c1 = Key.CompareRecords(Array[newIdx - 1],newRecord);
+					}
+					if (newIdx < Size - 1) {
+						c2 = Key.CompareRecords(Array[newIdx + 1],newRecord);
+					}
+
+					if (c1 == 0 || c2 == 0) {
+						_hasDuplicates = IndexDuplicatesState.True;
+					}
+				}
+			}
+		}
+
+		private void Add(DataRow row,int newRecord)
+		{
+			int newIdx;
+			if (Size == 0) {
+				newIdx = 0;
+			}
+			else {
+				newIdx = LazyBinarySearch(Array,0,Size - 1,newRecord);
+				// if newl value is greater - insert afer old value
+				// else - insert before old value
+				if (Key.CompareRecords(Array[newIdx],newRecord) < 0) {
+					newIdx++;
+				}
+			}
+					
+			Insert(newIdx,newRecord);
+
+			int c1 = 1;
+			int c2 = 1;
+			if (!(_hasDuplicates == IndexDuplicatesState.True)) {
+				if (newIdx > 0) {
+					c1 = Key.CompareRecords(Array[newIdx - 1],newRecord);
+				}
+				if (newIdx < Size - 1) {
+					c2 = Key.CompareRecords(Array[newIdx + 1],newRecord);
+				}
+
+				if (c1 == 0 || c2 == 0) {
+					_hasDuplicates = IndexDuplicatesState.True;
+				}
+			}
+		}
+
+		private void Insert(int index,int r)
+		{
+			if (Array.Length == Size) {
+				int[] tmp = (Size == 0) ? new int[16] : new int[Size << 1];
+				System.Array.Copy(Array,0,tmp,0,index);
+				tmp[index] = r;
+				System.Array.Copy(Array,index,tmp,index + 1,Size - index);
+				_array = tmp;
+			}
+			else {
+				System.Array.Copy(Array,index,Array,index + 1,Size - index);
+				Array[index] = r;
+			}
+			_size++;
+		}
+
+		private void MergeSort(int[] to, int length)
+        {
+            int[] from = new int[length];
+            System.Array.Copy(to, 0, from, 0, from.Length);
+
+            MergeSort(from, to, 0, from.Length);
+        }
+
+        private void MergeSort(int[] from, int[] to,int p, int r)
+        {
+            int q = (p + r) >> 1;
+	        if (q == p) {
+                return;
+            }        
+
+            MergeSort(to, from, p, q);
+            MergeSort(to, from, q, r);
+
+            // merge
+            for (int middle = q, current = p;;) {
+				int res = Key.CompareRecords(from[p],from[q]);
+                if (res > 0) {
+                    to[current++] = from[q++];
+
+                    if (q == r) {
+                        while( p < middle) {
+                                to[current++] = from[p++];
+						}
+                        break;
+                    }
+                }
+                else {
+
+					if (res == 0) {
+						_hasDuplicates = IndexDuplicatesState.True;
+					}
+
+                    to[current++] = from[p++];
+
+                    if (p == middle) {
+                        while( q < r) {
+                                to[current++] = from[q++];
+						}
+                        break;
+                    }
+                }
+            }
+		}
+
+		private void QuickSort(int[] a,int p,int r)
+		{
+			if (p < r) {
+				int q = Partition(a,p,r);
+				QuickSort(a,p,q);
+				QuickSort(a,q+1,r);
+			}
+		}
+
+		private int Partition(int[] a,int p,int r)
+		{
+			int x = a[p];
+			int i = p - 1;
+			int j = r + 1;
+
+			while(true) {
+				// decrement upper limit while values are greater then border value
+				do {
+					j--;
+				}
+				while(Key.CompareRecords(a[j],x) > 0);	//while(a[j] > x);
+
+				do {
+					i++;
+				}
+				while(Key.CompareRecords(a[i],x) < 0);	//while(a[i] < x);
+				
+				if (i<j) {
+					int tmp = a[j];
+					a[j] = a[i];
+					a[i] = tmp;
+				}
+				else {
+					return j;
+				}
+			}
+		}
+
+		private int BinarySearch(int[] a, int p, int r,int b)
+		{
+			int i = LazyBinarySearch(a,p,r,b);
+
+			return (Key.CompareRecords(a[i],b) == 0) ? i : -1;
+		}
+
+		// Lazy binary search only returns the cell number the search finished in,
+		// but does not checks that the correct value was actually found
+		private int LazyBinarySearch(int[] a, int p, int r,int b)
+		{
+			if ( p == r ) {
+				return p;
+			}
+
+			int q = (p+r) >> 1;
+
+			int compare = Key.CompareRecords(a[q],b);
+			if (compare < 0) { // if (a[q] < b) {
+				return LazyBinarySearch(a,q+1,r,b);
+			}
+			else if (compare > 0) { // a[q] > b
+				return LazyBinarySearch(a,p,q,b);
+			}	
+			else { // a[q] == b
+				return q;
+			}
+		}
+
+		internal void AddRef()
+		{
+			_refCount++;
+		}
+
+		internal void RemoveRef()
+		{
+			_refCount--;
+		}
+
+		#endregion // Methods
+	}
+}

+ 271 - 0
mcs/class/System.Data/System.Data.Common/JDCConnection.cs

@@ -0,0 +1,271 @@
+namespace System.Data.Common
+{
+
+    using java.sql;
+    using java.util;
+
+    using System;
+
+    public class JDCConnection : Connection
+    {
+
+        private JDCConnectionPool pool;
+        private Connection conn;
+        private bool inuse;
+        private long timestamp;
+
+
+        public JDCConnection(Connection conn, JDCConnectionPool pool)
+        {
+            this.conn=conn;
+            this.pool=pool;
+            this.inuse=false;
+            this.timestamp=0;
+        }
+
+        public bool lease()
+            
+        {
+            lock(this)
+            {
+                if(inuse)
+                {
+                    return false;
+                }
+                else
+                {
+                    inuse=true;
+                    timestamp = java.lang.System.currentTimeMillis();
+                    return true;
+                }
+            }
+        }
+        public bool validate()
+        {
+            try
+            {
+                conn.getMetaData();
+            }
+            catch (Exception)
+            {
+                return false;
+            }
+
+            return true;
+        }
+
+        public bool inUse()
+        {
+            return inuse;
+        }
+
+        public long getLastUse()
+        {
+            return timestamp;
+        }
+
+        public void close() //throws SQLException
+        {
+            pool.returnConnection(this);
+        }
+
+        public void expireLease()
+        {
+            inuse=false;
+        }
+
+        protected Connection getConnection()
+        {
+            return conn;
+        }
+
+        public void setTypeMap(Map map) //throws SQLException
+        {
+            conn.setTypeMap(map);
+        }
+
+
+        public Map getTypeMap() //throws SQLException
+        {
+            return conn.getTypeMap();
+        }
+
+        public PreparedStatement prepareStatement(String sql) //throws SQLException
+        {
+            return conn.prepareStatement(sql);
+        }
+
+        public PreparedStatement prepareStatement(String sql, int resultSetType, int resultSetConcurrency) //throws SQLException
+        {
+            return conn.prepareStatement(sql, resultSetType, resultSetConcurrency);
+        }
+
+        public CallableStatement prepareCall(String sql) //throws SQLException
+        {
+            return conn.prepareCall(sql);
+        }
+
+
+        public CallableStatement prepareCall(String sql, int resultSetType, int resultSetConcurrency) //throws SQLException
+        {
+            return conn.prepareCall(sql, resultSetType, resultSetConcurrency);
+        }
+
+
+        public Statement createStatement(int resultSetType, int resultSetConcurrency) //throws SQLException
+        {
+            return conn.createStatement(resultSetType, resultSetConcurrency);
+        }
+
+        public Statement createStatement() //throws SQLException
+        {
+            return conn.createStatement();
+        }
+
+        public String nativeSQL(String sql) //throws SQLException
+        {
+            return conn.nativeSQL(sql);
+        }
+
+        public void setAutoCommit(bool autoCommit) //throws SQLException
+        {
+            conn.setAutoCommit(autoCommit);
+        }
+
+        public bool getAutoCommit() //throws SQLException
+        {
+            return conn.getAutoCommit();
+        }
+
+        public void commit() //throws SQLException
+        {
+            conn.commit();
+        }
+
+        public void rollback() //throws SQLException
+        {
+            conn.rollback();
+        }
+
+        public bool isClosed() //throws SQLException
+        {
+            if(conn.isClosed())
+                return true;
+
+            return !inUse();
+        }
+
+        public DatabaseMetaData getMetaData() //throws SQLException
+        {
+            return conn.getMetaData();
+        }
+
+        public void setReadOnly(bool readOnly) //throws SQLException
+        {
+            conn.setReadOnly(readOnly);
+        }
+
+        public bool isReadOnly()// throws SQLException
+        {
+            return conn.isReadOnly();
+        }
+
+        public void setCatalog(String catalog) //throws SQLException
+        {
+            conn.setCatalog(catalog);
+        }
+
+        public String getCatalog() //throws SQLException
+        {
+            return conn.getCatalog();
+        }
+
+        public void setTransactionIsolation(int level) //throws SQLException
+        {
+            conn.setTransactionIsolation(level);
+        }
+
+        public int getTransactionIsolation() //throws SQLException
+        {
+            return conn.getTransactionIsolation();
+        }
+
+        public SQLWarning getWarnings() //throws SQLException
+        {
+            return conn.getWarnings();
+        }
+
+        public void clearWarnings() //throws SQLException
+        {
+            conn.clearWarnings();
+        }
+
+        // --------- JDBC 3.0 -------------
+        /*
+        public void setHoldability(int holdability)
+        {
+            conn.setHoldability(holdability);
+        }
+        
+        public int getHoldability()
+        {
+            return conn.getHoldability();
+        }
+
+        public Savepoint setSavepoint()
+        {
+            return conn.setSavepoint();
+        }
+
+        public Savepoint setSavepoint(string name)
+        {
+            return conn.setSavepoint(name);
+        }
+
+        public void rollback(Savepoint savepoint)
+        {
+            conn.rollback(savepoint);
+        }
+
+        public void releaseSavepoint(Savepoint savepoint)
+        {
+            conn.releaseSavepoint(savepoint);
+        }
+
+        public Statement createStatement(int resultSetType, int resultSetConcurrency, 
+            int resultSetHoldability)
+        {
+            return conn.createStatement(resultSetType, resultSetConcurrency, resultSetHoldability);
+        }
+
+        public PreparedStatement prepareStatement(String sql, int resultSetType, 
+            int resultSetConcurrency, int resultSetHoldability)
+        {
+            throw new NotImplementedException();
+        }
+
+        public CallableStatement prepareCall(String sql, int resultSetType, 
+            int resultSetConcurrency, 
+            int resultSetHoldability)
+        {
+            return conn.prepareCall(sql, resultSetType, resultSetConcurrency, resultSetHoldability);
+        }
+
+        public PreparedStatement prepareStatement(String sql, int autoGeneratedKeys)
+        {
+            return conn.prepareStatement(sql, autoGeneratedKeys);
+        }
+
+        public PreparedStatement prepareStatement(String sql, int[] columnIndexes)
+        {
+            return conn.prepareStatement(sql, columnIndexes);
+        }
+
+        public PreparedStatement prepareStatement(String sql, String[] columnNames)
+        {
+            return conn.prepareStatement(sql, columnNames);
+        }
+
+        */
+    }
+}

+ 63 - 0
mcs/class/System.Data/System.Data.Common/JDCConnectionDriver.cs

@@ -0,0 +1,63 @@
+namespace System.Data.Common
+{
+
+using java.sql;
+using java.util;
+
+
+class JDCConnectionDriver : Driver
+{
+
+    public static readonly String URL_PREFIX = "jdbc:jdc:";
+    private static readonly int MAJOR_VERSION = 1;
+    private static readonly int MINOR_VERSION = 0;
+    private JDCConnectionPool pool;
+
+    public JDCConnectionDriver(String driver, String url,
+                                 String user, String password)
+                            //throws ClassNotFoundException,
+                              // InstantiationException, IllegalAccessException,
+                                //SQLException
+    {
+        DriverManager.registerDriver(this);
+        java.lang.Class.forName(driver).newInstance();
+        pool = new JDCConnectionPool(url, user, password);
+    }
+
+    public Connection connect(String url, Properties props)
+                                      // throws SQLException
+    {
+        if(!url.StartsWith(URL_PREFIX))
+        {
+             return null;
+        }
+
+        return pool.getConnection();
+    }
+
+    public bool acceptsURL(String url)
+    {
+        return url.StartsWith(URL_PREFIX);
+    }
+
+    public int getMajorVersion()
+    {
+        return MAJOR_VERSION;
+    }
+
+    public int getMinorVersion()
+    {
+        return MINOR_VERSION;
+    }
+
+    public DriverPropertyInfo[] getPropertyInfo(String str, Properties props)
+    {
+        return new DriverPropertyInfo[0];
+    }
+
+    public bool jdbcCompliant()
+    {
+        return false;
+    }
+}
+}

+ 88 - 0
mcs/class/System.Data/System.Data.Common/JDCConnectionPool.cs

@@ -0,0 +1,88 @@
+namespace System.Data.Common
+{
+
+    using java.sql;
+    using java.util;
+
+
+    public class JDCConnectionPool
+    {
+
+        private ArrayList _connections;
+        private String _url, _user, _password;
+        readonly private long timeout = 10000;
+        readonly private int _initPoolsize = 10;
+        private int _maxPoolSize = 100;
+        private static bool _shutdown = false; 
+
+        public JDCConnectionPool(String url, String user, String password)
+        {
+            _url = url;
+            _user = user;
+            _password = password;
+            _connections = new ArrayList(_initPoolsize);
+        }
+
+    
+        public void closeConnections()
+        {
+            lock(this)
+            {
+                if(_connections.size() > 0)
+                {
+                    Iterator connlist = _connections.iterator();
+    
+                    while (connlist.hasNext())
+                    {
+                        JDCConnection conn = (JDCConnection) connlist.next();
+                        removeConnection(conn);
+                    }
+                }
+            }
+        }
+
+        private  void removeConnection(JDCConnection conn)
+        {
+            lock(this)
+            {
+                _connections.remove(conn);
+            }
+        }
+
+        public Connection getConnection() //throws SQLException
+                                          {
+                                              lock(this)
+    {
+
+        JDCConnection c;
+        for (int i = 0; i < _connections.size(); i++)
+    {
+        c = (JDCConnection) _connections.get(i);
+			
+        if (c.lease())
+        return c;
+    }
+        
+    if(_connections.size() < _maxPoolSize)
+{
+    Connection conn = DriverManager.getConnection(_url, _user, _password);
+    c = new JDCConnection(conn, this);
+    c.lease();
+    _connections.add(c);
+    return c;
+}
+        
+    return null;
+}
+	}
+
+	public void returnConnection(JDCConnection conn)
+	{
+        lock(this)
+        {
+            conn.expireLease();
+        }
+	}
+    
+}
+}

+ 226 - 0
mcs/class/System.Data/System.Data.Common/Key.cs

@@ -0,0 +1,226 @@
+//
+// System.Data.Common.Key.cs
+//
+// Author:
+//   Boris Kirzner  <[email protected]>
+//   Konstantin Triger ([email protected])
+//
+
+/*
+  * Copyright (c) 2002-2004 Mainsoft Corporation.
+  *
+  * 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 Mono.Data.SqlExpressions;
+using System.ComponentModel;
+
+namespace System.Data.Common
+{
+	internal class Key
+	{
+		#region Fields
+
+		DataTable _table;
+		DataColumn[] _columns;
+		ListSortDirection[] _sortDirection;
+		DataViewRowState _rowStateFilter;
+		IExpression _filter;
+		//Currently IExpression.Eval does not receive DataRowVersion
+		//	and always uses the _current version
+		//so need a temp row for Eval calls
+		DataRow _tmpRow;
+
+		#endregion //Fields
+
+		#region Constructors
+
+		internal Key(DataTable table,DataColumn[] columns,ListSortDirection[] sort, DataViewRowState rowState, IExpression filter)
+		{
+			_table = table;
+			_filter = filter;
+			if (_filter != null)
+				_tmpRow = _table.NewNotInitializedRow();
+			_columns = columns;
+			if (sort != null && sort.Length == columns.Length) {
+				_sortDirection = sort;
+			}
+			else {
+				_sortDirection = new ListSortDirection[columns.Length];
+				for(int i=0; i < _sortDirection.Length; i++) {
+					_sortDirection[i] = ListSortDirection.Ascending;
+				}
+			}
+
+			if (rowState != DataViewRowState.None) {
+				_rowStateFilter = rowState;
+			}
+			else {
+				// FIXME : what is the correct value ?
+				_rowStateFilter = DataViewRowState.CurrentRows;
+			}
+		}
+
+		#endregion // Constructors
+
+		#region Properties
+
+		internal DataColumn[] Columns
+		{
+			get {
+				return _columns;
+			}
+		}
+
+		internal DataTable Table
+		{
+			get {
+				return _table;
+			}
+		}
+
+		ListSortDirection[] Sort 
+		{
+			get {
+				return _sortDirection;
+			}
+		}
+
+		internal DataViewRowState RowStateFilter
+		{
+			get {
+				return _rowStateFilter;
+			}
+
+			set {
+				_rowStateFilter = value;
+			}
+		}
+
+		#endregion // Properties
+
+		#region Methods
+
+		internal int CompareRecords(int first, int second)
+		{
+			if (first == second) {
+				return 0;
+			}
+
+			for(int i = 0; i < Columns.Length; i++) {
+
+				int res = Columns[i].CompareValues(first,second);
+
+				if (res == 0) {
+					continue;
+				}
+
+				return (Sort[i] == ListSortDirection.Ascending) ? res : -res;
+			}
+			return 0;
+		}
+
+		internal int GetRecord(DataRow row)
+		{
+			int index = Key.GetRecord(row,_rowStateFilter);
+			if (_filter == null)
+				return index;
+
+			if (index < 0)
+				return index;
+
+			_tmpRow._current = index;
+			return _filter.EvalBoolean(_tmpRow) ? index : -1;
+		}
+
+		internal static int GetRecord(DataRow row, DataViewRowState rowStateFilter)
+		{
+
+			if (row.Original == row.Current) {
+				 if ((rowStateFilter & DataViewRowState.Unchanged) != DataViewRowState.None) {
+					 return row.Current;
+				 }
+			}
+			else if (row.Original == -1) {
+				  if ((rowStateFilter & DataViewRowState.Added) != DataViewRowState.None) {
+					return row.Current;
+				  }
+			}
+			else if (row.Current == -1) {
+				     if ((rowStateFilter & DataViewRowState.Deleted) != DataViewRowState.None) {
+						return row.Original;
+					 }
+			}
+			else if ((rowStateFilter & DataViewRowState.ModifiedCurrent) != DataViewRowState.None) {
+				return row.Current;
+			}
+			else if ((rowStateFilter & DataViewRowState.ModifiedOriginal) != DataViewRowState.None) {
+				return row.Original;
+			}
+
+            return -1;
+		}
+
+		/// <summary>
+		/// Checks for key equality to parameters set given
+		/// </summary>
+		/// <param name="columns">Columns the key consits of. If this parameter is null, it does not affects equality check</param>
+		/// <param name="sort">Sort order of columns. If this parameter is null, it does not affects equality check</param>
+		/// <param name="rowState">DataViewRowState to check for.If this parameter is null, it does not affects equality check</param>
+		/// <param name="unique">Indicates whenever the index managed by this key allows non-uniqie keys to appear.</param>
+		/// <param name="strict">Indicates whenever unique parameter should affect the equality check.</param>
+		/// <returns></returns>
+		internal bool Equals(DataColumn[] columns, ListSortDirection[] sort, DataViewRowState rowState, IExpression filter) 
+		{
+			if (rowState != DataViewRowState.None && RowStateFilter != rowState) {
+				return false;
+			}
+
+			if (_filter != filter)
+				return false;
+
+			if (Columns.Length != columns.Length) {
+				return false;
+			}
+
+			if (sort != null && Sort.Length != sort.Length) {
+				return false;
+			}
+
+			if (sort != null) {
+				for(int i=0; i < columns.Length; i++) {
+					if (Sort[i] != sort[i] || Columns[i] != columns[i]) {
+						return false;
+					}
+				}
+			}
+			else {
+				for(int i=0; i < columns.Length; i++) {
+					if (Columns[i] != columns[i]) {
+						return false;
+					}
+				}
+			}
+			return true;
+		}
+
+		#endregion // Methods
+	}
+}

+ 70 - 0
mcs/class/System.Data/System.Data.Common/ParameterMetadataWrapper.cs

@@ -0,0 +1,70 @@
+using System;
+
+using java.sql;
+
+namespace System.Data.Common
+{
+	public class ParameterMetadataWrapper : java.sql.ResultSetMetaData
+	{
+		#region Fields 
+
+		ParameterMetaData _parameterMetaData;
+
+		#endregion // Fields
+
+		#region Constructors
+
+		public ParameterMetadataWrapper(ParameterMetaData parameterMetaData)
+		{
+			_parameterMetaData = parameterMetaData;
+		}
+
+		#endregion // Constructors
+
+		#region Methods
+
+		public int getColumnCount() { throw new NotImplementedException(); }
+
+		public int getColumnDisplaySize(int i) { throw new NotImplementedException(); }
+
+		public int getColumnType(int i) { throw new NotImplementedException(); }
+
+		public int getPrecision(int i) { throw new NotImplementedException(); }
+
+		public int getScale(int i) { throw new NotImplementedException(); }
+
+		public int isNullable(int i) { throw new NotImplementedException(); }
+
+		public bool isAutoIncrement(int i) { throw new NotImplementedException(); }
+
+		public bool isCaseSensitive(int i) { throw new NotImplementedException(); }
+
+		public bool isCurrency(int i) { throw new NotImplementedException(); }
+
+		public bool isDefinitelyWritable(int i) { throw new NotImplementedException(); }
+
+		public bool isReadOnly(int i) { throw new NotImplementedException(); }
+
+		public bool isSearchable(int i) { throw new NotImplementedException(); }
+
+		public bool isSigned(int i) { throw new NotImplementedException(); }
+
+		public bool isWritable(int i) { throw new NotImplementedException(); }
+
+		public String getCatalogName(int i) { throw new NotImplementedException(); }
+
+		public String getColumnClassName(int i) { throw new NotImplementedException(); }
+
+		public String getColumnLabel(int i) { throw new NotImplementedException(); }
+
+		public String getColumnName(int i) { throw new NotImplementedException(); }
+
+		public String getColumnTypeName(int i) { return _parameterMetaData.getParameterTypeName(i); }
+
+		public String getSchemaName(int i) { throw new NotImplementedException(); }
+
+		public String getTableName(int i) { throw new NotImplementedException(); }
+
+		#endregion // Methods
+	}
+}

+ 659 - 0
mcs/class/System.Data/System.Data.Common/ReaderCache.cs

@@ -0,0 +1,659 @@
+using System;
+using java.sql;
+
+namespace System.Data.Common
+{
+	public interface IReaderCacheContainer
+	{
+		void Fetch(ResultSet rs, int columnIndex);
+		bool IsNull();
+		object GetValue();
+	}
+
+	internal abstract class ReaderCacheContainerBase : IReaderCacheContainer
+	{
+		#region Fields
+
+		bool _isNull;
+
+		#endregion // Fields
+
+		#region Methods
+
+		protected abstract void FetchInternal(ResultSet rs, int columnIndex);
+
+		public abstract object GetValue();		
+
+		public void Fetch(ResultSet rs, int columnIndex)
+		{
+			FetchInternal(rs, columnIndex + 1);
+			_isNull = rs.wasNull();
+		}
+
+		public bool IsNull()
+		{
+			return _isNull;
+		}
+
+		#endregion // Methods
+	}
+
+
+	internal sealed class ArrayReaderCacheContainer : ReaderCacheContainerBase // Types.ARRAY
+	{
+		#region Fields
+
+		java.sql.Array _a;
+
+		#endregion // Fields
+
+		#region Methods
+
+		protected override void FetchInternal(ResultSet rs, int columnIndex)
+		{
+			_a = rs.getArray(columnIndex);
+		}
+
+		public override object GetValue()
+		{
+			return _a;
+		}
+
+		internal java.sql.Array GetArray()
+		{
+			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 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 _b;
+		}
+
+		#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 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];
+
+		#endregion // Fields
+
+		#region Methods
+
+		protected override void FetchInternal(ResultSet rs, int columnIndex)
+		{
+			java.sql.Blob blob = rs.getBlob(columnIndex);
+			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()
+		{
+			return _b;
+		}
+
+		#endregion // Methods
+	}
+	
+
+	internal abstract class CharsReaderCacheContainer : ReaderCacheContainerBase // 
+	{
+		#region Fields
+		
+		#endregion // Fields
+
+		#region Methods
+
+		internal abstract char[] GetChars();
+
+		#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)
+		{
+			_g = new Guid(rs.getString(columnIndex));
+		}
+
+		public override object GetValue()
+		{
+			return _g;
+		}
+
+		internal Guid GetGuid()
+		{
+			return _g;
+		}
+
+		#endregion // Methods
+	}
+
+
+	internal sealed class ClobReaderCacheContainer : StringReaderCacheContainer // Types.CLOB
+	{
+		#region Fields
+		
+		char[] _c;
+
+		#endregion // Fields
+
+		#region Methods
+
+		// FIXME : conside adding stream wrapper interface
+
+		protected override void FetchInternal(ResultSet rs, int columnIndex)
+		{
+			java.sql.Clob clob = rs.getClob(columnIndex);			
+			if (clob != null) {
+				long length = clob.length();								
+				if (length == 0) {
+					_s = String.Empty;
+					_c = String.Empty.ToCharArray();
+				}
+				else {	
+					java.io.Reader reader = clob.getCharacterStream();	
+					char[] charValue = new char[length];
+					reader.read(charValue);
+					_c = charValue;
+					
+				}
+			}
+		}
+
+		public override object GetValue()
+		{
+			if (_s == null && _c != null) {
+				_s = (_c.Length != 0) ? new String(_c) : String.Empty;
+			}
+			return _s;
+		}
+
+		internal override char[] GetChars()
+		{
+			return _c;
+		}
+
+		#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 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 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 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 char[] GetChars()
+		{
+			return _s.ToCharArray();
+		}
+
+		#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 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 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 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
+	}
+
+}