// Mono.Data.TdsClient.TdsCommand.cs
//
// Author:
+// Rodrigo Moya (rodrigo@ximian.com)
+// Daniel Morgan (danmorg@sc.rr.com)
// Tim Coleman (tim@timcoleman.com)
//
-// Copyright (C) 2002 Tim Coleman
+// (C) Ximian, Inc 2002 http://www.ximian.com/
+// (C) Daniel Morgan, 2002
+// Copyright (C) Tim Coleman, 2002
//
+//
+// 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 Mono.Data.Tds;
using Mono.Data.Tds.Protocol;
using System;
+using System.Collections;
+using System.Collections.Specialized;
using System.ComponentModel;
using System.Data;
+using System.Data.Common;
+using System.Runtime.InteropServices;
+using System.Text;
namespace Mono.Data.TdsClient {
- public class TdsCommand : Component, ICloneable, IDbCommand
+ public sealed class TdsCommand : Component, IDbCommand, ICloneable
{
#region Fields
- string commandText;
+ bool disposed = false;
int commandTimeout;
+ bool designTimeVisible;
+ string commandText;
CommandType commandType;
TdsConnection connection;
- TdsParameterCollection parameters;
TdsTransaction transaction;
+ UpdateRowSource updatedRowSource;
+ CommandBehavior behavior = CommandBehavior.Default;
+ TdsParameterCollection parameters;
#endregion // Fields
#region Constructors
- public TdsCommand ()
+ public TdsCommand()
: this (String.Empty, null, null)
{
}
- public TdsCommand (string commandText)
+ public TdsCommand (string commandText)
: this (commandText, null, null)
{
+ commandText = commandText;
}
- public TdsCommand (string commandText, TdsConnection connection)
+ public TdsCommand (string commandText, TdsConnection connection)
: this (commandText, connection, null)
{
+ Connection = connection;
}
- public TdsCommand (string commandText, TdsConnection connection, TdsTransaction transaction)
+ public TdsCommand (string commandText, TdsConnection connection, TdsTransaction transaction)
{
this.commandText = commandText;
+ this.connection = connection;
this.transaction = transaction;
this.commandType = CommandType.Text;
- this.connection = connection;
+ this.updatedRowSource = UpdateRowSource.Both;
+
+ this.designTimeVisible = false;
+ this.commandTimeout = 30;
+ parameters = new TdsParameterCollection (this);
}
#endregion // Constructors
#region Properties
+ internal CommandBehavior CommandBehavior {
+ get { return behavior; }
+ }
+
public string CommandText {
get { return commandText; }
set { commandText = value; }
}
public int CommandTimeout {
- get { return commandTimeout; }
- set { commandTimeout = value; }
+ get { return commandTimeout; }
+ set {
+ if (commandTimeout < 0)
+ throw new ArgumentException ("The property value assigned is less than 0.");
+ commandTimeout = value;
+ }
}
- public CommandType CommandType {
+ public CommandType CommandType {
get { return commandType; }
- set { commandType = value; }
+ set {
+ if (value == CommandType.TableDirect)
+ throw new ArgumentException ("CommandType.TableDirect is not supported by the Mono TdsClient Data Provider.");
+ commandType = value;
+ }
}
- public TdsConnection Connection {
+ public TdsConnection Connection {
get { return connection; }
set {
if (transaction != null && connection.Transaction != null && connection.Transaction.IsOpen)
throw new InvalidOperationException ("The Connection property was changed while a transaction was in progress.");
transaction = null;
- connection = value;
+ connection = value;
}
}
+ public bool DesignTimeVisible {
+ get { return designTimeVisible; }
+ set { designTimeVisible = value; }
+ }
+
+ public TdsParameterCollection Parameters {
+ get { return parameters; }
+ }
+
+ internal ITds Tds {
+ get { return Connection.Tds; }
+ }
+
IDbConnection IDbCommand.Connection {
get { return Connection; }
set {
- if (!(value is TdsConnection))
- throw new ArgumentException ();
- Connection = (TdsConnection) value;
+ if (!(value is TdsConnection))
+ throw new InvalidCastException ("The value was not a valid TdsConnection.");
+ Connection = (TdsConnection) value;
}
}
- IDataParameterCollection IDbCommand.Parameters {
+ IDataParameterCollection IDbCommand.Parameters {
get { return Parameters; }
}
IDbTransaction IDbCommand.Transaction {
get { return Transaction; }
set {
- if (!(value is TdsTransaction))
+ if (!(value is TdsTransaction))
throw new ArgumentException ();
Transaction = (TdsTransaction) value;
}
}
- public TdsParameterCollection Parameters {
- get { return parameters; }
- }
-
- internal ITds Tds {
- get { return connection.Tds; }
- }
-
public TdsTransaction Transaction {
get { return transaction; }
set { transaction = value; }
+ }
+
+ public UpdateRowSource UpdatedRowSource {
+ get { return updatedRowSource; }
+ set { updatedRowSource = value; }
}
- [MonoTODO]
- public UpdateRowSource UpdatedRowSource {
- get { throw new NotImplementedException (); }
- set { throw new NotImplementedException (); }
+ #endregion // Fields
+
+ #region Methods
+
+ public void Cancel ()
+ {
+ if (Connection == null || Connection.Tds == null)
+ return;
+ Connection.Tds.Cancel ();
}
- #endregion // Properties
+ internal void CloseDataReader (bool moreResults)
+ {
+ GetOutputParameters ();
+ Connection.DataReader = null;
- #region Methods
+ if ((behavior & CommandBehavior.CloseConnection) != 0)
+ Connection.Close ();
+ }
- [MonoTODO]
- public void Cancel ()
+ public TdsParameter CreateParameter ()
{
- throw new NotImplementedException ();
+ return new TdsParameter ();
}
- [MonoTODO]
- TdsParameter CreateParameter ()
+ internal void DeriveParameters ()
{
- throw new NotImplementedException ();
+ if (commandType != CommandType.StoredProcedure)
+ throw new InvalidOperationException (String.Format ("TdsCommand DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
+ ValidateCommand ("DeriveParameters");
+
+ TdsParameterCollection localParameters = new TdsParameterCollection (this);
+ localParameters.Add ("@P1", TdsType.NVarChar, commandText.Length).Value = commandText;
+
+ string sql = "sp_procedure_params_rowset";
+
+ Connection.Tds.ExecProc (sql, localParameters.MetaParameters, 0, true);
+
+ TdsDataReader reader = new TdsDataReader (this);
+ parameters.Clear ();
+ object[] dbValues = new object[reader.FieldCount];
+
+ while (reader.Read ()) {
+ reader.GetValues (dbValues);
+ parameters.Add (new TdsParameter (dbValues));
+ }
+ reader.Close ();
+ }
+
+ private void Execute (CommandBehavior behavior, bool wantResults)
+ {
+ TdsMetaParameterCollection parms = Parameters.MetaParameters;
+ bool schemaOnly = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
+ bool keyInfo = ((CommandBehavior & CommandBehavior.SchemaOnly) > 0);
+
+ StringBuilder sql1 = new StringBuilder ();
+ StringBuilder sql2 = new StringBuilder ();
+
+ if (schemaOnly || keyInfo)
+ sql1.Append ("SET FMTONLY OFF;");
+ if (keyInfo) {
+ sql1.Append ("SET NO_BROWSETABLE ON;");
+ sql2.Append ("SET NO_BROWSETABLE OFF;");
+ }
+ if (schemaOnly) {
+ sql1.Append ("SET FMTONLY ON;");
+ sql2.Append ("SET FMTONLY OFF;");
+ }
+
+ switch (CommandType) {
+ case CommandType.StoredProcedure:
+ if (keyInfo || schemaOnly)
+ Connection.Tds.Execute (sql1.ToString ());
+ Connection.Tds.ExecProc (CommandText, parms, CommandTimeout, wantResults);
+ if (keyInfo || schemaOnly)
+ Connection.Tds.Execute (sql2.ToString ());
+ break;
+ case CommandType.Text:
+ string sql = String.Format ("{0}{1}{2}", sql1.ToString (), CommandText, sql2.ToString ());
+ Connection.Tds.Execute (sql, parms, CommandTimeout, wantResults);
+ break;
+ }
}
public int ExecuteNonQuery ()
{
ValidateCommand ("ExecuteNonQuery");
- return connection.Tds.ExecuteNonQuery (FormatQuery (commandText, commandType));
+ int result = 0;
+
+ try {
+ Execute (CommandBehavior.Default, false);
+ }
+ catch (TdsTimeoutException e) {
+ throw TdsException.FromTdsInternalException ((TdsInternalException) e);
+ }
+
+ GetOutputParameters ();
+ return result;
}
public TdsDataReader ExecuteReader ()
public TdsDataReader ExecuteReader (CommandBehavior behavior)
{
ValidateCommand ("ExecuteReader");
- connection.DataReader = new TdsDataReader (this);
- return connection.DataReader;
+ try {
+ Execute (behavior, true);
+ }
+ catch (TdsTimeoutException e) {
+ throw TdsException.FromTdsInternalException ((TdsInternalException) e);
+ }
+ Connection.DataReader = new TdsDataReader (this);
+ return Connection.DataReader;
}
- [MonoTODO]
public object ExecuteScalar ()
{
- throw new NotImplementedException ();
+ ValidateCommand ("ExecuteScalar");
+ try {
+ Execute (CommandBehavior.Default, true);
+ }
+ catch (TdsTimeoutException e) {
+ throw TdsException.FromTdsInternalException ((TdsInternalException) e);
+ }
+
+ if (!Connection.Tds.NextResult () || !Connection.Tds.NextRow ())
+ return null;
+
+ object result = Connection.Tds.ColumnValues [0];
+ CloseDataReader (true);
+ return result;
}
- private static string FormatQuery (string commandText, CommandType commandType)
+ private void GetOutputParameters ()
{
- switch (commandType) {
- case CommandType.Text :
- return commandText;
- case CommandType.TableDirect :
- return String.Format ("select * from {0}", commandText);
- case CommandType.StoredProcedure :
- return String.Format ("exec {0}", commandText);
+ Connection.Tds.SkipToEnd ();
+
+ IList list = Connection.Tds.ColumnValues;
+
+ if (list != null && list.Count > 0) {
+ int index = 0;
+ foreach (TdsParameter parameter in parameters) {
+ if (parameter.Direction != ParameterDirection.Input) {
+ parameter.Value = list [index];
+ index += 1;
+ }
+ if (index >= list.Count)
+ break;
+ }
}
- throw new InvalidOperationException ("Invalid command type");
}
- [MonoTODO]
- object ICloneable.Clone()
- {
- throw new NotImplementedException ();
- }
+ object ICloneable.Clone ()
+ {
+ return new TdsCommand (commandText, Connection);
+ }
IDbDataParameter IDbCommand.CreateParameter ()
{
return ExecuteReader (behavior);
}
- [MonoTODO]
public void Prepare ()
{
- throw new NotImplementedException ();
+ throw new NotSupportedException ("TdsClient does not support PREPARE.");
+ }
+
+ public void ResetCommandTimeout ()
+ {
+ commandTimeout = 30;
}
private void ValidateCommand (string method)
{
- if (connection == null)
+ if (Connection == null)
throw new InvalidOperationException (String.Format ("{0} requires a Connection object to continue.", method));
- if (connection.Transaction != null && transaction != connection.Transaction)
+ if (Connection.Transaction != null && transaction != Connection.Transaction)
throw new InvalidOperationException ("The Connection object does not have the same transaction as the command object.");
- if (connection.State != ConnectionState.Open)
+ if (Connection.State != ConnectionState.Open)
throw new InvalidOperationException (String.Format ("ExecuteNonQuery requires an open Connection object to continue. This connection is closed.", method));
if (commandText == String.Empty || commandText == null)
throw new InvalidOperationException ("The command text for this Command has not been set.");
- if (connection.DataReader != null)
+ if (Connection.DataReader != null)
throw new InvalidOperationException ("There is already an open DataReader associated with this Connection which must be closed first.");
}
- #endregion // Methods
+ #endregion // Methods
}
}