Просмотр исходного кода

2006-02-10 Senganal T <[email protected]>
* Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs :
- GetSequentialColumn,BeginLoad, EndLoad,
LoadData, SkipRow, SkipToColumnIndex
New Methods to Support sequential loading of row data
* Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsComm.cs :
- Skip : Changed arugment type from int to long.
* System.Data/Test/ProviderTests/System.Data.SqlClient/SqlDataReaderTest.cs :
Added more tests to verify Sequential reading of row data.
* System.Data/Test/ProviderTests/ProviderIndependant/DataReaderTest : Corrected a failing testcase.
* System.Data/System.Data.SqlClient/SqlDataReader.cs :
- GetBytes : Read binary/blob/clob data sequentially when
CommandBehavior is set to SequentialAcccess
- GetChars : Read String/clob data sequentially when CommandBehavior
is set to SequentialAccess
* System.Data/System.Data.SqlClient/SqlCommand.cs :
- ExecuteReader : set SequentialAccess property on TDS
- CloseDataReader : Reset the command behavior


svn path=/trunk/mcs/; revision=56757

Senganal T 20 лет назад
Родитель
Сommit
1ed319dc99

+ 9 - 0
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/ChangeLog

@@ -1,3 +1,12 @@
+2006-02-10  Senganal T  <[email protected]>
+
+	* Tds.cs :
+		- GetSequentialColumn,BeginLoad, EndLoad,
+		LoadData, SkipRow, SkipToColumnIndex
+		New Methods to Support sequential loading of row data
+	* TdsComm.cs :
+		- Skip : Changed arugment type from int to long.
+
 2006-01-27  Senganal T  <[email protected]>
 
 	* Tds.cs :

+ 5 - 0
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/ITds.cs

@@ -71,6 +71,11 @@ namespace Mono.Data.Tds.Protocol {
 			set;
 		}
 
+		bool SequentialAccess {
+			get;
+			set;
+		}
+
 		#endregion // Properties
 
 		#region Methods

+ 182 - 1
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/Tds.cs

