예제 #1
0
        internal MetaData(
			AdvanConnect advanConnect, string cmdText, bool expandSelectStar)
        {
            _advanConnect = advanConnect;

            if (AdvanConnect != null  &&  // if connection is Closed, just return
                !AdvanConnect.isClosed())
            {
                string str;

                if ((str = AdvanConnect.conn.dbCaps.getDbCap(
                        "DB_DELIMITED_CASE")) != null)
                    DelimitedIdentifierCase = str;  // "LOWER", "UPPER", or "MIXED"

                if ((str = AdvanConnect.conn.dbCaps.getDbCap(
                        "DB_NAME_CASE")) != null)
                    RegularIdentifierCase = str;
            }
            else
                AdvanConnect = null;

            try
            {
                // Scan the SELECT statment,
                // set the CmdTokenList token list for the SQL statement, and
                // build the column and table names lists.
                BuildTableColumnInfoForSELECTStatement(cmdText);
            }
            catch(FormatException)  // catch invalid syntax
            {}

            // At this point, the table and column lists just
            // have the names only.
            // If no tables could be scanned
            // from the SELECT statement (or no SELECT at all) then give up.
            if (Tables  == null  ||  Tables.Count  == 0)
                return;

            if (AdvanConnect == null)  // if no Connection to get catalog
                return;              // then just return

            // get the catalog to search for
            // table, column, and key information later.
            if (AdvanConnect.Catalog == null)
                AdvanConnect.Catalog =
                    new Catalog(AdvanConnect);
            catalog = AdvanConnect.Catalog;

            // Resolve missing schema names in the FROM table list.
            BuildCatalogTableInfoForSELECTStatement();

            // Build the KeyInfo metadata
            BuildKeyInfoForSELECTStatement(expandSelectStar);
        }
예제 #2
0
        /*
        ** Name: Close
        **
        ** History:
        **	27-Aug-02 (thoda04)
        **	    Created.
        */
        /// <summary>
        /// Close the database connection or release it back into connection pool.
        /// </summary>
        public override void Close()
        {
            if (_state == ConnectionState.Closed)
                return;

            if (ActiveDataReader != null)  // Close any open DataReader
                ActiveDataReader.Close();

            if (advanConnect != null)
            {
                if (Transaction != null  &&
                    Transaction.HasAlreadyBeenCommittedOrRolledBack == false)
                {
                    Transaction.Rollback();
                    Transaction = null;
                }

                // put the advantage connection back into pool or close it
                advanConnect.CloseOrPutBackIntoConnectionPool();
                advanConnect = null;
            }

            ConnectionState oldState = _state;
            _state = ConnectionState.Closed;
            _serverVersion = null;  // ServerVersion property is now invalid

            // Raise the connection state change
            FireStateChange(oldState, _state);  // old, new
        }
예제 #3
0
        /*
        ** Name: Open
        **
        ** History:
        **	27-Aug-02 (thoda04)
        **	    Created.
        */
        /// <summary>
        /// Open the database connection and set the ConnectionState property.
        /// </summary>
        public override void Open()
        {
            System.EnterpriseServices.ITransaction transaction;

            if (_state == ConnectionState.Open)
                throw new InvalidOperationException("The connection is already open.");

            if (config == null)  // if no connection string then bad news
                throw new InvalidOperationException("Host specification missing");

            string host = DataSource;
            if (host == null)
                throw new InvalidOperationException("Host specification missing");

            // if not "servername:port" format then
            // get the port number from keyword=value NameValueCollection
            if (host.IndexOf(":") == -1)
            {
                string port = config.Get(DrvConst.DRV_PROP_PORT);
                if (port == null || port.Length == 0)
                    port = "II7"; // no "Port=" then default to "II7"
                host += ":" + port.ToString();  // add ":portid" to host
            }

            advanConnect = AdvanConnectionPoolManager.Get(
                ConnectionString, this, host, config, null, ConnectionTimeout);

            // advanConnect internal connection object may be later used by
            // two threads: the application thread and the MSDTC proxy thread.
            // The advanConnect usage count will block release of the internal
            // connection advanConnect object back into the connection pool
            // until each is finished and calls
            // advanConnect.CloseOrPutBackIntoConnectionPool() method.
            // See DTCEnlistment.Enlist() method for MSDTC proxy claim stake.
            advanConnect.ReferenceCountIncrement();  // application thread stakes it claim

            ConnectionState oldState = _state;
            _state = ConnectionState.Open;

            // Raise the connection state change event
            FireStateChange(oldState, _state);  // old, new

            string persistSecurityInfo = config.Get(DrvConst.DRV_PROP_PERSISTSEC);
            if (persistSecurityInfo == null  ||
                (ToInvariantLower(persistSecurityInfo) != "true"  &&
                 ToInvariantLower(persistSecurityInfo) != "yes"))
                _connectionString = _connectionStringSanitized;

            transaction = EnlistDistributedTransactionIsNeeded();

            if (transaction != null)
                EnlistDistributedTransaction(transaction, false);  // implicit enlistment
        }
