Exemplo n.º 1
0
        // Uses SQLStatistics to retrieve key information for a table
        private int RetrieveKeyInfoFromStatistics(QualifiedTableName qualifiedTableName, bool quoted) {
            ODBC32.RetCode retcode;
            String      columnname = String.Empty;
            String      indexname = String.Empty;
            String      currentindexname = String.Empty;
            int[]       indexcolumnordinals = new int[16];
            int[]        pkcolumnordinals = new int[16];
            int         npkcols = 0;
            int         ncols = 0;                  // No of cols in the index
            bool        partialcolumnset = false;
            int         ordinal;
            int         indexordinal;
            IntPtr cbIndexLen = IntPtr.Zero;
            IntPtr cbColnameLen = IntPtr.Zero;
            int         keyColumns = 0;

            // devnote: this test is already done by calling method ...
            // if (IsClosed) return;   // protect against dead connection

            // MDAC 

            String tablename1 = String.Copy(qualifiedTableName.GetTable(quoted));

            // Select only unique indexes
            retcode = KeyInfoStatementHandle.Statistics(tablename1);

            if (retcode != ODBC32.RetCode.SUCCESS) {
                // We give up at this point
                return 0;
            }

            CNativeBuffer buffer = Buffer;
            bool          mustRelease = false;
            Debug.Assert(buffer.Length >= 544, "Native buffer to small (_buffer.Length < 544)");

            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                buffer.DangerousAddRef(ref mustRelease);

                const int colnameBufOffset = 0;
                const int indexBufOffset = 256;
                const int ordinalBufOffset = 512;
                const int colnameActualOffset = 520;
                const int indexActualOffset = 528;
                const int ordinalActualOffset = 536;
                HandleRef colnamebuf = buffer.PtrOffset(colnameBufOffset, 256);
                HandleRef indexbuf = buffer.PtrOffset(indexBufOffset, 256);
                HandleRef ordinalbuf = buffer.PtrOffset(ordinalBufOffset, 4);
                
                IntPtr colnameActual = buffer.PtrOffset(colnameActualOffset, IntPtr.Size).Handle;
                IntPtr indexActual = buffer.PtrOffset(indexActualOffset, IntPtr.Size).Handle;
                IntPtr ordinalActual = buffer.PtrOffset(ordinalActualOffset, IntPtr.Size).Handle;

                //We are interested in index name, column name, and ordinal
                buffer.WriteInt16(indexBufOffset, 0);
                retcode = KeyInfoStatementHandle.BindColumn2(
                            (short)(ODBC32.SQL_STATISTICS.INDEXNAME),
                            ODBC32.SQL_C.WCHAR,
                            indexbuf,
                            (IntPtr)256,
                            indexActual);
                retcode = KeyInfoStatementHandle.BindColumn2(
                            (short)(ODBC32.SQL_STATISTICS.ORDINAL_POSITION),
                            ODBC32.SQL_C.SSHORT,
                            ordinalbuf,
                            (IntPtr)4,
                            ordinalActual);
                buffer.WriteInt16(ordinalBufOffset, 0);
                retcode = KeyInfoStatementHandle.BindColumn2(
                            (short)(ODBC32.SQL_STATISTICS.COLUMN_NAME),
                            ODBC32.SQL_C.WCHAR,
                            colnamebuf,
                            (IntPtr)256,
                            colnameActual);
                // Find the best unique index on the table, use the ones whose columns are
                // completely covered by the query.
                while (ODBC32.RetCode.SUCCESS == (retcode = KeyInfoStatementHandle.Fetch())) {

                    cbColnameLen = buffer.ReadIntPtr(colnameActualOffset);
                    cbIndexLen = buffer.ReadIntPtr(indexActualOffset);

                    // If indexname is not returned, skip this row
                    if (0 == buffer.ReadInt16(indexBufOffset))
                        continue;       // Not an index row, get next row.

                    columnname = buffer.PtrToStringUni(colnameBufOffset, (int)cbColnameLen/2/*cch*/);
                    indexname = buffer.PtrToStringUni(indexBufOffset, (int)cbIndexLen/2/*cch*/);
                    ordinal = (int) buffer.ReadInt16(ordinalBufOffset);

                    if (SameIndexColumn(currentindexname, indexname, ordinal, ncols)) {
                        // We are still working on the same index
                        if (partialcolumnset)
                            continue;       // We don't have all the keys for this index, so we can't use it
                            
                        ordinal = this.GetOrdinalFromBaseColName(columnname, qualifiedTableName.Table);
                        if (ordinal == -1) {
                             partialcolumnset = true;
                        }
                        else {
                            // Add the column to the index column set
                            if (ncols < 16)
                                indexcolumnordinals[ncols++] = ordinal;
                            else    // Can't deal with indexes > 16 columns
                                partialcolumnset = true;
                        }
                    }
                    else {
                        // We got a new index, save the previous index information
                        if (!partialcolumnset && (ncols != 0)) {
                            // Choose the unique index with least columns as primary key
                            if ((npkcols == 0) || (npkcols > ncols)){
                                npkcols = ncols;
                                for (int i = 0 ; i < ncols ; i++)
                                    pkcolumnordinals[i] = indexcolumnordinals[i];
                            }
                        }
                        // Reset the parameters for a new index
                        ncols = 0;
                        currentindexname = indexname;
                        partialcolumnset = false;
                        // Add this column to index
                        ordinal = this.GetOrdinalFromBaseColName(columnname, qualifiedTableName.Table);
                        if (ordinal == -1) {
                             partialcolumnset = true;
                        }
                        else {
                            // Add the column to the index column set
                            indexcolumnordinals[ncols++] = ordinal;
                        }
                    }
                    // Go on to the next column
                }
                // Do we have an index?
                if (!partialcolumnset && (ncols != 0)) {
                    // Choose the unique index with least columns as primary key
                    if ((npkcols == 0) || (npkcols > ncols)){
                        npkcols = ncols;
                        for (int i = 0 ; i < ncols ; i++)
                            pkcolumnordinals[i] = indexcolumnordinals[i];
                    }
                }
                // Mark the chosen index as primary key
                if (npkcols != 0) {
                    for (int i = 0 ; i < npkcols ; i++) {
                        indexordinal = pkcolumnordinals[i];
                        keyColumns++;
                        this.metadata[indexordinal].isKeyColumn = true;
    // should we set isNullable = false?
    // This makes the QuikTest against Jet fail
    //
    // test test test - we don't know if this is nulalble or not so why do we want to set it to a value?
                        this.metadata[indexordinal].isNullable = false;
                        this.metadata[indexordinal].isUnique = true;
                        if (this.metadata[indexordinal].baseTableName == null) {
                            this.metadata[indexordinal].baseTableName = qualifiedTableName.Table;
                        }
                        if (this.metadata[indexordinal].baseColumnName == null) {
                            this.metadata[indexordinal].baseColumnName = columnname;
                        }
                    }
                }
                // Unbind the columns
                _cmdWrapper.FreeKeyInfoStatementHandle(ODBC32.STMT.UNBIND);
            }
            finally {
                if (mustRelease) {
                    buffer.DangerousRelease();
                }
            }
            return keyColumns;
        }
 private int RetrieveKeyInfoFromStatistics(QualifiedTableName qualifiedTableName, bool quoted)
 {
     string columnname = string.Empty;
     string indexname = string.Empty;
     string currentindexname = string.Empty;
     int[] numArray = new int[0x10];
     int[] numArray2 = new int[0x10];
     int num2 = 0;
     int ncols = 0;
     bool flag = false;
     IntPtr zero = IntPtr.Zero;
     IntPtr ptr = IntPtr.Zero;
     int num8 = 0;
     string tableName = string.Copy(qualifiedTableName.GetTable(quoted));
     if (this.KeyInfoStatementHandle.Statistics(tableName) != ODBC32.RetCode.SUCCESS)
     {
         return 0;
     }
     CNativeBuffer buffer = this.Buffer;
     bool success = false;
     RuntimeHelpers.PrepareConstrainedRegions();
     try
     {
         buffer.DangerousAddRef(ref success);
         HandleRef ref4 = buffer.PtrOffset(0, 0x100);
         HandleRef ref3 = buffer.PtrOffset(0x100, 0x100);
         HandleRef ref2 = buffer.PtrOffset(0x200, 4);
         IntPtr handle = buffer.PtrOffset(520, IntPtr.Size).Handle;
         IntPtr ptr4 = buffer.PtrOffset(0x210, IntPtr.Size).Handle;
         IntPtr ptr3 = buffer.PtrOffset(0x218, IntPtr.Size).Handle;
         buffer.WriteInt16(0x100, 0);
         ODBC32.RetCode code = this.KeyInfoStatementHandle.BindColumn2(6, ODBC32.SQL_C.WCHAR, ref3, (IntPtr) 0x100, ptr4);
         code = this.KeyInfoStatementHandle.BindColumn2(8, ODBC32.SQL_C.SSHORT, ref2, (IntPtr) 4, ptr3);
         buffer.WriteInt16(0x200, 0);
         code = this.KeyInfoStatementHandle.BindColumn2(9, ODBC32.SQL_C.WCHAR, ref4, (IntPtr) 0x100, handle);
         while ((code = this.KeyInfoStatementHandle.Fetch()) == ODBC32.RetCode.SUCCESS)
         {
             ptr = buffer.ReadIntPtr(520);
             zero = buffer.ReadIntPtr(0x210);
             if (buffer.ReadInt16(0x100) != 0)
             {
                 columnname = buffer.PtrToStringUni(0, ((int) ptr) / 2);
                 indexname = buffer.PtrToStringUni(0x100, ((int) zero) / 2);
                 int ordinal = buffer.ReadInt16(0x200);
                 if (this.SameIndexColumn(currentindexname, indexname, ordinal, ncols))
                 {
                     if (!flag)
                     {
                         ordinal = this.GetOrdinalFromBaseColName(columnname, qualifiedTableName.Table);
                         if (ordinal == -1)
                         {
                             flag = true;
                             continue;
                         }
                         if (ncols < 0x10)
                         {
                             numArray[ncols++] = ordinal;
                         }
                         else
                         {
                             flag = true;
                         }
                     }
                 }
                 else
                 {
                     if ((!flag && (ncols != 0)) && ((num2 == 0) || (num2 > ncols)))
                     {
                         num2 = ncols;
                         for (int i = 0; i < ncols; i++)
                         {
                             numArray2[i] = numArray[i];
                         }
                     }
                     ncols = 0;
                     currentindexname = indexname;
                     flag = false;
                     ordinal = this.GetOrdinalFromBaseColName(columnname, qualifiedTableName.Table);
                     if (ordinal == -1)
                     {
                         flag = true;
                     }
                     else
                     {
                         numArray[ncols++] = ordinal;
                     }
                 }
             }
         }
         if ((!flag && (ncols != 0)) && ((num2 == 0) || (num2 > ncols)))
         {
             num2 = ncols;
             for (int j = 0; j < ncols; j++)
             {
                 numArray2[j] = numArray[j];
             }
         }
         if (num2 != 0)
         {
             for (int k = 0; k < num2; k++)
             {
                 int index = numArray2[k];
                 num8++;
                 this.metadata[index].isKeyColumn = true;
                 this.metadata[index].isNullable = false;
                 this.metadata[index].isUnique = true;
                 if (this.metadata[index].baseTableName == null)
                 {
                     this.metadata[index].baseTableName = qualifiedTableName.Table;
                 }
                 if (this.metadata[index].baseColumnName == null)
                 {
                     this.metadata[index].baseColumnName = columnname;
                 }
             }
         }
         this._cmdWrapper.FreeKeyInfoStatementHandle(ODBC32.STMT.UNBIND);
     }
     finally
     {
         if (success)
         {
             buffer.DangerousRelease();
         }
     }
     return num8;
 }