@@ -89,6 +89,15 @@ namespace Mono.Data.Tds.Protocol {
 
 		int recordsAffected = -1;
 
+		long StreamLength = 0;
+		long StreamIndex = 0;
+		int StreamColumnIndex = 0;
+
+		bool sequentialAccess = false;
+		bool isRowRead = false;
+		bool isResultRead = false;
+		bool LoadInProgress = false;
+
 		#endregion // Fields
 
 		#region Properties
@@ -166,6 +175,156 @@ namespace Mono.Data.Tds.Protocol {
 			set { parameters = value; }
 		}
 
+		public bool SequentialAccess {
+			get { return sequentialAccess; }
+			set { sequentialAccess = value; }
+		}
+
+		private void SkipRow ()
+		{
+			SkipToColumnIndex (Columns.Count);
+
+			StreamLength = 0;
+			StreamColumnIndex = 0;
+			StreamIndex = 0;
+			LoadInProgress = false;
+		}
+
+		private void SkipToColumnIndex (int colIndex)
+		{
+			if (LoadInProgress)
+				EndLoad ();
+
+			if (colIndex < StreamColumnIndex)
+				throw new Exception ("Cannot Skip to a colindex less than the curr index");
+
+			while (colIndex != StreamColumnIndex) {
+				TdsColumnType colType = (TdsColumnType)Columns[StreamColumnIndex]["ColumnType"];
+				if (!(colType == TdsColumnType.Image ||
+					colType == TdsColumnType.Text ||
+					colType == TdsColumnType.NText)) {
+					GetColumnValue (colType, false, StreamColumnIndex);
+					StreamColumnIndex ++;
+				}
+				else {
+					BeginLoad (colType);
+					Comm.Skip (StreamLength);
+					StreamLength = 0;
+					EndLoad ();
+				}
+			}
+		}
+
+		public object GetSequentialColumnValue (int colIndex)
+		{
+			if (colIndex < StreamColumnIndex)
+				throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex); 
+
+			if (LoadInProgress)
+				EndLoad ();
+
+			if (colIndex != StreamColumnIndex)
+				SkipToColumnIndex (colIndex);
+
+			object o = GetColumnValue ((TdsColumnType)Columns[colIndex]["ColumnType"], false, colIndex);
+			StreamColumnIndex++;
+			return o;
+		}
+
+		public long GetSequentialColumnValue (int colIndex, long fieldIndex, byte[] buffer, int bufferIndex, int size) 
+		{
+			if (colIndex < StreamColumnIndex)
+				throw new InvalidOperationException ("Invalid attempt tp read from column ordinal" + colIndex); 
+
+			if (colIndex != StreamColumnIndex) 
+				SkipToColumnIndex (colIndex);
+
+			if (!LoadInProgress)
+				BeginLoad ((TdsColumnType)Columns[colIndex]["ColumnType"]);
+
+			if (buffer == null) {
+				return StreamLength;
+			}
+			return LoadData (fieldIndex, buffer, bufferIndex, size);
+		}
+
+		private void BeginLoad(TdsColumnType colType) 
+		{
+			if (LoadInProgress)
+				EndLoad ();
+
+			StreamLength = 0;
+		
+			switch (colType) {
+			case TdsColumnType.Text :
+			case TdsColumnType.NText:
+			case TdsColumnType.Image:
+				if (Comm.GetByte () != 0) {
+					Comm.Skip (24);
+					StreamLength = Comm.GetTdsInt ();
+				}
+				break;
+			case TdsColumnType.BigVarChar:
+			case TdsColumnType.BigChar:
+			case TdsColumnType.BigBinary:
+			case TdsColumnType.BigVarBinary:
+				Comm.GetTdsShort ();
+				StreamLength = Comm.GetTdsShort ();
+				break;
+			case TdsColumnType.VarChar :
+			case TdsColumnType.NVarChar :
+			case TdsColumnType.Char:
+			case TdsColumnType.NChar:
+			case TdsColumnType.Binary:
+			case TdsColumnType.VarBinary:
+				StreamLength = Comm.GetTdsShort ();
+				break;
+			default :
+				StreamLength = -1;
+				break;
+			}
+
+			StreamIndex = 0;
+			LoadInProgress = true;
+		}
+
+		private void EndLoad()
+		{
+			if (StreamLength > 0)
+				Comm.Skip (StreamLength);
+			StreamLength = 0;
+			StreamIndex = 0;
+			StreamColumnIndex++;
+			LoadInProgress = false;
+		}
+
+		private long LoadData (long fieldIndex, byte[] buffer, int bufferIndex, int size)
+		{
+			if (StreamLength <= 0)
+				return StreamLength;
+
+			if (fieldIndex < StreamIndex)
+				throw new InvalidOperationException ("field index less than stream pos");
+
+			if (fieldIndex >= (StreamLength + StreamIndex))
+				return 0;
+
+			// Skip to the index
+			Comm.Skip ((int) (fieldIndex - StreamIndex));
+			StreamIndex += (fieldIndex - StreamIndex);
+
+			// Load the reqd amt of bytes	
+			int loadlen = (int) ((size > StreamLength) ? StreamLength : size);
+			byte[] arr = Comm.GetBytes (loadlen, true);
+
+			// update the index and stream length
+			StreamIndex +=  loadlen + (fieldIndex - StreamIndex);
+			StreamLength -= loadlen;
+			arr.CopyTo (buffer, bufferIndex);
+
+			return arr.Length;
+		}
+
 		#endregion // Properties
 
 		#region Events