예제 #4
0
        /*
        ** Name: xa_open  - Open an RMI, registered earlier with the TP system.
        **
        ** Description:
        **
        ** Inputs:
        **      xa_info    - character string, contains the RMI open string.
        **      rmid       - RMI identifier, assigned by the TP system, unique to the
        **                   AS process w/which LIBQXA is linked in.
        **      flags      - TP system-specified flags, one of TMASYNC/TMNOFLAGS.
        **
        ** Outputs:
        **	Returns:
        **          XA_OK          - normal execution.
        **          XAER_ASYNC     - if TMASYNC was specified. Currently, we don't
        **                           support TMASYNC (post-Ingres65 feature).
        **          XAER_RMERR     - various internal errors.
        **          XAER_INVAL     - illegal input arguments.
        **          XAER_PROTO     - if the RMI is in the wrong state. Enforces the
        **                           state tables in the XA spec.
        **
        ** History:
        **	18-Aug-03 (thoda04)
        **	    Created.  Rich description copied from front/embed/libqxa.
        */
        /// <summary>
        /// xa_open is called by the transaction manager to initialize
        /// the resource manager.  This method is called first, before 
        /// any other xa_ methods are called.  xa_open is loaded and
        /// called at MSDTC enlistment.  It allows MSDTC to
        /// test that the connection parameters work while running under
        /// the MSDTC user identity and authorization.  If there is a
        /// problem, we want to know at enlistment time and not at
        /// a recovery situation.  MSDTC also calls xa_open
        /// when it wants to xa_recover and commit/rollback
        /// in-doubt transactions.  Unfortunately, these connections have
        /// different connection parms depending on the recover or 
        /// commit/rollback.  Therefore, we can't re-use the connection
        /// and we immediately close the connection after the successful
        /// test of the xa_open.
        /// </summary>
        /// <param name="xa_info">XA OpenString containing information to
        /// connect to the host and database.  Max length is 256 characters.</param>
        /// <param name="rmid">An integer, assigned by the transaction manager,
        /// uniquely identifies the called resource manager within the thread
        /// of control.  The TM passes this rmid on subsequent calls to XA
        /// routines to identify the RM.  This identifier remains constant
        /// until the TM in this thread closes the RM.</param>
        /// <param name="flags">TMASYNC if function to be performed async.
        /// TMNOFLAGS is no other flags are set.</param>
        /// <returns>XA_OK for normal execution or an XAER* error code.</returns>
        public int xa_open(
			[MarshalAs(UnmanagedType.LPStr)]
			string xa_info,
			int rmid,
			long flags)
        {
            int rc = XA_OK;
            int trace_level = 0;

            string sanitizedString;
            IConfig config;

            if (xa_info == null)
            {
                trace.write("xa_open: xa_info = <null>"+
                    ", rmid = " + rmid.ToString());
                return XAER_INVAL;  // invalid arguments were specified
            }

            if (xa_info.Length == 0)
            {
                trace.write("xa_open: xid = <Empty String>"+
                    ", rmid = " + rmid.ToString());
                return XAER_INVAL;  // invalid arguments were specified
            }

            try
            {
                config = ConnectStringConfig.ParseConnectionString(
                    xa_info, out sanitizedString, true);
            }
            catch (Exception)
            {
                trace.write("xa_open: xa_info = <invalid connection string>"+
                    ", rmid = " + rmid.ToString());
                return XAER_INVAL;  // invalid arguments were specified
            }

            // propagate the XA tracing from the application process
            // to this MSDTC process and send output to event log.
            string    strValue;
            // Check for XA tracing
            strValue = config.get(DrvConst.DRV_PROP_TRACE);
            if (strValue != null  &&  strValue.ToUpper(
                System.Globalization.CultureInfo.InvariantCulture)=="XA")
            {
                strValue = config.get(DrvConst.DRV_PROP_TRACELVL);
                if (strValue != null)
                {
                    try
                    {
                        trace_level = Int32.Parse(strValue);
                        if (trace_level < 0)
                            trace_level = 0;
                    }
                    catch {}
                }
            }

            if (trace_level >= 3)  // until tracing is setup, do this manually
            {
                System.Text.StringBuilder sb = new System.Text.StringBuilder(100);

                sb.Append("xa_info = ");
                sb.Append("\"");
                sb.Append(sanitizedString);

                sb.Append(", rmid = ");
                sb.Append(rmid);

                sb.Append(", flags = ");
                sb.Append(XAFlagsToString(flags));

                trace.write("xa_open: " + sb.ToString());
            }

            string host;

            host = config.get(DrvConst.DRV_PROP_HOST);
            if (host == null)  // default to local
                host = "";

            if (host == null)
            {
                trace.write("xa_open: Error: host specification missing"+
                    ", rmid = " + rmid.ToString());
                return XAER_INVAL;  // invalid connection string was specified
            }

            // if not "servername:port" format then
            // get the port number from keyword=value NameValueCollection
            if (host.IndexOf(":") == -1)
            {
                string port = config.get(DrvConst.DRV_PROP_PORT);
                if (port == null || port.Length == 0)
                    port = "II7"; // no "Port=" then default to "II7"
                host += ":" + port.ToString();  // add ":portid" to host
            }

            AdvanConnect conn;
            try
            {
                conn =
                    new AdvanConnect(null, host, config, trace, (AdvanXID) null);
            }
            catch (Exception ex)
            {
                if (trace_level >= 1) // until tracing is setup, do this manually
                trace.write("xa_open: Exception thrown on Connection open: "+
                    ex.ToString());
                return XAER_RMERR;  // could not connect
            }

            RM rm = new RM(rmid, conn, host, config, trace_level);
            lock(RMcollection)
            {
                RMcollection[rmid] = rm;

                if (trace_level > 0)  // if tracing requested, turn if on
                {
                    int old_trace_level = trace.setTraceLevel(trace_level);
                    if (old_trace_level > trace_level)  // if old > new
                        trace.setTraceLevel(old_trace_level);  // set it back
                    CountOfRMsTracing++;
                }
            }
            try
            {
                // we don't need this connection, close it.  We just needed
                // to test that it could open and get its values for later.
                // We don't want to find out that the connection string
                // is bad for the MSDTC user context at real recovery.
                conn.close();   // we don't need this connection, close it.
            }
            catch (Exception /* ignore any close errors*/)
            {}

            return rc;
        }
