Code:
/ Net / Net / 3.5.50727.3053 / DEVDIV / depot / DevDiv / releases / whidbey / netfxsp / ndp / fx / src / DataOracleClient / System / Data / OracleClient / OracleCommand.cs / 1 / OracleCommand.cs
//------------------------------------------------------------------------------ //// Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- namespace System.Data.OracleClient { using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.ProviderBase; using System.Data.SqlTypes; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; [ DefaultEvent("RecordsAffected"), ToolboxItem(true), Designer("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + AssemblyRef.MicrosoftVSDesigner) ] sealed public class OracleCommand : DbCommand, ICloneable { private static int _objectTypeCount; // Bid counter internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); private string _commandText; private CommandType _commandType; private UpdateRowSource _updatedRowSource = UpdateRowSource.Both; private bool _designTimeInvisible; private OracleConnection _connection; private OciStatementHandle _preparedStatementHandle; private int _preparedAtCloseCount; // The close count of the connection; used to decide if we're zombied private OracleParameterCollection _parameterCollection; private OCI.STMT _statementType; // set by the Execute method, so it's only valid after that. private OracleTransaction _transaction; // Construct an "empty" command public OracleCommand() : base() { GC.SuppressFinalize(this); } // Construct a command from a command text public OracleCommand(string commandText) : this() { CommandText = commandText; } // Construct a command from a command text and a connection object public OracleCommand(string commandText, OracleConnection connection) : this() { CommandText = commandText; Connection = connection; } // Construct a command from a command text, a connection object and a transaction public OracleCommand(string commandText, OracleConnection connection, OracleTransaction tx) : this() { CommandText = commandText; Connection = connection; Transaction = tx; } // (internal) Construct from an existing Command object (copy constructor) private OracleCommand(OracleCommand command) : this() { CommandText = command.CommandText; CommandType = command.CommandType; Connection = command.Connection; DesignTimeVisible = command.DesignTimeVisible; UpdatedRowSource = command.UpdatedRowSource; Transaction = command.Transaction; if (null != command._parameterCollection && 0 < command._parameterCollection.Count) { OracleParameterCollection parameters = Parameters; foreach(ICloneable parameter in command.Parameters) { parameters.Add(parameter.Clone()); } } } [ ResCategoryAttribute(Res.OracleCategory_Data), DefaultValue(""), ResDescriptionAttribute(Res.DbCommand_CommandText), RefreshProperties(RefreshProperties.All), Editor("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing) ] override public string CommandText { get { string value = _commandText; return ((null != value) ? value : ADP.StrEmpty); } set { if (Bid.TraceOn) { Bid.Trace("%d#, '", ObjectID); Bid.PutStr(value); // Use PutStr to write out entire string Bid.Trace("'\n"); } if (0 != ADP.SrcCompare(_commandText, value)) { PropertyChanging(); _commandText = value; } } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsableAttribute(EditorBrowsableState.Never), ResCategoryAttribute(Res.OracleCategory_Data), ResDescriptionAttribute(Res.DbCommand_CommandTimeout), ] public override int CommandTimeout { get { return 0; } set { } } public void ResetCommandTimeout() { // V1.2.3300 } private bool ShouldSerializeCommandTimeout() { // V1.2.3300 return false; } [ ResCategoryAttribute(Res.OracleCategory_Data), DefaultValue(System.Data.CommandType.Text), ResDescriptionAttribute(Res.DbCommand_CommandType), RefreshProperties(RefreshProperties.All) ] override public CommandType CommandType { get { CommandType cmdType = _commandType; return ((0 != cmdType) ? cmdType : CommandType.Text); } set { if (_commandType != value) { switch(value) { case CommandType.StoredProcedure: case CommandType.Text: PropertyChanging(); _commandType = value; break; case CommandType.TableDirect: throw ADP.NoOptimizedDirectTableAccess(); default: throw ADP.InvalidCommandType(value); } } } } [ ResCategoryAttribute(Res.OracleCategory_Behavior), DefaultValue(null), ResDescriptionAttribute(Res.DbCommand_Connection), Editor("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing) ] new public OracleConnection Connection { get { return _connection; } set { if (_connection != value) { PropertyChanging(); _connection = value; } } } private bool ConnectionIsClosed { // TRUE when the parent connection object has been closed get { OracleConnection conn = Connection; return (null == conn) || (ConnectionState.Closed == conn.State); } } override protected DbConnection DbConnection { // V1.2.3300 get { return Connection; } set { Connection = (OracleConnection)value; } } override protected DbParameterCollection DbParameterCollection { // V1.2.3300 get { return Parameters; } } override protected DbTransaction DbTransaction { // V1.2.3300 get { return Transaction; } set { Transaction = (OracleTransaction)value; } } // @devnote: By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray) // to limit the number of components that clutter the design surface, // when the DataAdapter design wizard generates the insert/update/delete commands it will // set the DesignTimeVisible property to false so that cmds won't appear as individual objects [ DefaultValue(true), DesignOnly(true), Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), ] public override bool DesignTimeVisible { // V1.2.3300, XXXCommand V1.0.5000 get { return !_designTimeInvisible; } set { _designTimeInvisible = !value; TypeDescriptor.Refresh(this); // VS7 208845 } } private OciEnvironmentHandle EnvironmentHandle { // Simplify getting the EnvironmentHandle get { return _connection.EnvironmentHandle; } } private OciErrorHandle ErrorHandle { // Every OCI call needs an error handle, so make it available internally. get { return _connection.ErrorHandle; } } internal int ObjectID { get { return _objectID; } } [ ResCategoryAttribute(Res.OracleCategory_Data), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), ResDescriptionAttribute(Res.DbCommand_Parameters) ] new public OracleParameterCollection Parameters { get { if (null == _parameterCollection) { _parameterCollection = new OracleParameterCollection(); } return _parameterCollection; } } internal string StatementText { // Combine the CommandType and CommandText into the statement that // needs to be passed to Oracle. get { string statementText = null; string commandText = CommandText; if (ADP.IsEmpty(commandText)) { throw ADP.NoCommandText(); } switch(CommandType) { case CommandType.StoredProcedure: { StringBuilder builder = new StringBuilder(); builder.Append("begin "); int parameterCount = Parameters.Count; int parameterUsed = 0; // Look for the return value: for (int i=0; i < parameterCount; ++i) { OracleParameter parameter = Parameters[i]; if (ADP.IsDirection(parameter, ParameterDirection.ReturnValue)) { builder.Append(":"); builder.Append(parameter.ParameterName); builder.Append(" := "); } } builder.Append(commandText); string separator = "("; for (int i=0; i < parameterCount; ++i) { OracleParameter parameter = Parameters[i]; if (ADP.IsDirection(parameter, ParameterDirection.ReturnValue)) { continue; // already did this one... } if ( !ADP.IsDirection(parameter, ParameterDirection.Output) && null == parameter.Value) { continue; // don't include parameters where the user asks for the default value. } // If the input-only parameter value is C# null, that's our "clue" that they // wish to use the default value. if (null != parameter.Value || ADP.IsDirection(parameter, ParameterDirection.Output)) { builder.Append(separator); separator = ", "; parameterUsed++; builder.Append(parameter.ParameterName); // builder.Append("=>:"); builder.Append(parameter.ParameterName); } } if (0 != parameterUsed) builder.Append("); end;"); else builder.Append("; end;"); statementText = builder.ToString(); } break; case CommandType.Text: statementText = commandText; break; default: Debug.Assert(false, "command type of "+CommandType+" is not supported"); break; } return statementText; } } private OciServiceContextHandle ServiceContextHandle { // Simplify getting the ServiceContextHandle get { return _connection.ServiceContextHandle; } } internal OCI.STMT StatementType { get { return _statementType; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), ResDescriptionAttribute(Res.DbCommand_Transaction) ] new public OracleTransaction Transaction { // Apparently, Yukon intends to move transaction support to the command // object and has requested that IDbCommand have a transaction property // to support that. get { // if the transaction object has been zombied, just return null if ((null != _transaction) && (null == _transaction.Connection)) { // MDAC 72720 _transaction = null; } return _transaction; } set { _transaction = value; } } [ DefaultValue(System.Data.UpdateRowSource.Both), ResCategoryAttribute(Res.DataCategory_Update), ResDescriptionAttribute(Res.DbCommand_UpdatedRowSource), ] override public UpdateRowSource UpdatedRowSource { // V1.2.3300, XXXCommand V1.0.5000 get { return _updatedRowSource; } set { switch(value) { // @perfnote: Enum.IsDefined case UpdateRowSource.None: case UpdateRowSource.OutputParameters: case UpdateRowSource.FirstReturnedRecord: case UpdateRowSource.Both: _updatedRowSource = value; break; default: throw ADP.InvalidUpdateRowSource(value); } } } // Cancel is supposed to be multi-thread safe. // It doesn't make sense to verify the connection exists or that it is open during cancel // because immediately after checkin the connection can be closed or removed via another thread. // override public void Cancel() { // According to [....]: Cancel is meant to cancel firehose cursors only, // not to cancel the execution of a statement. Given that for Oracle, you // don't need to tell the server you don't want any more results, it would // seem that this is unnecessary, so I'm commenting it out until someone // comes up with a reason for it. IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { #if UNUSED int rc = TracedNativeMethods.OCIBreak( ServiceContextHandle.GetHandle(), ErrorHandle.Handle ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } #endif // } finally { Bid.ScopeLeave(ref hscp); } } public object Clone() { OracleCommand clone = new OracleCommand(this); Bid.Trace(" %d#, clone=%d#\n", ObjectID, clone.ObjectID); return clone; } new public OracleParameter CreateParameter() { return new OracleParameter(); } override protected DbParameter CreateDbParameter() { return CreateParameter(); } internal string Execute(OciStatementHandle statementHandle, CommandBehavior behavior, out ArrayList resultParameterOrdinals) { OciRowidDescriptor temp1; return Execute(statementHandle, behavior, false, out temp1, out resultParameterOrdinals); } internal string Execute(OciStatementHandle statementHandle, CommandBehavior behavior, bool needRowid, out OciRowidDescriptor rowidDescriptor, out ArrayList resultParameterOrdinals) { // common routine used to execute all statements if (ConnectionIsClosed) { throw ADP.ClosedConnectionError(); } // throw if the connection is in a transaction but there is no // locally assigned transaction object if ((null == _transaction) && (null != Connection.Transaction)) { throw ADP.TransactionRequired(); } // if we have a transaction, check to ensure that the active // connection property matches the connection associated with // the transaction if ((null != _transaction) && (null != _transaction.Connection) && (Connection != _transaction.Connection)) { throw ADP.TransactionConnectionMismatch(); } rowidDescriptor = null; // if the connection has a command but it went out of scope, we need // to roll it back. We do this here instead of in the transaction // objects finalizer because it doesn't really matter when it gets // done, just as long as it is before the next command executes, and // it's easier to do it in the command object, than in the object // that is being finalized. Connection.RollbackDeadTransaction(); int rc = 0; NativeBuffer parameterBuffer = null; bool mustRelease = false; bool[] mustReleaseBindHandle = null; SafeHandle[] handleToBind = null; short tempub2; int iterations; OracleParameterBinding[] parameterBinding = null; string statementText = null; resultParameterOrdinals = null; RuntimeHelpers.PrepareConstrainedRegions(); try { // If we've already sent the statement to the server, then we don't need // to prepare it again... if (_preparedStatementHandle != statementHandle) { statementText = StatementText; rc = TracedNativeMethods.OCIStmtPrepare( statementHandle, ErrorHandle, statementText, OCI.SYNTAX.OCI_NTV_SYNTAX, OCI.MODE.OCI_DEFAULT, Connection ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } } // Figure out what kind of statement we're dealing with and pick the // appropriate iteration count. statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_STMT_TYPE, out tempub2, ErrorHandle); _statementType = (OCI.STMT)tempub2; if (OCI.STMT.OCI_STMT_SELECT != _statementType) { iterations = 1; } else { iterations = 0; if (CommandBehavior.SingleRow != behavior) { // We're doing our own "prefetching" to avoid double copies, so we // need to turn off Oracle's or it won't really help. statementHandle.SetAttribute(OCI.ATTR.OCI_ATTR_PREFETCH_ROWS, 0, ErrorHandle); statementHandle.SetAttribute(OCI.ATTR.OCI_ATTR_PREFETCH_MEMORY, 0, ErrorHandle); } } // Pick the execution mode we need to use OCI.MODE executeMode = OCI.MODE.OCI_DEFAULT; if (0 == iterations) { if (IsBehavior(behavior, CommandBehavior.SchemaOnly)) { // If we're only supposed to "describe" the data columns for the rowset, then // use the describe only execute mode executeMode |= OCI.MODE.OCI_DESCRIBE_ONLY; } } else { if (TransactionState.AutoCommit == _connection.TransactionState) { // If we're in autocommit mode, then we have to tell Oracle to automatically // commit the transaction it automatically created. executeMode |= OCI.MODE.OCI_COMMIT_ON_SUCCESS; } else if (TransactionState.GlobalStarted != _connection.TransactionState) { // If we're not in "auto commit mode" then we can presume that Oracle // will automatically start a transaction, so we need to keep track // of that. _connection.TransactionState = TransactionState.LocalStarted; } } // Bind all the parameter values, unless we're just looking for schema info if (0 == (executeMode & OCI.MODE.OCI_DESCRIBE_ONLY)) { if (null != _parameterCollection && _parameterCollection.Count > 0) { int parameterBufferLength = 0; int length = _parameterCollection.Count; mustReleaseBindHandle = new bool[length]; handleToBind = new SafeHandle[length]; parameterBinding = new OracleParameterBinding[length]; for (int i = 0; i < length; ++i) { parameterBinding[i] = new OracleParameterBinding(this, _parameterCollection[i]); parameterBinding[i].PrepareForBind( _connection, ref parameterBufferLength ); // If this is a ref cursor parameter that we're supposed to include // in the data reader, then add it to our list of those. if (OracleType.Cursor == _parameterCollection[i].OracleType || 0 < _parameterCollection[i].CommandSetResult) { if (null == resultParameterOrdinals) { resultParameterOrdinals = new ArrayList(); } resultParameterOrdinals.Add(i); } } parameterBuffer = new NativeBuffer_ParameterBuffer(parameterBufferLength); parameterBuffer.DangerousAddRef(ref mustRelease); for (int i = 0; i < length; ++i) { parameterBinding[i].Bind( statementHandle, parameterBuffer, _connection, ref mustReleaseBindHandle[i], ref handleToBind[i] ); } } } // OK, now go ahead and execute rc = TracedNativeMethods.OCIStmtExecute( ServiceContextHandle, // svchp statementHandle, // stmtp ErrorHandle, // errhp iterations, // iters executeMode // mode ); if (0 != rc) Connection.CheckError(ErrorHandle, rc); // and now, create the output parameter values if (null != parameterBinding) { int length = parameterBinding.Length; for (int i = 0; i < length; ++i) { parameterBinding[i].PostExecute( parameterBuffer, _connection ); parameterBinding[i].Dispose(); parameterBinding[i] = null; } parameterBinding = null; } if (needRowid && 0 == (executeMode & OCI.MODE.OCI_DESCRIBE_ONLY)) { switch (_statementType) { case OCI.STMT.OCI_STMT_UPDATE: case OCI.STMT.OCI_STMT_DELETE: case OCI.STMT.OCI_STMT_INSERT: rowidDescriptor = statementHandle.GetRowid(EnvironmentHandle, ErrorHandle); break; default: rowidDescriptor = null; break; } } } finally { if (mustRelease) { parameterBuffer.DangerousRelease(); } if (null != parameterBuffer) { // We're done with these, get rid of them. parameterBuffer.Dispose(); parameterBuffer = null; } // and now, release/free the output parameter values if (null != parameterBinding) { int length = parameterBinding.Length; for (int i = 0; i < length; ++i) { if (null != parameterBinding[i]) { parameterBinding[i].Dispose(); parameterBinding[i] = null; } } parameterBinding = null; } if (null != mustReleaseBindHandle && null != handleToBind) { int length = mustReleaseBindHandle.Length; for (int i = 0; i < length; ++i) { if (mustReleaseBindHandle[i]) { handleToBind[i].DangerousRelease(); } } } } return statementText; } override protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior) { return ExecuteReader(behavior); } override public int ExecuteNonQuery() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { OciRowidDescriptor temp = null; int result = ExecuteNonQueryInternal(false, out temp); OciHandle.SafeDispose(ref temp); // shouldn't be necessary, but just in case... return result; } finally { Bid.ScopeLeave(ref hscp); } } private int ExecuteNonQueryInternal(bool needRowid, out OciRowidDescriptor rowidDescriptor) { OciStatementHandle statementHandle = null; int rowcount = -1; try { try { ArrayList resultParameterOrdinals = new ArrayList(); statementHandle = GetStatementHandle(); Execute( statementHandle, CommandBehavior.Default, needRowid, out rowidDescriptor, out resultParameterOrdinals ); if (null != resultParameterOrdinals) { rowcount = 0; foreach (int resultParameterOrdinal in resultParameterOrdinals) { OracleParameter resultParameter = _parameterCollection[resultParameterOrdinal]; if (OracleType.Cursor != resultParameter.OracleType) { Debug.Assert(0 < resultParameter.CommandSetResult, "non-ref cursor, non recordsaffected parameter?"); rowcount += (int)resultParameter.Value; } } } else { if (OCI.STMT.OCI_STMT_SELECT != _statementType) { statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out rowcount, ErrorHandle); } } } finally { if (null != statementHandle) ReleaseStatementHandle(statementHandle); } } catch { // Prevent exception filters from running in our space throw; } return rowcount; } public int ExecuteOracleNonQuery(out OracleString rowid) { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { OciRowidDescriptor rowidDescriptor = null; int result = ExecuteNonQueryInternal(true, out rowidDescriptor); rowid = GetPersistedRowid( Connection, rowidDescriptor ); OciHandle.SafeDispose(ref rowidDescriptor); return result; } finally { Bid.ScopeLeave(ref hscp); } } public object ExecuteOracleScalar() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#", ObjectID); try { OciRowidDescriptor temp = null; object result = ExecuteScalarInternal(false, false, out temp); OciHandle.SafeDispose(ref temp); // shouldn't be necessary, but just in case... return result; } finally { Bid.ScopeLeave(ref hscp); } } new public OracleDataReader ExecuteReader() { return ExecuteReader(CommandBehavior.Default); } new public OracleDataReader ExecuteReader(CommandBehavior behavior) { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior); try { OciStatementHandle statementHandle = null;; OracleDataReader reader = null; ArrayList resultParameterOrdinals = null; try { statementHandle = GetStatementHandle(); string statementText = Execute( statementHandle, behavior, out resultParameterOrdinals); // We're about to handle the prepared statement handle (if there was one) // to the data reader object; so we can't really hold on to it any longer. if (statementHandle == _preparedStatementHandle) { // Don't dispose the handle, we still need it! just make our reference to it null. _preparedStatementHandle = null; // } if (null == resultParameterOrdinals) reader = new OracleDataReader(this, statementHandle, statementText, behavior); else reader = new OracleDataReader(this, resultParameterOrdinals, statementText, behavior); } finally { // if we didn't hand the statement to a reader, then release it if (null != statementHandle && (null == reader || null != resultParameterOrdinals)) { ReleaseStatementHandle(statementHandle); } } return reader; } finally { Bid.ScopeLeave(ref hscp); } } override public object ExecuteScalar() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { OciRowidDescriptor temp; object result = ExecuteScalarInternal(true, false, out temp); OciHandle.SafeDispose(ref temp); // shouldn't be necessary, but just in case... return result; } finally { Bid.ScopeLeave(ref hscp); } } private object ExecuteScalarInternal(bool needCLStype, bool needRowid, out OciRowidDescriptor rowidDescriptor) { OciStatementHandle statementHandle = null; object result = null; int rc = 0; try { statementHandle = GetStatementHandle(); ArrayList temp = new ArrayList(); Execute( statementHandle, CommandBehavior.Default, needRowid, out rowidDescriptor, out temp ); if (OCI.STMT.OCI_STMT_SELECT == _statementType) { // We only care about one column; Oracle will handle the fact that the // rest aren't define so don't bother allocating and gathering more column // information than we need. OracleColumn column = new OracleColumn(statementHandle, 0, ErrorHandle, _connection); int columnBufferLength = 0; bool mustRelease = false; bool mustReleaseBindHandle = false; SafeHandle bindHandle = null; column.Describe(ref columnBufferLength, _connection, ErrorHandle); NativeBuffer_RowBuffer columnBuffer = new NativeBuffer_RowBuffer(columnBufferLength, 1); RuntimeHelpers.PrepareConstrainedRegions(); try { columnBuffer.DangerousAddRef(ref mustRelease); column.Bind(statementHandle, columnBuffer, ErrorHandle, 0); column.Rebind(_connection, ref mustReleaseBindHandle, ref bindHandle); // Now fetch one row into the buffer we've provided rc = TracedNativeMethods.OCIStmtFetch( statementHandle, // stmtp ErrorHandle, // errhp 1, // crows OCI.FETCH.OCI_FETCH_NEXT, // orientation OCI.MODE.OCI_DEFAULT // mode ); if ((int)OCI.RETURNCODE.OCI_NO_DATA != rc) { if (0 != rc) Connection.CheckError(ErrorHandle, rc); // Ask the column for the object value (we need to get the Value from // the object to ensure that we have a URT type object, not an Oracle // type object) if (needCLStype) result = column.GetValue(columnBuffer); else result = column.GetOracleValue(columnBuffer); } } finally { if (mustReleaseBindHandle) { bindHandle.DangerousRelease(); } if (mustRelease) { columnBuffer.DangerousRelease(); } } GC.KeepAlive(column); } } finally { if (null != statementHandle) { ReleaseStatementHandle(statementHandle); } } return result; } static internal OracleString GetPersistedRowid(OracleConnection connection, OciRowidDescriptor rowidHandle) { // This method returns an OracleString that holds the base64 string // representation of the rowid, which can be persisted past the lifetime // of this process. OracleString result = OracleString.Null; if (null == rowidHandle) goto done; // null if there isn't a rowid! OciErrorHandle errorHandle = connection.ErrorHandle; NativeBuffer rowidBuffer = connection.GetScratchBuffer(3970); bool mustRelease = false; bool mustReleaseRowidHandle = false; int rc; RuntimeHelpers.PrepareConstrainedRegions(); try { rowidBuffer.DangerousAddRef(ref mustRelease); if (OCI.ClientVersionAtLeastOracle9i) { int bufferLength = rowidBuffer.Length; rc = TracedNativeMethods.OCIRowidToChar(rowidHandle, rowidBuffer, ref bufferLength, errorHandle ); if (0 != rc) { connection.CheckError(errorHandle, rc); } string stringValue = rowidBuffer.PtrToStringAnsi(0, bufferLength); // ROWID's always come back as Ansi... result = new OracleString(stringValue); } else { rowidHandle.DangerousAddRef(ref mustReleaseRowidHandle); OciServiceContextHandle serviceContextHandle = connection.ServiceContextHandle; OciStatementHandle tempHandle = new OciStatementHandle(serviceContextHandle); string tempText = "begin :rowid := :rdesc; end;"; int rdescIndicatorOffset= 0; int rdescLengthOffset = 4; int rdescValueOffset = 8; int rowidIndicatorOffset= 12; int rowidLengthOffset = 16; int rowidValueOffset = 20; try { rc = TracedNativeMethods.OCIStmtPrepare( tempHandle, errorHandle, tempText, OCI.SYNTAX.OCI_NTV_SYNTAX, OCI.MODE.OCI_DEFAULT, connection ); if (0 != rc) connection.CheckError(errorHandle, rc); IntPtr h1; IntPtr h2; // Need to clean these out, since we're re-using the scratch buffer, which // the prepare uses to convert the statement text. rowidBuffer.WriteIntPtr(rdescValueOffset, rowidHandle.DangerousGetHandle()); rowidBuffer.WriteInt32 (rdescIndicatorOffset, 0); rowidBuffer.WriteInt32 (rdescLengthOffset, 4); rowidBuffer.WriteInt32 (rowidIndicatorOffset, 0); rowidBuffer.WriteInt32 (rowidLengthOffset, 3950); rc = TracedNativeMethods.OCIBindByName( tempHandle, out h1, errorHandle, "rowid", 5, rowidBuffer.DangerousGetDataPtr(rowidValueOffset), 3950, OCI.DATATYPE.VARCHAR2, rowidBuffer.DangerousGetDataPtr(rowidIndicatorOffset), rowidBuffer.DangerousGetDataPtr(rowidLengthOffset), OCI.MODE.OCI_DEFAULT ); if (0 != rc) connection.CheckError(errorHandle, rc); rc = TracedNativeMethods.OCIBindByName( tempHandle, out h2, errorHandle, "rdesc", 5, rowidBuffer.DangerousGetDataPtr(rdescValueOffset), 4, OCI.DATATYPE.ROWID_DESC, rowidBuffer.DangerousGetDataPtr(rdescIndicatorOffset), rowidBuffer.DangerousGetDataPtr(rdescLengthOffset), OCI.MODE.OCI_DEFAULT ); if (0 != rc) connection.CheckError(errorHandle, rc); rc = TracedNativeMethods.OCIStmtExecute( serviceContextHandle, // svchp tempHandle, // stmtp errorHandle, // errhp 1, // iters OCI.MODE.OCI_DEFAULT // mode ); if (0 != rc) connection.CheckError(errorHandle, rc); if (rowidBuffer.ReadInt16(rowidIndicatorOffset) == (Int16)OCI.INDICATOR.ISNULL) goto done; result = new OracleString( rowidBuffer, rowidValueOffset, rowidLengthOffset, MetaType.GetMetaTypeForType(OracleType.RowId), connection, false, // it's not unicode! true ); GC.KeepAlive(rowidHandle); } finally { OciHandle.SafeDispose(ref tempHandle); } } } finally{ if (mustReleaseRowidHandle) { rowidHandle.DangerousRelease(); } if (mustRelease) { rowidBuffer.DangerousRelease(); } } done: return result; } private OciStatementHandle GetStatementHandle() { // return either the prepared statement handle or a new one if nothign // is prepared. if (ConnectionIsClosed) { throw ADP.ClosedConnectionError(); } if (null != _preparedStatementHandle) { // When we prepare the statement, we keep track of it's closed // count; if the connection has been closed since we prepared, then // the statement handle is no longer valid and must be tossed. if (_connection.CloseCount == _preparedAtCloseCount) { return _preparedStatementHandle; } _preparedStatementHandle.Dispose(); _preparedStatementHandle = null; } return new OciStatementHandle(ServiceContextHandle); } static internal bool IsBehavior(CommandBehavior value, CommandBehavior condition) { return (condition == (condition & value)); } override public void Prepare() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { if (ConnectionIsClosed) { throw ADP.ClosedConnectionError(); } if (CommandType.Text == CommandType) { OciStatementHandle preparedStatementHandle = GetStatementHandle(); int preparedAtCloseCount = _connection.CloseCount; string statementText = StatementText; int rc = TracedNativeMethods.OCIStmtPrepare( preparedStatementHandle, ErrorHandle, statementText, OCI.SYNTAX.OCI_NTV_SYNTAX, OCI.MODE.OCI_DEFAULT, Connection ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } short tempub2; preparedStatementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_STMT_TYPE, out tempub2, ErrorHandle); _statementType = (OCI.STMT)tempub2; if (OCI.STMT.OCI_STMT_SELECT == _statementType) { rc = TracedNativeMethods.OCIStmtExecute( _connection.ServiceContextHandle, // svchp preparedStatementHandle, // stmtp ErrorHandle, // errhp 0, // iters OCI.MODE.OCI_DESCRIBE_ONLY // mode ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } } if (preparedStatementHandle != _preparedStatementHandle) { OciHandle.SafeDispose(ref _preparedStatementHandle); } _preparedStatementHandle = preparedStatementHandle; _preparedAtCloseCount = preparedAtCloseCount; } else if (null != _preparedStatementHandle) { OciHandle.SafeDispose(ref _preparedStatementHandle); } } finally { Bid.ScopeLeave(ref hscp); } } private void PropertyChanging() { // common routine used to get rid of a statement handle; it disposes // of the handle unless it's the prepared handle if (null != _preparedStatementHandle) { _preparedStatementHandle.Dispose(); // the existing prepared statement is no longer valid _preparedStatementHandle = null; } } private void ReleaseStatementHandle (OciStatementHandle statementHandle) { // common routine used to get rid of a statement handle; it disposes // of the handle unless it's the prepared handle if (ConnectionState.Closed != Connection.State && _preparedStatementHandle != statementHandle) { OciHandle.SafeDispose(ref statementHandle); } } }; } // File provided for Reference Use Only by Microsoft Corporation (c) 2007. //------------------------------------------------------------------------------ // // Copyright (c) Microsoft Corporation. All rights reserved. // //[....] //----------------------------------------------------------------------------- namespace System.Data.OracleClient { using System; using System.Collections; using System.ComponentModel; using System.Data; using System.Data.Common; using System.Data.ProviderBase; using System.Data.SqlTypes; using System.Diagnostics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; [ DefaultEvent("RecordsAffected"), ToolboxItem(true), Designer("Microsoft.VSDesigner.Data.VS.OracleCommandDesigner, " + AssemblyRef.MicrosoftVSDesigner) ] sealed public class OracleCommand : DbCommand, ICloneable { private static int _objectTypeCount; // Bid counter internal readonly int _objectID = System.Threading.Interlocked.Increment(ref _objectTypeCount); private string _commandText; private CommandType _commandType; private UpdateRowSource _updatedRowSource = UpdateRowSource.Both; private bool _designTimeInvisible; private OracleConnection _connection; private OciStatementHandle _preparedStatementHandle; private int _preparedAtCloseCount; // The close count of the connection; used to decide if we're zombied private OracleParameterCollection _parameterCollection; private OCI.STMT _statementType; // set by the Execute method, so it's only valid after that. private OracleTransaction _transaction; // Construct an "empty" command public OracleCommand() : base() { GC.SuppressFinalize(this); } // Construct a command from a command text public OracleCommand(string commandText) : this() { CommandText = commandText; } // Construct a command from a command text and a connection object public OracleCommand(string commandText, OracleConnection connection) : this() { CommandText = commandText; Connection = connection; } // Construct a command from a command text, a connection object and a transaction public OracleCommand(string commandText, OracleConnection connection, OracleTransaction tx) : this() { CommandText = commandText; Connection = connection; Transaction = tx; } // (internal) Construct from an existing Command object (copy constructor) private OracleCommand(OracleCommand command) : this() { CommandText = command.CommandText; CommandType = command.CommandType; Connection = command.Connection; DesignTimeVisible = command.DesignTimeVisible; UpdatedRowSource = command.UpdatedRowSource; Transaction = command.Transaction; if (null != command._parameterCollection && 0 < command._parameterCollection.Count) { OracleParameterCollection parameters = Parameters; foreach(ICloneable parameter in command.Parameters) { parameters.Add(parameter.Clone()); } } } [ ResCategoryAttribute(Res.OracleCategory_Data), DefaultValue(""), ResDescriptionAttribute(Res.DbCommand_CommandText), RefreshProperties(RefreshProperties.All), Editor("Microsoft.VSDesigner.Data.Oracle.Design.OracleCommandTextEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing) ] override public string CommandText { get { string value = _commandText; return ((null != value) ? value : ADP.StrEmpty); } set { if (Bid.TraceOn) { Bid.Trace("%d#, '", ObjectID); Bid.PutStr(value); // Use PutStr to write out entire string Bid.Trace("'\n"); } if (0 != ADP.SrcCompare(_commandText, value)) { PropertyChanging(); _commandText = value; } } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), EditorBrowsableAttribute(EditorBrowsableState.Never), ResCategoryAttribute(Res.OracleCategory_Data), ResDescriptionAttribute(Res.DbCommand_CommandTimeout), ] public override int CommandTimeout { get { return 0; } set { } } public void ResetCommandTimeout() { // V1.2.3300 } private bool ShouldSerializeCommandTimeout() { // V1.2.3300 return false; } [ ResCategoryAttribute(Res.OracleCategory_Data), DefaultValue(System.Data.CommandType.Text), ResDescriptionAttribute(Res.DbCommand_CommandType), RefreshProperties(RefreshProperties.All) ] override public CommandType CommandType { get { CommandType cmdType = _commandType; return ((0 != cmdType) ? cmdType : CommandType.Text); } set { if (_commandType != value) { switch(value) { case CommandType.StoredProcedure: case CommandType.Text: PropertyChanging(); _commandType = value; break; case CommandType.TableDirect: throw ADP.NoOptimizedDirectTableAccess(); default: throw ADP.InvalidCommandType(value); } } } } [ ResCategoryAttribute(Res.OracleCategory_Behavior), DefaultValue(null), ResDescriptionAttribute(Res.DbCommand_Connection), Editor("Microsoft.VSDesigner.Data.Design.DbConnectionEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing) ] new public OracleConnection Connection { get { return _connection; } set { if (_connection != value) { PropertyChanging(); _connection = value; } } } private bool ConnectionIsClosed { // TRUE when the parent connection object has been closed get { OracleConnection conn = Connection; return (null == conn) || (ConnectionState.Closed == conn.State); } } override protected DbConnection DbConnection { // V1.2.3300 get { return Connection; } set { Connection = (OracleConnection)value; } } override protected DbParameterCollection DbParameterCollection { // V1.2.3300 get { return Parameters; } } override protected DbTransaction DbTransaction { // V1.2.3300 get { return Transaction; } set { Transaction = (OracleTransaction)value; } } // @devnote: By default, the cmd object is visible on the design surface (i.e. VS7 Server Tray) // to limit the number of components that clutter the design surface, // when the DataAdapter design wizard generates the insert/update/delete commands it will // set the DesignTimeVisible property to false so that cmds won't appear as individual objects [ DefaultValue(true), DesignOnly(true), Browsable(false), EditorBrowsableAttribute(EditorBrowsableState.Never), ] public override bool DesignTimeVisible { // V1.2.3300, XXXCommand V1.0.5000 get { return !_designTimeInvisible; } set { _designTimeInvisible = !value; TypeDescriptor.Refresh(this); // VS7 208845 } } private OciEnvironmentHandle EnvironmentHandle { // Simplify getting the EnvironmentHandle get { return _connection.EnvironmentHandle; } } private OciErrorHandle ErrorHandle { // Every OCI call needs an error handle, so make it available internally. get { return _connection.ErrorHandle; } } internal int ObjectID { get { return _objectID; } } [ ResCategoryAttribute(Res.OracleCategory_Data), DesignerSerializationVisibility(DesignerSerializationVisibility.Content), ResDescriptionAttribute(Res.DbCommand_Parameters) ] new public OracleParameterCollection Parameters { get { if (null == _parameterCollection) { _parameterCollection = new OracleParameterCollection(); } return _parameterCollection; } } internal string StatementText { // Combine the CommandType and CommandText into the statement that // needs to be passed to Oracle. get { string statementText = null; string commandText = CommandText; if (ADP.IsEmpty(commandText)) { throw ADP.NoCommandText(); } switch(CommandType) { case CommandType.StoredProcedure: { StringBuilder builder = new StringBuilder(); builder.Append("begin "); int parameterCount = Parameters.Count; int parameterUsed = 0; // Look for the return value: for (int i=0; i < parameterCount; ++i) { OracleParameter parameter = Parameters[i]; if (ADP.IsDirection(parameter, ParameterDirection.ReturnValue)) { builder.Append(":"); builder.Append(parameter.ParameterName); builder.Append(" := "); } } builder.Append(commandText); string separator = "("; for (int i=0; i < parameterCount; ++i) { OracleParameter parameter = Parameters[i]; if (ADP.IsDirection(parameter, ParameterDirection.ReturnValue)) { continue; // already did this one... } if ( !ADP.IsDirection(parameter, ParameterDirection.Output) && null == parameter.Value) { continue; // don't include parameters where the user asks for the default value. } // If the input-only parameter value is C# null, that's our "clue" that they // wish to use the default value. if (null != parameter.Value || ADP.IsDirection(parameter, ParameterDirection.Output)) { builder.Append(separator); separator = ", "; parameterUsed++; builder.Append(parameter.ParameterName); // builder.Append("=>:"); builder.Append(parameter.ParameterName); } } if (0 != parameterUsed) builder.Append("); end;"); else builder.Append("; end;"); statementText = builder.ToString(); } break; case CommandType.Text: statementText = commandText; break; default: Debug.Assert(false, "command type of "+CommandType+" is not supported"); break; } return statementText; } } private OciServiceContextHandle ServiceContextHandle { // Simplify getting the ServiceContextHandle get { return _connection.ServiceContextHandle; } } internal OCI.STMT StatementType { get { return _statementType; } } [ Browsable(false), DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), ResDescriptionAttribute(Res.DbCommand_Transaction) ] new public OracleTransaction Transaction { // Apparently, Yukon intends to move transaction support to the command // object and has requested that IDbCommand have a transaction property // to support that. get { // if the transaction object has been zombied, just return null if ((null != _transaction) && (null == _transaction.Connection)) { // MDAC 72720 _transaction = null; } return _transaction; } set { _transaction = value; } } [ DefaultValue(System.Data.UpdateRowSource.Both), ResCategoryAttribute(Res.DataCategory_Update), ResDescriptionAttribute(Res.DbCommand_UpdatedRowSource), ] override public UpdateRowSource UpdatedRowSource { // V1.2.3300, XXXCommand V1.0.5000 get { return _updatedRowSource; } set { switch(value) { // @perfnote: Enum.IsDefined case UpdateRowSource.None: case UpdateRowSource.OutputParameters: case UpdateRowSource.FirstReturnedRecord: case UpdateRowSource.Both: _updatedRowSource = value; break; default: throw ADP.InvalidUpdateRowSource(value); } } } // Cancel is supposed to be multi-thread safe. // It doesn't make sense to verify the connection exists or that it is open during cancel // because immediately after checkin the connection can be closed or removed via another thread. // override public void Cancel() { // According to [....]: Cancel is meant to cancel firehose cursors only, // not to cancel the execution of a statement. Given that for Oracle, you // don't need to tell the server you don't want any more results, it would // seem that this is unnecessary, so I'm commenting it out until someone // comes up with a reason for it. IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { #if UNUSED int rc = TracedNativeMethods.OCIBreak( ServiceContextHandle.GetHandle(), ErrorHandle.Handle ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } #endif // } finally { Bid.ScopeLeave(ref hscp); } } public object Clone() { OracleCommand clone = new OracleCommand(this); Bid.Trace(" %d#, clone=%d#\n", ObjectID, clone.ObjectID); return clone; } new public OracleParameter CreateParameter() { return new OracleParameter(); } override protected DbParameter CreateDbParameter() { return CreateParameter(); } internal string Execute(OciStatementHandle statementHandle, CommandBehavior behavior, out ArrayList resultParameterOrdinals) { OciRowidDescriptor temp1; return Execute(statementHandle, behavior, false, out temp1, out resultParameterOrdinals); } internal string Execute(OciStatementHandle statementHandle, CommandBehavior behavior, bool needRowid, out OciRowidDescriptor rowidDescriptor, out ArrayList resultParameterOrdinals) { // common routine used to execute all statements if (ConnectionIsClosed) { throw ADP.ClosedConnectionError(); } // throw if the connection is in a transaction but there is no // locally assigned transaction object if ((null == _transaction) && (null != Connection.Transaction)) { throw ADP.TransactionRequired(); } // if we have a transaction, check to ensure that the active // connection property matches the connection associated with // the transaction if ((null != _transaction) && (null != _transaction.Connection) && (Connection != _transaction.Connection)) { throw ADP.TransactionConnectionMismatch(); } rowidDescriptor = null; // if the connection has a command but it went out of scope, we need // to roll it back. We do this here instead of in the transaction // objects finalizer because it doesn't really matter when it gets // done, just as long as it is before the next command executes, and // it's easier to do it in the command object, than in the object // that is being finalized. Connection.RollbackDeadTransaction(); int rc = 0; NativeBuffer parameterBuffer = null; bool mustRelease = false; bool[] mustReleaseBindHandle = null; SafeHandle[] handleToBind = null; short tempub2; int iterations; OracleParameterBinding[] parameterBinding = null; string statementText = null; resultParameterOrdinals = null; RuntimeHelpers.PrepareConstrainedRegions(); try { // If we've already sent the statement to the server, then we don't need // to prepare it again... if (_preparedStatementHandle != statementHandle) { statementText = StatementText; rc = TracedNativeMethods.OCIStmtPrepare( statementHandle, ErrorHandle, statementText, OCI.SYNTAX.OCI_NTV_SYNTAX, OCI.MODE.OCI_DEFAULT, Connection ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } } // Figure out what kind of statement we're dealing with and pick the // appropriate iteration count. statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_STMT_TYPE, out tempub2, ErrorHandle); _statementType = (OCI.STMT)tempub2; if (OCI.STMT.OCI_STMT_SELECT != _statementType) { iterations = 1; } else { iterations = 0; if (CommandBehavior.SingleRow != behavior) { // We're doing our own "prefetching" to avoid double copies, so we // need to turn off Oracle's or it won't really help. statementHandle.SetAttribute(OCI.ATTR.OCI_ATTR_PREFETCH_ROWS, 0, ErrorHandle); statementHandle.SetAttribute(OCI.ATTR.OCI_ATTR_PREFETCH_MEMORY, 0, ErrorHandle); } } // Pick the execution mode we need to use OCI.MODE executeMode = OCI.MODE.OCI_DEFAULT; if (0 == iterations) { if (IsBehavior(behavior, CommandBehavior.SchemaOnly)) { // If we're only supposed to "describe" the data columns for the rowset, then // use the describe only execute mode executeMode |= OCI.MODE.OCI_DESCRIBE_ONLY; } } else { if (TransactionState.AutoCommit == _connection.TransactionState) { // If we're in autocommit mode, then we have to tell Oracle to automatically // commit the transaction it automatically created. executeMode |= OCI.MODE.OCI_COMMIT_ON_SUCCESS; } else if (TransactionState.GlobalStarted != _connection.TransactionState) { // If we're not in "auto commit mode" then we can presume that Oracle // will automatically start a transaction, so we need to keep track // of that. _connection.TransactionState = TransactionState.LocalStarted; } } // Bind all the parameter values, unless we're just looking for schema info if (0 == (executeMode & OCI.MODE.OCI_DESCRIBE_ONLY)) { if (null != _parameterCollection && _parameterCollection.Count > 0) { int parameterBufferLength = 0; int length = _parameterCollection.Count; mustReleaseBindHandle = new bool[length]; handleToBind = new SafeHandle[length]; parameterBinding = new OracleParameterBinding[length]; for (int i = 0; i < length; ++i) { parameterBinding[i] = new OracleParameterBinding(this, _parameterCollection[i]); parameterBinding[i].PrepareForBind( _connection, ref parameterBufferLength ); // If this is a ref cursor parameter that we're supposed to include // in the data reader, then add it to our list of those. if (OracleType.Cursor == _parameterCollection[i].OracleType || 0 < _parameterCollection[i].CommandSetResult) { if (null == resultParameterOrdinals) { resultParameterOrdinals = new ArrayList(); } resultParameterOrdinals.Add(i); } } parameterBuffer = new NativeBuffer_ParameterBuffer(parameterBufferLength); parameterBuffer.DangerousAddRef(ref mustRelease); for (int i = 0; i < length; ++i) { parameterBinding[i].Bind( statementHandle, parameterBuffer, _connection, ref mustReleaseBindHandle[i], ref handleToBind[i] ); } } } // OK, now go ahead and execute rc = TracedNativeMethods.OCIStmtExecute( ServiceContextHandle, // svchp statementHandle, // stmtp ErrorHandle, // errhp iterations, // iters executeMode // mode ); if (0 != rc) Connection.CheckError(ErrorHandle, rc); // and now, create the output parameter values if (null != parameterBinding) { int length = parameterBinding.Length; for (int i = 0; i < length; ++i) { parameterBinding[i].PostExecute( parameterBuffer, _connection ); parameterBinding[i].Dispose(); parameterBinding[i] = null; } parameterBinding = null; } if (needRowid && 0 == (executeMode & OCI.MODE.OCI_DESCRIBE_ONLY)) { switch (_statementType) { case OCI.STMT.OCI_STMT_UPDATE: case OCI.STMT.OCI_STMT_DELETE: case OCI.STMT.OCI_STMT_INSERT: rowidDescriptor = statementHandle.GetRowid(EnvironmentHandle, ErrorHandle); break; default: rowidDescriptor = null; break; } } } finally { if (mustRelease) { parameterBuffer.DangerousRelease(); } if (null != parameterBuffer) { // We're done with these, get rid of them. parameterBuffer.Dispose(); parameterBuffer = null; } // and now, release/free the output parameter values if (null != parameterBinding) { int length = parameterBinding.Length; for (int i = 0; i < length; ++i) { if (null != parameterBinding[i]) { parameterBinding[i].Dispose(); parameterBinding[i] = null; } } parameterBinding = null; } if (null != mustReleaseBindHandle && null != handleToBind) { int length = mustReleaseBindHandle.Length; for (int i = 0; i < length; ++i) { if (mustReleaseBindHandle[i]) { handleToBind[i].DangerousRelease(); } } } } return statementText; } override protected DbDataReader ExecuteDbDataReader(CommandBehavior behavior) { return ExecuteReader(behavior); } override public int ExecuteNonQuery() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { OciRowidDescriptor temp = null; int result = ExecuteNonQueryInternal(false, out temp); OciHandle.SafeDispose(ref temp); // shouldn't be necessary, but just in case... return result; } finally { Bid.ScopeLeave(ref hscp); } } private int ExecuteNonQueryInternal(bool needRowid, out OciRowidDescriptor rowidDescriptor) { OciStatementHandle statementHandle = null; int rowcount = -1; try { try { ArrayList resultParameterOrdinals = new ArrayList(); statementHandle = GetStatementHandle(); Execute( statementHandle, CommandBehavior.Default, needRowid, out rowidDescriptor, out resultParameterOrdinals ); if (null != resultParameterOrdinals) { rowcount = 0; foreach (int resultParameterOrdinal in resultParameterOrdinals) { OracleParameter resultParameter = _parameterCollection[resultParameterOrdinal]; if (OracleType.Cursor != resultParameter.OracleType) { Debug.Assert(0 < resultParameter.CommandSetResult, "non-ref cursor, non recordsaffected parameter?"); rowcount += (int)resultParameter.Value; } } } else { if (OCI.STMT.OCI_STMT_SELECT != _statementType) { statementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_ROW_COUNT, out rowcount, ErrorHandle); } } } finally { if (null != statementHandle) ReleaseStatementHandle(statementHandle); } } catch { // Prevent exception filters from running in our space throw; } return rowcount; } public int ExecuteOracleNonQuery(out OracleString rowid) { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { OciRowidDescriptor rowidDescriptor = null; int result = ExecuteNonQueryInternal(true, out rowidDescriptor); rowid = GetPersistedRowid( Connection, rowidDescriptor ); OciHandle.SafeDispose(ref rowidDescriptor); return result; } finally { Bid.ScopeLeave(ref hscp); } } public object ExecuteOracleScalar() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#", ObjectID); try { OciRowidDescriptor temp = null; object result = ExecuteScalarInternal(false, false, out temp); OciHandle.SafeDispose(ref temp); // shouldn't be necessary, but just in case... return result; } finally { Bid.ScopeLeave(ref hscp); } } new public OracleDataReader ExecuteReader() { return ExecuteReader(CommandBehavior.Default); } new public OracleDataReader ExecuteReader(CommandBehavior behavior) { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#, behavior=%d{ds.CommandBehavior}\n", ObjectID, (int)behavior); try { OciStatementHandle statementHandle = null;; OracleDataReader reader = null; ArrayList resultParameterOrdinals = null; try { statementHandle = GetStatementHandle(); string statementText = Execute( statementHandle, behavior, out resultParameterOrdinals); // We're about to handle the prepared statement handle (if there was one) // to the data reader object; so we can't really hold on to it any longer. if (statementHandle == _preparedStatementHandle) { // Don't dispose the handle, we still need it! just make our reference to it null. _preparedStatementHandle = null; // } if (null == resultParameterOrdinals) reader = new OracleDataReader(this, statementHandle, statementText, behavior); else reader = new OracleDataReader(this, resultParameterOrdinals, statementText, behavior); } finally { // if we didn't hand the statement to a reader, then release it if (null != statementHandle && (null == reader || null != resultParameterOrdinals)) { ReleaseStatementHandle(statementHandle); } } return reader; } finally { Bid.ScopeLeave(ref hscp); } } override public object ExecuteScalar() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { OciRowidDescriptor temp; object result = ExecuteScalarInternal(true, false, out temp); OciHandle.SafeDispose(ref temp); // shouldn't be necessary, but just in case... return result; } finally { Bid.ScopeLeave(ref hscp); } } private object ExecuteScalarInternal(bool needCLStype, bool needRowid, out OciRowidDescriptor rowidDescriptor) { OciStatementHandle statementHandle = null; object result = null; int rc = 0; try { statementHandle = GetStatementHandle(); ArrayList temp = new ArrayList(); Execute( statementHandle, CommandBehavior.Default, needRowid, out rowidDescriptor, out temp ); if (OCI.STMT.OCI_STMT_SELECT == _statementType) { // We only care about one column; Oracle will handle the fact that the // rest aren't define so don't bother allocating and gathering more column // information than we need. OracleColumn column = new OracleColumn(statementHandle, 0, ErrorHandle, _connection); int columnBufferLength = 0; bool mustRelease = false; bool mustReleaseBindHandle = false; SafeHandle bindHandle = null; column.Describe(ref columnBufferLength, _connection, ErrorHandle); NativeBuffer_RowBuffer columnBuffer = new NativeBuffer_RowBuffer(columnBufferLength, 1); RuntimeHelpers.PrepareConstrainedRegions(); try { columnBuffer.DangerousAddRef(ref mustRelease); column.Bind(statementHandle, columnBuffer, ErrorHandle, 0); column.Rebind(_connection, ref mustReleaseBindHandle, ref bindHandle); // Now fetch one row into the buffer we've provided rc = TracedNativeMethods.OCIStmtFetch( statementHandle, // stmtp ErrorHandle, // errhp 1, // crows OCI.FETCH.OCI_FETCH_NEXT, // orientation OCI.MODE.OCI_DEFAULT // mode ); if ((int)OCI.RETURNCODE.OCI_NO_DATA != rc) { if (0 != rc) Connection.CheckError(ErrorHandle, rc); // Ask the column for the object value (we need to get the Value from // the object to ensure that we have a URT type object, not an Oracle // type object) if (needCLStype) result = column.GetValue(columnBuffer); else result = column.GetOracleValue(columnBuffer); } } finally { if (mustReleaseBindHandle) { bindHandle.DangerousRelease(); } if (mustRelease) { columnBuffer.DangerousRelease(); } } GC.KeepAlive(column); } } finally { if (null != statementHandle) { ReleaseStatementHandle(statementHandle); } } return result; } static internal OracleString GetPersistedRowid(OracleConnection connection, OciRowidDescriptor rowidHandle) { // This method returns an OracleString that holds the base64 string // representation of the rowid, which can be persisted past the lifetime // of this process. OracleString result = OracleString.Null; if (null == rowidHandle) goto done; // null if there isn't a rowid! OciErrorHandle errorHandle = connection.ErrorHandle; NativeBuffer rowidBuffer = connection.GetScratchBuffer(3970); bool mustRelease = false; bool mustReleaseRowidHandle = false; int rc; RuntimeHelpers.PrepareConstrainedRegions(); try { rowidBuffer.DangerousAddRef(ref mustRelease); if (OCI.ClientVersionAtLeastOracle9i) { int bufferLength = rowidBuffer.Length; rc = TracedNativeMethods.OCIRowidToChar(rowidHandle, rowidBuffer, ref bufferLength, errorHandle ); if (0 != rc) { connection.CheckError(errorHandle, rc); } string stringValue = rowidBuffer.PtrToStringAnsi(0, bufferLength); // ROWID's always come back as Ansi... result = new OracleString(stringValue); } else { rowidHandle.DangerousAddRef(ref mustReleaseRowidHandle); OciServiceContextHandle serviceContextHandle = connection.ServiceContextHandle; OciStatementHandle tempHandle = new OciStatementHandle(serviceContextHandle); string tempText = "begin :rowid := :rdesc; end;"; int rdescIndicatorOffset= 0; int rdescLengthOffset = 4; int rdescValueOffset = 8; int rowidIndicatorOffset= 12; int rowidLengthOffset = 16; int rowidValueOffset = 20; try { rc = TracedNativeMethods.OCIStmtPrepare( tempHandle, errorHandle, tempText, OCI.SYNTAX.OCI_NTV_SYNTAX, OCI.MODE.OCI_DEFAULT, connection ); if (0 != rc) connection.CheckError(errorHandle, rc); IntPtr h1; IntPtr h2; // Need to clean these out, since we're re-using the scratch buffer, which // the prepare uses to convert the statement text. rowidBuffer.WriteIntPtr(rdescValueOffset, rowidHandle.DangerousGetHandle()); rowidBuffer.WriteInt32 (rdescIndicatorOffset, 0); rowidBuffer.WriteInt32 (rdescLengthOffset, 4); rowidBuffer.WriteInt32 (rowidIndicatorOffset, 0); rowidBuffer.WriteInt32 (rowidLengthOffset, 3950); rc = TracedNativeMethods.OCIBindByName( tempHandle, out h1, errorHandle, "rowid", 5, rowidBuffer.DangerousGetDataPtr(rowidValueOffset), 3950, OCI.DATATYPE.VARCHAR2, rowidBuffer.DangerousGetDataPtr(rowidIndicatorOffset), rowidBuffer.DangerousGetDataPtr(rowidLengthOffset), OCI.MODE.OCI_DEFAULT ); if (0 != rc) connection.CheckError(errorHandle, rc); rc = TracedNativeMethods.OCIBindByName( tempHandle, out h2, errorHandle, "rdesc", 5, rowidBuffer.DangerousGetDataPtr(rdescValueOffset), 4, OCI.DATATYPE.ROWID_DESC, rowidBuffer.DangerousGetDataPtr(rdescIndicatorOffset), rowidBuffer.DangerousGetDataPtr(rdescLengthOffset), OCI.MODE.OCI_DEFAULT ); if (0 != rc) connection.CheckError(errorHandle, rc); rc = TracedNativeMethods.OCIStmtExecute( serviceContextHandle, // svchp tempHandle, // stmtp errorHandle, // errhp 1, // iters OCI.MODE.OCI_DEFAULT // mode ); if (0 != rc) connection.CheckError(errorHandle, rc); if (rowidBuffer.ReadInt16(rowidIndicatorOffset) == (Int16)OCI.INDICATOR.ISNULL) goto done; result = new OracleString( rowidBuffer, rowidValueOffset, rowidLengthOffset, MetaType.GetMetaTypeForType(OracleType.RowId), connection, false, // it's not unicode! true ); GC.KeepAlive(rowidHandle); } finally { OciHandle.SafeDispose(ref tempHandle); } } } finally{ if (mustReleaseRowidHandle) { rowidHandle.DangerousRelease(); } if (mustRelease) { rowidBuffer.DangerousRelease(); } } done: return result; } private OciStatementHandle GetStatementHandle() { // return either the prepared statement handle or a new one if nothign // is prepared. if (ConnectionIsClosed) { throw ADP.ClosedConnectionError(); } if (null != _preparedStatementHandle) { // When we prepare the statement, we keep track of it's closed // count; if the connection has been closed since we prepared, then // the statement handle is no longer valid and must be tossed. if (_connection.CloseCount == _preparedAtCloseCount) { return _preparedStatementHandle; } _preparedStatementHandle.Dispose(); _preparedStatementHandle = null; } return new OciStatementHandle(ServiceContextHandle); } static internal bool IsBehavior(CommandBehavior value, CommandBehavior condition) { return (condition == (condition & value)); } override public void Prepare() { OracleConnection.ExecutePermission.Demand(); IntPtr hscp; Bid.ScopeEnter(out hscp, " %d#\n", ObjectID); try { if (ConnectionIsClosed) { throw ADP.ClosedConnectionError(); } if (CommandType.Text == CommandType) { OciStatementHandle preparedStatementHandle = GetStatementHandle(); int preparedAtCloseCount = _connection.CloseCount; string statementText = StatementText; int rc = TracedNativeMethods.OCIStmtPrepare( preparedStatementHandle, ErrorHandle, statementText, OCI.SYNTAX.OCI_NTV_SYNTAX, OCI.MODE.OCI_DEFAULT, Connection ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } short tempub2; preparedStatementHandle.GetAttribute(OCI.ATTR.OCI_ATTR_STMT_TYPE, out tempub2, ErrorHandle); _statementType = (OCI.STMT)tempub2; if (OCI.STMT.OCI_STMT_SELECT == _statementType) { rc = TracedNativeMethods.OCIStmtExecute( _connection.ServiceContextHandle, // svchp preparedStatementHandle, // stmtp ErrorHandle, // errhp 0, // iters OCI.MODE.OCI_DESCRIBE_ONLY // mode ); if (0 != rc) { Connection.CheckError(ErrorHandle, rc); } } if (preparedStatementHandle != _preparedStatementHandle) { OciHandle.SafeDispose(ref _preparedStatementHandle); } _preparedStatementHandle = preparedStatementHandle; _preparedAtCloseCount = preparedAtCloseCount; } else if (null != _preparedStatementHandle) { OciHandle.SafeDispose(ref _preparedStatementHandle); } } finally { Bid.ScopeLeave(ref hscp); } } private void PropertyChanging() { // common routine used to get rid of a statement handle; it disposes // of the handle unless it's the prepared handle if (null != _preparedStatementHandle) { _preparedStatementHandle.Dispose(); // the existing prepared statement is no longer valid _preparedStatementHandle = null; } } private void ReleaseStatementHandle (OciStatementHandle statementHandle) { // common routine used to get rid of a statement handle; it disposes // of the handle unless it's the prepared handle if (ConnectionState.Closed != Connection.State && _preparedStatementHandle != statementHandle) { OciHandle.SafeDispose(ref statementHandle); } } }; } // File provided for Reference Use Only by Microsoft Corporation (c) 2007.
Link Menu