@@ -300,6 +459,13 @@ namespace Mono.Data.Tds.Protocol {
 
 		public bool NextResult ()
 		{
+			if (SequentialAccess) {
+				if (isResultRead) {
+					while (NextRow ()) {}
+					isRowRead = false;
+					isResultRead = false;
+				}
+			}
 			if (!moreResults)
 				return false;
 
@@ -347,6 +513,13 @@ namespace Mono.Data.Tds.Protocol {
 
 		public bool NextRow ()
 		{
+			if (SequentialAccess) {
+				if (isRowRead) {
+					SkipRow ();
+					isRowRead = false;
+				}
+			}
+
 			TdsPacketSubType subType;
 			bool done = false;
 			bool result = false;
@@ -430,7 +603,7 @@ namespace Mono.Data.Tds.Protocol {
 				element = GetIntValue (colType);
 				break;
 			case TdsColumnType.Image :
-				if (outParam) 
+				if (outParam)
 					comm.Skip (1);
 				element = GetImageValue ();
 				break;
@@ -891,6 +1064,14 @@ namespace Mono.Data.Tds.Protocol {
 
 		protected void LoadRow ()
 		{
+			if (SequentialAccess) {
+				if (isRowRead)
+					SkipRow ();
+				isRowRead = true;
+				isResultRead = true;
+				return;
+			}
+
 			currentRow = new TdsDataRow ();
 
 			int i = 0;

+ 1 - 1
mcs/class/Mono.Data.Tds/Mono.Data.Tds.Protocol/TdsComm.cs

@@ -511,7 +511,7 @@ namespace Mono.Data.Tds.Protocol {
 			}
 		}
 		
-		public void Skip (int i)
+		public void Skip (long i)
 		{
 			for ( ; i > 0; i--)
 				GetByte ();

+ 10 - 0
mcs/class/System.Data/System.Data.SqlClient/ChangeLog

@@ -1,3 +1,13 @@
+2006-02-10  Senganal T  <[email protected]>
+	* SqlDataReader.cs :
+		- GetBytes : Read binary/blob/clob data sequentially when
+		CommandBehavior is set to SequentialAcccess
+		- GetChars : Read String/clob data sequentially when CommandBehavior
+		is set to SequentialAccess
+	* SqlCommand.cs :
+		- ExecuteReader : set SequentialAccess property on TDS
+		- CloseDataReader : Reset the command behavior
+
 2006-01-27  Senganal T  <[email protected]>
 
 	* SqlCommandBuilder.cs :

+ 6 - 0
mcs/class/System.Data/System.Data.SqlClient/SqlCommand.cs

@@ -291,6 +291,10 @@ namespace System.Data.SqlClient {
 
 			if ((behavior & CommandBehavior.CloseConnection) != 0)
 				Connection.Close ();
+
+			// Reset the behavior
+			behavior = CommandBehavior.Default;
+			Tds.SequentialAccess = false;
 		}
 
 		public new SqlParameter CreateParameter () 
@@ -395,6 +399,8 @@ namespace System.Data.SqlClient {
 			ValidateCommand ("ExecuteReader");
 			try {
                                 this.behavior = behavior;
+				if ((behavior & CommandBehavior.SequentialAccess) != 0)
+					Tds.SequentialAccess = true;
 				Execute (behavior, true);
                                 Connection.DataReader = new SqlDataReader (this);
 			}

+ 64 - 11
mcs/class/System.Data/System.Data.SqlClient/SqlDataReader.cs

@@ -36,6 +36,7 @@
 
 using Mono.Data.Tds.Protocol;
 using System;
+using System.Text;
 using System.Collections;
 using System.ComponentModel;
 using System.Data;
@@ -262,6 +263,15 @@ namespace System.Data.SqlClient {
 #endif // NET_2_0
                 long GetBytes (int i, long dataIndex, byte[] buffer, int bufferIndex, int length)
 		{
+			if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
+				long len = ((Tds)command.Tds).GetSequentialColumnValue (i, dataIndex, buffer, bufferIndex, length);
+				if (len == -1)
+					throw new InvalidCastException ("Invalid attempt to GetBytes on column "
+							+ "'" + command.Tds.Columns[i]["ColumnName"] + "'." + "The GetBytes function"
+							+ " can only be used on columns of type Text, NText, or Image");
+				return len;
+			}
+
 			object value = GetValue (i);
 			if (!(value is byte [])) {
 				if (value is DBNull) throw new SqlNullValueException ();
@@ -269,16 +279,16 @@ namespace System.Data.SqlClient {
 			}
 			
 			if ( buffer == null )
-                                return ((byte []) value).Length; // Return length of data
-                        
-                        // Copy data into buffer
-                        int availLen = (int) ( ( (byte []) value).Length - dataIndex);
-                        if (availLen < length)
-                                length = availLen;
-                        Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
-                        return length; // return actual read count
+				return ((byte []) value).Length; // Return length of data
+
+			// Copy data into buffer
+			int availLen = (int) ( ( (byte []) value).Length - dataIndex);
+			if (availLen < length)
+				length = availLen;
+			Array.Copy ((byte []) value, (int) dataIndex, buffer, bufferIndex, length);
+			return length; // return actual read count
 		}
-                                                                                                    
+
 		[EditorBrowsableAttribute (EditorBrowsableState.Never)]
 		public 
 #if NET_2_0
@@ -300,8 +310,46 @@ namespace System.Data.SqlClient {
 #endif // NET_2_0
                 long GetChars (int i, long dataIndex, char[] buffer, int bufferIndex, int length)
 		{
-			object value = GetValue (i);
+			if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
+				Encoding encoding = null;
+				byte mul = 1;
+				TdsColumnType colType = (TdsColumnType) command.Tds.Columns[i]["ColumnType"];
+				switch (colType) {
+					case TdsColumnType.Text :
+					case TdsColumnType.VarChar:
+					case TdsColumnType.Char:
+					case TdsColumnType.BigVarChar:
+						encoding = Encoding.ASCII;
+						break;
+					case TdsColumnType.NText :
+					case TdsColumnType.NVarChar:
+					case TdsColumnType.NChar:
+						encoding = Encoding.Unicode;
+						mul = 2 ;
+						break;
+					default :
+						return -1;
+				}
+
+				long count = 0;
+				if (buffer == null) {
+					count = GetBytes (i,0,(byte[]) null,0,0);
+					return (count/mul);
+				}
+
+				length *= mul;
+				byte[] arr = new byte [length];
+				count = GetBytes (i, dataIndex, arr, 0, length);
+				if (count == -1)
+					throw new InvalidCastException ("Specified cast is not valid");
+
+				Char[] val = encoding.GetChars (arr, 0, (int)count);
+				val.CopyTo (buffer, bufferIndex);
+				return val.Length;
+			}
+
 			char [] valueBuffer;
+			object value = GetValue (i);
 			
 			if (value is char[])
 				valueBuffer = (char[])value;
@@ -933,8 +981,13 @@ namespace System.Data.SqlClient {
 #endif // NET_2_0
                 object GetValue (int i)
 		{
-			if (i < 0 || i >= command.Tds.ColumnValues.Count)
+			if (i < 0 || i >= command.Tds.Columns.Count)
 				throw new IndexOutOfRangeException ();
+
+			if ((command.CommandBehavior & CommandBehavior.SequentialAccess) != 0) {
+				return ((Tds)command.Tds).GetSequentialColumnValue (i);
+			}
+
 			return command.Tds.ColumnValues [i];
 		}
 

+ 4 - 0
mcs/class/System.Data/Test/ProviderTests/ProviderIndependant/ChangeLog

@@ -1,3 +1,7 @@
+2006-02-10  Senganal T  <[email protected]>
+	
+	* DataReaderTest : Corrected a failing testcase.
+
 2006-01-27  Senganal T  <[email protected]>
 	
 	* DataReaderTest : Corrected a failing testcase.

+ 1 - 1
mcs/class/System.Data/Test/ProviderTests/ProviderIndependant/DataReaderTest.cs

@@ -183,7 +183,7 @@ namespace MonoTests.System.Data
 						Assert.Fail ("#2 No test data");
 					// for null value, length in bytes should return 0
 					if (reader.Read ()) 
-						Assert.AreEqual (-1, reader.GetBytes (0, 0, null, 0, 0), 
+						Assert.AreEqual (0, reader.GetBytes (0, 0, null, 0, 0), 
 								 "#3 on null value, it should return -1");
 					else
 						Assert.Fail ("#4 No test data");

+ 5 - 0
mcs/class/System.Data/Test/ProviderTests/System.Data.SqlClient/ChangeLog

@@ -1,3 +1,8 @@
+2006-02-10  Senganal T  <[email protected]>
+
+	* SqlDataReaderTest.cs : Added more tests to verify Sequential
+	reading of row data.
+
 2006-02-05  Senganal T  <[email protected]>
 
 	* SqlParameterTest.cs : New : Testcase for bug #77410

+ 118 - 0
mcs/class/System.Data/Test/ProviderTests/System.Data.SqlClient/SqlDataReaderTest.cs

@@ -454,6 +454,124 @@ namespace MonoTests.System.Data.SqlClient
 			// do i need to test for image/binary values also ??? 
 		}
 
+		[Test]
+		public void GetBytes_Binary ()
+		{
+			cmd.CommandText = "Select type_binary,type_varbinary,type_blob ";
+			cmd.CommandText += "from binary_family where id=1";
+			reader = cmd.ExecuteReader ();
+			reader.Read ();
+			byte[] binary = (byte[])reader.GetValue (0);
+			byte[] varbinary = (byte[])reader.GetValue (1);
+			byte[] image = (byte[])reader.GetValue (2);
+			reader.Close ();
+
+			reader = cmd.ExecuteReader (CommandBehavior.SequentialAccess);
+			reader.Read ();
+			int len = 0;
+			byte[] arr ;
+			len = (int)reader.GetBytes (0,0,null,0,0);
+			Assert.AreEqual (binary.Length, len, "#1");
+			arr = new byte [len];
+			reader.GetBytes (0,0,arr,0,len);
+			for (int i=0; i<len; ++i)
+				Assert.AreEqual (binary[i], arr[i], "#2");
+
+
+			len = (int)reader.GetBytes (1,0,null,0,0);
+			Assert.AreEqual (varbinary.Length, len, "#1");
+			arr = new byte [len];
+			reader.GetBytes (1,0,arr,0,len);
+			for (int i=0; i<len; ++i)
+				Assert.AreEqual (varbinary[i], arr[i], "#2");
+
+			len = (int)reader.GetBytes (2,0,null,0,0);
+			Assert.AreEqual (image.Length, len, "#1");
+			arr = new byte [len];
+			reader.GetBytes (2,0,arr,0,len);
+			for (int i=0; i<len; ++i)
+				Assert.AreEqual (image[i], arr[i], "#2");
+
+			reader.Close ();
+
+			cmd.CommandText = "Select type_binary,type_varbinary,type_blob ";
+			cmd.CommandText += "from binary_family where id=1";
+		
+			reader = cmd.ExecuteReader (CommandBehavior.SequentialAccess);
+			reader.Read ();
+		
+			len  = (int)reader.GetBytes (0,0,null,0,0);	
+			arr = new byte [100];
+			for (int i=0; i<len; ++i) {
+				Assert.AreEqual (len-i, reader.GetBytes (0, i, null, 0, 0), "#1_"+i);
+				Assert.AreEqual (1, reader.GetBytes (0, i, arr, 0, 1), "#2_"+i);
+				Assert.AreEqual (binary [i], arr [0], "#3_"+i);
+			}
+			Assert.AreEqual (0, reader.GetBytes (0, len+10, null, 0, 0));
+			reader.Close ();
+		}
+
+		[Test]
+		public void GetChars ()
+		{
+			cmd.CommandText = "Select type_char, type_varchar,type_text, type_ntext ";
+			cmd.CommandText += "from string_family where id=1";
+			reader = cmd.ExecuteReader ();
+			reader.Read ();
+			string charstring = reader.GetString (0);
+			//string ncharstring = reader.GetString (1);
+			string varcharstring = reader.GetString (1);
+			//string nvarcharstring = reader.GetString (2);
+			string textstring = reader.GetString (2);
+			string ntextstring = reader.GetString (3);
+			reader.Close ();
+			
+			reader = cmd.ExecuteReader (CommandBehavior.SequentialAccess);
+			reader.Read ();
+			int len = 0;
+			char[] arr; 
+
+			len = (int)reader.GetChars (0,0,null,0,0);
+			Assert.AreEqual (charstring.Length, len, "#1");
+			arr = new char [len];
+			reader.GetChars (0,0,arr,0,len);
+			Assert.AreEqual (0, charstring.CompareTo (new String (arr)), "#2");
+
+			len = (int)reader.GetChars (1,0,null,0,0);
+			Assert.AreEqual (varcharstring.Length, len, "#3");
+			arr = new char [len];
+			reader.GetChars (1,0,arr,0,len);
+			Assert.AreEqual (0, varcharstring.CompareTo (new String (arr)), "#4");
+
+			len = (int)reader.GetChars (2,0,null,0,0);
+			Assert.AreEqual (textstring.Length, len, "#5");
+			arr = new char [len];
+			reader.GetChars (2,0,arr,0,len);
+			Assert.AreEqual (0, textstring.CompareTo (new String (arr)), "#6");
+
+			len = (int)reader.GetChars (3,0,null,0,0);
+			Assert.AreEqual (ntextstring.Length, len, "#7");
+			arr = new char [len];
+			reader.GetChars (3,0,arr,0,len);
+			Assert.AreEqual (0, ntextstring.CompareTo (new String (arr)), "#8");
+
+			reader.Close ();
+
+			reader = cmd.ExecuteReader (CommandBehavior.SequentialAccess);
+			reader.Read ();
+			
+			len  = (int)reader.GetChars (0,0,null,0,0);	
+			arr = new char [10];
+			for (int i=0; i<len; ++i) {
+				Assert.AreEqual (len-i, reader.GetChars (0, i, null, 0, 0), "#9_"+i);
+				Assert.AreEqual (1, reader.GetChars (0, i, arr, 0, 1), "#10_"+i);
+				Assert.AreEqual (charstring [i], arr [0], "#11_"+i);
+			}
+			Assert.AreEqual (0, reader.GetChars (0, len+10, null, 0, 0));
+
+			reader.Close ();
+		}
+
 		[Test]
 		public void GetStringTest ()
 		{