예제 #5
0
            /// <summary>
            /// Constructor for Resource Manager class.
            /// </summary>
            /// <param name="rmid"></param>
            /// <param name="conn"></param>
            /// <param name="host"></param>
            /// <param name="config"></param>
            /// <param name="trace_level"></param>
            public RM(int rmid, AdvanConnect conn, string host, 
				IConfig config,
				int trace_level)
            {
                this._conn         = conn;
                this._config           = config;
                this._host         = conn.host;
                this._databaseName = conn.database;
                this._trace_level  = trace_level;
            }
예제 #6
0
        /// <summary>
        /// Start the recovery scan for XIDs and position cursor at start of list.
        /// </summary>
        /// <param name="rm">Resource manager to start scan for.</param>
        /// <returns>Count of XIDs in whole list or XAER* error code.</returns>
        private int xa_recover_startrscan(RM rm)
        {
            const string MASTER_DB = "iidbdb";

            int rc = XA_OK;
            rm.Xids = new AdvanXID[0];  // init to empty in case bad things happen
            AdvanXID[] xids = rm.Xids;

            AdvanConnect conn;

            ConnectStringConfig config =  // make a copy
                new ConnectStringConfig(rm.Config);

            // XIDs need to come from iidbdb database
            config.Set(DrvConst.DRV_PROP_DB, MASTER_DB);

            try
            {
                conn =
                    new AdvanConnect(
                    null, rm.Host, config, trace, (AdvanXID)null);
            }
            catch (Exception ex)
            {
                trace.write("xa_recover: Exception thrown on Connection open: "+
                    ex.ToString());
                return XAER_RMFAIL;  // could not connect
            }

            try
            {
                xids = conn.getPreparedTransactionIDs(rm.DatabaseName);
            }
            catch (Exception ex)
            {
                trace.write("xa_recover: Exception thrown on GetXIDs: "+
                    ex.ToString());
                rc = XAER_RMERR;  // could not connect
            }
            finally
            {
                try
                {
                    conn.close();
                }
                catch(Exception /* ignore */) {}
            }

            if (rc != XA_OK)
                return rc;

            rm.Cursor =0;      // reset cursor to XID list back to start
            if (xids != null)  // safety check
                rm.Xids = xids;  // new list of XIDs

            return rm.Xids.Length;
        }
