OdbcConnection.cs source code in C# .NET

Source code for the .NET framework in C#

                        

Code:

/ 4.0 / 4.0 / DEVDIV_TFS / Dev10 / Releases / RTMRel / ndp / fx / src / Data / System / Data / Odbc / OdbcConnection.cs / 1305376 / OdbcConnection.cs

                            //------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.ProviderBase; 
using System.Diagnostics;
using System.Globalization; 
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions; 
using System.Text;
using System.Threading;
using SysTx = System.Transactions;
 
namespace System.Data.Odbc {
 
    [DefaultEvent("InfoMessage")] 
    public sealed partial class OdbcConnection : DbConnection, ICloneable {
        private int connectionTimeout = ADP.DefaultConnectionTimeout; 

        private OdbcInfoMessageEventHandler infoMessageEventHandler;
        private WeakReference weakTransaction;
 
        private OdbcConnectionHandle _connectionHandle;
        private ConnectionState _extraState;    // extras, like Executing and Fetching, that we add to the State. 
 
        public OdbcConnection(string connectionString) : this() {
            ConnectionString = connectionString; 
        }

        private OdbcConnection(OdbcConnection connection) : this() { // Clone
            CopyFrom(connection); 
            connectionTimeout = connection.connectionTimeout;
        } 
 
        internal OdbcConnectionHandle ConnectionHandle {
            get { 
                return _connectionHandle;
            }
            set {
                Debug.Assert(null == _connectionHandle, "reopening a connection?"); 
                _connectionHandle = value;
            } 
        } 

        [ 
        DefaultValue(""),
        Editor("Microsoft.VSDesigner.Data.Odbc.Design.OdbcConnectionStringEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
#pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
        RecommendedAsConfigurable(true), 
#pragma warning restore 618
        SettingsBindableAttribute(true), 
        RefreshProperties(RefreshProperties.All), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OdbcConnection_ConnectionString), 
        ]
        override public string ConnectionString {
            get {
                return ConnectionString_Get(); 
            }
            set { 
                ConnectionString_Set(value); 
            }
        } 

        [
        DefaultValue(ADP.DefaultConnectionTimeout),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OdbcConnection_ConnectionTimeout), 
        ] 
        new public int ConnectionTimeout {
            get { 
                return connectionTimeout;
            }
            set {
                if (value < 0) 
                    throw ODBC.NegativeArgument();
                if (IsOpen) 
                    throw ODBC.CantSetPropertyOnOpenConnection(); 
                connectionTimeout = value;
            } 
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        ResDescriptionAttribute(Res.OdbcConnection_Database),
        ] 
        override public string Database { 
            get {
                if (IsOpen && !ProviderInfo.NoCurrentCatalog) { 
                    //Note: CURRENT_CATALOG may not be supported by the current driver.  In which
                    //case we ignore any error (without throwing), and just return string.empty.
                    //As we really don't want people to have to have try/catch around simple properties
                    return GetConnectAttrString(ODBC32.SQL_ATTR.CURRENT_CATALOG); 
                }
                //Database is not available before open, and its not worth parsing the 
                //connection string over. 
                return String.Empty;
            } 
        }

