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
- CodeGeneratorOptions.cs
- mda.cs
- MissingMemberException.cs
- SecureStringHasher.cs
- QilLiteral.cs
- DbBuffer.cs
- ExpressionPrinter.cs
- ClientTargetCollection.cs
- RequestSecurityTokenResponse.cs
- MsmqIntegrationAppDomainProtocolHandler.cs
- DynamicDataManager.cs
- DataConnectionHelper.cs
- RoutingUtilities.cs
- XmlAttributeAttribute.cs
- WindowsGraphics.cs
- Pkcs7Recipient.cs
- ApplicationActivator.cs
- ListenerAdaptersInstallComponent.cs
- FormViewModeEventArgs.cs
- ScheduleChanges.cs
- GeneralTransform3D.cs
- DocumentGridPage.cs
- TypeDescriptor.cs
- XmlObjectSerializer.cs
- Group.cs
- Encoding.cs
- Msec.cs
- MulticastNotSupportedException.cs
- MD5CryptoServiceProvider.cs
- TTSEngineProxy.cs
- MaskedTextBoxTextEditor.cs
- SqlFlattener.cs
- XmlDomTextWriter.cs
- HtmlInputButton.cs
- TagPrefixAttribute.cs
- ValueType.cs
- RuntimeTransactionHandle.cs
- HitTestWithGeometryDrawingContextWalker.cs
- AnnotationResourceChangedEventArgs.cs
- HiddenFieldPageStatePersister.cs
- MethodBuilder.cs
- TCPClient.cs
- LoginUtil.cs
- OSFeature.cs
- WebPartAddingEventArgs.cs
- KnownTypes.cs
- SoapSchemaImporter.cs
- DeflateEmulationStream.cs
- PeerPresenceInfo.cs
- ManagedFilter.cs
- TypeContext.cs
- Transform3DCollection.cs
- EncodingDataItem.cs
- CommentEmitter.cs
- SmiGettersStream.cs
- FixUp.cs
- BrowserDefinition.cs
- Msmq.cs
- RecognizeCompletedEventArgs.cs
- InstanceStore.cs
- DbConnectionPoolOptions.cs
- ReadOnlyHierarchicalDataSourceView.cs
- HttpHostedTransportConfiguration.cs
- UserPreferenceChangedEventArgs.cs
- Normalization.cs
- ReachFixedPageSerializerAsync.cs
- MaterializeFromAtom.cs
- ObjectParameterCollection.cs
- NumericPagerField.cs
- SmiConnection.cs
- Slider.cs
- TypedReference.cs
- Rotation3D.cs
- InputLangChangeRequestEvent.cs
- Brush.cs
- EditorAttribute.cs
- FindCriteriaCD1.cs
- StructuralObject.cs
- UInt16Converter.cs
- CommonProperties.cs
- Maps.cs
- PointAnimationUsingKeyFrames.cs
- GridViewUpdatedEventArgs.cs
- DllNotFoundException.cs
- XsdDuration.cs
- ReturnType.cs
- SmiGettersStream.cs
- FieldToken.cs
- DoubleUtil.cs
- CaseInsensitiveHashCodeProvider.cs
- SqlBuffer.cs
- KeyboardNavigation.cs
- SchemaCollectionPreprocessor.cs
- SiteMapSection.cs
- Completion.cs
- ObjectReaderCompiler.cs
- PropertyInformationCollection.cs
- ApplicationException.cs
- RSAPKCS1SignatureFormatter.cs
- ArithmeticException.cs