|
//------------------------------------------------------------------------------
// <copyright file="OleDbConnectionInternal.cs" company="Microsoft">
// Copyright (c) Microsoft Corporation. All rights reserved.
// </copyright>
// <owner current="true" primary="true">Microsoft</owner>
// <owner current="true" primary="false">Microsoft</owner>
//------------------------------------------------------------------------------
namespace System.Data.OleDb {
using System;
using System.Collections.Generic;
using System.Data;
using System.Data.Common;
using System.Data.ProviderBase;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Text;
using System.Threading;
using SysES = System.EnterpriseServices;
using SysTx = System.Transactions;
sealed internal class OleDbConnectionInternal : DbConnectionInternal, IDisposable {
static private volatile OleDbServicesWrapper idataInitialize;
static private object dataInitializeLock = new object();
internal readonly OleDbConnectionString ConnectionString; // parsed connection string attributes
// A SafeHandle is used instead of a RCW because we need to fake the CLR into not marshalling
// OLE DB Services is marked apartment thread, but it actually supports/requires free-threading.
// However the CLR doesn't know this and attempts to marshal the interfaces back to their original context.
// But the OLE DB doesn't marshal very well if at all. Our workaround is based on the fact
// OLE DB is free-threaded and allows the workaround.
// Creating DataSource/Session would requiring marshalling DataLins to its original context
// and has a severe performance impact (when working with transactions), hence our workaround to not Marshal.
// Creating a Command would requiring marshalling Session to its original context and
// actually doesn't work correctly, without our workaround you must execute the command in
// the same context of the connection open. This doesn't work for pooled objects that contain
// an open OleDbConnection.
// We don't do extra work at this time to allow the DataReader to be used in a different context
// from which the command was executed in. See WebData 64320, IRowset.GetNextRows will throw InvalidCastException
// In V1.0, we worked around the performance impact of creating a DataSource/Session using
// WrapIUnknownWithComObject which creates a new RCW without searching for existing RCW
// effectively faking out the CLR into thinking the call is in the correct context.
// We also would use Marshal.ReleaseComObject to force the release of the 'temporary' RCW.
// In V1.1, we worked around the CreateCommand issue with the same WrapIUnknownWithComObject trick.
// In V2.0, the performance of using WrapIUnknownWithComObject & ReleaseComObject severly degraded.
// Using a SafeHandle (for lifetime control) and a delegate to call the apporiate COM method
// offered much better performance.
// the "Data Source object".
private readonly DataSourceWrapper _datasrcwrp;
// the "Session object".
private readonly SessionWrapper _sessionwrp;
private WeakReference weakTransaction;
// When set to true the current connection is enlisted in a transaction that must be
// un-enlisted during Deactivate.
private bool _unEnlistDuringDeactivate;
internal OleDbConnectionInternal(OleDbConnectionString constr, OleDbConnection connection) : base () {
#if DEBUG
try { // use this to help validate this object is only created after the following permission has been previously demanded in the current codepath
if (null != connection) {
connection.UserConnectionOptions.DemandPermission();
}
else {
constr.DemandPermission();
}
}
catch(System.Security.SecurityException) {
System.Diagnostics.Debug.Assert(false, "unexpected SecurityException for current codepath");
throw;
}
#endif
Debug.Assert((null != constr) && !constr.IsEmpty, "empty connectionstring");
ConnectionString = constr;
if (constr.PossiblePrompt && !System.Environment.UserInteractive) {
throw ODB.PossiblePromptNotUserInteractive();
}
try {
// this is the native DataLinks object which pools the native datasource/session
OleDbServicesWrapper wrapper = OleDbConnectionInternal.GetObjectPool();
_datasrcwrp = new DataSourceWrapper();
// DataLinks wrapper will call IDataInitialize::GetDataSource to create the DataSource
// uses constr.ActualConnectionString, no InfoMessageEvent checking
wrapper.GetDataSource(constr, ref _datasrcwrp);
Debug.Assert(!_datasrcwrp.IsInvalid, "bad DataSource");
// initialization is delayed because of OleDbConnectionStringBuilder only wants
// pre-Initialize IDBPropertyInfo & IDBProperties on the data source
if (null != connection) {
_sessionwrp = new SessionWrapper();
// From the DataSource object, will call IDBInitialize.Initialize & IDBCreateSession.CreateSession
// We always need both called so we use a single call for a single DangerousAddRef/DangerousRelease pair.
OleDbHResult hr = _datasrcwrp.InitializeAndCreateSession(constr, ref _sessionwrp);
// process the HResult here instead of from the SafeHandle because the possibility
// of an InfoMessageEvent.
if ((0 <= hr) && !_sessionwrp.IsInvalid) { // process infonessage events
OleDbConnection.ProcessResults(hr, connection, connection);
}
else {
Exception e = OleDbConnection.ProcessResults(hr, null, null);
Debug.Assert(null != e, "CreateSessionError");
throw e;
}
Debug.Assert(!_sessionwrp.IsInvalid, "bad Session");
}
}
catch {
if (null != _sessionwrp) {
_sessionwrp.Dispose();
_sessionwrp = null;
}
if (null != _datasrcwrp) {
_datasrcwrp.Dispose();
_datasrcwrp = null;
}
throw;
}
}
internal OleDbConnection Connection {
get {
return (OleDbConnection)Owner;
}
}
internal bool HasSession {
get {
return (null != _sessionwrp);
}
}
internal OleDbTransaction LocalTransaction {
get {
OleDbTransaction result = null;
if (null != weakTransaction) {
result = ((OleDbTransaction)weakTransaction.Target);
}
return result;
}
set {
weakTransaction = null;
if (null != value) {
weakTransaction = new WeakReference((OleDbTransaction)value);
}
}
}
private string Provider {
get { return ConnectionString.Provider; }
}
override public string ServerVersion { // MDAC 55481
// consider making a method, not a property
get {
object value = GetDataSourceValue(OleDbPropertySetGuid.DataSourceInfo, ODB.DBPROP_DBMSVER);
return Convert.ToString(value, CultureInfo.InvariantCulture);
}
}
// grouping the native OLE DB casts togther by required interfaces and optional interfaces, connection then session
// want these to be methods, not properties otherwise they appear in VS7 managed debugger which attempts to evaluate them
// required interface, safe cast
internal IDBPropertiesWrapper IDBProperties() {
Debug.Assert(null != _datasrcwrp, "IDBProperties: null datasource");
return _datasrcwrp.IDBProperties(this);
}
// required interface, safe cast
internal IOpenRowsetWrapper IOpenRowset() {
Debug.Assert(null != _datasrcwrp, "IOpenRowset: null datasource");
Debug.Assert(null != _sessionwrp, "IOpenRowset: null session");
return _sessionwrp.IOpenRowset(this);
}
// optional interface, unsafe cast
private IDBInfoWrapper IDBInfo() {
Debug.Assert(null != _datasrcwrp, "IDBInfo: null datasource");
return _datasrcwrp.IDBInfo(this);
}
// optional interface, unsafe cast
internal IDBSchemaRowsetWrapper IDBSchemaRowset() {
Debug.Assert(null != _datasrcwrp, "IDBSchemaRowset: null datasource");
Debug.Assert(null != _sessionwrp, "IDBSchemaRowset: null session");
return _sessionwrp.IDBSchemaRowset(this);
}
// optional interface, unsafe cast
internal ITransactionJoinWrapper ITransactionJoin() {
Debug.Assert(null != _datasrcwrp, "ITransactionJoin: null datasource");
Debug.Assert(null != _sessionwrp, "ITransactionJoin: null session");
return _sessionwrp.ITransactionJoin(this);
}
// optional interface, unsafe cast
internal UnsafeNativeMethods.ICommandText ICommandText() {
Debug.Assert(null != _datasrcwrp, "IDBCreateCommand: null datasource");
Debug.Assert(null != _sessionwrp, "IDBCreateCommand: null session");
object icommandText = null;
OleDbHResult hr = _sessionwrp.CreateCommand(ref icommandText);
Debug.Assert((0 <= hr) || (null == icommandText), "CreateICommandText: error with ICommandText");
if (hr < 0) {
if (OleDbHResult.E_NOINTERFACE != hr) { // MDAC 57856
ProcessResults(hr);
}
else {
SafeNativeMethods.Wrapper.ClearErrorInfo();
}
}
return (UnsafeNativeMethods.ICommandText)icommandText;
}
override protected void Activate(SysTx.Transaction transaction) {
throw ADP.NotSupported();
}
override public DbTransaction BeginTransaction(IsolationLevel isolationLevel) {
OleDbConnection.ExecutePermission.Demand();
OleDbConnection outerConnection = Connection;
if (null != LocalTransaction) {
throw ADP.ParallelTransactionsNotSupported(outerConnection);
}
object unknown = null;
OleDbTransaction transaction;
try {
transaction = new OleDbTransaction(outerConnection, null, isolationLevel);
Bid.Trace("<oledb.IUnknown.QueryInterface|API|OLEDB|session> %d#, ITransactionLocal\n", ObjectID);
Debug.Assert(null != _datasrcwrp, "ITransactionLocal: null datasource");
Debug.Assert(null != _sessionwrp, "ITransactionLocal: null session");
unknown = _sessionwrp.ComWrapper();
UnsafeNativeMethods.ITransactionLocal value = (unknown as UnsafeNativeMethods.ITransactionLocal);
if (null == value) {
throw ODB.TransactionsNotSupported(Provider, (Exception)null);
}
transaction.BeginInternal(value);
}
finally {
if (null != unknown) {
Marshal.ReleaseComObject(unknown);
}
}
LocalTransaction = transaction;
return transaction;
}
override protected DbReferenceCollection CreateReferenceCollection() {
return new OleDbReferenceCollection();
}
override protected void Deactivate() { // used by both managed and native pooling
NotifyWeakReference(OleDbReferenceCollection.Closing);
if (_unEnlistDuringDeactivate) {
// Un-enlist transaction as OLEDB connection pool is unaware of managed transactions.
EnlistTransactionInternal(null);
}
OleDbTransaction transaction = LocalTransaction;
if (null != transaction) {
LocalTransaction = null;
// required to rollback any transactions on this connection
// before releasing the back to the oledb connection pool
transaction.Dispose();
}
}
public override void Dispose() { // MDAC 65459
Debug.Assert(null == LocalTransaction, "why was Deactivate not called first");
if (null != _sessionwrp) {
_sessionwrp.Dispose();
}
if (null != _datasrcwrp) {
_datasrcwrp.Dispose();
}
base.Dispose();
}
override public void EnlistTransaction(SysTx.Transaction transaction) { // MDAC 78997
OleDbConnection.VerifyExecutePermission();
OleDbConnection outerConnection = Connection;
if (null != LocalTransaction) {
throw ADP.LocalTransactionPresent();
}
EnlistTransactionInternal(transaction);
}
internal void EnlistTransactionInternal(SysTx.Transaction transaction) {
OleDbConnection.VerifyExecutePermission();
SysTx.IDtcTransaction oleTxTransaction = ADP.GetOletxTransaction(transaction);
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<oledb.ITransactionJoin.JoinTransaction|API|OLEDB> %d#\n", ObjectID);
try {
using(ITransactionJoinWrapper transactionJoin = ITransactionJoin()) {
if (null == transactionJoin.Value) {
throw ODB.TransactionsNotSupported(Provider, (Exception)null);
}
transactionJoin.Value.JoinTransaction(oleTxTransaction, (int) IsolationLevel.Unspecified, 0, IntPtr.Zero);
_unEnlistDuringDeactivate = (null != transaction);
}
}
finally {
Bid.ScopeLeave(ref hscp);
}
EnlistedTransaction = transaction;
}
internal object GetDataSourceValue(Guid propertySet, int propertyID) {
object value = GetDataSourcePropertyValue(propertySet, propertyID);
if ((value is OleDbPropertyStatus) || Convert.IsDBNull(value)) {
value = null;
}
return value;
}
internal object GetDataSourcePropertyValue(Guid propertySet, int propertyID) {
OleDbHResult hr;
tagDBPROP[] dbprops;
using(IDBPropertiesWrapper idbProperties = IDBProperties()) {
using(PropertyIDSet propidset = new PropertyIDSet(propertySet, propertyID)) {
using(DBPropSet propset = new DBPropSet(idbProperties.Value, propidset, out hr)) {
if (hr < 0) {
// VSDD 621427: OLEDB Data Reader masks provider specific errors by raising "Internal .Net Framework Data Provider error 30."
// DBPropSet c-tor will register the exception and it will be raised at GetPropertySet call in case of failure
SafeNativeMethods.Wrapper.ClearErrorInfo();
}
dbprops = propset.GetPropertySet(0, out propertySet);
}
}
}
if (OleDbPropertyStatus.Ok == dbprops[0].dwStatus) {
return dbprops[0].vValue;
}
return dbprops[0].dwStatus;
}
internal DataTable BuildInfoLiterals() {
using(IDBInfoWrapper wrapper = IDBInfo()) {
UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
if (null == dbInfo) {
return null;
}
DataTable table = new DataTable("DbInfoLiterals");
table.Locale = CultureInfo.InvariantCulture;
DataColumn literalName = new DataColumn("LiteralName", typeof(String));
DataColumn literalValue = new DataColumn("LiteralValue", typeof(String));
DataColumn invalidChars = new DataColumn("InvalidChars", typeof(String));
DataColumn invalidStart = new DataColumn("InvalidStartingChars", typeof(String));
DataColumn literal = new DataColumn("Literal", typeof(Int32));
DataColumn maxlen = new DataColumn("Maxlen", typeof(Int32));
table.Columns.Add(literalName);
table.Columns.Add(literalValue);
table.Columns.Add(invalidChars);
table.Columns.Add(invalidStart);
table.Columns.Add(literal);
table.Columns.Add(maxlen);
OleDbHResult hr;
int literalCount = 0;
IntPtr literalInfo = ADP.PtrZero;
using(DualCoTaskMem handle = new DualCoTaskMem(dbInfo, null, out literalCount, out literalInfo, out hr)) {
// All literals were either invalid or unsupported. The provider allocates memory for *prgLiteralInfo and sets the value of the fSupported element in all of the structures to FALSE. The consumer frees this memory when it no longer needs the information.
if (OleDbHResult.DB_E_ERRORSOCCURRED != hr) {
long offset = literalInfo.ToInt64();
tagDBLITERALINFO tag = new tagDBLITERALINFO();
for (int i = 0; i < literalCount; ++i, offset += ODB.SizeOf_tagDBLITERALINFO) {
Marshal.PtrToStructure((IntPtr)offset, tag);
DataRow row = table.NewRow();
row[literalName ] = ((OleDbLiteral) tag.it).ToString();
row[literalValue] = tag.pwszLiteralValue;
row[invalidChars] = tag.pwszInvalidChars;
row[invalidStart] = tag.pwszInvalidStartingChars;
row[literal ] = tag.it;
row[maxlen ] = tag.cchMaxLen;
table.Rows.Add(row);
row.AcceptChanges();
}
if (hr < 0) { // ignore infomsg
ProcessResults(hr);
}
}
else {
SafeNativeMethods.Wrapper.ClearErrorInfo();
}
}
return table;
}
}
internal DataTable BuildInfoKeywords() {
DataTable table = new DataTable(ODB.DbInfoKeywords);
table.Locale = CultureInfo.InvariantCulture;
DataColumn keyword = new DataColumn(ODB.Keyword, typeof(String));
table.Columns.Add(keyword);
if(!AddInfoKeywordsToTable(table,keyword)){
table = null;
}
return table;
}
internal bool AddInfoKeywordsToTable(DataTable table, DataColumn keyword) {
using(IDBInfoWrapper wrapper = IDBInfo()) {
UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
if (null == dbInfo) {
return false;
}
OleDbHResult hr;
string keywords;
Bid.Trace("<oledb.IDBInfo.GetKeywords|API|OLEDB> %d#\n", ObjectID);
hr = dbInfo.GetKeywords(out keywords);
Bid.Trace("<oledb.IDBInfo.GetKeywords|API|OLEDB|RET> %08X{HRESULT}\n", hr);
if (hr < 0) { // ignore infomsg
ProcessResults(hr);
}
if (null != keywords) {
string[] values = keywords.Split(new char[1] { ',' });
for (int i = 0; i < values.Length; ++i) {
DataRow row = table.NewRow();
row[keyword] = values[i];
table.Rows.Add(row);
row.AcceptChanges();
}
}
return true;
}
}
internal DataTable BuildSchemaGuids() {
DataTable table = new DataTable(ODB.SchemaGuids);
table.Locale = CultureInfo.InvariantCulture;
DataColumn schemaGuid = new DataColumn(ODB.Schema, typeof(Guid));
DataColumn restrictionSupport = new DataColumn(ODB.RestrictionSupport, typeof(Int32));
table.Columns.Add(schemaGuid);
table.Columns.Add(restrictionSupport);
SchemaSupport[] supportedSchemas = GetSchemaRowsetInformation();
if (null != supportedSchemas) {
object[] values = new object[2];
table.BeginLoadData();
for (int i = 0; i < supportedSchemas.Length; ++i) {
values[0] = supportedSchemas[i]._schemaRowset;
values[1] = supportedSchemas[i]._restrictions;
table.LoadDataRow(values, LoadOption.OverwriteChanges);
}
table.EndLoadData();
}
return table;
}
internal string GetLiteralInfo(int literal) {
using(IDBInfoWrapper wrapper = IDBInfo()) {
UnsafeNativeMethods.IDBInfo dbInfo = wrapper.Value;
if (null == dbInfo) {
return null;
}
string literalValue = null;
IntPtr literalInfo = ADP.PtrZero;
int literalCount = 0;
OleDbHResult hr;
using(DualCoTaskMem handle = new DualCoTaskMem(dbInfo, new int[1] { literal }, out literalCount, out literalInfo, out hr)) {
// All literals were either invalid or unsupported. The provider allocates memory for *prgLiteralInfo and sets the value of the fSupported element in all of the structures to FALSE. The consumer frees this memory when it no longer needs the information.
if (OleDbHResult.DB_E_ERRORSOCCURRED != hr) {
if ((1 == literalCount) && Marshal.ReadInt32(literalInfo, ODB.OffsetOf_tagDBLITERALINFO_it) == literal) { // WebData 98612
literalValue = Marshal.PtrToStringUni(Marshal.ReadIntPtr(literalInfo, 0));
}
if (hr < 0) { // ignore infomsg
ProcessResults(hr);
}
}
else {
SafeNativeMethods.Wrapper.ClearErrorInfo();
}
}
return literalValue;
}
}
internal SchemaSupport[] GetSchemaRowsetInformation() {
OleDbConnectionString constr = ConnectionString;
SchemaSupport[] supportedSchemas = constr.SchemaSupport;
if (null != supportedSchemas) {
return supportedSchemas;
}
using(IDBSchemaRowsetWrapper wrapper = IDBSchemaRowset()) {
UnsafeNativeMethods.IDBSchemaRowset dbSchemaRowset = wrapper.Value;
if (null == dbSchemaRowset) {
return null; // IDBSchemaRowset not supported
}
OleDbHResult hr;
int schemaCount = 0;
IntPtr schemaGuids = ADP.PtrZero;
IntPtr schemaRestrictions = ADP.PtrZero;
using(DualCoTaskMem safehandle = new DualCoTaskMem(dbSchemaRowset, out schemaCount, out schemaGuids, out schemaRestrictions, out hr)) {
dbSchemaRowset = null;
if (hr < 0) { // ignore infomsg
ProcessResults(hr);
}
supportedSchemas = new SchemaSupport[schemaCount];
if (ADP.PtrZero != schemaGuids) {
for (int i = 0, offset = 0; i < supportedSchemas.Length; ++i, offset += ODB.SizeOf_Guid) {
IntPtr ptr = ADP.IntPtrOffset(schemaGuids, i * ODB.SizeOf_Guid);
supportedSchemas[i]._schemaRowset = (Guid) Marshal.PtrToStructure(ptr, typeof(Guid));
}
}
if (ADP.PtrZero != schemaRestrictions) {
for (int i = 0; i < supportedSchemas.Length; ++i) {
supportedSchemas[i]._restrictions = Marshal.ReadInt32(schemaRestrictions, i * 4);
}
}
}
constr.SchemaSupport = supportedSchemas;
return supportedSchemas;
}
}
internal DataTable GetSchemaRowset(Guid schema, object[] restrictions) {
IntPtr hscp;
Bid.ScopeEnter(out hscp, "<oledb.OleDbConnectionInternal.GetSchemaRowset|INFO> %d#, schema=%ls, restrictions\n", ObjectID, schema);
try {
if (null == restrictions) { // MDAC 62243
restrictions = new object[0];
}
DataTable dataTable = null;
using(IDBSchemaRowsetWrapper wrapper = IDBSchemaRowset()) {
UnsafeNativeMethods.IDBSchemaRowset dbSchemaRowset = wrapper.Value;
if (null == dbSchemaRowset) {
throw ODB.SchemaRowsetsNotSupported(Provider);
}
UnsafeNativeMethods.IRowset rowset = null;
OleDbHResult hr;
Bid.Trace("<oledb.IDBSchemaRowset.GetRowset|API|OLEDB> %d#\n", ObjectID);
hr = dbSchemaRowset.GetRowset(ADP.PtrZero, ref schema, restrictions.Length, restrictions, ref ODB.IID_IRowset, 0, ADP.PtrZero, out rowset);
Bid.Trace("<oledb.IDBSchemaRowset.GetRowset|API|OLEDB|RET> %08X{HRESULT}\n", hr);
if (hr < 0) { // ignore infomsg
ProcessResults(hr);
}
if (null != rowset) {
using(OleDbDataReader dataReader = new OleDbDataReader(Connection, null, 0, CommandBehavior.Default)) {
dataReader.InitializeIRowset(rowset, ChapterHandle.DB_NULL_HCHAPTER, IntPtr.Zero);
dataReader.BuildMetaInfo();
dataReader.HasRowsRead();
dataTable = new DataTable();
dataTable.Locale = CultureInfo.InvariantCulture;
dataTable.TableName = OleDbSchemaGuid.GetTextFromValue(schema);
OleDbDataAdapter.FillDataTable(dataReader, dataTable);
}
}
return dataTable;
}
}
finally {
Bid.ScopeLeave(ref hscp);
}
}
// returns true if there is an active data reader on the specified command
internal bool HasLiveReader(OleDbCommand cmd) {
OleDbDataReader reader = null;
if (null != ReferenceCollection) {
reader = ReferenceCollection.FindItem<OleDbDataReader>(OleDbReferenceCollection.DataReaderTag, (dataReader) => cmd == dataReader.Command);
}
return (reader != null);
}
private void ProcessResults(OleDbHResult hr) {
OleDbConnection connection = Connection; // get value from weakref only once
Exception e = OleDbConnection.ProcessResults(hr, connection, connection);
if (null != e) { throw e; }
}
internal bool SupportSchemaRowset(Guid schema) {
SchemaSupport[] schemaSupport = GetSchemaRowsetInformation();
if (null != schemaSupport) { // MDAC 68385
for (int i = 0; i < schemaSupport.Length; ++i) {
if (schema == schemaSupport[i]._schemaRowset) {
return true;
}
}
}
return false;
}
[SecurityPermission(SecurityAction.Assert, Flags=SecurityPermissionFlag.UnmanagedCode)]
static private object CreateInstanceDataLinks() {
Type datalink = Type.GetTypeFromCLSID(ODB.CLSID_DataLinks, true);
return Activator.CreateInstance(datalink, System.Reflection.BindingFlags.Public|System.Reflection.BindingFlags.Instance, null, null, CultureInfo.InvariantCulture, null);
}
// @devnote: should be multithread safe access to OleDbConnection.idataInitialize,
// though last one wins for setting variable. It may be different objects, but
// OLE DB will ensure I'll work with just the single pool
static private OleDbServicesWrapper GetObjectPool() {
OleDbServicesWrapper wrapper = OleDbConnectionInternal.idataInitialize;
if (null == wrapper) {
lock(dataInitializeLock) {
wrapper = OleDbConnectionInternal.idataInitialize;
if (null == wrapper) {
VersionCheck();
object datalinks;
try {
datalinks = CreateInstanceDataLinks();
}
catch (Exception e) {
//
if (!ADP.IsCatchableExceptionType(e)) {
throw;
}
throw ODB.MDACNotAvailable(e);
}
if (null == datalinks) {
throw ODB.MDACNotAvailable(null);
}
wrapper = new OleDbServicesWrapper(datalinks);
OleDbConnectionInternal.idataInitialize = wrapper;
}
}
}
Debug.Assert(null != wrapper, "GetObjectPool: null dataInitialize");
return wrapper;
}
static private void VersionCheck() {
// $
if (ApartmentState.Unknown == Thread.CurrentThread.GetApartmentState()) {
SetMTAApartmentState();
}
ADP.CheckVersionMDAC(false);
}
[System.Runtime.CompilerServices.MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.NoInlining)]
static private void SetMTAApartmentState() {
// we are defaulting to a multithread apartment state
Thread.CurrentThread.SetApartmentState(ApartmentState.MTA);
}
// @devnote: should be multithread safe
static public void ReleaseObjectPool() {
OleDbConnectionInternal.idataInitialize = null;
}
internal OleDbTransaction ValidateTransaction(OleDbTransaction transaction, string method) {
if (null != this.weakTransaction) {
OleDbTransaction head = (OleDbTransaction) this.weakTransaction.Target;
if ((null != head) && this.weakTransaction.IsAlive) {
head = OleDbTransaction.TransactionUpdate(head);
// either we are wrong or finalize was called and object still alive
Debug.Assert(null != head, "unexcpted Transaction state");
}
// else transaction has finalized on user
if (null != head) {
if (null == transaction) {
// valid transaction exists and cmd doesn't have it
throw ADP.TransactionRequired(method);
}
else {
OleDbTransaction tail = OleDbTransaction.TransactionLast(head);
if (tail != transaction) {
if (tail.Connection != transaction.Connection) {
throw ADP.TransactionConnectionMismatch();
}
// else cmd has incorrect transaction
throw ADP.TransactionCompleted();
}
// else cmd has correct transaction
return transaction;
}
}
else { // cleanup for Finalized transaction
this.weakTransaction = null;
}
}
else if ((null != transaction) && (null != transaction.Connection)) { // MDAC 72706
throw ADP.TransactionConnectionMismatch();
}
// else no transaction and cmd is correct
// MDAC 61649
// if transactionObject is from this connection but zombied
// and no transactions currently exists - then ignore the bogus object
return null;
}
internal Dictionary<string,OleDbPropertyInfo> GetPropertyInfo(Guid[] propertySets) {
bool isopen = HasSession;
OleDbConnectionString constr = ConnectionString;
Dictionary<string,OleDbPropertyInfo> properties = null;
if (null == propertySets) {
propertySets = new Guid[0];
}
using(PropertyIDSet propidset = new PropertyIDSet(propertySets)) {
using(IDBPropertiesWrapper idbProperties = IDBProperties()) {
using(PropertyInfoSet infoset = new PropertyInfoSet(idbProperties.Value, propidset)) {
properties = infoset.GetValues();
}
}
}
return properties;
}
}
}
|