        [
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.OdbcConnection_DataSource), 
        ] 
        override public string DataSource {
            get { 
                if (IsOpen) {
                    // note: This will return an empty string if the driver keyword was used to connect
                    // see ODBC3.0 Programmers Reference, SQLGetInfo
                    // 
                    return GetInfoStringUnhandled(ODBC32.SQL_INFO.SERVER_NAME, true);
                } 
                return String.Empty; 
            }
        } 

        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        ResDescriptionAttribute(Res.OdbcConnection_ServerVersion),
        ] 
        override public string ServerVersion { 
            get {
                return InnerConnection.ServerVersion; 
            }
        }

        internal OdbcConnectionPoolGroupProviderInfo ProviderInfo { 
            get {
                Debug.Assert(null != this.PoolGroup, "PoolGroup must never be null when accessing ProviderInfo"); 
                return (OdbcConnectionPoolGroupProviderInfo)this.PoolGroup.ProviderInfo; 
            }
        } 

        internal ConnectionState InternalState {
            get {
                return (this.State | _extraState); 
            }
        } 
 
        internal bool IsOpen {
            get { 
                return (InnerConnection is OdbcConnectionOpen);
            }
        }
 
        internal OdbcTransaction LocalTransaction {
 
            get { 
                OdbcTransaction result = null;
                if (null != weakTransaction) { 
                    result = ((OdbcTransaction)weakTransaction.Target);
                }
                return result;
            } 

            set { 
                weakTransaction = null; 

                if (null != value) { 
                    weakTransaction = new WeakReference((OdbcTransaction)value);
                }
            }
        } 

        [ 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.OdbcConnection_Driver), 
        ]
        public string Driver {
            get {
                if(IsOpen) { 
                    if (ProviderInfo.DriverName == null) {
                        ProviderInfo.DriverName = GetInfoStringUnhandled(ODBC32.SQL_INFO.DRIVER_NAME); 
                    } 
                    return ProviderInfo.DriverName;
                } 
                return ADP.StrEmpty;
            }
        }
 
        internal bool IsV3Driver {
            get { 
                if (ProviderInfo.DriverVersion == null) { 
                    ProviderInfo.DriverVersion = GetInfoStringUnhandled(ODBC32.SQL_INFO.DRIVER_ODBC_VER);
                    // protected against null and index out of range. Number cannot be bigger than 99 
                    if (ProviderInfo.DriverVersion != null && ProviderInfo.DriverVersion.Length>=2) {
                        try {   // mdac 89269: driver may return malformatted string
                            ProviderInfo.IsV3Driver = (int.Parse(ProviderInfo.DriverVersion.Substring(0,2), CultureInfo.InvariantCulture) >= 3);
                        } 
                        catch (System.FormatException e) {
                            ProviderInfo.IsV3Driver = false; 
                            ADP.TraceExceptionWithoutRethrow(e); 
                        }
                    } 
                    else {
                        ProviderInfo.DriverVersion = "";
                    }
                } 
                return ProviderInfo.IsV3Driver;
            } 
        } 

        [ 
        ResCategoryAttribute(Res.DataCategory_InfoMessage),
        ResDescriptionAttribute(Res.DbConnection_InfoMessage),
        ]
        public event OdbcInfoMessageEventHandler InfoMessage { 
            add {
                infoMessageEventHandler += value; 
            } 
            remove {
                infoMessageEventHandler -= value; 
            }
        }

        internal char EscapeChar(string method) { 
            CheckState(method);
            if (!ProviderInfo.HasEscapeChar) { 
                string escapeCharString; 
                escapeCharString = GetInfoStringUnhandled(ODBC32.SQL_INFO.SEARCH_PATTERN_ESCAPE);
                Debug.Assert((escapeCharString.Length <= 1), "Can't handle multichar quotes"); 
                ProviderInfo.EscapeChar = (escapeCharString.Length==1)?escapeCharString[0]:QuoteChar(method)[0];
            }
            return ProviderInfo.EscapeChar;
        } 

        internal string QuoteChar(string method) { 
            CheckState(method); 
            if (!ProviderInfo.HasQuoteChar) {
                string quoteCharString; 
                quoteCharString = GetInfoStringUnhandled(ODBC32.SQL_INFO.IDENTIFIER_QUOTE_CHAR);
                Debug.Assert((quoteCharString.Length <= 1), "Can't handle multichar quotes");
                ProviderInfo.QuoteChar = (1==quoteCharString.Length)?quoteCharString:"\0";
            } 
            return ProviderInfo.QuoteChar;
        } 
 
        new public OdbcTransaction BeginTransaction() {
            return BeginTransaction(IsolationLevel.Unspecified); 
            }

        new public OdbcTransaction BeginTransaction(IsolationLevel isolevel) {
            return (OdbcTransaction)InnerConnection.BeginTransaction(isolevel); 
            }
 
        private void RollbackDeadTransaction() { 
            WeakReference weak = weakTransaction;
            if ((null != weak) && !weak.IsAlive) { 
                weakTransaction = null;
                ConnectionHandle.CompleteTransaction(ODBC32.SQL_ROLLBACK);
            }
        } 

        override public void ChangeDatabase(string value) { 
            InnerConnection.ChangeDatabase(value); 
            }
 
        internal void CheckState(string method) {
            ConnectionState state = InternalState;
            if (ConnectionState.Open != state) {
                throw ADP.OpenConnectionRequired(method, state); // MDAC 68323 
            }
        } 
 
        object ICloneable.Clone() {
            OdbcConnection clone = new OdbcConnection(this); 
            Bid.Trace(" %d#, clone=%d#\n", ObjectID, clone.ObjectID);
            return clone;
        }
 
        internal bool ConnectionIsAlive(Exception innerException) {
            if (IsOpen) { 
                if (!ProviderInfo.NoConnectionDead) { 
                    int isDead = GetConnectAttr(ODBC32.SQL_ATTR.CONNECTION_DEAD, ODBC32.HANDLER.IGNORE);
                    if (ODBC32.SQL_CD_TRUE == isDead) { 
                        Close();
                        throw ADP.ConnectionIsDisabled(innerException);
                    }
                } 
                // else connection is still alive or attribute not supported
                return true; 
            } 
            return false;
        } 

        new public OdbcCommand CreateCommand() {
            return new OdbcCommand(String.Empty, this);
            } 

        internal OdbcStatementHandle CreateStatementHandle() { 
            return new OdbcStatementHandle(ConnectionHandle); 
        }
 
        override public void Close() {
            InnerConnection.CloseConnection(this, ConnectionFactory);

            OdbcConnectionHandle connectionHandle = _connectionHandle; 

            if (null != connectionHandle) { 
                _connectionHandle = null; 

                // If there is a pending transaction, automatically rollback. 
                WeakReference weak = this.weakTransaction;
                if (null != weak) {
                    this.weakTransaction = null;
                    IDisposable transaction = weak.Target as OdbcTransaction; 
                    if ((null != transaction) && weak.IsAlive) {
                        transaction.Dispose(); 
                    } 
                    // else transaction will be rolled back when handle is disposed
                } 
                connectionHandle.Dispose();
            }
        }
 
        private void DisposeMe(bool disposing) { // MDAC 65459
        } 
 
        public void EnlistDistributedTransaction(System.EnterpriseServices.ITransaction transaction) {
            EnlistDistributedTransactionHelper(transaction); 
        }

        internal string GetConnectAttrString(ODBC32.SQL_ATTR attribute) {
            string value = ""; 
            Int32 cbActual = 0;
            byte[] buffer = new byte[100]; 
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            if (null != connectionHandle) {
                ODBC32.RetCode retcode = connectionHandle.GetConnectionAttribute(attribute, buffer, out cbActual); 
                if (buffer.Length+2 <= cbActual) {
                    // 2 bytes for unicode null-termination character
                    // retry with cbActual because original buffer was too small
                    buffer = new byte[cbActual + 2]; 
                    retcode = connectionHandle.GetConnectionAttribute(attribute, buffer, out cbActual);
                } 
                if ((ODBC32.RetCode.SUCCESS == retcode) || (ODBC32.RetCode.SUCCESS_WITH_INFO == retcode)) { 
                    value = Encoding.Unicode.GetString(buffer, 0, Math.Min(cbActual, buffer.Length));
                } 
                else if (retcode == ODBC32.RetCode.ERROR) {
                    string sqlstate = GetDiagSqlState();
                    if (("HYC00" == sqlstate) || ("HY092" == sqlstate) || ("IM001" == sqlstate)) {
                        FlagUnsupportedConnectAttr(attribute); 
                    }
                    // not throwing errors if not supported or other failure 
                } 
            }
            return value; 
        }

        internal int GetConnectAttr(ODBC32.SQL_ATTR attribute, ODBC32.HANDLER handler) {
            Int32 retval = -1; 
            Int32 cbActual = 0;
            byte[] buffer = new byte[4]; 
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            if (null != connectionHandle) {
                ODBC32.RetCode retcode = connectionHandle.GetConnectionAttribute(attribute, buffer, out cbActual); 

                if ((ODBC32.RetCode.SUCCESS == retcode) || (ODBC32.RetCode.SUCCESS_WITH_INFO == retcode)) {
                    retval = BitConverter.ToInt32(buffer, 0);
                } 
                else {
                    if (retcode == ODBC32.RetCode.ERROR) { 
                        string sqlstate = GetDiagSqlState(); 
                        if (("HYC00" == sqlstate) || ("HY092" == sqlstate) || ("IM001" == sqlstate)) {
                            FlagUnsupportedConnectAttr(attribute); 
                        }
                    }
                    if (handler == ODBC32.HANDLER.THROW) {
                        this.HandleError(connectionHandle, retcode); 
                    }
                } 
            } 
            return retval;
        } 

        private string GetDiagSqlState () {
            OdbcConnectionHandle connectionHandle = ConnectionHandle;
            string sqlstate; 
            connectionHandle.GetDiagnosticField(out sqlstate);
            return sqlstate; 
        } 

        internal ODBC32.RetCode GetInfoInt16Unhandled(ODBC32.SQL_INFO info, out Int16 resultValue) { 
            byte[] buffer = new byte[2];
            ODBC32.RetCode retcode = ConnectionHandle.GetInfo1(info, buffer);
            resultValue = BitConverter.ToInt16(buffer, 0);
            return retcode; 
        }
 
        internal ODBC32.RetCode GetInfoInt32Unhandled(ODBC32.SQL_INFO info, out Int32 resultValue) { 
            byte[] buffer = new byte[4];
            ODBC32.RetCode retcode = ConnectionHandle.GetInfo1(info, buffer); 
            resultValue = BitConverter.ToInt32(buffer, 0);
            return retcode;
        }
 
        private Int32 GetInfoInt32Unhandled(ODBC32.SQL_INFO infotype) {
            byte[] buffer = new byte[4]; 
            ConnectionHandle.GetInfo1(infotype, buffer); 
            return BitConverter.ToInt32(buffer, 0);
        } 

        internal string GetInfoStringUnhandled(ODBC32.SQL_INFO info) {
            return GetInfoStringUnhandled(info, false);
        } 

        private string GetInfoStringUnhandled(ODBC32.SQL_INFO info, bool handleError) { 
            //SQLGetInfo 
            string value = null;
            Int16 cbActual  = 0; 
            byte[] buffer = new byte[100];
            OdbcConnectionHandle connectionHandle = ConnectionHandle;
            if (null != connectionHandle) {
                ODBC32.RetCode retcode = connectionHandle.GetInfo2(info, buffer, out cbActual); 
                if (buffer.Length < cbActual-2) {
                    // 2 bytes for unicode null-termination character 
                    // retry with cbActual because original buffer was too small 
                    buffer = new byte[cbActual + 2];
                    retcode = connectionHandle.GetInfo2(info, buffer, out cbActual); 
                }
                if (retcode == ODBC32.RetCode.SUCCESS || retcode == ODBC32.RetCode.SUCCESS_WITH_INFO) {
                    value = Encoding.Unicode.GetString(buffer, 0, Math.Min(cbActual, buffer.Length));
                } 
                else if (handleError) {
                    this.HandleError(ConnectionHandle, retcode); 
                } 
            }
            else if (handleError) { 
                value = "";
            }
            return value;
        } 

        // non-throwing HandleError 
        internal Exception HandleErrorNoThrow(OdbcHandle hrHandle, ODBC32.RetCode retcode) { 

            Debug.Assert(retcode!=ODBC32.RetCode.INVALID_HANDLE, "retcode must never be ODBC32.RetCode.INVALID_HANDLE"); 

            switch(retcode) {
            case ODBC32.RetCode.SUCCESS:
                break; 
            case ODBC32.RetCode.SUCCESS_WITH_INFO: {
                //Optimize to only create the event objects and obtain error info if 
                //the user is really interested in retriveing the events... 
                if (infoMessageEventHandler != null) {
                    OdbcErrorCollection errors = ODBC32.GetDiagErrors(null, hrHandle, retcode); 
                    errors.SetSource(this.Driver);
                    OnInfoMessage(new OdbcInfoMessageEventArgs(errors));
                }
                break; 
            }
            default: 
                OdbcException e = OdbcException.CreateException(ODBC32.GetDiagErrors(null, hrHandle, retcode), retcode); 
                if (e != null) {
                    e.Errors.SetSource(this.Driver); 
                }
                ConnectionIsAlive(e);        // this will close and throw if the connection is dead
                return (Exception)e;
            } 
            return null;
        } 
 
        internal void HandleError(OdbcHandle hrHandle, ODBC32.RetCode retcode) {
            Exception e = HandleErrorNoThrow(hrHandle, retcode); 
            switch(retcode) {
            case ODBC32.RetCode.SUCCESS:
            case ODBC32.RetCode.SUCCESS_WITH_INFO:
                Debug.Assert(null == e, "success exception"); 
                break;
            default: 
                Debug.Assert(null != e, "failure without exception"); 
                throw e;
            } 
        }

        override public void Open() {
            InnerConnection.OpenConnection(this, ConnectionFactory); 

            // SQLBUDT #276132 - need to manually enlist in some cases, because 
            // native ODBC doesn't know about SysTx transactions. 
            if (ADP.NeedManualEnlistment()) {
                EnlistTransaction(SysTx.Transaction.Current); 
            }
        }

        private void OnInfoMessage(OdbcInfoMessageEventArgs args) { 
            if (null != infoMessageEventHandler) {
                try { 
                    infoMessageEventHandler(this, args); 
                }
                catch (Exception e) { 
                    //
                    if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
                        throw;
                    } 
                    ADP.TraceExceptionWithoutRethrow(e);
                } 
            } 
        }
 
        static public void ReleaseObjectPool() {
            (new OdbcPermission(PermissionState.Unrestricted)).Demand();
            OdbcEnvironment.ReleaseObjectPool();
        } 

        internal OdbcTransaction SetStateExecuting(string method, OdbcTransaction transaction) { // MDAC 69003 
            if (null != weakTransaction) { // transaction may exist 
                OdbcTransaction weak = (weakTransaction.Target as OdbcTransaction);
                if (transaction != weak) { // transaction doesn't exist 
                    if (null == transaction) { // transaction exists
                        throw ADP.TransactionRequired(method);
                    }
                    if (this!= transaction.Connection) { 
                        // transaction can't have come from this connection
                        throw ADP.TransactionConnectionMismatch(); 
                    } 
                    // if transaction is zombied, we don't know the original connection
                    transaction = null; // MDAC 69264 
                }
            }
            else if (null != transaction) { // no transaction started
                if (null != transaction.Connection) { 
                    // transaction can't have come from this connection
                    throw ADP.TransactionConnectionMismatch(); 
                } 
                // if transaction is zombied, we don't know the original connection
                transaction = null; // MDAC 69264 
            }
            ConnectionState state = InternalState;
            if (ConnectionState.Open != state) {
                NotifyWeakReference(OdbcReferenceCollection.Recover); // recover for a potentially finalized reader 

                state = InternalState; 
                if (ConnectionState.Open != state) { 
                    if (0 != (ConnectionState.Fetching & state)) {
                        throw ADP.OpenReaderExists(); 
                    }
                    throw ADP.OpenConnectionRequired(method, state);
                }
            } 
            return transaction;
        } 
 
        // This adds a type to the list of types that are supported by the driver
        // (don't need to know that for all the types) 
        //

        internal void SetSupportedType (ODBC32.SQL_TYPE sqltype) {
            ODBC32.SQL_CVT sqlcvt; 

            switch (sqltype) { 
                case ODBC32.SQL_TYPE.NUMERIC: { 
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC;
                    break; 
                }
                case ODBC32.SQL_TYPE.WCHAR: {
                    sqlcvt = ODBC32.SQL_CVT.WCHAR;
                    break; 
                }
                case ODBC32.SQL_TYPE.WVARCHAR: { 
                    sqlcvt = ODBC32.SQL_CVT.WVARCHAR; 
                    break;
                } 
                case ODBC32.SQL_TYPE.WLONGVARCHAR: {
                    sqlcvt = ODBC32.SQL_CVT.WLONGVARCHAR;
                    break;
                } 
                default:
                    // other types are irrelevant at this time 
                    return; 
            }
            ProviderInfo.TestedSQLTypes |= (int)sqlcvt; 
            ProviderInfo.SupportedSQLTypes |= (int)sqlcvt;
        }

        internal void FlagRestrictedSqlBindType(ODBC32.SQL_TYPE sqltype) { 
            ODBC32.SQL_CVT sqlcvt;
 
            switch (sqltype) { 
                case ODBC32.SQL_TYPE.NUMERIC: {
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC; 
                    break;
                }
                case ODBC32.SQL_TYPE.DECIMAL: {
                    sqlcvt = ODBC32.SQL_CVT.DECIMAL; 
                    break;
                } 
                default: 
                    // other types are irrelevant at this time
                    return; 
            }
            ProviderInfo.RestrictedSQLBindTypes |= (int)sqlcvt;
        }
 
        internal void FlagUnsupportedConnectAttr (ODBC32.SQL_ATTR Attribute) {
            switch (Attribute) { 
                case ODBC32.SQL_ATTR.CURRENT_CATALOG: 
                    ProviderInfo.NoCurrentCatalog = true;
                    break; 
                case ODBC32.SQL_ATTR.CONNECTION_DEAD:
                    ProviderInfo.NoConnectionDead = true;
                    break;
                default: 
                    Debug.Assert (false, "Can't flag unknown Attribute");
                    break; 
            } 
        }
 
        internal void FlagUnsupportedStmtAttr (ODBC32.SQL_ATTR Attribute) {
            switch (Attribute) {
                case ODBC32.SQL_ATTR.QUERY_TIMEOUT:
                    ProviderInfo.NoQueryTimeout = true; 
                    break;
                case (ODBC32.SQL_ATTR)ODBC32.SQL_SOPT_SS.NOBROWSETABLE: 
                    ProviderInfo.NoSqlSoptSSNoBrowseTable = true; 
                    break;
                case (ODBC32.SQL_ATTR)ODBC32.SQL_SOPT_SS.HIDDEN_COLUMNS: 
                    ProviderInfo.NoSqlSoptSSHiddenColumns = true;
                    break;
                default:
                    Debug.Assert (false, "Can't flag unknown Attribute"); 
                    break;
            } 
        } 

        internal void FlagUnsupportedColAttr (ODBC32.SQL_DESC v3FieldId, ODBC32.SQL_COLUMN v2FieldId) { 
            if (IsV3Driver) {
                switch ( v3FieldId){
                    case (ODBC32.SQL_DESC)ODBC32.SQL_CA_SS.COLUMN_KEY:
                        // SSS_WARNINGS_OFF 
                        ProviderInfo.NoSqlCASSColumnKey = true;
                        break; 
                        // SSS_WARNINGS_ON 
                    default:
                        Debug.Assert (false, "Can't flag unknown Attribute"); 
                        break;
                }
            }
            else { 
                switch ( v2FieldId) {
                    default: 
                        Debug.Assert (false, "Can't flag unknown Attribute"); 
                        break;
                } 
            }
        }

        internal Boolean SQLGetFunctions(ODBC32.SQL_API odbcFunction) { 
            //SQLGetFunctions
            ODBC32.RetCode retcode; 
            Int16 fExists; 
            Debug.Assert ((Int16) odbcFunction != 0,"SQL_API_ALL_FUNCTIONS is not supported");
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            if (null != connectionHandle) {
                retcode = connectionHandle.GetFunctions(odbcFunction, out fExists);
            }
            else { 
                Debug.Assert (false, "GetFunctions called and ConnectionHandle is null (connection is diposed?)");
                // retcode = ODBC32.RETCODE.INVALID_HANDLE; 
                throw ADP.InvalidOperation("what is the right exception to throw here?"); 
            }
 
            if(retcode != ODBC32.RetCode.SUCCESS)
                this.HandleError(connectionHandle, retcode);

            if (fExists == 0){ 
                return false;
            } 
            else { 
                return true;
            } 

        }

        internal bool TestTypeSupport (ODBC32.SQL_TYPE sqltype){ 
            ODBC32.SQL_CONVERT sqlconvert;
            ODBC32.SQL_CVT sqlcvt; 
 
            // we need to convert the sqltype to sqlconvert and sqlcvt first
            // 
            switch (sqltype) {
                case ODBC32.SQL_TYPE.NUMERIC: {
                    sqlconvert = ODBC32.SQL_CONVERT.NUMERIC;
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC; 
                    break;
                } 
                case ODBC32.SQL_TYPE.WCHAR: { 
                    sqlconvert = ODBC32.SQL_CONVERT.CHAR;
                    sqlcvt = ODBC32.SQL_CVT.WCHAR; 
                    break;
                }
                case ODBC32.SQL_TYPE.WVARCHAR: {
                    sqlconvert = ODBC32.SQL_CONVERT.VARCHAR; 
                    sqlcvt = ODBC32.SQL_CVT.WVARCHAR;
                    break; 
                } 
                case ODBC32.SQL_TYPE.WLONGVARCHAR: {
                    sqlconvert = ODBC32.SQL_CONVERT.LONGVARCHAR; 
                    sqlcvt = ODBC32.SQL_CVT.WLONGVARCHAR;
                    break;
                }
                default: 
                    Debug.Assert(false, "Testing that sqltype is currently not supported");
                    return false; 
            } 
            // now we can check if we have already tested that type
            // if not we need to do so 
            if (0 == (ProviderInfo.TestedSQLTypes & (int)sqlcvt)) {
                int flags;

                flags = GetInfoInt32Unhandled((ODBC32.SQL_INFO)sqlconvert); 
                flags = flags & (int)sqlcvt;
 
                ProviderInfo.TestedSQLTypes |= (int)sqlcvt; 
                ProviderInfo.SupportedSQLTypes |= flags;
            } 

            // now check if the type is supported and return the result
            //
            return (0 != (ProviderInfo.SupportedSQLTypes & (int)sqlcvt)); 
        }
 
        internal bool TestRestrictedSqlBindType (ODBC32.SQL_TYPE sqltype){ 
            ODBC32.SQL_CVT sqlcvt;
            switch (sqltype) { 
                case ODBC32.SQL_TYPE.NUMERIC: {
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC;
                    break;
                } 
                case ODBC32.SQL_TYPE.DECIMAL: {
                    sqlcvt = ODBC32.SQL_CVT.DECIMAL; 
                    break; 
                }
                default: 
                    Debug.Assert(false, "Testing that sqltype is currently not supported");
                    return false;
            }
            return (0 != (ProviderInfo.RestrictedSQLBindTypes & (int)sqlcvt)); 
        }
 
        internal OdbcTransaction Open_BeginTransaction(IsolationLevel isolevel) { 
            OdbcConnection.ExecutePermission.Demand();
 
            CheckState(ADP.BeginTransaction); // MDAC 68323

            RollbackDeadTransaction();
 
            if ((null != this.weakTransaction) && this.weakTransaction.IsAlive) { // regression from Dispose/Finalize work
                throw ADP.ParallelTransactionsNotSupported(this); 
            } 

            //Use the default for unspecified. 
            switch(isolevel) {
            case IsolationLevel.Unspecified:
            case IsolationLevel.ReadUncommitted:
            case IsolationLevel.ReadCommitted: 
            case IsolationLevel.RepeatableRead:
            case IsolationLevel.Serializable: 
            case IsolationLevel.Snapshot: 
                break;
            case IsolationLevel.Chaos: 
                throw ODBC.NotSupportedIsolationLevel(isolevel);
            default:
                throw ADP.InvalidIsolationLevel(isolevel);
            }; 

            //Start the transaction 
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            ODBC32.RetCode retcode = connectionHandle.BeginTransaction(ref isolevel);
            if (retcode == ODBC32.RetCode.ERROR) { 
                HandleError(connectionHandle, retcode);
            }
            OdbcTransaction transaction = new OdbcTransaction(this, isolevel, connectionHandle);
            this.weakTransaction = new WeakReference(transaction); // MDAC 69188 
            return transaction;
        } 
 
        internal void Open_ChangeDatabase(string value) {
            OdbcConnection.ExecutePermission.Demand(); 

            CheckState(ADP.ChangeDatabase);

            // Database name must not be null, empty or whitspace 
            if ((null == value) || (0 == value.Trim().Length)) { // MDAC 62679
                throw ADP.EmptyDatabaseName(); 
            } 
            if (1024 < value.Length*2+2) {
                throw ADP.DatabaseNameTooLong(); 
            }
            RollbackDeadTransaction();

            //Set the database 
            OdbcConnectionHandle connectionHandle = ConnectionHandle;
            ODBC32.RetCode retcode = connectionHandle.SetConnectionAttribute3(ODBC32.SQL_ATTR.CURRENT_CATALOG, value, checked((Int32)value.Length*2)); 
 
            if (retcode != ODBC32.RetCode.SUCCESS) {
                HandleError(connectionHandle, retcode); 
            }
        }

        internal void Open_EnlistTransaction(SysTx.Transaction transaction) { 
            OdbcConnection.VerifyExecutePermission();
 
            if ((null != this.weakTransaction) && this.weakTransaction.IsAlive) { 
                throw ADP.LocalTransactionPresent();
            } 

            SysTx.IDtcTransaction oleTxTransaction = ADP.GetOletxTransaction(transaction);

            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            ODBC32.RetCode retcode;
            if (null == oleTxTransaction) { 
                retcode = connectionHandle.SetConnectionAttribute2(ODBC32.SQL_ATTR.SQL_COPT_SS_ENLIST_IN_DTC, (IntPtr) ODBC32.SQL_DTC_DONE, ODBC32.SQL_IS_PTR); 
            }
            else { 
                retcode = connectionHandle.SetConnectionAttribute4(ODBC32.SQL_ATTR.SQL_COPT_SS_ENLIST_IN_DTC,  oleTxTransaction, ODBC32.SQL_IS_PTR);
            }

            if (retcode != ODBC32.RetCode.SUCCESS) { 
                HandleError(connectionHandle, retcode);
            } 
 
            // Tell the base class about our enlistment
            ((OdbcConnectionOpen)InnerConnection).EnlistedTransaction = transaction; 
        }

        internal string Open_GetServerVersion() {
            //SQLGetInfo - SQL_DBMS_VER 
            return GetInfoStringUnhandled(ODBC32.SQL_INFO.DBMS_VER, true);
        } 
    } 
}
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.
//------------------------------------------------------------------------------ 
// 
//      Copyright (c) Microsoft Corporation.  All rights reserved.
// 
// [....] 
// [....]
//----------------------------------------------------------------------------- 
 