Exemplo n.º 3
0
        internal int RetrieveKeyInfo(bool needkeyinfo, QualifiedTableName qualifiedTableName, bool quoted) {
            ODBC32.RetCode retcode;
            string      columnname;
            int         ordinal;
            int         keyColumns = 0;
            IntPtr cbActual = IntPtr.Zero;

            if (IsClosed || (_cmdWrapper == null)) {
                return 0;     // Can't do anything without a second handle
            }
            _cmdWrapper.CreateKeyInfoStatementHandle();

            CNativeBuffer   buffer = Buffer;
            bool            mustRelease = false;
            Debug.Assert(buffer.Length >= 264, "Native buffer to small (_buffer.Length < 264)");

            RuntimeHelpers.PrepareConstrainedRegions();
            try {
                buffer.DangerousAddRef(ref mustRelease);

                if (needkeyinfo) {
                    if (!Connection.ProviderInfo.NoSqlPrimaryKeys) {
                        // Get the primary keys
                        retcode = KeyInfoStatementHandle.PrimaryKeys(
                                    qualifiedTableName.Catalog,
                                    qualifiedTableName.Schema,
                                    qualifiedTableName.GetTable(quoted));

                        if ((retcode == ODBC32.RetCode.SUCCESS) || (retcode == ODBC32.RetCode.SUCCESS_WITH_INFO)) {
                            bool noUniqueKey = false;

                            // We are only interested in column name
                            buffer.WriteInt16(0, 0);
                            retcode = KeyInfoStatementHandle.BindColumn2(
                                           (short)(ODBC32.SQL_PRIMARYKEYS.COLUMNNAME),    // Column Number
                                           ODBC32.SQL_C.WCHAR,
                                           buffer.PtrOffset(0, 256),
                                           (IntPtr)256,
                                           buffer.PtrOffset(256, IntPtr.Size).Handle);
                            while (ODBC32.RetCode.SUCCESS == (retcode = KeyInfoStatementHandle.Fetch())) {
                                cbActual = buffer.ReadIntPtr(256);
                                columnname = buffer.PtrToStringUni(0, (int)cbActual/2/*cch*/);
                                ordinal = this.GetOrdinalFromBaseColName(columnname);
                                if (ordinal != -1) {
                                    keyColumns ++;
                                    this.metadata[ordinal].isKeyColumn = true;
                                    this.metadata[ordinal].isUnique = true;
                                    this.metadata[ordinal].isNullable = false;
                                    this.metadata[ordinal].baseTableName = qualifiedTableName.Table;

                                    if (this.metadata[ordinal].baseColumnName == null) {
                                        this.metadata[ordinal].baseColumnName = columnname;
                                    }
                                }
                                else {
                                    noUniqueKey = true;
                                    break;  // no need to go over the remaining columns anymore
                                }
                            }
// 




// if we got keyinfo from the column we dont even get to here!
//
                            // reset isUnique flag if the key(s) are not unique
                            //
                            if (noUniqueKey) {
                                foreach (MetaData metadata in this.metadata) {
                                    metadata.isKeyColumn = false;
                                }
                            }

                            // Unbind the column
                            retcode = KeyInfoStatementHandle.BindColumn3(
                                (short)(ODBC32.SQL_PRIMARYKEYS.COLUMNNAME),      // SQLUSMALLINT ColumnNumber
                                ODBC32.SQL_C.WCHAR,                     // SQLSMALLINT  TargetType
                                buffer.DangerousGetHandle());                                   // SQLLEN *     StrLen_or_Ind
                        }
                        else {
                            if ("IM001" == Command.GetDiagSqlState()) {
                                Connection.ProviderInfo.NoSqlPrimaryKeys = true;
                            }
                        }
                    }

                    if (keyColumns == 0) {
                        // SQLPrimaryKeys did not work. Have to use the slower SQLStatistics to obtain key information
                        KeyInfoStatementHandle.MoreResults();
                        keyColumns += RetrieveKeyInfoFromStatistics(qualifiedTableName, quoted);
                    }
                    KeyInfoStatementHandle.MoreResults();
                }

                // Get the special columns for version
                retcode = KeyInfoStatementHandle.SpecialColumns(qualifiedTableName.GetTable(quoted));

                if ((retcode == ODBC32.RetCode.SUCCESS) || (retcode == ODBC32.RetCode.SUCCESS_WITH_INFO)) {
                    // We are only interested in column name
                    cbActual = IntPtr.Zero;
                    buffer.WriteInt16(0, 0);
                    retcode = KeyInfoStatementHandle.BindColumn2(
                                   (short)(ODBC32.SQL_SPECIALCOLUMNSET.COLUMN_NAME),
                                   ODBC32.SQL_C.WCHAR,
                                   buffer.PtrOffset(0, 256),
                                   (IntPtr)256,
                                   buffer.PtrOffset(256, IntPtr.Size).Handle);

                    while (ODBC32.RetCode.SUCCESS == (retcode = KeyInfoStatementHandle.Fetch())) {
                        cbActual = buffer.ReadIntPtr(256);
                        columnname = buffer.PtrToStringUni(0, (int)cbActual/2/*cch*/);
                        ordinal = this.GetOrdinalFromBaseColName(columnname);
                        if (ordinal != -1) {
                            this.metadata[ordinal].isRowVersion = true;
                            if (this.metadata[ordinal].baseColumnName == null) {
                                this.metadata[ordinal].baseColumnName = columnname;
                            }
                        }
                    }
                    // Unbind the column
                    retcode = KeyInfoStatementHandle.BindColumn3(
                                   (short)(ODBC32.SQL_SPECIALCOLUMNSET.COLUMN_NAME),
                                   ODBC32.SQL_C.WCHAR,
                                   buffer.DangerousGetHandle());

                    retcode = KeyInfoStatementHandle.MoreResults();
                }
                else {
                //  i've seen "DIAG [HY000] [Microsoft][ODBC SQL Server Driver]Connection is busy with results for another hstmt (0) "
                //  how did we get here? SqlServer does not allow a second handle (Keyinfostmt) anyway...
                //
                /*
                    string msg = "Unexpected failure of SQLSpecialColumns. Code = " + Command.GetDiagSqlState();
                    Debug.Assert (false, msg);
                */
                }
            }
            finally {
                if (mustRelease) {
                    buffer.DangerousRelease();
                }
            }
            return keyColumns;
        }
 internal int RetrieveKeyInfo(bool needkeyinfo, QualifiedTableName qualifiedTableName, bool quoted)
 {
     int num2 = 0;
     IntPtr zero = IntPtr.Zero;
     if (this.IsClosed || (this._cmdWrapper == null))
     {
         return 0;
     }
     this._cmdWrapper.CreateKeyInfoStatementHandle();
     CNativeBuffer buffer = this.Buffer;
     bool success = false;
     RuntimeHelpers.PrepareConstrainedRegions();
     try
     {
         int ordinalFromBaseColName;
         ODBC32.RetCode code;
         string str;
         buffer.DangerousAddRef(ref success);
         if (!needkeyinfo)
         {
             goto Label_0206;
         }
         if (!this.Connection.ProviderInfo.NoSqlPrimaryKeys)
         {
             code = this.KeyInfoStatementHandle.PrimaryKeys(qualifiedTableName.Catalog, qualifiedTableName.Schema, qualifiedTableName.GetTable(quoted));
             switch (code)
             {
                 case ODBC32.RetCode.SUCCESS:
                 case ODBC32.RetCode.SUCCESS_WITH_INFO:
                 {
                     bool flag = false;
                     buffer.WriteInt16(0, 0);
                     code = this.KeyInfoStatementHandle.BindColumn2(4, ODBC32.SQL_C.WCHAR, buffer.PtrOffset(0, 0x100), (IntPtr) 0x100, buffer.PtrOffset(0x100, IntPtr.Size).Handle);
                     while ((code = this.KeyInfoStatementHandle.Fetch()) == ODBC32.RetCode.SUCCESS)
                     {
                         zero = buffer.ReadIntPtr(0x100);
                         str = buffer.PtrToStringUni(0, ((int) zero) / 2);
                         ordinalFromBaseColName = this.GetOrdinalFromBaseColName(str);
                         if (ordinalFromBaseColName != -1)
                         {
                             num2++;
                             this.metadata[ordinalFromBaseColName].isKeyColumn = true;
                             this.metadata[ordinalFromBaseColName].isUnique = true;
                             this.metadata[ordinalFromBaseColName].isNullable = false;
                             this.metadata[ordinalFromBaseColName].baseTableName = qualifiedTableName.Table;
                             if (this.metadata[ordinalFromBaseColName].baseColumnName == null)
                             {
                                 this.metadata[ordinalFromBaseColName].baseColumnName = str;
                             }
                         }
                         else
                         {
                             flag = true;
                             break;
                         }
                     }
                     if (flag)
                     {
                         foreach (MetaData data in this.metadata)
                         {
                             data.isKeyColumn = false;
                         }
                     }
                     code = this.KeyInfoStatementHandle.BindColumn3(4, ODBC32.SQL_C.WCHAR, buffer.DangerousGetHandle());
                     goto Label_01E0;
                 }
             }
             if ("IM001" == this.Command.GetDiagSqlState())
             {
                 this.Connection.ProviderInfo.NoSqlPrimaryKeys = true;
             }
         }
     Label_01E0:
         if (num2 == 0)
         {
             this.KeyInfoStatementHandle.MoreResults();
             num2 += this.RetrieveKeyInfoFromStatistics(qualifiedTableName, quoted);
         }
         this.KeyInfoStatementHandle.MoreResults();
     Label_0206:
         code = this.KeyInfoStatementHandle.SpecialColumns(qualifiedTableName.GetTable(quoted));
         if ((code != ODBC32.RetCode.SUCCESS) && (code != ODBC32.RetCode.SUCCESS_WITH_INFO))
         {
             return num2;
         }
         zero = IntPtr.Zero;
         buffer.WriteInt16(0, 0);
         code = this.KeyInfoStatementHandle.BindColumn2(2, ODBC32.SQL_C.WCHAR, buffer.PtrOffset(0, 0x100), (IntPtr) 0x100, buffer.PtrOffset(0x100, IntPtr.Size).Handle);
         while ((code = this.KeyInfoStatementHandle.Fetch()) == ODBC32.RetCode.SUCCESS)
         {
             zero = buffer.ReadIntPtr(0x100);
             str = buffer.PtrToStringUni(0, ((int) zero) / 2);
             ordinalFromBaseColName = this.GetOrdinalFromBaseColName(str);
             if (ordinalFromBaseColName != -1)
             {
                 this.metadata[ordinalFromBaseColName].isRowVersion = true;
                 if (this.metadata[ordinalFromBaseColName].baseColumnName == null)
                 {
                     this.metadata[ordinalFromBaseColName].baseColumnName = str;
                 }
             }
         }
         code = this.KeyInfoStatementHandle.BindColumn3(2, ODBC32.SQL_C.WCHAR, buffer.DangerousGetHandle());
         code = this.KeyInfoStatementHandle.MoreResults();
     }
     finally
     {
         if (success)
         {
             buffer.DangerousRelease();
         }
     }
     return num2;
 }