This book is available now!
Buy at Amazon US or
Buy at Amazon UK
- ContainerFilterService.cs
- ImmutablePropertyDescriptorGridEntry.cs
- DLinqAssociationProvider.cs
- DisplayInformation.cs
- StrokeSerializer.cs
- SiteMapPath.cs
- FunctionDetailsReader.cs
- TableParagraph.cs
- XNodeNavigator.cs
- Int16Storage.cs
- ServiceOperation.cs
- ValidatorCollection.cs
- CatalogPart.cs
- ConnectionPoint.cs
- FtpCachePolicyElement.cs
- ReaderWriterLock.cs
- SettingsPropertyIsReadOnlyException.cs
- Vector3DAnimationBase.cs
- MetadataHelper.cs
- IntSecurity.cs
- GeometryModel3D.cs
- ComponentSerializationService.cs
- HyperLinkField.cs
- ApplicationFileParser.cs
- Helpers.cs
- ActivityMarkupSerializationProvider.cs
- FixUp.cs
- OleDbParameter.cs
- AuthenticationSection.cs
- DescriptionAttribute.cs
- RIPEMD160.cs
- MetafileHeader.cs
- UseLicense.cs
- DataSourceCacheDurationConverter.cs
- SkewTransform.cs
- PeerHelpers.cs
- ListBoxItem.cs
- DataRecordInfo.cs
- CompatibleComparer.cs
- SystemIPInterfaceProperties.cs
- OutgoingWebRequestContext.cs
- CqlErrorHelper.cs
- IIS7UserPrincipal.cs
- MeasureData.cs
- MenuItemCollection.cs
- SqlGatherProducedAliases.cs
- FormViewUpdatedEventArgs.cs
- MdiWindowListItemConverter.cs
- HostingPreferredMapPath.cs
- DiscoveryEndpointValidator.cs
- NamedObject.cs
- RoleManagerModule.cs
- LexicalChunk.cs
- DBCSCodePageEncoding.cs
- FixedPage.cs
- CharAnimationUsingKeyFrames.cs
- InputLanguage.cs
- TypeListConverter.cs
- BrushValueSerializer.cs
- RuntimeWrappedException.cs
- TerminatorSinks.cs
- _HeaderInfo.cs
- SafeRegistryHandle.cs
- DecoderNLS.cs
- PeerNeighborManager.cs
- URLMembershipCondition.cs
- InstanceCollisionException.cs
- WinInetCache.cs
- BitmapInitialize.cs
- OleDbError.cs
- CannotUnloadAppDomainException.cs
- SqlDataRecord.cs
- InvalidProgramException.cs
- DataListItem.cs
- DataGridColumnCollection.cs
- ProjectionPath.cs
- MailDefinitionBodyFileNameEditor.cs
- GrammarBuilderWildcard.cs
- AccessibleObject.cs
- CompilationLock.cs
- AnnotationHighlightLayer.cs
- WebPartCloseVerb.cs
- FieldBuilder.cs
- InstalledFontCollection.cs
- XmlNodeReader.cs
- TreeNodeBindingDepthConverter.cs
- CertificateManager.cs
- DeclarationUpdate.cs
- MappedMetaModel.cs
- SerializerProvider.cs
- ParameterElement.cs
- AvTraceDetails.cs
- XpsFilter.cs
- SymLanguageType.cs
- TypographyProperties.cs
- SqlInternalConnection.cs
- TimeZone.cs
- EntityContainer.cs
- SqlSupersetValidator.cs
- MultiDataTrigger.cs