Jo Shields 3c1f479b9d Imported Upstream version 4.0.0~alpha1
Former-commit-id: 806294f5ded97629b74c85c09952f2a74fe182d9
2015-04-07 09:35:12 +01:00

688 lines
17 KiB
C#

//
// OracleCommand.cs
//
// Part of the Mono class libraries at
// mcs/class/System.Data.OracleClient/System.Data.OracleClient
//
// Assembly: System.Data.OracleClient.dll
// Namespace: System.Data.OracleClient
//
// Authors:
// Daniel Morgan <danielmorgan@verizon.net>
// Tim Coleman <tim@timcoleman.com>
// Marek Safar <marek.safar@gmail.com>
//
// Copyright (C) Daniel Morgan, 2002, 2004-2005
// Copyright (C) Tim Coleman , 2003
//
// Licensed under the MIT/X11 License.
//
using System;
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.OracleClient.Oci;
using System.Drawing.Design;
using System.Text;
using System.Threading;
namespace System.Data.OracleClient
{
[DefaultEvent ("RecordsAffected")]
[Designer ("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + Consts.AssemblyMicrosoft_VSDesigner)]
[ToolboxItem (true)]
public sealed class OracleCommand :
DbCommand, ICloneable
{
#region Fields
CommandBehavior behavior;
string commandText;
CommandType commandType;
OracleConnection connection;
bool designTimeVisible;
OracleParameterCollection parameters;
OracleTransaction transaction;
UpdateRowSource updatedRowSource;
OciStatementHandle preparedStatement;
int moreResults;
#endregion // Fields
#region Constructors
public OracleCommand ()
: this (String.Empty, null, null)
{
}
public OracleCommand (string commandText)
: this (commandText, null, null)
{
}
public OracleCommand (string commandText, OracleConnection connection)
: this (commandText, connection, null)
{
}
public OracleCommand (string commandText, OracleConnection connection, OracleTransaction tx)
{
moreResults = -1;
preparedStatement = null;
CommandText = commandText;
Connection = connection;
Transaction = tx;
CommandType = CommandType.Text;
UpdatedRowSource = UpdateRowSource.Both;
DesignTimeVisible = true;
parameters = new OracleParameterCollection ();
}
#endregion // Constructors
#region Properties
[DefaultValue ("")]
[RefreshProperties (RefreshProperties.All)]
[Editor ("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
public
override
string CommandText {
get {
if (commandText == null)
return string.Empty;
return commandText;
}
set { commandText = value; }
}
[RefreshProperties (RefreshProperties.All)]
[DefaultValue (CommandType.Text)]
public
override
CommandType CommandType {
get { return commandType; }
set {
if (value == CommandType.TableDirect)
throw new ArgumentException ("OracleClient provider does not support TableDirect CommandType.");
commandType = value;
}
}
[DefaultValue (null)]
[Editor ("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + Consts.AssemblyMicrosoft_VSDesigner, typeof(UITypeEditor))]
public
new
OracleConnection Connection {
get { return connection; }
set { connection = value; }
}
[Browsable (false)]
[EditorBrowsable (EditorBrowsableState.Never)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public override int CommandTimeout {
get { return 0; }
set { }
}
[MonoTODO]
protected override DbConnection DbConnection {
get { return Connection; }
set { Connection = (OracleConnection) value; }
}
[MonoTODO]
protected override DbParameterCollection DbParameterCollection {
get { return Parameters; }
}
[MonoTODO]
protected override DbTransaction DbTransaction {
get { return Transaction; }
set { Transaction = (OracleTransaction) value; }
}
[DefaultValue (true)]
[Browsable (false)]
[DesignOnly (true)]
[EditorBrowsable (EditorBrowsableState.Never)]
public
override
bool DesignTimeVisible {
get { return designTimeVisible; }
set { designTimeVisible = value; }
}
internal OciEnvironmentHandle Environment {
get { return Connection.Environment; }
}
internal OciErrorHandle ErrorHandle {
get { return Connection.ErrorHandle; }
}
[DesignerSerializationVisibility(DesignerSerializationVisibility.Content)]
public
new
OracleParameterCollection Parameters {
get { return parameters; }
}
[Browsable (false)]
[DesignerSerializationVisibility (DesignerSerializationVisibility.Hidden)]
public
new
OracleTransaction Transaction {
get { return transaction; }
set { transaction = value; }
}
[DefaultValue (UpdateRowSource.Both)]
public
override
UpdateRowSource UpdatedRowSource {
get { return updatedRowSource; }
set { updatedRowSource = value; }
}
#endregion
#region Methods
private void AssertCommandTextIsSet ()
{
if (CommandText.Length == 0)
throw new InvalidOperationException ("The command text for this Command has not been set.");
}
private void AssertConnectionIsOpen ()
{
if (Connection == null || Connection.State == ConnectionState.Closed)
throw new InvalidOperationException ("An open Connection object is required to continue.");
}
private void AssertTransactionMatch ()
{
if (Connection.Transaction != null && Transaction != Connection.Transaction)
throw new InvalidOperationException ("Execute requires the Command object to have a Transaction object when the Connection object assigned to the command is in a pending local transaction. The Transaction property of the Command has not been initialized.");
}
private void BindParameters (OciStatementHandle statement)
{
for (int p = 0; p < Parameters.Count; p++)
Parameters[p].Bind (statement, Connection, (uint) p);
}
[MonoTODO]
public
override
void Cancel ()
{
throw new NotImplementedException ();
}
[MonoTODO]
public object Clone ()
{
// create a new OracleCommand object with the same properties
OracleCommand cmd = new OracleCommand ();
cmd.CommandText = this.CommandText;
cmd.CommandType = this.CommandType;
// FIXME: not sure if I should set the same object here
// or get a clone of these too
cmd.Connection = this.Connection;
cmd.Transaction = this.Transaction;
foreach (OracleParameter parm in this.Parameters) {
OracleParameter newParm = cmd.CreateParameter ();
newParm.DbType = parm.DbType;
newParm.Direction = parm.Direction;
newParm.IsNullable = parm.IsNullable;
newParm.Offset = parm.Offset;
newParm.OracleType = parm.OracleType;
newParm.ParameterName = parm.ParameterName;
//newParm.Precision = parm.Precision;
//newParm.Scale = parm.Scale;
newParm.SourceColumn = parm.SourceColumn;
newParm.SourceVersion = parm.SourceVersion;
newParm.Value = parm.Value;
cmd.Parameters.Add (newParm);
}
//cmd.Container = this.Container;
cmd.DesignTimeVisible = this.DesignTimeVisible;
//cmd.DesignMode = this.DesignMode;
cmd.Site = this.Site;
//cmd.UpdateRowSource = this.UpdateRowSource;
return cmd;
}
protected override DbParameter CreateDbParameter ()
{
return CreateParameter ();
}
protected override DbDataReader ExecuteDbDataReader (CommandBehavior behavior)
{
return ExecuteReader (behavior);
}
internal void UpdateParameterValues ()
{
moreResults = -1;
if (Parameters.Count > 0) {
bool foundCursor = false;
for (int p = 0; p < Parameters.Count; p++) {
OracleParameter parm = Parameters [p];
if (parm.OracleType.Equals (OracleType.Cursor)) {
if (!foundCursor && parm.Direction != ParameterDirection.Input) {
// if there are multiple REF CURSORs,
// you only can get the first cursor for now
// because user of OracleDataReader
// will do a NextResult to get the next
// REF CURSOR (if it exists)
foundCursor = true;
parm.Update (this);
if (p + 1 == Parameters.Count)
moreResults = -1;
else
moreResults = p;
}
} else
parm.Update (this);
}
}
}
internal void CloseDataReader ()
{
Connection.DataReader = null;
if ((behavior & CommandBehavior.CloseConnection) != 0)
Connection.Close ();
}
public
new
OracleParameter CreateParameter ()
{
return new OracleParameter ();
}
internal void DeriveParameters ()
{
if (commandType != CommandType.StoredProcedure)
throw new InvalidOperationException (String.Format ("OracleCommandBuilder DeriveParameters only supports CommandType.StoredProcedure, not CommandType.{0}", commandType));
//OracleParameterCollection localParameters = new OracleParameterCollection (this);
throw new NotImplementedException ();
}
private int ExecuteNonQueryInternal (OciStatementHandle statement, bool useAutoCommit)
{
moreResults = -1;
if (preparedStatement == null)
PrepareStatement (statement);
bool isNonQuery = IsNonQuery (statement);
BindParameters (statement);
if (isNonQuery == true)
statement.ExecuteNonQuery (useAutoCommit);
else
statement.ExecuteQuery (false);
UpdateParameterValues ();
int rowsAffected = statement.GetAttributeInt32 (OciAttributeType.RowCount, ErrorHandle);
return rowsAffected;
}
public
override
int ExecuteNonQuery ()
{
moreResults = -1;
AssertConnectionIsOpen ();
AssertTransactionMatch ();
AssertCommandTextIsSet ();
bool useAutoCommit = false;
if (Transaction != null)
Transaction.AttachToServiceContext ();
else
useAutoCommit = true;
OciStatementHandle statement = GetStatementHandle ();
try {
return ExecuteNonQueryInternal (statement, useAutoCommit);
} finally {
SafeDisposeHandle (statement);
}
}
public int ExecuteOracleNonQuery (out OracleString rowid)
{
moreResults = -1;
AssertConnectionIsOpen ();
AssertTransactionMatch ();
AssertCommandTextIsSet ();
bool useAutoCommit = false;
if (Transaction != null)
Transaction.AttachToServiceContext ();
else
useAutoCommit = true;
OciStatementHandle statement = GetStatementHandle ();
try {
int retval = ExecuteNonQueryInternal (statement, useAutoCommit);
OciRowIdDescriptor rowIdDescriptor = statement.GetAttributeRowIdDescriptor (ErrorHandle, Environment);
string srowid = rowIdDescriptor.GetRowIdToString (ErrorHandle);
rowid = new OracleString (srowid);
rowIdDescriptor = null;
return retval;
} finally {
SafeDisposeHandle (statement);
}
}
public object ExecuteOracleScalar ()
{
moreResults = -1;
object output = DBNull.Value;
AssertConnectionIsOpen ();
AssertTransactionMatch ();
AssertCommandTextIsSet ();
if (Transaction != null)
Transaction.AttachToServiceContext ();
OciStatementHandle statement = GetStatementHandle ();
try {
if (preparedStatement == null)
PrepareStatement (statement);
bool isNonQuery = IsNonQuery (statement);
BindParameters (statement);
if (isNonQuery == true)
ExecuteNonQueryInternal (statement, false);
else {
statement.ExecuteQuery (false);
if (statement.Fetch ()) {
OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
if (!defineHandle.IsNull)
output = defineHandle.GetOracleValue (Connection.SessionFormatProvider, Connection);
switch (defineHandle.DataType) {
case OciDataType.Blob:
case OciDataType.Clob:
((OracleLob) output).connection = Connection;
break;
}
}
UpdateParameterValues ();
}
return output;
} finally {
SafeDisposeHandle (statement);
}
}
private bool IsNonQuery (OciStatementHandle statementHandle)
{
// assumes Prepare() has been called prior to calling this function
OciStatementType statementType = statementHandle.GetStatementType ();
if (statementType.Equals (OciStatementType.Select))
return false;
return true;
}
public
new
OracleDataReader ExecuteReader ()
{
return ExecuteReader (CommandBehavior.Default);
}
public
new
OracleDataReader ExecuteReader (CommandBehavior behavior)
{
AssertConnectionIsOpen ();
AssertTransactionMatch ();
AssertCommandTextIsSet ();
moreResults = -1;
bool hasRows = false;
this.behavior = behavior;
if (Transaction != null)
Transaction.AttachToServiceContext ();
OciStatementHandle statement = GetStatementHandle ();
OracleDataReader rd = null;
try {
if (preparedStatement == null)
PrepareStatement (statement);
else
preparedStatement = null; // OracleDataReader releases the statement handle
bool isNonQuery = IsNonQuery (statement);
BindParameters (statement);
if (isNonQuery)
ExecuteNonQueryInternal (statement, false);
else {
if ((behavior & CommandBehavior.SchemaOnly) != 0)
statement.ExecuteQuery (true);
else
hasRows = statement.ExecuteQuery (false);
UpdateParameterValues ();
}
if (Parameters.Count > 0) {
for (int p = 0; p < Parameters.Count; p++) {
OracleParameter parm = Parameters [p];
if (parm.OracleType.Equals (OracleType.Cursor)) {
if (parm.Direction != ParameterDirection.Input) {
rd = (OracleDataReader) parm.Value;
break;
}
}
}
}
if (rd == null)
rd = new OracleDataReader (this, statement, hasRows, behavior);
} finally {
if (statement != null && rd == null)
statement.Dispose();
}
return rd;
}
public
override
object ExecuteScalar ()
{
moreResults = -1;
object output = null;//if we find nothing we return this
AssertConnectionIsOpen ();
AssertTransactionMatch ();
AssertCommandTextIsSet ();
if (Transaction != null)
Transaction.AttachToServiceContext ();
OciStatementHandle statement = GetStatementHandle ();
try {
if (preparedStatement == null)
PrepareStatement (statement);
bool isNonQuery = IsNonQuery (statement);
BindParameters (statement);
if (isNonQuery == true)
ExecuteNonQueryInternal (statement, false);
else {
statement.ExecuteQuery (false);
if (statement.Fetch ()) {
OciDefineHandle defineHandle = (OciDefineHandle) statement.Values [0];
if (!defineHandle.IsNull)
{
switch (defineHandle.DataType) {
case OciDataType.Blob:
case OciDataType.Clob:
OracleLob lob = (OracleLob) defineHandle.GetValue (
Connection.SessionFormatProvider, Connection);
lob.connection = Connection;
output = lob.Value;
lob.Close ();
break;
default:
output = defineHandle.GetValue (
Connection.SessionFormatProvider, Connection);
break;
}
}
}
UpdateParameterValues ();
}
} finally {
SafeDisposeHandle (statement);
}
return output;
}
internal OciStatementHandle GetNextResult ()
{
if (moreResults == -1)
return null;
if (Parameters.Count > 0) {
int p = moreResults + 1;
if (p >= Parameters.Count) {
moreResults = -1;
return null;
}
for (; p < Parameters.Count; p++) {
OracleParameter parm = Parameters [p];
if (parm.OracleType.Equals (OracleType.Cursor)) {
if (parm.Direction != ParameterDirection.Input) {
if (p + 1 == Parameters.Count)
moreResults = -1;
else
moreResults = p;
return parm.GetOutRefCursor (this);
}
}
}
}
moreResults = -1;
return null;
}
private OciStatementHandle GetStatementHandle ()
{
AssertConnectionIsOpen ();
if (preparedStatement != null)
return preparedStatement;
OciStatementHandle h = (OciStatementHandle) Connection.Environment.Allocate (OciHandleType.Statement);
h.ErrorHandle = Connection.ErrorHandle;
h.Service = Connection.ServiceContext;
h.Command = this;
return h;
}
private void SafeDisposeHandle (OciStatementHandle h)
{
if (h != null && h != preparedStatement)
h.Dispose();
}
void PrepareStatement (OciStatementHandle statement)
{
if (commandType == CommandType.StoredProcedure) {
StringBuilder sb = new StringBuilder ();
if (Parameters.Count > 0)
foreach (OracleParameter parm in Parameters) {
if (sb.Length > 0)
sb.Append (",");
sb.Append (parm.ParameterName + "=>:" + parm.ParameterName);
}
string sql = "begin " + commandText + "(" + sb.ToString() + "); end;";
statement.Prepare (sql);
} else // Text
statement.Prepare (commandText);
}
public
override
void Prepare ()
{
AssertConnectionIsOpen ();
OciStatementHandle statement = GetStatementHandle ();
PrepareStatement (statement);
preparedStatement = statement;
}
protected override void Dispose (bool disposing)
{
if (preparedStatement != null)
OciCalls.OCIHandleFree(preparedStatement,
OciHandleType.Statement);
if (disposing)
if (Parameters.Count > 0)
foreach (OracleParameter parm in Parameters)
parm.FreeHandle ();
base.Dispose (disposing);
}
#endregion // Methods
}
}