예제 #7
0
        /// <summary>
        /// Common code for xa_commit and xa_rollback
        /// </summary>
        /// <param name="isCommit">If commit then true, else rollback.</param>
        /// <param name="xid">XID to perform the work on.</param>
        /// <param name="rmid">An integer, assigned by the transaction manager,
        /// uniquely identifies the called resource manager within the thread
        /// of control.</param>
        /// <param name="flags"></param>
        /// <returns>XA_OK for normal execution or an XAER* error code.</returns>
        private int xa_commit_or_rollback(
			bool     isCommit,
			AdvanXID xid,
			int rmid,
			long flags)
        {
            string title = isCommit?"xa_commit":"xa_rollback";

            RM rm = FindRM(rmid);
            if (rm == null)  // if RM not found, error
                return XAER_INVAL;

            AdvanConnect conn;
            try
            {
                conn =
                    new AdvanConnect(
                        null, rm.Host, rm.Config, trace, xid);
            }
            catch (Exception ex)
            {
                trace.write(title+": Exception thrown on Connection open: "+
                    ex.ToString());
                return XAER_RMERR;  // could not connect
            }

            try
            {
                if (isCommit)
                    conn.commit();
                else
                    conn.rollback();
            }
            catch (Exception ex)
            {
                trace.write(title+": Exception thrown on "+
                    (isCommit?"commit()":"rollback()") + ": " +
                    ex.ToString());
                return XAER_RMERR;  // could not connect
            }

            try
            {
                conn.close();
            }
            catch
            {}

            return XA_OK;
        }
