// Diego Caravana (diego@toth.it)
// Sebastien Pouliot (sebastien@ximian.com)
// Daniel Morgan (danielmorgan@verizon.net)
+// Gert Driesen (drieseng@users.sourceforge.net)
+// Veerapuram Varadhan (vvaradhan@novell.com)
//
// Copyright (C) 2002 Tim Coleman
// Portions (C) 2003 Motus Technologies Inc. (http://www.motus.com)
// Portions (C) 2003 Daniel Morgan
//
-
//
// Permission is hereby granted, free of charge, to any person obtaining
// a copy of this software and associated documentation files (the
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
//
-using Mono.Security.Protocol.Ntlm;
using System;
+using System.Globalization;
using System.Text;
-namespace Mono.Data.Tds.Protocol {
- public class Tds70 : Tds
+using Mono.Security.Protocol.Ntlm;
+
+namespace Mono.Data.Tds.Protocol
+{
+ public class Tds70 : Tds
{
#region Fields
- public readonly static TdsVersion Version = TdsVersion.tds70;
+ //public readonly static TdsVersion Version = TdsVersion.tds70;
+ static readonly decimal SMALLMONEY_MIN = -214748.3648m;
+ static readonly decimal SMALLMONEY_MAX = 214748.3647m;
#endregion // Fields
}
public Tds70 (string server, int port, int packetSize, int timeout)
- : base (server, port, packetSize, timeout, Version)
+ : base (server, port, packetSize, timeout, TdsVersion.tds70)
{
}
+ public Tds70 (string server, int port, int packetSize, int timeout, TdsVersion version)
+ : base (server, port, packetSize, timeout, version)
+ {
+ }
+
#endregion // Constructors
+ #region Properties
+
+ protected virtual byte[] ClientVersion {
+ get { return new byte[] {0x00, 0x0, 0x0, 0x70};}
+ }
+ #endregion // Properties
+
#region Methods
private string BuildExec (string sql)
StringBuilder result = new StringBuilder ();
foreach (TdsMetaParameter p in Parameters) {
+ string parameterName = p.ParameterName;
+ if (parameterName [0] == '@') {
+ parameterName = parameterName.Substring (1);
+ }
if (p.Direction != TdsParameterDirection.ReturnValue) {
- if (result.Length > 0)
- result.Append (", ");
+ if (result.Length > 0)
+ result.Append (", ");
if (p.Direction == TdsParameterDirection.InputOutput)
- result.Append (String.Format("{0}={0} output", p.ParameterName));
+ result.AppendFormat ("@{0}={0} output", parameterName);
else
- result.Append (FormatParameter (p));
- }
+ result.Append (FormatParameter (p));
+ }
}
return result.ToString ();
}
int count = 0;
if (Parameters != null) {
foreach (TdsMetaParameter p in Parameters) {
- if (p.Direction != TdsParameterDirection.Input) {
+ string parameterName = p.ParameterName;
+ if (parameterName [0] == '@') {
+ parameterName = parameterName.Substring (1);
+ }
+ if (p.Direction != TdsParameterDirection.Input) {
if (count == 0)
select.Append ("select ");
else
select.Append (", ");
- select.Append (p.ParameterName);
+ select.Append ("@" + parameterName);
declare.Append (String.Format ("declare {0}\n", p.Prepare ()));
if (p.Direction != TdsParameterDirection.ReturnValue) {
- if( p.Direction == TdsParameterDirection.InputOutput )
+ if (p.Direction == TdsParameterDirection.InputOutput)
set.Append (String.Format ("set {0}\n", FormatParameter(p)));
else
- set.Append (String.Format ("set {0}=NULL\n", p.ParameterName));
+ set.Append (String.Format ("set @{0}=NULL\n", parameterName));
}
- count += 1;
- }
-
- if (p.Direction == TdsParameterDirection.ReturnValue) {
- exec = p.ParameterName + "=";
+ count++;
}
+ if (p.Direction == TdsParameterDirection.ReturnValue)
+ exec = "@" + parameterName + "=";
}
}
- exec = "exec " + exec;
-
- string sql = String.Format ("{0}{1}{2}{3} {4}\n{5}", declare.ToString (), set.ToString (), exec, procedure, BuildParameters (), select.ToString ());
- return sql;
+ exec = "exec " + exec;
+
+ return String.Format ("{0}{1}{2}{3} {4}\n{5}",
+ declare.ToString (), set.ToString (), exec,
+ procedure, BuildParameters (), select.ToString ());
}
public override bool Connect (TdsConnectionParameters connectionParameters)
short authLen = 0;
byte pad = (byte) 0;
- byte[] domainMagic = { 6, 0x7d, 0x0f, 0xfd, 0xff, 0x0, 0x0, 0x0,
+ byte[] domainMagic = { 6, 0x7d, 0x0f, 0xfd, 0xff, 0x0, 0x0, 0x0,
0x0, 0xe0, 0x83, 0x0, 0x0,
0x68, 0x01, 0x00, 0x00, 0x09, 0x04, 0x00, 0x00 };
- byte[] sqlserverMagic = { 6, 0x83, 0xf2, 0xf8,
- 0xff, 0x0, 0x0, 0x0,
+ byte[] sqlserverMagic = { 6, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0, 0x0,
0x0, 0xe0, 0x03, 0x0,
- 0x0, 0x88, 0xff, 0xff, 0xff, 0x36,
- 0x04, 0x00, 0x00 };
+ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0,
+ 0x0, 0x0, 0x0 };
byte[] magic = null;
- if (connectionParameters.DomainLogin == true)
+ if (connectionParameters.DomainLogin)
magic = domainMagic;
else
magic = sqlserverMagic;
string username = connectionParameters.User;
+ string domain = null;
- string domain = Environment.UserDomainName;
- domain = connectionParameters.DefaultDomain = Environment.UserDomainName;
-
- int idx = 0;
- if ((idx = username.IndexOf ("\\")) > -1) {
+ int idx = username.IndexOf ("\\");
+ if (idx != -1) {
domain = username.Substring (0, idx);
username = username.Substring (idx + 1);
connectionParameters.DefaultDomain = domain;
connectionParameters.User = username;
+ } else {
+ domain = Environment.UserDomainName;
+ connectionParameters.DefaultDomain = domain;
}
-
+
short partialPacketSize = (short) (86 + (
- connectionParameters.Hostname.Length +
- connectionParameters.ApplicationName.Length +
+ connectionParameters.Hostname.Length +
+ connectionParameters.ApplicationName.Length +
DataSource.Length +
connectionParameters.LibraryName.Length +
Language.Length +
connectionParameters.Database.Length +
- connectionParameters.AttachDBFileName.Length) * 2);
-
- if(connectionParameters.DomainLogin == true) {
+ connectionParameters.AttachDBFileName.Length) * 2);
+
+ if (connectionParameters.DomainLogin) {
authLen = ((short) (32 + (connectionParameters.Hostname.Length +
domain.Length)));
partialPacketSize += authLen;
- }
- else
+ } else
partialPacketSize += ((short) ((username.Length + connectionParameters.Password.Length) * 2));
int totalPacketSize = partialPacketSize;
Comm.Append (totalPacketSize);
- Comm.Append (empty, 3, pad);
- Comm.Append ((byte) 0x70); // TDS Version 7
+ //Comm.Append (empty, 3, pad);
+ //byte[] version = {0x00, 0x0, 0x0, 0x71};
+ //Console.WriteLine ("Version: {0}", ClientVersion[3]);
+ Comm.Append (ClientVersion); // TDS Version 7
Comm.Append ((int)this.PacketSize); // Set the Block Size
Comm.Append (empty, 3, pad);
Comm.Append (magic);
short curPos = 86;
- // Hostname
+ // Hostname
Comm.Append (curPos);
Comm.Append ((short) connectionParameters.Hostname.Length);
curPos += (short) (connectionParameters.Hostname.Length * 2);
- if(connectionParameters.DomainLogin.Equals(true))
- {
+ if (connectionParameters.DomainLogin) {
Comm.Append((short)0);
Comm.Append((short)0);
Comm.Append((short)0);
Comm.Append((short)0);
- }
- else
- {
+ } else {
// Username
Comm.Append (curPos);
Comm.Append ((short) username.Length);
curPos += (short) (connectionParameters.Password.Length * 2);
}
- // AppName
+ // AppName
Comm.Append (curPos);
Comm.Append ((short) connectionParameters.ApplicationName.Length);
curPos += (short) (connectionParameters.ApplicationName.Length * 2);
curPos += (short) (DataSource.Length * 2);
// Unknown
- Comm.Append ((short) 0);
+ Comm.Append ((short) curPos);
Comm.Append ((short) 0);
// Library Name
// Authentication Stuff
Comm.Append ((short) curPos);
- if (connectionParameters.DomainLogin == true)
- {
+ if (connectionParameters.DomainLogin) {
Comm.Append ((short) authLen);
curPos += (short) authLen;
- }
- else
+ } else
Comm.Append ((short) 0);
// Unknown
// Connection Parameters
Comm.Append (connectionParameters.Hostname);
- if (connectionParameters.DomainLogin == false)
- {
+ if (!connectionParameters.DomainLogin) {
// SQL Server Authentication
Comm.Append (connectionParameters.User);
string scrambledPwd = EncryptPassword (connectionParameters.Password);
Comm.Append (Language);
Comm.Append (connectionParameters.Database);
- if (connectionParameters.DomainLogin)
- {
+ if (connectionParameters.DomainLogin) {
// the rest of the packet is NTLMSSP authentication
Type1Message msg = new Type1Message ();
msg.Domain = domain;
msg.Host = connectionParameters.Hostname;
- msg.Flags = NtlmFlags.NegotiateUnicode |
- NtlmFlags.NegotiateNtlm |
- NtlmFlags.NegotiateDomainSupplied |
- NtlmFlags.NegotiateWorkstationSupplied |
+ msg.Flags = NtlmFlags.NegotiateUnicode |
+ NtlmFlags.NegotiateNtlm |
+ NtlmFlags.NegotiateDomainSupplied |
+ NtlmFlags.NegotiateWorkstationSupplied |
NtlmFlags.NegotiateAlwaysSign; // 0xb201
Comm.Append (msg.GetBytes ());
}
public override bool Reset ()
{
- try {
- ExecProc ("sp_reset_connection");
- base.Reset ();
- } catch (Exception e) {
- System.Reflection.PropertyInfo pinfo = e.GetType ().GetProperty ("Class");
- if (pinfo != null && pinfo.PropertyType == typeof (byte)) {
- byte klass = (byte) pinfo.GetValue (e, null);
- // 11 to 16 indicates error that can be fixed by the user such as 'Invalid object name'
- if (klass < 11 || klass > 16)
- return false;
- }
- }
+ // Check validity of the connection - a false removes
+ // the connection from the pool
+ // NOTE: MS implementation will throw a connection-reset error as it will
+ // try to use the same connection
+ if (!Comm.IsConnected ())
+ return false;
+ // Set "reset-connection" bit for the next message packet
+ Comm.ResetConnection = true;
+ base.Reset ();
return true;
}
public override void ExecPrepared (string commandText, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
{
Parameters = parameters;
- ExecuteQuery (BuildPreparedQuery (commandText), timeout, wantResults);
+ if (Parameters != null && Parameters.Count > 0)
+ ExecRPC (TdsRpcProcId.ExecuteSql, commandText, parameters, timeout, wantResults);
+ else
+ ExecuteQuery (BuildPreparedQuery (commandText), timeout, wantResults);
}
public override void ExecProc (string commandText, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
{
- if (parameters != null && parameters.Count > 0) {
- Parameters = parameters;
- ExecuteQuery (BuildProcedureCall (commandText), timeout, wantResults);
- } else {
- ExecRPC (commandText, parameters, timeout, wantResults);
+ Parameters = parameters;
+ ExecRPC (commandText, parameters, timeout, wantResults);
+ }
+
+ private void WriteRpcParameterInfo (TdsMetaParameterCollection parameters)
+ {
+ if (parameters != null) {
+ foreach (TdsMetaParameter param in parameters) {
+ if (param.Direction == TdsParameterDirection.ReturnValue)
+ continue;
+ string pname = param.ParameterName;
+ if (pname != null && pname.Length > 0 && pname [0] == '@') {
+ Comm.Append ( (byte) pname.Length);
+ Comm.Append (pname);
+ } else {
+ Comm.Append ( (byte) (pname.Length + 1));
+ Comm.Append ("@" + pname);
+ }
+ short status = 0; // unused
+ if (param.Direction != TdsParameterDirection.Input)
+ status |= 0x01; // output
+ Comm.Append ( (byte) status);
+ WriteParameterInfo (param);
+ }
}
}
+
+ private void WritePreparedParameterInfo (TdsMetaParameterCollection parameters)
+ {
+ if (parameters == null)
+ return;
+
+ string param = BuildPreparedParameters ();
+ Comm.Append ((byte) 0x00); // no param meta data name
+ Comm.Append ((byte) 0x00); // no status flags
+
+ // Type_info - parameter info
+ WriteParameterInfo (new TdsMetaParameter ("prep_params",
+ param.Length > 4000 ? "ntext" : "nvarchar",
+ param));
+ }
+
+ private void ExecRPC (TdsRpcProcId rpcId, string sql,
+ TdsMetaParameterCollection parameters,
+ int timeout, bool wantResults)
+ {
+ // clean up
+ InitExec ();
+ Comm.StartPacket (TdsPacketType.RPC);
+
+ Comm.Append ((ushort) 0xFFFF);
+ Comm.Append ((ushort) rpcId);
+ Comm.Append ((short) 0x02); // no meta data
+
+ Comm.Append ((byte) 0x00); // no param meta data name
+ Comm.Append ((byte) 0x00); // no status flags
+
+ // Write sql as a parameter value - UCS2
+ TdsMetaParameter param = new TdsMetaParameter ("sql",
+ sql.Length > 4000 ? "ntext":"nvarchar",
+ sql);
+ WriteParameterInfo (param);
+
+ // Write Parameter infos - name and type
+ WritePreparedParameterInfo (parameters);
+ // Write parameter/value info
+ WriteRpcParameterInfo (parameters);
+ Comm.SendPacket ();
+ CheckForData (timeout);
+ if (!wantResults)
+ SkipToEnd ();
+ }
+
protected override void ExecRPC (string rpcName, TdsMetaParameterCollection parameters,
int timeout, bool wantResults)
{
- // clean up
+ // clean up
InitExec ();
-
Comm.StartPacket (TdsPacketType.RPC);
Comm.Append ( (short) rpcName.Length);
Comm.Append (rpcName);
Comm.Append ( (short) 0); //no meta data
-
- // FIXME : support parameters here
-
+ WriteRpcParameterInfo (parameters);
Comm.SendPacket ();
CheckForData (timeout);
- if (!wantResults)
+ if (!wantResults)
SkipToEnd ();
+ }
+
+ private void WriteParameterInfo (TdsMetaParameter param)
+ {
+ /*
+ Ms.net send non-nullable datatypes as nullable and allows setting null values
+ to int/float etc.. So, using Nullable form of type for all data
+ */
+ param.IsNullable = true;
+ TdsColumnType colType = param.GetMetaType ();
+ param.IsNullable = false;
+
+ bool partLenType = false;
+ int size = param.Size;
+ if (size < 1) {
+ if (size < 0)
+ partLenType = true;
+ size = param.GetActualSize ();
+ }
+
+ // Change colType according to the following table
+ /*
+ * Original Type Maxlen New Type
+ *
+ * NVarChar 4000 UCS2 NText
+ * BigVarChar 8000 ASCII Text
+ * BigVarBinary 8000 bytes Image
+ *
+ */
+ TdsColumnType origColType = colType;
+ if (colType == TdsColumnType.BigNVarChar) {
+ // param.GetActualSize() returns len*2
+ if (size == param.Size)
+ size <<= 1;
+ if ((size >> 1) > 4000)
+ colType = TdsColumnType.NText;
+ } else if (colType == TdsColumnType.BigVarChar) {
+ if (size > 8000)
+ colType = TdsColumnType.Text;
+ } else if (colType == TdsColumnType.BigVarBinary) {
+ if (size > 8000)
+ colType = TdsColumnType.Image;
+ }
+ // Calculation of TypeInfo field
+ /*
+ * orig size value TypeInfo field
+ *
+ * >= 0 <= Maxlen origColType + content len
+ * > Maxlen NewType as per above table + content len
+ * -1 origColType + USHORTMAXLEN (0xFFFF) + content len (TDS 9)
+ *
+ */
+ // Write updated colType, iff partLenType == false
+ if (TdsVersion > TdsVersion.tds81 && partLenType) {
+ Comm.Append ((byte)origColType);
+ Comm.Append ((short)-1);
+ } else if (ServerTdsVersion > TdsVersion.tds70
+ && origColType == TdsColumnType.Decimal) {
+ Comm.Append ((byte)TdsColumnType.Numeric);
+ } else {
+ Comm.Append ((byte)colType);
+ }
+
+ if (IsLargeType (colType))
+ Comm.Append ((short)size); // Parameter size passed in SqlParameter
+ else if (IsBlobType (colType))
+ Comm.Append (size); // Parameter size passed in SqlParameter
+ else
+ Comm.Append ((byte)size);
+
+ // Precision and Scale are non-zero for only decimal/numeric
+ if ( param.TypeName == "decimal" || param.TypeName == "numeric") {
+ Comm.Append ((param.Precision !=0 ) ? param.Precision : (byte) 29);
+ Comm.Append (param.Scale);
+ // Convert the decimal value according to Scale
+ if (param.Value != null && param.Value != DBNull.Value &&
+ ((decimal)param.Value) != Decimal.MaxValue &&
+ ((decimal)param.Value) != Decimal.MinValue) {
+ decimal expo = new Decimal (System.Math.Pow (10, (double)param.Scale));
+ int pVal = (int)(((decimal)param.Value) * expo);
+ param.Value = (decimal)pVal;
+ }
+ }
+
+ /* VARADHAN: TDS 8 Debugging */
+ /*
+ if (Collation != null) {
+ Console.WriteLine ("Collation is not null");
+ Console.WriteLine ("Column Type: {0}", colType);
+ Console.WriteLine ("Collation bytes: {0} {1} {2} {3} {4}", Collation[0], Collation[1], Collation[2],
+ Collation[3], Collation[4]);
+ } else {
+ Console.WriteLine ("Collation is null");
+ }
+ */
+
+ // Tds > 7.0 uses collation
+ if (Collation != null &&
+ (colType == TdsColumnType.BigChar || colType == TdsColumnType.BigNVarChar ||
+ colType == TdsColumnType.BigVarChar || colType == TdsColumnType.NChar ||
+ colType == TdsColumnType.NVarChar || colType == TdsColumnType.Text ||
+ colType == TdsColumnType.NText))
+ Comm.Append (Collation);
+
+ // LAMESPEC: size should be 0xFFFF for any bigvarchar, bignvarchar and bigvarbinary
+ // types if param value is NULL
+ if ((colType == TdsColumnType.BigVarChar ||
+ colType == TdsColumnType.BigNVarChar ||
+ colType == TdsColumnType.BigVarBinary) &&
+ (param.Value == null || param.Value == DBNull.Value))
+ size = -1;
+ else
+ size = param.GetActualSize ();
+
+ if (IsLargeType (colType))
+ Comm.Append ((short)size);
+ else if (IsBlobType (colType))
+ Comm.Append (size);
+ else
+ Comm.Append ((byte)size);
+
+ if (size > 0) {
+ switch (param.TypeName) {
+ case "money" : {
+ Decimal val = (decimal) param.Value;
+ int[] arr = Decimal.GetBits (val);
+
+ if (val >= 0) {
+ Comm.Append (arr[1]);
+ Comm.Append (arr[0]);
+ } else {
+ Comm.Append (~arr[1]);
+ Comm.Append (~arr[0] + 1);
+ }
+ break;
+ }
+ case "smallmoney": {
+ Decimal val = (decimal) param.Value;
+ if (val < SMALLMONEY_MIN || val > SMALLMONEY_MAX)
+ throw new OverflowException (string.Format (
+ CultureInfo.InvariantCulture,
+ "Value '{0}' is not valid for SmallMoney."
+ + " Must be between {1:N4} and {2:N4}.",
+#if NET_2_0
+ val,
+#else
+ val.ToString (CultureInfo.CurrentCulture),
+#endif
+ SMALLMONEY_MIN, SMALLMONEY_MAX));
+
+ int[] arr = Decimal.GetBits (val);
+ int sign = (val>0 ? 1: -1);
+ Comm.Append (sign * arr[0]);
+ break;
+ }
+ case "datetime":
+ Comm.Append ((DateTime)param.Value, 8);
+ break;
+ case "smalldatetime":
+ Comm.Append ((DateTime)param.Value, 4);
+ break;
+ case "varchar" :
+ case "nvarchar" :
+ case "char" :
+ case "nchar" :
+ case "text" :
+ case "ntext" :
+ byte [] tmp = param.GetBytes ();
+ Comm.Append (tmp);
+ break;
+ case "uniqueidentifier" :
+ Comm.Append (((Guid)param.Value).ToByteArray());
+ break;
+ default :
+ Comm.Append (param.Value);
+ break;
+ }
+ }
+ return;
}
public override void Execute (string commandText, TdsMetaParameterCollection parameters, int timeout, bool wantResults)
{
Parameters = parameters;
string sql = commandText;
- if (wantResults || (Parameters != null && Parameters.Count > 0))
- sql = BuildExec (commandText);
- ExecuteQuery (sql, timeout, wantResults);
- }
-
- private bool IsBlobType (TdsColumnType columnType)
- {
- return (columnType == TdsColumnType.Text || columnType == TdsColumnType.Image || columnType == TdsColumnType.NText);
- }
- private bool IsLargeType (TdsColumnType columnType)
- {
- return (columnType == TdsColumnType.NChar || (byte) columnType > 128);
+ if (Parameters != null && Parameters.Count > 0) {
+ ExecRPC (TdsRpcProcId.ExecuteSql, commandText, parameters, timeout, wantResults);
+ } else {
+ if (wantResults)
+ sql = BuildExec (commandText);
+ ExecuteQuery (sql, timeout, wantResults);
+ }
}
private string FormatParameter (TdsMetaParameter parameter)
{
+ string parameterName = parameter.ParameterName;
+ if (parameterName [0] == '@') {
+ parameterName = parameterName.Substring (1);
+ }
if (parameter.Direction == TdsParameterDirection.Output)
- return String.Format ("{0}={0} output", parameter.ParameterName);
-
+ return String.Format ("@{0}=@{0} output", parameterName);
if (parameter.Value == null || parameter.Value == DBNull.Value)
- return parameter.ParameterName + "=NULL";
+ return String.Format ("@{0}=NULL", parameterName);
string value = null;
switch (parameter.TypeName) {
- case "smalldatetime":
+ case "smalldatetime":
case "datetime":
DateTime d = Convert.ToDateTime (parameter.Value);
- value = String.Format(System.Globalization.CultureInfo.InvariantCulture,
- "'{0:MMM dd yyyy hh:mm:ss tt}'", d );
- break;
+ value = String.Format (base.Locale,
+ "'{0:MMM dd yyyy hh:mm:ss.fff tt}'", d);
+ break;
case "bigint":
case "decimal":
case "float":
value = String.Format ("N'{0}'", parameter.Value.ToString ().Replace ("'", "''"));
break;
case "uniqueidentifier":
- value = String.Format ("'{0}'", ((Guid) parameter.Value).ToString (""));
+ value = String.Format ("'{0}'", ((Guid) parameter.Value).ToString (string.Empty));
break;
case "bit":
if (parameter.Value.GetType () == typeof (bool))
value = (((bool) parameter.Value) ? "0x1" : "0x0");
else
value = parameter.Value.ToString ();
-
break;
case "image":
case "binary":
if (byteArray.Length == 0)
value = "0x";
else
- value = String.Format ("0x{0}", BitConverter.ToString (byteArray).Replace ("-", "").ToLower ());
+ value = String.Format ("0x{0}", BitConverter.ToString (byteArray).Replace ("-", string.Empty).ToLower ());
break;
default:
value = String.Format ("'{0}'", parameter.Value.ToString ().Replace ("'", "''"));
break;
}
- return parameter.ParameterName + "=" + value;
+ return "@" + parameterName + "=" + value;
}
public override string Prepare (string commandText, TdsMetaParameterCollection parameters)
Parameters = parameters;
TdsMetaParameterCollection parms = new TdsMetaParameterCollection ();
- TdsMetaParameter parm = new TdsMetaParameter ("@P1", "int", null);
+ TdsMetaParameter parm = new TdsMetaParameter ("@Handle", "int", null);
parm.Direction = TdsParameterDirection.Output;
parms.Add (parm);
- parms.Add (new TdsMetaParameter ("@P2", "nvarchar", BuildPreparedParameters ()));
- parms.Add (new TdsMetaParameter ("@P3", "nvarchar", commandText));
+ parms.Add (new TdsMetaParameter ("@VarDecl", "nvarchar", BuildPreparedParameters ()));
+ parms.Add (new TdsMetaParameter ("@Query", "nvarchar", commandText));
ExecProc ("sp_prepare", parms, 0, true);
- SkipToEnd ();
- if (ColumnValues [0] == null || ColumnValues [0] == DBNull.Value)
- throw new TdsInternalException ();
- return ColumnValues [0].ToString ();
+ SkipToEnd ();
+ return OutputParameters[0].ToString () ;
+ //if (ColumnValues == null || ColumnValues [0] == null || ColumnValues [0] == DBNull.Value)
+ // throw new TdsInternalException ();
+ //return string.Empty;
+ //return ColumnValues [0].ToString ();
}
- protected override TdsDataColumnCollection ProcessColumnInfo ()
+ protected override void ProcessColumnInfo ()
{
- TdsDataColumnCollection result = new TdsDataColumnCollection ();
int numColumns = Comm.GetTdsShort ();
-
for (int i = 0; i < numColumns; i += 1) {
byte[] flagData = new byte[4];
for (int j = 0; j < 4; j += 1)
flagData[j] = Comm.GetByte ();
bool nullable = (flagData[2] & 0x01) > 0;
- bool caseSensitive = (flagData[2] & 0x02) > 0;
+ //bool caseSensitive = (flagData[2] & 0x02) > 0;
bool writable = (flagData[2] & 0x0c) > 0;
bool autoIncrement = (flagData[2] & 0x10) > 0;
bool isIdentity = (flagData[2] & 0x10) > 0;
- TdsColumnType columnType = (TdsColumnType) (Comm.GetByte () & 0xff);
- if ((byte) columnType == 0xef)
- columnType = TdsColumnType.NChar;
-
+ TdsColumnType columnType = (TdsColumnType) ((Comm.GetByte () & 0xff));
+
byte xColumnType = 0;
if (IsLargeType (columnType)) {
xColumnType = (byte) columnType;
if (IsBlobType (columnType)) {
columnSize = Comm.GetTdsInt ();
tableName = Comm.GetString (Comm.GetTdsShort ());
- }
-
- else if (IsFixedSizeColumn (columnType))
+ } else if (IsFixedSizeColumn (columnType)) {
columnSize = LookupBufferSize (columnType);
- else if (IsLargeType ((TdsColumnType) xColumnType))
+ } else if (IsLargeType ((TdsColumnType) xColumnType)) {
columnSize = Comm.GetTdsShort ();
- else
+ } else {
columnSize = Comm.GetByte () & 0xff;
+ }
+
+ if (IsWideType ((TdsColumnType) columnType))
+ columnSize /= 2;
byte precision = 0;
byte scale = 0;
- switch (columnType) {
- case TdsColumnType.NText:
- case TdsColumnType.NChar:
- case TdsColumnType.NVarChar:
- columnSize /= 2;
- break;
- case TdsColumnType.Decimal:
- case TdsColumnType.Numeric:
+ if (columnType == TdsColumnType.Decimal || columnType == TdsColumnType.Numeric) {
precision = Comm.GetByte ();
scale = Comm.GetByte ();
- break;
+ } else {
+ precision = GetPrecision (columnType, columnSize);
+ scale = GetScale (columnType, columnSize);
}
string columnName = Comm.GetString (Comm.GetByte ());
- int index = result.Add (new TdsDataColumn ());
- result[index]["AllowDBNull"] = nullable;
- result[index]["ColumnName"] = columnName;
- result[index]["ColumnSize"] = columnSize;
- result[index]["ColumnType"] = columnType;
- result[index]["IsAutoIncrement"] = autoIncrement;
- result[index]["IsIdentity"] = isIdentity;
- result[index]["IsReadOnly"] = !writable;
- result[index]["NumericPrecision"] = precision;
- result[index]["NumericScale"] = scale;
- result[index]["BaseTableName"] = tableName;
+ TdsDataColumn col = new TdsDataColumn ();
+ Columns.Add (col);
+#if NET_2_0
+ col.ColumnType = columnType;
+ col.ColumnName = columnName;
+ col.IsAutoIncrement = autoIncrement;
+ col.IsIdentity = isIdentity;
+ col.ColumnSize = columnSize;
+ col.NumericPrecision = precision;
+ col.NumericScale = scale;
+ col.IsReadOnly = !writable;
+ col.AllowDBNull = nullable;
+ col.BaseTableName = tableName;
+ col.DataTypeName = Enum.GetName (typeof (TdsColumnType), xColumnType);
+#else
+ col ["ColumnType"] = columnType;
+ col ["ColumnName"] = columnName;
+ col ["IsAutoIncrement"] = autoIncrement;
+ col ["IsIdentity"] = isIdentity;
+ col ["ColumnSize"] = columnSize;
+ col ["NumericPrecision"] = precision;
+ col ["NumericScale"] = scale;
+ col ["IsReadOnly"] = !writable;
+ col ["AllowDBNull"] = nullable;
+ col ["BaseTableName"] = tableName;
+ col ["DataTypeName"] = Enum.GetName (typeof (TdsColumnType), xColumnType);
+#endif
}
-
- return result;
}
public override void Unprepare (string statementId)
return true;
}
+ protected override void ProcessReturnStatus ()
+ {
+ int result = Comm.GetTdsInt ();
+ if (Parameters != null) {
+ foreach (TdsMetaParameter param in Parameters) {
+ if (param.Direction == TdsParameterDirection.ReturnValue) {
+ param.Value = result;
+ break;
+ }
+ }
+ }
+ }
+
+ byte GetScale (TdsColumnType type, int columnSize)
+ {
+ switch (type) {
+ case TdsColumnType.DateTime:
+ return 0x03;
+ case TdsColumnType.DateTime4:
+ return 0x00;
+ case TdsColumnType.DateTimeN:
+ switch (columnSize) {
+ case 4:
+ return 0x00;
+ case 8:
+ return 0x03;
+ }
+ break;
+ default:
+ return 0xff;
+ }
+
+ throw new NotSupportedException (string.Format (
+ CultureInfo.InvariantCulture,
+ "Fixed scale not defined for column " +
+ "type '{0}' with size {1}.", type, columnSize));
+ }
+
+ byte GetPrecision (TdsColumnType type, int columnSize)
+ {
+ switch (type) {
+ case TdsColumnType.Binary:
+ return 0xff;
+ case TdsColumnType.Bit:
+ return 0xff;
+ case TdsColumnType.Char:
+ return 0xff;
+ case TdsColumnType.DateTime:
+ return 0x17;
+ case TdsColumnType.DateTime4:
+ return 0x10;
+ case TdsColumnType.DateTimeN:
+ switch (columnSize) {
+ case 4:
+ return 0x10;
+ case 8:
+ return 0x17;
+ }
+ break;
+ case TdsColumnType.Real:
+ return 0x07;
+ case TdsColumnType.Float8:
+ return 0x0f;
+ case TdsColumnType.FloatN:
+ switch (columnSize) {
+ case 4:
+ return 0x07;
+ case 8:
+ return 0x0f;
+ }
+ break;
+ case TdsColumnType.Image:
+ return 0xff;
+ case TdsColumnType.Int1:
+ return 0x03;
+ case TdsColumnType.Int2:
+ return 0x05;
+ case TdsColumnType.Int4:
+ return 0x0a;
+ case TdsColumnType.IntN:
+ switch (columnSize) {
+ case 1:
+ return 0x03;
+ case 2:
+ return 0x05;
+ case 4:
+ return 0x0a;
+ }
+ break;
+ case TdsColumnType.Void:
+ return 0x01;
+ case TdsColumnType.Text:
+ return 0xff;
+ case TdsColumnType.UniqueIdentifier:
+ return 0xff;
+ case TdsColumnType.VarBinary:
+ return 0xff;
+ case TdsColumnType.VarChar:
+ return 0xff;
+ case TdsColumnType.Money:
+ return 19;
+ case TdsColumnType.NText:
+ return 0xff;
+ case TdsColumnType.NVarChar:
+ return 0xff;
+ case TdsColumnType.BitN:
+ return 0xff;
+ case TdsColumnType.MoneyN:
+ switch (columnSize) {
+ case 4:
+ return 0x0a;
+ case 8:
+ return 0x13;
+ }
+ break;
+ case TdsColumnType.Money4:
+ return 0x0a;
+ case TdsColumnType.NChar:
+ return 0xff;
+ case TdsColumnType.BigBinary:
+ return 0xff;
+ case TdsColumnType.BigVarBinary:
+ return 0xff;
+ case TdsColumnType.BigVarChar:
+ return 0xff;
+ case TdsColumnType.BigNVarChar:
+ return 0xff;
+ case TdsColumnType.BigChar:
+ return 0xff;
+ case TdsColumnType.SmallMoney:
+ return 0x0a;
+ case TdsColumnType.Variant:
+ return 0xff;
+ case TdsColumnType.BigInt:
+ return 0xff;
+ }
+
+ throw new NotSupportedException (string.Format (
+ CultureInfo.InvariantCulture,
+ "Fixed precision not defined for column " +
+ "type '{0}' with size {1}.", type, columnSize));
+ }
+
#endregion // Methods
#if NET_2_0
- #region Asynchronous Methods
- public override IAsyncResult BeginExecuteNonQuery (string cmdText,
+ #region Asynchronous Methods
+
+ public override IAsyncResult BeginExecuteNonQuery (string cmdText,
TdsMetaParameterCollection parameters,
AsyncCallback callback,
object state)
- {
- Parameters = parameters;
- string sql = cmdText;
+ {
+ Parameters = parameters;
+ string sql = cmdText;
if (Parameters != null && Parameters.Count > 0)
sql = BuildExec (cmdText);
- IAsyncResult ar = BeginExecuteQueryInternal (sql, false, callback, state);
- return ar;
- }
+ IAsyncResult ar = BeginExecuteQueryInternal (sql, false, callback, state);
+ return ar;
+ }
- public override void EndExecuteNonQuery (IAsyncResult ar)
- {
- EndExecuteQueryInternal (ar);
- }
+ public override void EndExecuteNonQuery (IAsyncResult ar)
+ {
+ EndExecuteQueryInternal (ar);
+ }
- public override IAsyncResult BeginExecuteQuery (string cmdText,
+ public override IAsyncResult BeginExecuteQuery (string cmdText,
TdsMetaParameterCollection parameters,
AsyncCallback callback,
object state)
- {
- Parameters = parameters;
- string sql = cmdText;
+ {
+ Parameters = parameters;
+ string sql = cmdText;
if (Parameters != null && Parameters.Count > 0)
sql = BuildExec (cmdText);
- IAsyncResult ar = BeginExecuteQueryInternal (sql, true, callback, state);
- return ar;
- }
-
- public override void EndExecuteQuery (IAsyncResult ar)
- {
- EndExecuteQueryInternal (ar);
- }
+ IAsyncResult ar = BeginExecuteQueryInternal (sql, true, callback, state);
+ return ar;
+ }
+ public override void EndExecuteQuery (IAsyncResult ar)
+ {
+ EndExecuteQueryInternal (ar);
+ }
- public override IAsyncResult BeginExecuteProcedure (string prolog,
+ public override IAsyncResult BeginExecuteProcedure (string prolog,
string epilog,
string cmdText,
bool IsNonQuery,
TdsMetaParameterCollection parameters,
AsyncCallback callback,
object state)
- {
-
-
- Parameters = parameters;
+ {
+ Parameters = parameters;
string pcall = BuildProcedureCall (cmdText);
- string sql = String.Format ("{0};{1};{2};", prolog, pcall, epilog);
-
- IAsyncResult ar = BeginExecuteQueryInternal (sql, !IsNonQuery, callback, state);
- return ar;
- }
-
- public override void EndExecuteProcedure (IAsyncResult ar)
- {
- EndExecuteQueryInternal (ar);
- }
+ string sql = String.Format ("{0};{1};{2};", prolog, pcall, epilog);
+ IAsyncResult ar = BeginExecuteQueryInternal (sql, !IsNonQuery, callback, state);
+ return ar;
+ }
+ public override void EndExecuteProcedure (IAsyncResult ar)
+ {
+ EndExecuteQueryInternal (ar);
+ }
- #endregion // Asynchronous Methods
+ #endregion // Asynchronous Methods
#endif // NET_2_0
-
}
}