using System;
using System.Collections; 
using System.ComponentModel;
using System.Data;
using System.Data.Common;
using System.Data.ProviderBase; 
using System.Diagnostics;
using System.Globalization; 
using System.Runtime.InteropServices; 
using System.Security;
using System.Security.Permissions; 
using System.Text;
using System.Threading;
using SysTx = System.Transactions;
 
namespace System.Data.Odbc {
 
    [DefaultEvent("InfoMessage")] 
    public sealed partial class OdbcConnection : DbConnection, ICloneable {
        private int connectionTimeout = ADP.DefaultConnectionTimeout; 

        private OdbcInfoMessageEventHandler infoMessageEventHandler;
        private WeakReference weakTransaction;
 
        private OdbcConnectionHandle _connectionHandle;
        private ConnectionState _extraState;    // extras, like Executing and Fetching, that we add to the State. 
 
        public OdbcConnection(string connectionString) : this() {
            ConnectionString = connectionString; 
        }

        private OdbcConnection(OdbcConnection connection) : this() { // Clone
            CopyFrom(connection); 
            connectionTimeout = connection.connectionTimeout;
        } 
 
        internal OdbcConnectionHandle ConnectionHandle {
            get { 
                return _connectionHandle;
            }
            set {
                Debug.Assert(null == _connectionHandle, "reopening a connection?"); 
                _connectionHandle = value;
            } 
        } 