예제 #8
0
        /*
        ** Name: Enlist
        **
        ** Description:
        **	Enlist in the Microsoft Distributed Transaction Coordinator (MSDTC).
        **	Called by Connection.EnlistDistributedTransaction(ITransaction).
        **
        ** History:
        **	01-Oct-03 (thoda04)
        **	    Created.
        */
        /// <summary>
        /// Enlist in the Microsoft Distributed Transaction Coordinator (MSDTC).
        /// </summary>
        /// <param name="advanConnection">Internal connection.</param>
        /// <param name="tx">ITransaction interface of object.</param>
        /// <param name="nv">Connection string parameter values list.</param>
        internal void Enlist(
			AdvanConnect advanConnection,
			ITransaction tx,
			ConnectStringConfig nv)
        {
            this.advanConnect = advanConnection;
            this.Transaction = tx;

            trace.write(3, title + ": Enlist()");
            if (debugging)
                Console.WriteLine(title + ": Enlist() begins...");

            /*
            Call DtcGetTransactionManager in MS DTC proxy to
            establish a connection to the Transaction Manager.
            From the TM, get the XATM's Single Pipe Helper interface
            that will help establish an enlistment in MSDTC
            using the XA protocol (XaSwitch and XIDs).
            */
            XaHelperSinglePipe = GetDtcToXaHelperSinglePipe();

            /*
            Obtain the Resource Manager (RM) cookie.  The XARMCreate
            method is invoked once per connection.  The information provided
            makes it possible for the transaction manager to connect to the
            database to perform recovery.  The transaction manager durably records
            this information in it's log file.  If recovery is necessary, the
            transaction manager reads the log file, reconnects to the database,
            and initiates XA recovery.

            Calling XARMCreate results in a message from the DTC proxy
            to the XA Transaction Manager (TM).  When the XA TM receives a message that
            contains the DSN and the name of the client DLL, TM will:
               1) LoadLibrary the client dll (Ingres.Support.dll which will
                  drag in the referenced Ingres.ProviderInternals from the GAC).
               2) GetProcAddress the GetXaSwitch function in the dll.
               3) Call the GetXaSwitch function to obtain the XA_Switch.
               4) Call the xa_open function to open an XA connection with the
                  resource manager (Ingres).  When the our xa_open function is called,
                 the DTC TM passes in the DSN parm as the OPEN_STRING.  It then
                 closes the connection by calling xa_close.  (It's just testing
                 the connection information so that it won't be surprised
                 when it's in the middle of recovery later.)
               5) Generate a RM GUID for the connection.
               6) Write a record to the DTCXATM.LOG file indicating that a new
                 resource manager is being established.  The log record contains
                 the DSN parm, the name of our RM (Ingres.Support.dll), and
                 the RM GUID.  This information will be used to reconnect to
                 Ingres should recovery be necessary.

            XARMCreate method also causes the MS DTC proxy to create a resource
            manager object and returns an opaque pointer to that object as
            the RMCookie.  This RMCookie represents the connection to the TM.
            */

            nv = new ConnectStringConfig(nv);  // create a working copy
            // Connection attempts with MSG_P_DTMC will raise error:
            //    GC000B_RMT_LOGIN_FAIL Login failure: invalid username/password
            // if you try to send login information
            nv.Remove(DrvConst.DRV_PROP_USR);   // remove "user="******"password="******"group="
            nv.Remove(DrvConst.DRV_PROP_ROLE);  // remove "role="

            string xa_open_string = ConnectStringConfig.ToConnectionString(nv);
            int trace_level = trace.getTraceLevel("XA");
            if (trace_level > 0)
            {
                xa_open_string +=  // tell MSDTC process to trace XASwitch
                    ";Trace=XA;TraceLevel=" + trace_level.ToString();
            }

            // Locate the Ingres.Support.dll that holds our XASwitch
            // support.  The dll should be in the GAC so use a type from
            // the Ingres.Support assembly, qualified by the same
            // Version and PublicKeyToken that the currently executing
            // Ingres.Support assembly is using.
            System.Reflection.Assembly assembly =
                System.Reflection.Assembly.GetExecutingAssembly();
            string fullname = assembly.FullName;
            string version;
            int index = fullname.IndexOf(',');  // locate ", Verison=..."
            if (index != -1)
                version = fullname.Substring(index);
            else  // should not happen unless in a debugging environment
                version = ", Version=2.0.0.0, Culture=neutral" +
                          ", PublicKeyToken=1234567890123456";

            Type type = Type.GetType(
                "Ingres.Support.XAProvider" +
                ", Ingres.Support" + version);
            // BTW, type will be null if Ingres.Support is not properly
            // in the GAC or has a different version number from
            // Ingres.Client.  A NullReferenceException would follow.
            string dll = type.Assembly.Location;

            XaHelperSinglePipe_XARMCreate(
                xa_open_string,
                dll,
                out this.RMCookie);

            /*
            Obtain an XID from an ITransaction interface pointer.
            The ITransaction pointer is offered by a transaction object.
            The transaction object contains a DTC transaction that is
            identified by a transaction identifier (TRID) which is a globally
            unique identifier (GUID).  Given a TRID, one can always create an XID.
            The MS DTC proxy generates an XID and returns it.

            Into the XID's formatID, MS puts 0x00445443 ("DTC").
            Into the XID's gtrid (length=0x10), MS puts a GUID
            identifying the global transaction identifier.  (Same as
            Transaction.Current.TransactionInformation.DistributedIdentifier.)
            Into the XID's bqual (length=0x30), MS puts a second
            GUID identifying the TM that is coordinating the transaction
            and also a third GUID identifying the database connection.
            If two components in the same transaction have their own connections,
            then they will be loosely coupled XA threads of control (different
            bquals).  MS goes beyond the XA spec and expects that the two
            loosely coupled threads will not deadlock on resource locks.
            */
            XAXIDStruct xaXIDstruct = new XAXIDStruct(-1,0,0,new byte[128]);

            XaHelperSinglePipe_ConvertTridToXID(
                Transaction, this.RMCookie, ref xaXIDstruct);
            advanXID = new AdvanXID(xaXIDstruct);

            /*
            Tell the DTC proxy to enlist on behalf of the XA resource manager.
            EnlistWithRM is called for every transaction that the connection
            is requested to be enlisted in. The provider is responsible for
            implementing the ITransactionResourceAsync interface.  This
            interface includes the PrepareRequest, CommitRequest, AbortRequest,
            and TMDown callbacks.  The transaction manager will invoke these
            callback methods to deliver phase one and phase two notifications
            to the provider.
            The MS DTC proxy informs the transaction manager that the provider
            wishes to enlist in the transaction.  The transaction
            manager creates an internal enlistment object to record the fact
            that the provider is participating in the transaction.
            Upon return from EnlistWithRM, the MS DTC proxy will have created
            an enlistment object and returns the pITransactionEnlistmentAsync
            interface pointer of the enlistment object back to the provider.
            */

            try
            {
            StartMSDTCRequest(MSDTCRequest.ENLIST);  // start worker thread

            if (EnlistmentException != null)
                throw EnlistmentException;

            // wait until EnlistWithRM is completed under the worker thread
            advanConnect.msg.LockConnection();
            advanConnect.msg.UnlockConnection();

            advanConnect.startTransaction(advanXID);
            TxBranchState = TXBRANCHSTATE.Active;
            }
            catch
            {
                // release our bad connection to MS DTC and
                // shutdown our worker thread to MS DTC.
                XaHelperSinglePipe_ReleaseRMCookie(ref this.RMCookie);
                StartMSDTCRequest(MSDTCRequest.DELIST);
                throw;
            }

            // At this point we have a good MSDTC enlistment!

            // The advanConnect internal connection object is now being used by
            // two threads: the application thread and the MSDTC proxy thread.
            // The advanConnect usage count will block release of the internal
            // connection advanConnect object back into the connection pool
            // until each is finished and calls
            // advanConnect.CloseOrPutBackIntoConnectionPool() method.
            // See IngresConnection.Open() method for application's claim stake.
            advanConnect.ReferenceCountIncrement();  // MSDTC proxy thread stakes it claim

            trace.write(3, title + ": Enlist() complete");
            if (debugging)
                Console.WriteLine(title + ": Enlist() complete");
        }