        [ 
        DefaultValue(""),
        Editor("Microsoft.VSDesigner.Data.Odbc.Design.OdbcConnectionStringEditor, " + AssemblyRef.MicrosoftVSDesigner, "System.Drawing.Design.UITypeEditor, " + AssemblyRef.SystemDrawing),
#pragma warning disable 618 // ignore obsolete warning about RecommendedAsConfigurable to use SettingsBindableAttribute
        RecommendedAsConfigurable(true), 
#pragma warning restore 618
        SettingsBindableAttribute(true), 
        RefreshProperties(RefreshProperties.All), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OdbcConnection_ConnectionString), 
        ]
        override public string ConnectionString {
            get {
                return ConnectionString_Get(); 
            }
            set { 
                ConnectionString_Set(value); 
            }
        } 

        [
        DefaultValue(ADP.DefaultConnectionTimeout),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        ResCategoryAttribute(Res.DataCategory_Data),
        ResDescriptionAttribute(Res.OdbcConnection_ConnectionTimeout), 
        ] 
        new public int ConnectionTimeout {
            get { 
                return connectionTimeout;
            }
            set {
                if (value < 0) 
                    throw ODBC.NegativeArgument();
                if (IsOpen) 
                    throw ODBC.CantSetPropertyOnOpenConnection(); 
                connectionTimeout = value;
            } 
        }

        [
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        ResDescriptionAttribute(Res.OdbcConnection_Database),
        ] 
        override public string Database { 
            get {
                if (IsOpen && !ProviderInfo.NoCurrentCatalog) { 
                    //Note: CURRENT_CATALOG may not be supported by the current driver.  In which
                    //case we ignore any error (without throwing), and just return string.empty.
                    //As we really don't want people to have to have try/catch around simple properties
                    return GetConnectAttrString(ODBC32.SQL_ATTR.CURRENT_CATALOG); 
                }
                //Database is not available before open, and its not worth parsing the 
                //connection string over. 
                return String.Empty;
            } 
        }

        [
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.OdbcConnection_DataSource), 
        ] 
        override public string DataSource {
            get { 
                if (IsOpen) {
                    // note: This will return an empty string if the driver keyword was used to connect
                    // see ODBC3.0 Programmers Reference, SQLGetInfo
                    // 
                    return GetInfoStringUnhandled(ODBC32.SQL_INFO.SERVER_NAME, true);
                } 
                return String.Empty; 
            }
        } 

        [
        Browsable(false),
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden), 
        ResDescriptionAttribute(Res.OdbcConnection_ServerVersion),
        ] 
        override public string ServerVersion { 
            get {
                return InnerConnection.ServerVersion; 
            }
        }

        internal OdbcConnectionPoolGroupProviderInfo ProviderInfo { 
            get {
                Debug.Assert(null != this.PoolGroup, "PoolGroup must never be null when accessing ProviderInfo"); 
                return (OdbcConnectionPoolGroupProviderInfo)this.PoolGroup.ProviderInfo; 
            }
        } 

        internal ConnectionState InternalState {
            get {
                return (this.State | _extraState); 
            }
        } 
 
        internal bool IsOpen {
            get { 
                return (InnerConnection is OdbcConnectionOpen);
            }
        }
 
        internal OdbcTransaction LocalTransaction {
 
            get { 
                OdbcTransaction result = null;
                if (null != weakTransaction) { 
                    result = ((OdbcTransaction)weakTransaction.Target);
                }
                return result;
            } 

            set { 
                weakTransaction = null; 

                if (null != value) { 
                    weakTransaction = new WeakReference((OdbcTransaction)value);
                }
            }
        } 

        [ 
        Browsable(false), 
        DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden),
        ResDescriptionAttribute(Res.OdbcConnection_Driver), 
        ]
        public string Driver {
            get {
                if(IsOpen) { 
                    if (ProviderInfo.DriverName == null) {
                        ProviderInfo.DriverName = GetInfoStringUnhandled(ODBC32.SQL_INFO.DRIVER_NAME); 
                    } 
                    return ProviderInfo.DriverName;
                } 
                return ADP.StrEmpty;
            }
        }
 
        internal bool IsV3Driver {
            get { 
                if (ProviderInfo.DriverVersion == null) { 
                    ProviderInfo.DriverVersion = GetInfoStringUnhandled(ODBC32.SQL_INFO.DRIVER_ODBC_VER);
                    // protected against null and index out of range. Number cannot be bigger than 99 
                    if (ProviderInfo.DriverVersion != null && ProviderInfo.DriverVersion.Length>=2) {
                        try {   // mdac 89269: driver may return malformatted string
                            ProviderInfo.IsV3Driver = (int.Parse(ProviderInfo.DriverVersion.Substring(0,2), CultureInfo.InvariantCulture) >= 3);
                        } 
                        catch (System.FormatException e) {
                            ProviderInfo.IsV3Driver = false; 
                            ADP.TraceExceptionWithoutRethrow(e); 
                        }
                    } 
                    else {
                        ProviderInfo.DriverVersion = "";
                    }
                } 
                return ProviderInfo.IsV3Driver;
            } 
        } 

        [ 
        ResCategoryAttribute(Res.DataCategory_InfoMessage),
        ResDescriptionAttribute(Res.DbConnection_InfoMessage),
        ]
        public event OdbcInfoMessageEventHandler InfoMessage { 
            add {
                infoMessageEventHandler += value; 
            } 
            remove {
                infoMessageEventHandler -= value; 
            }
        }

        internal char EscapeChar(string method) { 
            CheckState(method);
            if (!ProviderInfo.HasEscapeChar) { 
                string escapeCharString; 
                escapeCharString = GetInfoStringUnhandled(ODBC32.SQL_INFO.SEARCH_PATTERN_ESCAPE);
                Debug.Assert((escapeCharString.Length <= 1), "Can't handle multichar quotes"); 
                ProviderInfo.EscapeChar = (escapeCharString.Length==1)?escapeCharString[0]:QuoteChar(method)[0];
            }
            return ProviderInfo.EscapeChar;
        } 

        internal string QuoteChar(string method) { 
            CheckState(method); 
            if (!ProviderInfo.HasQuoteChar) {
                string quoteCharString; 
                quoteCharString = GetInfoStringUnhandled(ODBC32.SQL_INFO.IDENTIFIER_QUOTE_CHAR);
                Debug.Assert((quoteCharString.Length <= 1), "Can't handle multichar quotes");
                ProviderInfo.QuoteChar = (1==quoteCharString.Length)?quoteCharString:"\0";
            } 
            return ProviderInfo.QuoteChar;
        } 
 
        new public OdbcTransaction BeginTransaction() {
            return BeginTransaction(IsolationLevel.Unspecified); 
            }

        new public OdbcTransaction BeginTransaction(IsolationLevel isolevel) {
            return (OdbcTransaction)InnerConnection.BeginTransaction(isolevel); 
            }
 
        private void RollbackDeadTransaction() { 
            WeakReference weak = weakTransaction;
            if ((null != weak) && !weak.IsAlive) { 
                weakTransaction = null;
                ConnectionHandle.CompleteTransaction(ODBC32.SQL_ROLLBACK);
            }
        } 

        override public void ChangeDatabase(string value) { 
            InnerConnection.ChangeDatabase(value); 
            }
 
        internal void CheckState(string method) {
            ConnectionState state = InternalState;
            if (ConnectionState.Open != state) {
                throw ADP.OpenConnectionRequired(method, state); // MDAC 68323 
            }
        } 
 
        object ICloneable.Clone() {
            OdbcConnection clone = new OdbcConnection(this); 
            Bid.Trace(" %d#, clone=%d#\n", ObjectID, clone.ObjectID);
            return clone;
        }
 
        internal bool ConnectionIsAlive(Exception innerException) {
            if (IsOpen) { 
                if (!ProviderInfo.NoConnectionDead) { 
                    int isDead = GetConnectAttr(ODBC32.SQL_ATTR.CONNECTION_DEAD, ODBC32.HANDLER.IGNORE);
                    if (ODBC32.SQL_CD_TRUE == isDead) { 
                        Close();
                        throw ADP.ConnectionIsDisabled(innerException);
                    }
                } 
                // else connection is still alive or attribute not supported
                return true; 
            } 
            return false;
        } 

        new public OdbcCommand CreateCommand() {
            return new OdbcCommand(String.Empty, this);
            } 

        internal OdbcStatementHandle CreateStatementHandle() { 
            return new OdbcStatementHandle(ConnectionHandle); 
        }
 
        override public void Close() {
            InnerConnection.CloseConnection(this, ConnectionFactory);

            OdbcConnectionHandle connectionHandle = _connectionHandle; 

            if (null != connectionHandle) { 
                _connectionHandle = null; 

                // If there is a pending transaction, automatically rollback. 
                WeakReference weak = this.weakTransaction;
                if (null != weak) {
                    this.weakTransaction = null;
                    IDisposable transaction = weak.Target as OdbcTransaction; 
                    if ((null != transaction) && weak.IsAlive) {
                        transaction.Dispose(); 
                    } 
                    // else transaction will be rolled back when handle is disposed
                } 
                connectionHandle.Dispose();
            }
        }
 
        private void DisposeMe(bool disposing) { // MDAC 65459
        } 
 
        public void EnlistDistributedTransaction(System.EnterpriseServices.ITransaction transaction) {
            EnlistDistributedTransactionHelper(transaction); 
        }

        internal string GetConnectAttrString(ODBC32.SQL_ATTR attribute) {
            string value = ""; 
            Int32 cbActual = 0;
            byte[] buffer = new byte[100]; 
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            if (null != connectionHandle) {
                ODBC32.RetCode retcode = connectionHandle.GetConnectionAttribute(attribute, buffer, out cbActual); 
                if (buffer.Length+2 <= cbActual) {
                    // 2 bytes for unicode null-termination character
                    // retry with cbActual because original buffer was too small
                    buffer = new byte[cbActual + 2]; 
                    retcode = connectionHandle.GetConnectionAttribute(attribute, buffer, out cbActual);
                } 
                if ((ODBC32.RetCode.SUCCESS == retcode) || (ODBC32.RetCode.SUCCESS_WITH_INFO == retcode)) { 
                    value = Encoding.Unicode.GetString(buffer, 0, Math.Min(cbActual, buffer.Length));
                } 
                else if (retcode == ODBC32.RetCode.ERROR) {
                    string sqlstate = GetDiagSqlState();
                    if (("HYC00" == sqlstate) || ("HY092" == sqlstate) || ("IM001" == sqlstate)) {
                        FlagUnsupportedConnectAttr(attribute); 
                    }
                    // not throwing errors if not supported or other failure 
                } 
            }
            return value; 
        }

        internal int GetConnectAttr(ODBC32.SQL_ATTR attribute, ODBC32.HANDLER handler) {
            Int32 retval = -1; 
            Int32 cbActual = 0;
            byte[] buffer = new byte[4]; 
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            if (null != connectionHandle) {
                ODBC32.RetCode retcode = connectionHandle.GetConnectionAttribute(attribute, buffer, out cbActual); 

                if ((ODBC32.RetCode.SUCCESS == retcode) || (ODBC32.RetCode.SUCCESS_WITH_INFO == retcode)) {
                    retval = BitConverter.ToInt32(buffer, 0);
                } 
                else {
                    if (retcode == ODBC32.RetCode.ERROR) { 
                        string sqlstate = GetDiagSqlState(); 
                        if (("HYC00" == sqlstate) || ("HY092" == sqlstate) || ("IM001" == sqlstate)) {
                            FlagUnsupportedConnectAttr(attribute); 
                        }
                    }
                    if (handler == ODBC32.HANDLER.THROW) {
                        this.HandleError(connectionHandle, retcode); 
                    }
                } 
            } 
            return retval;
        } 

        private string GetDiagSqlState () {
            OdbcConnectionHandle connectionHandle = ConnectionHandle;
            string sqlstate; 
            connectionHandle.GetDiagnosticField(out sqlstate);
            return sqlstate; 
        } 

        internal ODBC32.RetCode GetInfoInt16Unhandled(ODBC32.SQL_INFO info, out Int16 resultValue) { 
            byte[] buffer = new byte[2];
            ODBC32.RetCode retcode = ConnectionHandle.GetInfo1(info, buffer);
            resultValue = BitConverter.ToInt16(buffer, 0);
            return retcode; 
        }
 
        internal ODBC32.RetCode GetInfoInt32Unhandled(ODBC32.SQL_INFO info, out Int32 resultValue) { 
            byte[] buffer = new byte[4];
            ODBC32.RetCode retcode = ConnectionHandle.GetInfo1(info, buffer); 
            resultValue = BitConverter.ToInt32(buffer, 0);
            return retcode;
        }
 
        private Int32 GetInfoInt32Unhandled(ODBC32.SQL_INFO infotype) {
            byte[] buffer = new byte[4]; 
            ConnectionHandle.GetInfo1(infotype, buffer); 
            return BitConverter.ToInt32(buffer, 0);
        } 

        internal string GetInfoStringUnhandled(ODBC32.SQL_INFO info) {
            return GetInfoStringUnhandled(info, false);
        } 

        private string GetInfoStringUnhandled(ODBC32.SQL_INFO info, bool handleError) { 
            //SQLGetInfo 
            string value = null;
            Int16 cbActual  = 0; 
            byte[] buffer = new byte[100];
            OdbcConnectionHandle connectionHandle = ConnectionHandle;
            if (null != connectionHandle) {
                ODBC32.RetCode retcode = connectionHandle.GetInfo2(info, buffer, out cbActual); 
                if (buffer.Length < cbActual-2) {
                    // 2 bytes for unicode null-termination character 
                    // retry with cbActual because original buffer was too small 
                    buffer = new byte[cbActual + 2];
                    retcode = connectionHandle.GetInfo2(info, buffer, out cbActual); 
                }
                if (retcode == ODBC32.RetCode.SUCCESS || retcode == ODBC32.RetCode.SUCCESS_WITH_INFO) {
                    value = Encoding.Unicode.GetString(buffer, 0, Math.Min(cbActual, buffer.Length));
                } 
                else if (handleError) {
                    this.HandleError(ConnectionHandle, retcode); 
                } 
            }
            else if (handleError) { 
                value = "";
            }
            return value;
        } 

        // non-throwing HandleError 
        internal Exception HandleErrorNoThrow(OdbcHandle hrHandle, ODBC32.RetCode retcode) { 

            Debug.Assert(retcode!=ODBC32.RetCode.INVALID_HANDLE, "retcode must never be ODBC32.RetCode.INVALID_HANDLE"); 

            switch(retcode) {
            case ODBC32.RetCode.SUCCESS:
                break; 
            case ODBC32.RetCode.SUCCESS_WITH_INFO: {
                //Optimize to only create the event objects and obtain error info if 
                //the user is really interested in retriveing the events... 
                if (infoMessageEventHandler != null) {
                    OdbcErrorCollection errors = ODBC32.GetDiagErrors(null, hrHandle, retcode); 
                    errors.SetSource(this.Driver);
                    OnInfoMessage(new OdbcInfoMessageEventArgs(errors));
                }
                break; 
            }
            default: 
                OdbcException e = OdbcException.CreateException(ODBC32.GetDiagErrors(null, hrHandle, retcode), retcode); 
                if (e != null) {
                    e.Errors.SetSource(this.Driver); 
                }
                ConnectionIsAlive(e);        // this will close and throw if the connection is dead
                return (Exception)e;
            } 
            return null;
        } 
 
        internal void HandleError(OdbcHandle hrHandle, ODBC32.RetCode retcode) {
            Exception e = HandleErrorNoThrow(hrHandle, retcode); 
            switch(retcode) {
            case ODBC32.RetCode.SUCCESS:
            case ODBC32.RetCode.SUCCESS_WITH_INFO:
                Debug.Assert(null == e, "success exception"); 
                break;
            default: 
                Debug.Assert(null != e, "failure without exception"); 
                throw e;
            } 
        }

        override public void Open() {
            InnerConnection.OpenConnection(this, ConnectionFactory); 

            // SQLBUDT #276132 - need to manually enlist in some cases, because 
            // native ODBC doesn't know about SysTx transactions. 
            if (ADP.NeedManualEnlistment()) {
                EnlistTransaction(SysTx.Transaction.Current); 
            }
        }

        private void OnInfoMessage(OdbcInfoMessageEventArgs args) { 
            if (null != infoMessageEventHandler) {
                try { 
                    infoMessageEventHandler(this, args); 
                }
                catch (Exception e) { 
                    //
                    if (!ADP.IsCatchableOrSecurityExceptionType(e)) {
                        throw;
                    } 
                    ADP.TraceExceptionWithoutRethrow(e);
                } 
            } 
        }
 
        static public void ReleaseObjectPool() {
            (new OdbcPermission(PermissionState.Unrestricted)).Demand();
            OdbcEnvironment.ReleaseObjectPool();
        } 

        internal OdbcTransaction SetStateExecuting(string method, OdbcTransaction transaction) { // MDAC 69003 
            if (null != weakTransaction) { // transaction may exist 
                OdbcTransaction weak = (weakTransaction.Target as OdbcTransaction);
                if (transaction != weak) { // transaction doesn't exist 
                    if (null == transaction) { // transaction exists
                        throw ADP.TransactionRequired(method);
                    }
                    if (this!= transaction.Connection) { 
                        // transaction can't have come from this connection
                        throw ADP.TransactionConnectionMismatch(); 
                    } 
                    // if transaction is zombied, we don't know the original connection
                    transaction = null; // MDAC 69264 
                }
            }
            else if (null != transaction) { // no transaction started
                if (null != transaction.Connection) { 
                    // transaction can't have come from this connection
                    throw ADP.TransactionConnectionMismatch(); 
                } 
                // if transaction is zombied, we don't know the original connection
                transaction = null; // MDAC 69264 
            }
            ConnectionState state = InternalState;
            if (ConnectionState.Open != state) {
                NotifyWeakReference(OdbcReferenceCollection.Recover); // recover for a potentially finalized reader 

                state = InternalState; 
                if (ConnectionState.Open != state) { 
                    if (0 != (ConnectionState.Fetching & state)) {
                        throw ADP.OpenReaderExists(); 
                    }
                    throw ADP.OpenConnectionRequired(method, state);
                }
            } 
            return transaction;
        } 
 
        // This adds a type to the list of types that are supported by the driver
        // (don't need to know that for all the types) 
        //

        internal void SetSupportedType (ODBC32.SQL_TYPE sqltype) {
            ODBC32.SQL_CVT sqlcvt; 

            switch (sqltype) { 
                case ODBC32.SQL_TYPE.NUMERIC: { 
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC;
                    break; 
                }
                case ODBC32.SQL_TYPE.WCHAR: {
                    sqlcvt = ODBC32.SQL_CVT.WCHAR;
                    break; 
                }
                case ODBC32.SQL_TYPE.WVARCHAR: { 
                    sqlcvt = ODBC32.SQL_CVT.WVARCHAR; 
                    break;
                } 
                case ODBC32.SQL_TYPE.WLONGVARCHAR: {
                    sqlcvt = ODBC32.SQL_CVT.WLONGVARCHAR;
                    break;
                } 
                default:
                    // other types are irrelevant at this time 
                    return; 
            }
            ProviderInfo.TestedSQLTypes |= (int)sqlcvt; 
            ProviderInfo.SupportedSQLTypes |= (int)sqlcvt;
        }

        internal void FlagRestrictedSqlBindType(ODBC32.SQL_TYPE sqltype) { 
            ODBC32.SQL_CVT sqlcvt;
 
            switch (sqltype) { 
                case ODBC32.SQL_TYPE.NUMERIC: {
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC; 
                    break;
                }
                case ODBC32.SQL_TYPE.DECIMAL: {
                    sqlcvt = ODBC32.SQL_CVT.DECIMAL; 
                    break;
                } 
                default: 
                    // other types are irrelevant at this time
                    return; 
            }
            ProviderInfo.RestrictedSQLBindTypes |= (int)sqlcvt;
        }
 
        internal void FlagUnsupportedConnectAttr (ODBC32.SQL_ATTR Attribute) {
            switch (Attribute) { 
                case ODBC32.SQL_ATTR.CURRENT_CATALOG: 
                    ProviderInfo.NoCurrentCatalog = true;
                    break; 
                case ODBC32.SQL_ATTR.CONNECTION_DEAD:
                    ProviderInfo.NoConnectionDead = true;
                    break;
                default: 
                    Debug.Assert (false, "Can't flag unknown Attribute");
                    break; 
            } 
        }
 
        internal void FlagUnsupportedStmtAttr (ODBC32.SQL_ATTR Attribute) {
            switch (Attribute) {
                case ODBC32.SQL_ATTR.QUERY_TIMEOUT:
                    ProviderInfo.NoQueryTimeout = true; 
                    break;
                case (ODBC32.SQL_ATTR)ODBC32.SQL_SOPT_SS.NOBROWSETABLE: 
                    ProviderInfo.NoSqlSoptSSNoBrowseTable = true; 
                    break;
                case (ODBC32.SQL_ATTR)ODBC32.SQL_SOPT_SS.HIDDEN_COLUMNS: 
                    ProviderInfo.NoSqlSoptSSHiddenColumns = true;
                    break;
                default:
                    Debug.Assert (false, "Can't flag unknown Attribute"); 
                    break;
            } 
        } 

        internal void FlagUnsupportedColAttr (ODBC32.SQL_DESC v3FieldId, ODBC32.SQL_COLUMN v2FieldId) { 
            if (IsV3Driver) {
                switch ( v3FieldId){
                    case (ODBC32.SQL_DESC)ODBC32.SQL_CA_SS.COLUMN_KEY:
                        // SSS_WARNINGS_OFF 
                        ProviderInfo.NoSqlCASSColumnKey = true;
                        break; 
                        // SSS_WARNINGS_ON 
                    default:
                        Debug.Assert (false, "Can't flag unknown Attribute"); 
                        break;
                }
            }
            else { 
                switch ( v2FieldId) {
                    default: 
                        Debug.Assert (false, "Can't flag unknown Attribute"); 
                        break;
                } 
            }
        }

        internal Boolean SQLGetFunctions(ODBC32.SQL_API odbcFunction) { 
            //SQLGetFunctions
            ODBC32.RetCode retcode; 
            Int16 fExists; 
            Debug.Assert ((Int16) odbcFunction != 0,"SQL_API_ALL_FUNCTIONS is not supported");
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            if (null != connectionHandle) {
                retcode = connectionHandle.GetFunctions(odbcFunction, out fExists);
            }
            else { 
                Debug.Assert (false, "GetFunctions called and ConnectionHandle is null (connection is diposed?)");
                // retcode = ODBC32.RETCODE.INVALID_HANDLE; 
                throw ADP.InvalidOperation("what is the right exception to throw here?"); 
            }
 
            if(retcode != ODBC32.RetCode.SUCCESS)
                this.HandleError(connectionHandle, retcode);

            if (fExists == 0){ 
                return false;
            } 
            else { 
                return true;
            } 

        }

        internal bool TestTypeSupport (ODBC32.SQL_TYPE sqltype){ 
            ODBC32.SQL_CONVERT sqlconvert;
            ODBC32.SQL_CVT sqlcvt; 
 
            // we need to convert the sqltype to sqlconvert and sqlcvt first
            // 
            switch (sqltype) {
                case ODBC32.SQL_TYPE.NUMERIC: {
                    sqlconvert = ODBC32.SQL_CONVERT.NUMERIC;
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC; 
                    break;
                } 
                case ODBC32.SQL_TYPE.WCHAR: { 
                    sqlconvert = ODBC32.SQL_CONVERT.CHAR;
                    sqlcvt = ODBC32.SQL_CVT.WCHAR; 
                    break;
                }
                case ODBC32.SQL_TYPE.WVARCHAR: {
                    sqlconvert = ODBC32.SQL_CONVERT.VARCHAR; 
                    sqlcvt = ODBC32.SQL_CVT.WVARCHAR;
                    break; 
                } 
                case ODBC32.SQL_TYPE.WLONGVARCHAR: {
                    sqlconvert = ODBC32.SQL_CONVERT.LONGVARCHAR; 
                    sqlcvt = ODBC32.SQL_CVT.WLONGVARCHAR;
                    break;
                }
                default: 
                    Debug.Assert(false, "Testing that sqltype is currently not supported");
                    return false; 
            } 
            // now we can check if we have already tested that type
            // if not we need to do so 
            if (0 == (ProviderInfo.TestedSQLTypes & (int)sqlcvt)) {
                int flags;

                flags = GetInfoInt32Unhandled((ODBC32.SQL_INFO)sqlconvert); 
                flags = flags & (int)sqlcvt;
 
                ProviderInfo.TestedSQLTypes |= (int)sqlcvt; 
                ProviderInfo.SupportedSQLTypes |= flags;
            } 

            // now check if the type is supported and return the result
            //
            return (0 != (ProviderInfo.SupportedSQLTypes & (int)sqlcvt)); 
        }
 
        internal bool TestRestrictedSqlBindType (ODBC32.SQL_TYPE sqltype){ 
            ODBC32.SQL_CVT sqlcvt;
            switch (sqltype) { 
                case ODBC32.SQL_TYPE.NUMERIC: {
                    sqlcvt = ODBC32.SQL_CVT.NUMERIC;
                    break;
                } 
                case ODBC32.SQL_TYPE.DECIMAL: {
                    sqlcvt = ODBC32.SQL_CVT.DECIMAL; 
                    break; 
                }
                default: 
                    Debug.Assert(false, "Testing that sqltype is currently not supported");
                    return false;
            }
            return (0 != (ProviderInfo.RestrictedSQLBindTypes & (int)sqlcvt)); 
        }
 
        internal OdbcTransaction Open_BeginTransaction(IsolationLevel isolevel) { 
            OdbcConnection.ExecutePermission.Demand();
 
            CheckState(ADP.BeginTransaction); // MDAC 68323

            RollbackDeadTransaction();
 
            if ((null != this.weakTransaction) && this.weakTransaction.IsAlive) { // regression from Dispose/Finalize work
                throw ADP.ParallelTransactionsNotSupported(this); 
            } 

            //Use the default for unspecified. 
            switch(isolevel) {
            case IsolationLevel.Unspecified:
            case IsolationLevel.ReadUncommitted:
            case IsolationLevel.ReadCommitted: 
            case IsolationLevel.RepeatableRead:
            case IsolationLevel.Serializable: 
            case IsolationLevel.Snapshot: 
                break;
            case IsolationLevel.Chaos: 
                throw ODBC.NotSupportedIsolationLevel(isolevel);
            default:
                throw ADP.InvalidIsolationLevel(isolevel);
            }; 

            //Start the transaction 
            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            ODBC32.RetCode retcode = connectionHandle.BeginTransaction(ref isolevel);
            if (retcode == ODBC32.RetCode.ERROR) { 
                HandleError(connectionHandle, retcode);
            }
            OdbcTransaction transaction = new OdbcTransaction(this, isolevel, connectionHandle);
            this.weakTransaction = new WeakReference(transaction); // MDAC 69188 
            return transaction;
        } 
 
        internal void Open_ChangeDatabase(string value) {
            OdbcConnection.ExecutePermission.Demand(); 

            CheckState(ADP.ChangeDatabase);

            // Database name must not be null, empty or whitspace 
            if ((null == value) || (0 == value.Trim().Length)) { // MDAC 62679
                throw ADP.EmptyDatabaseName(); 
            } 
            if (1024 < value.Length*2+2) {
                throw ADP.DatabaseNameTooLong(); 
            }
            RollbackDeadTransaction();

            //Set the database 
            OdbcConnectionHandle connectionHandle = ConnectionHandle;
            ODBC32.RetCode retcode = connectionHandle.SetConnectionAttribute3(ODBC32.SQL_ATTR.CURRENT_CATALOG, value, checked((Int32)value.Length*2)); 
 
            if (retcode != ODBC32.RetCode.SUCCESS) {
                HandleError(connectionHandle, retcode); 
            }
        }

        internal void Open_EnlistTransaction(SysTx.Transaction transaction) { 
            OdbcConnection.VerifyExecutePermission();
 
            if ((null != this.weakTransaction) && this.weakTransaction.IsAlive) { 
                throw ADP.LocalTransactionPresent();
            } 

            SysTx.IDtcTransaction oleTxTransaction = ADP.GetOletxTransaction(transaction);

            OdbcConnectionHandle connectionHandle = ConnectionHandle; 
            ODBC32.RetCode retcode;
            if (null == oleTxTransaction) { 
                retcode = connectionHandle.SetConnectionAttribute2(ODBC32.SQL_ATTR.SQL_COPT_SS_ENLIST_IN_DTC, (IntPtr) ODBC32.SQL_DTC_DONE, ODBC32.SQL_IS_PTR); 
            }
            else { 
                retcode = connectionHandle.SetConnectionAttribute4(ODBC32.SQL_ATTR.SQL_COPT_SS_ENLIST_IN_DTC,  oleTxTransaction, ODBC32.SQL_IS_PTR);
            }

            if (retcode != ODBC32.RetCode.SUCCESS) { 
                HandleError(connectionHandle, retcode);
            } 
 
            // Tell the base class about our enlistment
            ((OdbcConnectionOpen)InnerConnection).EnlistedTransaction = transaction; 
        }

        internal string Open_GetServerVersion() {
            //SQLGetInfo - SQL_DBMS_VER 
            return GetInfoStringUnhandled(ODBC32.SQL_INFO.DBMS_VER, true);
        } 
    } 
}
 


// File provided for Reference Use Only by Microsoft Corporation (c) 2007.

                        

Link Menu

Network programming in C#, Network Programming in VB.NET, Network Programming in .NET
This book is available now!
Buy at Amazon US or
Buy at Amazon UK