Example #1
0
        internal bool TryReadSqlValueInternal(SqlBuffer value, byte tdsType, int length, TdsParserStateObject stateObj)
        {
            switch (tdsType)
            {
                case TdsEnums.SQLBIT:
                case TdsEnums.SQLBITN:
                    Debug.Assert(length == 1, "invalid length for SqlBoolean type!");
                    byte byteValue;
                    if (!stateObj.TryReadByte(out byteValue))
                    {
                        return false;
                    }
                    value.Boolean = (byteValue != 0);
                    break;

                case TdsEnums.SQLINTN:
                    if (length == 1)
                    {
                        goto case TdsEnums.SQLINT1;
                    }
                    else if (length == 2)
                    {
                        goto case TdsEnums.SQLINT2;
                    }
                    else if (length == 4)
                    {
                        goto case TdsEnums.SQLINT4;
                    }
                    else
                    {
                        goto case TdsEnums.SQLINT8;
                    }

                case TdsEnums.SQLINT1:
                    Debug.Assert(length == 1, "invalid length for SqlByte type!");
                    if (!stateObj.TryReadByte(out byteValue))
                    {
                        return false;
                    }
                    value.Byte = byteValue;
                    break;

                case TdsEnums.SQLINT2:
                    Debug.Assert(length == 2, "invalid length for SqlInt16 type!");
                    short shortValue;
                    if (!stateObj.TryReadInt16(out shortValue))
                    {
                        return false;
                    }
                    value.Int16 = shortValue;
                    break;

                case TdsEnums.SQLINT4:
                    Debug.Assert(length == 4, "invalid length for SqlInt32 type!");
                    int intValue;
                    if (!stateObj.TryReadInt32(out intValue))
                    {
                        return false;
                    }
                    value.Int32 = intValue;
                    break;

                case TdsEnums.SQLINT8:
                    Debug.Assert(length == 8, "invalid length for SqlInt64 type!");
                    long longValue;
                    if (!stateObj.TryReadInt64(out longValue))
                    {
                        return false;
                    }
                    value.Int64 = longValue;
                    break;

                case TdsEnums.SQLFLTN:
                    if (length == 4)
                    {
                        goto case TdsEnums.SQLFLT4;
                    }
                    else
                    {
                        goto case TdsEnums.SQLFLT8;
                    }

                case TdsEnums.SQLFLT4:
                    Debug.Assert(length == 4, "invalid length for SqlSingle type!");
                    float singleValue;
                    if (!stateObj.TryReadSingle(out singleValue))
                    {
                        return false;
                    }
                    value.Single = singleValue;
                    break;

                case TdsEnums.SQLFLT8:
                    Debug.Assert(length == 8, "invalid length for SqlDouble type!");
                    double doubleValue;
                    if (!stateObj.TryReadDouble(out doubleValue))
                    {
                        return false;
                    }
                    value.Double = doubleValue;
                    break;

                case TdsEnums.SQLMONEYN:
                    if (length == 4)
                    {
                        goto case TdsEnums.SQLMONEY4;
                    }
                    else
                    {
                        goto case TdsEnums.SQLMONEY;
                    }

                case TdsEnums.SQLMONEY:
                    {
                        int mid;
                        uint lo;

                        if (!stateObj.TryReadInt32(out mid))
                        {
                            return false;
                        }
                        if (!stateObj.TryReadUInt32(out lo))
                        {
                            return false;
                        }

                        long l = (((long)mid) << 0x20) + ((long)lo);

                        value.SetToMoney(l);
                        break;
                    }

                case TdsEnums.SQLMONEY4:
                    if (!stateObj.TryReadInt32(out intValue))
                    {
                        return false;
                    }
                    value.SetToMoney(intValue);
                    break;

                case TdsEnums.SQLDATETIMN:
                    if (length == 4)
                    {
                        goto case TdsEnums.SQLDATETIM4;
                    }
                    else
                    {
                        goto case TdsEnums.SQLDATETIME;
                    }

                case TdsEnums.SQLDATETIM4:
                    ushort daypartShort, timepartShort;
                    if (!stateObj.TryReadUInt16(out daypartShort))
                    {
                        return false;
                    }
                    if (!stateObj.TryReadUInt16(out timepartShort))
                    {
                        return false;
                    }
                    value.SetToDateTime(daypartShort, timepartShort * SqlDateTime.SQLTicksPerMinute);
                    break;

                case TdsEnums.SQLDATETIME:
                    int daypart;
                    uint timepart;
                    if (!stateObj.TryReadInt32(out daypart))
                    {
                        return false;
                    }
                    if (!stateObj.TryReadUInt32(out timepart))
                    {
                        return false;
                    }
                    value.SetToDateTime(daypart, (int)timepart);
                    break;

                case TdsEnums.SQLUNIQUEID:
                    {
                        Debug.Assert(length == 16, "invalid length for SqlGuid type!");

                        byte[] b = new byte[length];

                        if (!stateObj.TryReadByteArray(b, 0, length))
                        {
                            return false;
                        }
                        value.SqlGuid = new SqlGuid(b, true);   // doesn't copy the byte array
                        break;
                    }

                case TdsEnums.SQLBINARY:
                case TdsEnums.SQLBIGBINARY:
                case TdsEnums.SQLBIGVARBINARY:
                case TdsEnums.SQLVARBINARY:
                case TdsEnums.SQLIMAGE:
                    {
                        // Note: Better not come here with plp data!!
                        Debug.Assert(length <= TdsEnums.MAXSIZE);
                        byte[] b = new byte[length];
                        if (!stateObj.TryReadByteArray(b, 0, length))
                        {
                            return false;
                        }
                        value.SqlBinary = new SqlBinary(b, true);   // doesn't copy the byte array

                        break;
                    }

                case TdsEnums.SQLVARIANT:
                    if (!TryReadSqlVariant(value, length, stateObj))
                    {
                        return false;
                    }
                    break;

                default:
                    Debug.Assert(false, "Unknown SqlType!" + tdsType.ToString(CultureInfo.InvariantCulture));
                    break;
            } // switch

            return true;
        }
Example #2
0
        internal bool TryProcessCollation(TdsParserStateObject stateObj, out SqlCollation collation)
        {
            SqlCollation newCollation = new SqlCollation();

            if (!stateObj.TryReadUInt32(out newCollation.info))
            {
                collation = null;
                return false;
            }
            if (!stateObj.TryReadByte(out newCollation.sortId))
            {
                collation = null;
                return false;
            }

            collation = newCollation;
            return true;
        }
Example #3
0
        private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col)
        {
            byte byteLen;
            UInt32 userType;

            // read user type - 4 bytes Yukon, 2 backwards
            if (!stateObj.TryReadUInt32(out userType))
            {
                return false;
            }

            // read flags and set appropriate flags in structure
            byte flags;
            if (!stateObj.TryReadByte(out flags))
            {
                return false;
            }

            col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2);
            col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable));
            col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity));

            // read second byte of column metadata flags
            if (!stateObj.TryReadByte(out flags))
            {
                return false;
            }


            byte tdsType;
            if (!stateObj.TryReadByte(out tdsType))
            {
                return false;
            }

            if (tdsType == TdsEnums.SQLXMLTYPE)
                col.length = TdsEnums.SQL_USHORTVARMAXLEN;  //Use the same length as other plp datatypes
            else if (IsVarTimeTds(tdsType))
                col.length = 0;  // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN
            else if (tdsType == TdsEnums.SQLDATE)
            {
                col.length = 3;
            }
            else
            {
                if (!TryGetTokenLength(tdsType, stateObj, out col.length))
                {
                    return false;
                }
            }

            col.metaType = MetaType.GetSqlDataType(tdsType, userType, col.length);
            col.type = col.metaType.SqlDbType;

            col.tdsType = (col.isNullable ? col.metaType.NullableType : col.metaType.TDSType);

            {
                if (TdsEnums.SQLUDT == tdsType)
                {
                    throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString());
                }

                if (col.length == TdsEnums.SQL_USHORTVARMAXLEN)
                {
                    Debug.Assert(tdsType == TdsEnums.SQLXMLTYPE ||
                                 tdsType == TdsEnums.SQLBIGVARCHAR ||
                                 tdsType == TdsEnums.SQLBIGVARBINARY ||
                                 tdsType == TdsEnums.SQLNVARCHAR ||
                                 tdsType == TdsEnums.SQLUDT,
                                 "Invalid streaming datatype");
                    col.metaType = MetaType.GetMaxMetaTypeFromMetaType(col.metaType);
                    Debug.Assert(col.metaType.IsLong, "Max datatype not IsLong");
                    col.length = Int32.MaxValue;
                    if (tdsType == TdsEnums.SQLXMLTYPE)
                    {
                        byte schemapresent;
                        if (!stateObj.TryReadByte(out schemapresent))
                        {
                            return false;
                        }

                        if ((schemapresent & 1) != 0)
                        {
                            if (!stateObj.TryReadByte(out byteLen))
                            {
                                return false;
                            }
                            if (byteLen != 0)
                            {
                                if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionDatabase))
                                {
                                    return false;
                                }
                            }

                            if (!stateObj.TryReadByte(out byteLen))
                            {
                                return false;
                            }
                            if (byteLen != 0)
                            {
                                if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionOwningSchema))
                                {
                                    return false;
                                }
                            }

                            short shortLen;
                            if (!stateObj.TryReadInt16(out shortLen))
                            {
                                return false;
                            }
                            if (byteLen != 0)
                            {
                                if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollectionName))
                                {
                                    return false;
                                }
                            }
                        }
                    }
                }
            }

            if (col.type == SqlDbType.Decimal)
            {
                if (!stateObj.TryReadByte(out col.precision))
                {
                    return false;
                }
                if (!stateObj.TryReadByte(out col.scale))
                {
                    return false;
                }
            }

            if (col.metaType.IsVarTime)
            {
                if (!stateObj.TryReadByte(out col.scale))
                {
                    return false;
                }

                Debug.Assert(0 <= col.scale && col.scale <= 7);

                // calculate actual column length here
                switch (col.metaType.SqlDbType)
                {
                    case SqlDbType.Time:
                        col.length = MetaType.GetTimeSizeFromScale(col.scale);
                        break;
                    case SqlDbType.DateTime2:
                        // Date in number of days (3 bytes) + time
                        col.length = 3 + MetaType.GetTimeSizeFromScale(col.scale);
                        break;
                    case SqlDbType.DateTimeOffset:
                        // Date in days (3 bytes) + offset in minutes (2 bytes) + time
                        col.length = 5 + MetaType.GetTimeSizeFromScale(col.scale);
                        break;

                    default:
                        Debug.Assert(false, "Unknown VariableTime type!");
                        break;
                }
            }

            // read the collation for 7.x servers
            if (col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE))
            {
                if (!TryProcessCollation(stateObj, out col.collation))
                {
                    return false;
                }

                int codePage = GetCodePage(col.collation, stateObj);

                if (codePage == _defaultCodePage)
                {
                    col.codePage = _defaultCodePage;
                    col.encoding = _defaultEncoding;
                }
                else
                {
                    col.codePage = codePage;
                    col.encoding = System.Text.Encoding.GetEncoding(col.codePage);
                }
            }

            if (col.metaType.IsLong && !col.metaType.IsPlp)
            {
                int unusedLen = 0xFFFF;      //We ignore this value
                if (!TryProcessOneTable(stateObj, ref unusedLen, out col.multiPartTableName))
                {
                    return false;
                }
            }

            if (!stateObj.TryReadByte(out byteLen))
            {
                return false;
            }
            if (!stateObj.TryReadString(byteLen, out col.column))
            {
                return false;
            }

            // We get too many DONE COUNTs from the server, causing too meany StatementCompleted event firings.
            // We only need to fire this event when we actually have a meta data stream with 0 or more rows.
            stateObj._receivedColMetaData = true;
            return true;
        }
Example #4
0
        private bool TryProcessSessionState(TdsParserStateObject stateObj, int length, SessionData sdata)
        {
            if (length < 5)
            {
                throw SQL.ParsingError();
            }
            UInt32 seqNum;
            if (!stateObj.TryReadUInt32(out seqNum))
            {
                return false;
            }
            if (seqNum == UInt32.MaxValue)
            {
                _connHandler.DoNotPoolThisConnection();
            }
            byte status;
            if (!stateObj.TryReadByte(out status))
            {
                return false;
            }
            if (status > 1)
            {
                throw SQL.ParsingError();
            }
            bool recoverable = status != 0;
            length -= 5;
            while (length > 0)
            {
                byte stateId;
                if (!stateObj.TryReadByte(out stateId))
                {
                    return false;
                }
                int stateLen;
                byte stateLenByte;
                if (!stateObj.TryReadByte(out stateLenByte))
                {
                    return false;
                }
                if (stateLenByte < 0xFF)
                {
                    stateLen = stateLenByte;
                }
                else
                {
                    if (!stateObj.TryReadInt32(out stateLen))
                    {
                        return false;
                    }
                }
                byte[] buffer = null;
                lock (sdata._delta)
                {
                    if (sdata._delta[stateId] == null)
                    {
                        buffer = new byte[stateLen];
                        sdata._delta[stateId] = new SessionStateRecord { _version = seqNum, _dataLength = stateLen, _data = buffer, _recoverable = recoverable };
                        sdata._deltaDirty = true;
                        if (!recoverable)
                        {
                            checked { sdata._unrecoverableStatesCount++; }
                        }
                    }
                    else
                    {
                        if (sdata._delta[stateId]._version <= seqNum)
                        {
                            SessionStateRecord sv = sdata._delta[stateId];
                            sv._version = seqNum;
                            sv._dataLength = stateLen;
                            if (sv._recoverable != recoverable)
                            {
                                if (recoverable)
                                {
                                    Debug.Assert(sdata._unrecoverableStatesCount > 0, "Unrecoverable states count >0");
                                    sdata._unrecoverableStatesCount--;
                                }
                                else
                                {
                                    checked { sdata._unrecoverableStatesCount++; }
                                }
                                sv._recoverable = recoverable;
                            }
                            buffer = sv._data;
                            if (buffer.Length < stateLen)
                            {
                                buffer = new byte[stateLen];
                                sv._data = buffer;
                            }
                        }
                    }
                }
                if (buffer != null)
                {
                    if (!stateObj.TryReadByteArray(buffer, 0, stateLen))
                    {
                        return false;
                    }
                }
                else
                {
                    if (!stateObj.TrySkipBytes(stateLen))
                        return false;
                }

                if (stateLenByte < 0xFF)
                {
                    length -= 2 + stateLen;
                }
                else
                {
                    length -= 6 + stateLen;
                }
            }
            sdata.AssertUnrecoverableStateCountIsCorrect();

            return true;
        }
Example #5
0
        internal bool TryProcessReturnValue(int length, TdsParserStateObject stateObj, out SqlReturnValue returnValue)
        {
            returnValue = null;
            SqlReturnValue rec = new SqlReturnValue();
            rec.length = length;        // In Yukon this length is -1
            ushort parameterIndex;
            if (!stateObj.TryReadUInt16(out parameterIndex))
            {
                return false;
            }
            byte len;
            if (!stateObj.TryReadByte(out len))
            { // Length of parameter name
                return false;
            }

            if (len > 0)
            {
                if (!stateObj.TryReadString(len, out rec.parameter))
                {
                    return false;
                }
            }

            // read status and ignore
            byte ignored;
            if (!stateObj.TryReadByte(out ignored))
            {
                return false;
            }

            UInt32 userType;

            // read user type - 4 bytes Yukon, 2 backwards
            if (!stateObj.TryReadUInt32(out userType))
            {
                return false;
            }

            // read off the flags
            ushort ignoredFlags;
            if (!stateObj.TryReadUInt16(out ignoredFlags))
            {
                return false;
            }

            // read the type
            byte tdsType;
            if (!stateObj.TryReadByte(out tdsType))
            {
                return false;
            }

            // read the MaxLen
            // For xml datatpyes, there is no tokenLength
            int tdsLen;

            if (tdsType == TdsEnums.SQLXMLTYPE)
            {
                tdsLen = TdsEnums.SQL_USHORTVARMAXLEN;
            }
            else if (IsVarTimeTds(tdsType))
                tdsLen = 0;  // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN
            else if (tdsType == TdsEnums.SQLDATE)
            {
                tdsLen = 3;
            }
            else
            {
                if (!TryGetTokenLength(tdsType, stateObj, out tdsLen))
                {
                    return false;
                }
            }

            rec.metaType = MetaType.GetSqlDataType(tdsType, userType, tdsLen);
            rec.type = rec.metaType.SqlDbType;

            // always use the nullable type for parameters if Shiloh or later
            // Sphinx sometimes sends fixed length return values
            rec.tdsType = rec.metaType.NullableType;
            rec.isNullable = true;
            if (tdsLen == TdsEnums.SQL_USHORTVARMAXLEN)
            {
                rec.metaType = MetaType.GetMaxMetaTypeFromMetaType(rec.metaType);
            }

            if (rec.type == SqlDbType.Decimal)
            {
                if (!stateObj.TryReadByte(out rec.precision))
                {
                    return false;
                }
                if (!stateObj.TryReadByte(out rec.scale))
                {
                    return false;
                }
            }

            if (rec.metaType.IsVarTime)
            {
                if (!stateObj.TryReadByte(out rec.scale))
                {
                    return false;
                }
            }

            if (tdsType == TdsEnums.SQLUDT)
            {
                throw SQL.UnsupportedFeatureAndToken(_connHandler, SqlDbType.Udt.ToString());
            }

            if (rec.type == SqlDbType.Xml)
            {
                // Read schema info
                byte schemapresent;
                if (!stateObj.TryReadByte(out schemapresent))
                {
                    return false;
                }

                if ((schemapresent & 1) != 0)
                {
                    if (!stateObj.TryReadByte(out len))
                    {
                        return false;
                    }
                    if (len != 0)
                    {
                        if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionDatabase))
                        {
                            return false;
                        }
                    }

                    if (!stateObj.TryReadByte(out len))
                    {
                        return false;
                    }
                    if (len != 0)
                    {
                        if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionOwningSchema))
                        {
                            return false;
                        }
                    }

                    short slen;
                    if (!stateObj.TryReadInt16(out slen))
                    {
                        return false;
                    }

                    if (slen != 0)
                    {
                        if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollectionName))
                        {
                            return false;
                        }
                    }
                }
            }
            else if (rec.metaType.IsCharType)
            {
                // read the collation for 8.x servers
                if (!TryProcessCollation(stateObj, out rec.collation))
                {
                    return false;
                }

                int codePage = GetCodePage(rec.collation, stateObj);

                // if the column lcid is the same as the default, use the default encoder
                if (codePage == _defaultCodePage)
                {
                    rec.codePage = _defaultCodePage;
                    rec.encoding = _defaultEncoding;
                }
                else
                {
                    rec.codePage = codePage;
                    rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage);
                }
            }

            // for now we coerce return values into a SQLVariant, not good...
            bool isNull = false;
            ulong valLen;
            if (!TryProcessColumnHeaderNoNBC(rec, stateObj, out isNull, out valLen))
            {
                return false;
            }

            // always read as sql types
            Debug.Assert(valLen < (ulong)(Int32.MaxValue), "ProcessReturnValue received data size > 2Gb");

            int intlen = valLen > (ulong)(Int32.MaxValue) ? Int32.MaxValue : (int)valLen;

            if (rec.metaType.IsPlp)
            {
                intlen = Int32.MaxValue;    // If plp data, read it all
            }

            if (isNull)
            {
                GetNullSqlValue(rec.value, rec);
            }
            else
            {
                if (!TryReadSqlValue(rec.value, rec, intlen, stateObj))
                {
                    return false;
                }
            }

            returnValue = rec;
            return true;
        }
Example #6
0
        private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col, SqlTceCipherInfoTable? cipherTable, bool fColMD, SqlCommandColumnEncryptionSetting columnEncryptionSetting) {
            byte byteLen;
            UInt32 userType;

            // read user type - 4 bytes Yukon, 2 backwards
            if (IsYukonOrNewer) {
                if (!stateObj.TryReadUInt32(out userType)) {
                    return false;
                }
            }
            else {
                ushort userTypeShort;
                if (!stateObj.TryReadUInt16(out userTypeShort)) {
                    return false;
                }
                userType = userTypeShort;
            }

            // read flags and set appropriate flags in structure
            byte flags;
            if (!stateObj.TryReadByte(out flags)) {
                return false;
            }

            col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2);
            col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable));
            col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity));

            // read second byte of column metadata flags
            if (!stateObj.TryReadByte(out flags)) {
                return false;
            }
            
            col.isColumnSet = (TdsEnums.IsColumnSet == (flags & TdsEnums.IsColumnSet));
            if (fColMD && _serverSupportsColumnEncryption) {
                col.isEncrypted = (TdsEnums.IsEncrypted == (flags & TdsEnums.IsEncrypted));
            }

            // Read TypeInfo
            if (!TryProcessTypeInfo (stateObj, col, userType)) {
                return false;
            }

            // Read tablename if present
            if (col.metaType.IsLong && !col.metaType.IsPlp) {
                if (_isYukon) {
                    int  unusedLen = 0xFFFF;      //We ignore this value
                    if (!TryProcessOneTable(stateObj, ref unusedLen, out col.multiPartTableName)) {
                        return false;
                    }
                } else {
                    ushort shortLen;
                    if (!stateObj.TryReadUInt16(out shortLen)) {
                        return false;
                    }
                    string tableName;
                    if (!stateObj.TryReadString(shortLen, out tableName)) {
                        return false;
                    }
                    // with Sql2000 this is returned as an unquoted mix of catalog.owner.table
                    // all of which may contain "." and unable to parse correctly from the string alone
                    // example "select * from pubs..[A.B.C.D.E]" AND only when * will contain a image/text/ntext column
                    // by delay parsing from execute to SqlDataReader.GetSchemaTable to enable more scenarios
                    col.multiPartTableName = new MultiPartTableName(tableName);
                }
            }

            // Read the TCE column cryptoinfo
            if (fColMD && _serverSupportsColumnEncryption && col.isEncrypted) {
                // If the column is encrypted, we should have a valid cipherTable
                if (cipherTable.HasValue && !TryProcessTceCryptoMetadata (stateObj, col, cipherTable.Value, columnEncryptionSetting, isReturnValue: false)) {
                    return false;
                }
            }

            // Read the column name 
            if (!stateObj.TryReadByte(out byteLen)) {
                return false;
            }
            if (!stateObj.TryReadString(byteLen, out col.column)) {
                return false;
            }

            // We get too many DONE COUNTs from the server, causing too meany StatementCompleted event firings.
            // We only need to fire this event when we actually have a meta data stream with 0 or more rows.
            stateObj._receivedColMetaData = true;
            return true;
        }
Example #7
0
 private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj)
 {
     // read feature ID
     byte featureId;
     do
     {
         if (!stateObj.TryReadByte(out featureId))
         {
             return false;
         }
         if (featureId != TdsEnums.FEATUREEXT_TERMINATOR)
         {
             UInt32 dataLen;
             if (!stateObj.TryReadUInt32(out dataLen))
             {
                 return false;
             }
             byte[] data = new byte[dataLen];
             if (dataLen > 0)
             {
                 if (!stateObj.TryReadByteArray(data, 0, checked((int)dataLen)))
                 {
                     return false;
                 }
             }
             _connHandler.OnFeatureExtAck(featureId, data);
         }
     } while (featureId != TdsEnums.FEATUREEXT_TERMINATOR);
     return true;
 }
Example #8
0
        internal bool TryProcessTceCryptoMetadata (TdsParserStateObject stateObj, 
            SqlMetaDataPriv col, 
            SqlTceCipherInfoTable? cipherTable, 
            SqlCommandColumnEncryptionSetting columnEncryptionSetting,
            bool isReturnValue) {
            Debug.Assert(isReturnValue == (cipherTable == null), "Ciphertable is not set iff this is a return value");

            // Read the ordinal into cipher table
            ushort index = 0;
            UInt32 userType;

            // For return values there is not cipher table and no ordinal.
            if (cipherTable.HasValue) {
                if (!stateObj.TryReadUInt16(out index)) {
                    return false;
                }

                // validate the index (ordinal passed)
                if (index >= cipherTable.Value.Size) {
                    Bid.Trace("<sc.TdsParser.TryProcessTceCryptoMetadata|TCE> Incorrect ordinal received %d, max tab size: %d\n", index, cipherTable.Value.Size);
                    throw SQL.ParsingErrorValue(ParsingErrorState.TceInvalidOrdinalIntoCipherInfoTable, index);
                }
            }

            // Read the user type
            if (!stateObj.TryReadUInt32(out userType)) {
                return false;
            }

            // Read the base TypeInfo
            col.baseTI = new SqlMetaDataPriv();
            if (!TryProcessTypeInfo(stateObj, col.baseTI, userType)) {
                return false;
            }

            // Read the cipher algorithm Id
            byte cipherAlgorithmId;
            if (!stateObj.TryReadByte(out cipherAlgorithmId)) {
                return false;
            }

            string cipherAlgorithmName = null;
            if (TdsEnums.CustomCipherAlgorithmId == cipherAlgorithmId) {
                // Custom encryption algorithm, read the name
                byte nameSize;
                if (!stateObj.TryReadByte(out nameSize)) {
                    return false;
                }

                if (!stateObj.TryReadString(nameSize, out cipherAlgorithmName)) {
                    return false;
                }
            }

            // Read Encryption Type. 
            byte encryptionType;
            if (!stateObj.TryReadByte(out encryptionType)) {
                return false;
            }

            // Read Normalization Rule Version.
            byte normalizationRuleVersion;
            if (!stateObj.TryReadByte(out normalizationRuleVersion)) {
                return false;
            }

            Debug.Assert(col.cipherMD == null, "col.cipherMD should be null in TryProcessTceCryptoMetadata.");

            // Check if TCE is enable and if it is set the crypto MD for the column.
            // TCE is enabled if the command is set to enabled or to resultset only and this is not a return value
            // or if it is set to use connection setting and the connection has TCE enabled.
            if ((columnEncryptionSetting == SqlCommandColumnEncryptionSetting.Enabled ||
                (columnEncryptionSetting == SqlCommandColumnEncryptionSetting.ResultSetOnly && !isReturnValue)) ||
                (columnEncryptionSetting == SqlCommandColumnEncryptionSetting.UseConnectionSetting &&
                _connHandler != null && _connHandler.ConnectionOptions != null &&
                _connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled)) {
                col.cipherMD = new SqlCipherMetadata(cipherTable.HasValue ? (SqlTceCipherInfoEntry?)cipherTable.Value[index] : null,
                                                        index,
                                                        cipherAlgorithmId: cipherAlgorithmId,
                                                        cipherAlgorithmName: cipherAlgorithmName,
                                                        encryptionType: encryptionType,
                                                        normalizationRuleVersion: normalizationRuleVersion);
            }
            else {
                // If TCE is disabled mark the MD as not encrypted.
                col.isEncrypted = false;
            }

            return true;
        }
Example #9
0
        internal bool TryProcessReturnValue(int length,
                                            TdsParserStateObject stateObj,
                                            out SqlReturnValue returnValue,
                                            SqlCommandColumnEncryptionSetting columnEncryptionSetting) {
            returnValue = null;
            SqlReturnValue rec = new SqlReturnValue();
            rec.length = length;        // In Yukon this length is -1
            if (_isYukon) {
                if (!stateObj.TryReadUInt16(out rec.parmIndex)) {
                    return false;
                }
            }
            byte len;
            if (!stateObj.TryReadByte(out len)) { // Length of parameter name
                return false;
            }

            rec.parameter = null;
            if (len > 0) {
                if (!stateObj.TryReadString(len, out rec.parameter)) {
                    return false;
                }
            }

            // read status and ignore
            byte ignored;
            if (!stateObj.TryReadByte(out ignored)) {
                return false;
            }

            UInt32 userType;

            // read user type - 4 bytes Yukon, 2 backwards
            if (IsYukonOrNewer) {
                if (!stateObj.TryReadUInt32(out userType)) {
                    return false;
                }
            }
            else {
                ushort userTypeShort;
                if (!stateObj.TryReadUInt16(out userTypeShort)) {
                    return false;
                }
                userType = userTypeShort;
            }

            // Read off the flags.
            // The first byte is ignored since it doesn't contain any interesting information.
            byte flags;
            if (!stateObj.TryReadByte(out flags)) {
                return false;
            }

            if (!stateObj.TryReadByte(out flags)) {
                return false;
            }

            // Check if the column is encrypted.
            if (_serverSupportsColumnEncryption) {
                rec.isEncrypted = (TdsEnums.IsEncrypted == (flags & TdsEnums.IsEncrypted));
            }

            // read the type
            byte tdsType;
            if (!stateObj.TryReadByte(out tdsType)) {
                return false;
            }

            // read the MaxLen
            // For xml datatpyes, there is no tokenLength
            int tdsLen;

            if (tdsType == TdsEnums.SQLXMLTYPE) {
                tdsLen = TdsEnums.SQL_USHORTVARMAXLEN;
            }
            else if (IsVarTimeTds(tdsType))
                tdsLen = 0;  // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN
            else if (tdsType == TdsEnums.SQLDATE) {
                tdsLen = 3;
            }
            else {
                if (!TryGetTokenLength(tdsType, stateObj, out tdsLen)) {
                    return false;
                }
            }

            rec.metaType = MetaType.GetSqlDataType(tdsType, userType, tdsLen);
            rec.type = rec.metaType.SqlDbType;

            // always use the nullable type for parameters if Shiloh or later
            // Sphinx sometimes sends fixed length return values
            if (_isShiloh) {
                rec.tdsType = rec.metaType.NullableType;
                rec.isNullable = true;
                if (tdsLen == TdsEnums.SQL_USHORTVARMAXLEN) {
                    Debug.Assert(_isYukon, "plp data from pre-Yukon server");
                    rec.metaType = MetaType.GetMaxMetaTypeFromMetaType(rec.metaType);
                }
            }
            else {      // For sphinx, keep the fixed type if that is what is returned
                if (rec.metaType.NullableType == tdsType)
                    rec.isNullable = true;

                rec.tdsType = (byte)tdsType;
            }

            if (rec.type == SqlDbType.Decimal) {
                if (!stateObj.TryReadByte(out rec.precision)) {
                    return false;
                }
                if (!stateObj.TryReadByte(out rec.scale)) {
                    return false;
                }
            }

            if (rec.metaType.IsVarTime) {
                if (!stateObj.TryReadByte(out rec.scale)) {
                    return false;
                }
            }

            if (tdsType == TdsEnums.SQLUDT) {
                if (!TryProcessUDTMetaData((SqlMetaDataPriv) rec, stateObj)) {
                    return false;
                }
            }

            if (rec.type == SqlDbType.Xml) {
                // Read schema info
                byte schemapresent;
                if (!stateObj.TryReadByte(out schemapresent)) {
                    return false;
                }

                if ((schemapresent & 1) != 0) {
                    if (!stateObj.TryReadByte(out len)) {
                        return false;
                    }
                    if (len != 0) {
                        if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionDatabase)) {
                            return false;
                        }
                    }

                    if (!stateObj.TryReadByte(out len)) {
                        return false;
                    }
                    if (len != 0) {
                        if (!stateObj.TryReadString(len, out rec.xmlSchemaCollectionOwningSchema)) {
                            return false;
                        }
                    }

                    short slen;
                    if (!stateObj.TryReadInt16(out slen)) {
                        return false;
                    }

                    if (slen != 0) {
                        if (!stateObj.TryReadString(slen, out rec.xmlSchemaCollectionName)) {
                            return false;
                        }
                    }

                }
            }
            else if (_isShiloh && rec.metaType.IsCharType) {
                // read the collation for 8.x servers
                if (!TryProcessCollation(stateObj, out rec.collation)) {
                    return false;
                }

                int codePage = GetCodePage(rec.collation, stateObj);

                // if the column lcid is the same as the default, use the default encoder
                if (codePage == _defaultCodePage) {
                    rec.codePage = _defaultCodePage;
                    rec.encoding = _defaultEncoding;
                }
                else {
                    rec.codePage = codePage;
                    rec.encoding = System.Text.Encoding.GetEncoding(rec.codePage);
                }
            }

            // For encrypted parameters, read the unencrypted type and encryption information.
            if (_serverSupportsColumnEncryption && rec.isEncrypted) {
                if (!TryProcessTceCryptoMetadata(stateObj, rec, cipherTable: null, columnEncryptionSetting: columnEncryptionSetting, isReturnValue: true)) {
                    return false;
                }
            }

            // for now we coerce return values into a SQLVariant, not good...
            bool isNull = false;
            ulong valLen;
            if (!TryProcessColumnHeaderNoNBC(rec, stateObj, out isNull, out valLen)) {
                return false;
            }

            // always read as sql types
            Debug.Assert(valLen < (ulong)(Int32.MaxValue), "ProcessReturnValue received data size > 2Gb");

            int intlen = valLen > (ulong)(Int32.MaxValue) ? Int32.MaxValue : (int)valLen;

            if (rec.metaType.IsPlp) {
                intlen = Int32.MaxValue;    // If plp data, read it all
            }

            if (isNull) {
                GetNullSqlValue(rec.value, rec, SqlCommandColumnEncryptionSetting.Disabled, _connHandler);
            }
            else {
                // We should never do any decryption here, so pass disabled as the command encryption override.
                // We only read the binary value and decryption will be performed by OnReturnValue().
                if (!TryReadSqlValue(rec.value, rec, intlen, stateObj, SqlCommandColumnEncryptionSetting.Disabled, columnName:null /*Not used*/)) {
                    return false;
                }
            }

            returnValue = rec;
            return true;
        }
Example #10
0
        private bool TryProcessFedAuthInfo(TdsParserStateObject stateObj, int tokenLen, out SqlFedAuthInfo sqlFedAuthInfo) {
            sqlFedAuthInfo = null;
            SqlFedAuthInfo tempFedAuthInfo = new SqlFedAuthInfo();

            // Skip reading token length, since it has already been read in caller

            if (Bid.AdvancedOn) {
                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FEDAUTHINFO token stream length = {0}\n", tokenLen);
            }

            if (tokenLen < sizeof(uint)) {
                // the token must at least contain a DWORD indicating the number of info IDs
                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream length too short for CountOfInfoIDs.\n");
                throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForCountOfInfoIds, tokenLen);
            }

            // read how many FedAuthInfo options there are
            uint optionsCount;
            if (!stateObj.TryReadUInt32(out optionsCount)) {
                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read CountOfInfoIDs in FEDAUTHINFO token stream.\n");
                throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadCountOfInfoIds);
            }
            tokenLen -= sizeof(uint); // remaining length is shortened since we read optCount

            if (Bid.AdvancedOn) {
                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> CountOfInfoIDs = {0}\n", optionsCount.ToString(CultureInfo.InvariantCulture));
            }

            if (tokenLen > 0) {
                // read the rest of the token
                byte[] tokenData = new byte[tokenLen];
                int totalRead = 0;
                bool successfulRead = stateObj.TryReadByteArray(tokenData, 0, tokenLen, out totalRead);

                if (Bid.AdvancedOn) {
                    Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Read rest of FEDAUTHINFO token stream: {0}\n", BitConverter.ToString(tokenData, 0, totalRead));
                }

                if (!successfulRead || totalRead != tokenLen) {
                    Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read FEDAUTHINFO token stream. Attempted to read {0} bytes, actually read {1}\n", tokenLen, totalRead);
                    throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadTokenStream);
                }

                // each FedAuthInfoOpt is 9 bytes:
                //    1 byte for FedAuthInfoID
                //    4 bytes for FedAuthInfoDataLen
                //    4 bytes for FedAuthInfoDataOffset
                // So this is the index in tokenData for the i-th option
                const uint optionSize = 9;

                // the total number of bytes for all FedAuthInfoOpts together
                uint totalOptionsSize = checked(optionsCount * optionSize);

                for (uint i = 0; i < optionsCount; i++) {
                    uint currentOptionOffset = checked(i * optionSize);

                    byte id = tokenData[currentOptionOffset];
                    uint dataLen = BitConverter.ToUInt32(tokenData, checked((int)(currentOptionOffset + 1)));
                    uint dataOffset = BitConverter.ToUInt32(tokenData, checked((int)(currentOptionOffset + 5)));

                    if (Bid.AdvancedOn) {
                        Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FedAuthInfoOpt: ID={0}, DataLen={1}, Offset={2}\n", id, dataLen.ToString(CultureInfo.InvariantCulture), dataOffset.ToString(CultureInfo.InvariantCulture));
                    }

                    // offset is measured from optCount, so subtract to make offset measured
                    // from the beginning of tokenData
                    checked {
                        dataOffset -= sizeof(uint);
                    }

                    // if dataOffset points to a region within FedAuthInfoOpt or after the end of the token, throw
                    if (dataOffset < totalOptionsSize || dataOffset >= tokenLen) {
                        Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FedAuthInfoDataOffset points to an invalid location.\n");
                        throw SQL.ParsingErrorOffset(ParsingErrorState.FedAuthInfoInvalidOffset, unchecked((int)dataOffset));
                    }

                    // try to read data and throw if the arguments are bad, meaning the server sent us a bad token
                    string data;
                    try {
                        data = System.Text.Encoding.Unicode.GetString(tokenData, checked((int)dataOffset), checked((int)dataLen));
                    }
                    catch (ArgumentOutOfRangeException e) {
                        Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> Failed to read FedAuthInfoData.\n");
                        throw SQL.ParsingError(ParsingErrorState.FedAuthInfoFailedToReadData, e);
                    }
                    catch (ArgumentException e) {
                        Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FedAuthInfoData is not in unicode format.\n");
                        throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDataNotUnicode, e);
                    }

                    if (Bid.AdvancedOn) {
                        Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> FedAuthInfoData: {0}\n", data);
                    }

                    // store data in tempFedAuthInfo
                    switch ((TdsEnums.FedAuthInfoId)id) {
                        case TdsEnums.FedAuthInfoId.Spn:
                            tempFedAuthInfo.spn = data;
                            break;
                        case TdsEnums.FedAuthInfoId.Stsurl:
                            tempFedAuthInfo.stsurl = data;
                            break;
                        default:
                            if (Bid.AdvancedOn) {
                                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Ignoring unknown federated authentication info option: {0}\n", id);
                            }
                            break;
                    }
                }
            }
            else {
                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream is not long enough to contain the data it claims to.\n");
                throw SQL.ParsingErrorLength(ParsingErrorState.FedAuthInfoLengthTooShortForData, tokenLen);
            }

            Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo> Processed FEDAUTHINFO token stream: {0}\n", tempFedAuthInfo.ToString());

            if (String.IsNullOrWhiteSpace(tempFedAuthInfo.stsurl) || String.IsNullOrWhiteSpace(tempFedAuthInfo.spn)) {
                // We should be receiving both stsurl and spn
                Bid.Trace("<sc.TdsParser.TryProcessFedAuthInfo|ERR> FEDAUTHINFO token stream does not contain both STSURL and SPN.\n");
                throw SQL.ParsingError(ParsingErrorState.FedAuthInfoDoesNotContainStsurlAndSpn);
            }

            sqlFedAuthInfo = tempFedAuthInfo;
            return true;
        }
Example #11
0
        private bool TryProcessFeatureExtAck(TdsParserStateObject stateObj) {
            // read feature ID
            byte featureId;
            do {
                if (!stateObj.TryReadByte(out featureId)) {
                    return false;
                }
                if (featureId != TdsEnums.FEATUREEXT_TERMINATOR) {
                    UInt32 dataLen;
                    if (!stateObj.TryReadUInt32(out dataLen)) {
                        return false;
                    }                    
                    byte[] data = new byte[dataLen];
                    if (dataLen > 0) {
                        if (!stateObj.TryReadByteArray(data, 0, checked ((int)dataLen))) {
                            return false;
                        }
                    }
                    _connHandler.OnFeatureExtAck(featureId, data);
                }
            } while (featureId != TdsEnums.FEATUREEXT_TERMINATOR);

            // Check if column encryption was on and feature wasn't acknowledged.
            if (_connHandler.ConnectionOptions.ColumnEncryptionSetting == SqlConnectionColumnEncryptionSetting.Enabled && !IsColumnEncryptionSupported) {
                throw SQL.TceNotSupported ();
            }

            return true;
        }
Example #12
0
        private bool TryCommonProcessMetaData(TdsParserStateObject stateObj, _SqlMetaData col) {
            byte byteLen;
            UInt32 userType;

            // read user type - 4 bytes Yukon, 2 backwards
            if (IsYukonOrNewer) {
                if (!stateObj.TryReadUInt32(out userType)) {
                    return false;
                }
            }
            else {
                ushort userTypeShort;
                if (!stateObj.TryReadUInt16(out userTypeShort)) {
                    return false;
                }
                userType = userTypeShort;
            }

            // read flags and set appropriate flags in structure
            byte flags;
            if (!stateObj.TryReadByte(out flags)) {
                return false;
            }

            col.updatability = (byte)((flags & TdsEnums.Updatability) >> 2);
            col.isNullable = (TdsEnums.Nullable == (flags & TdsEnums.Nullable));
            col.isIdentity = (TdsEnums.Identity == (flags & TdsEnums.Identity));

            // read second byte of column metadata flags
            if (!stateObj.TryReadByte(out flags)) {
                return false;
            }
            
            col.isColumnSet = (TdsEnums.IsColumnSet == (flags & TdsEnums.IsColumnSet));

            byte tdsType;
            if (!stateObj.TryReadByte(out tdsType)) {
                return false;
            }

            if (tdsType == TdsEnums.SQLXMLTYPE)
                col.length = TdsEnums.SQL_USHORTVARMAXLEN;  //Use the same length as other plp datatypes
            else if (IsVarTimeTds(tdsType))
                col.length = 0;  // placeholder until we read the scale, just make sure it's not SQL_USHORTVARMAXLEN
            else if (tdsType == TdsEnums.SQLDATE) {
                col.length = 3;
            }
            else {
                if (!TryGetTokenLength(tdsType, stateObj, out col.length)) {
                    return false;
                }
            }

            col.metaType = MetaType.GetSqlDataType(tdsType, userType, col.length);
            col.type = col.metaType.SqlDbType;

            // If sphinx, do not change to nullable type
            if (_isShiloh)
                col.tdsType = (col.isNullable ? col.metaType.NullableType : col.metaType.TDSType);
            else
                col.tdsType = tdsType;

            if (_isYukon) {
                if (TdsEnums.SQLUDT == tdsType) {
                    if (!TryProcessUDTMetaData((SqlMetaDataPriv) col, stateObj)) {
                        return false;
                    }
                }

                if (col.length == TdsEnums.SQL_USHORTVARMAXLEN) {
                    Debug.Assert(tdsType == TdsEnums.SQLXMLTYPE ||
                                 tdsType == TdsEnums.SQLBIGVARCHAR ||
                                 tdsType == TdsEnums.SQLBIGVARBINARY ||
                                 tdsType == TdsEnums.SQLNVARCHAR ||
                                 tdsType == TdsEnums.SQLUDT,
                                 "Invalid streaming datatype");
                    col.metaType = MetaType.GetMaxMetaTypeFromMetaType(col.metaType);
                    Debug.Assert(col.metaType.IsLong, "Max datatype not IsLong");
                    col.length = Int32.MaxValue;
                    if (tdsType == TdsEnums.SQLXMLTYPE) {
                        byte schemapresent;
                        if (!stateObj.TryReadByte(out schemapresent)) {
                            return false;
                        }

                        if ((schemapresent & 1) != 0) {
                            if (!stateObj.TryReadByte(out byteLen)) {
                                return false;
                            }
                            if (byteLen != 0) {
                                if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionDatabase)) {
                                    return false;
                                }
                            }

                            if (!stateObj.TryReadByte(out byteLen)) {
                                return false;
                            }
                            if (byteLen != 0) {
                                if (!stateObj.TryReadString(byteLen, out col.xmlSchemaCollectionOwningSchema)) {
                                    return false;
                                }
                            }

                            short shortLen;
                            if (!stateObj.TryReadInt16(out shortLen)) {
                                return false;
                            }
                            if (byteLen != 0) {
                                if (!stateObj.TryReadString(shortLen, out col.xmlSchemaCollectionName)) {
                                    return false;
                                }
                            }
                        }
                    }
                }
            }

            if (col.type == SqlDbType.Decimal) {
                if (!stateObj.TryReadByte(out col.precision)) {
                    return false;
                }
                if (!stateObj.TryReadByte(out col.scale)) {
                    return false;
                }
            }

            if (col.metaType.IsVarTime) {
                if (!stateObj.TryReadByte(out col.scale)) {
                    return false;
                }

                Debug.Assert(0 <= col.scale && col.scale <= 7);

                // calculate actual column length here
                // 
                switch (col.metaType.SqlDbType)
                {
                    case SqlDbType.Time:
                        col.length = MetaType.GetTimeSizeFromScale(col.scale);
                        break;
                    case SqlDbType.DateTime2:
                        // Date in number of days (3 bytes) + time
                        col.length = 3 + MetaType.GetTimeSizeFromScale(col.scale);
                        break;
                    case SqlDbType.DateTimeOffset:
                        // Date in days (3 bytes) + offset in minutes (2 bytes) + time
                        col.length = 5 + MetaType.GetTimeSizeFromScale(col.scale);
                        break;

                    default:
                        Debug.Assert(false, "Unknown VariableTime type!");
                        break;
                }
            }

            // read the collation for 7.x servers
            if (_isShiloh && col.metaType.IsCharType && (tdsType != TdsEnums.SQLXMLTYPE)) {
                if (!TryProcessCollation(stateObj, out col.collation)) {
                    return false;
                }

                int codePage = GetCodePage(col.collation, stateObj);

                if (codePage == _defaultCodePage) {
                    col.codePage = _defaultCodePage;
                    col.encoding = _defaultEncoding;
                }
                else {
                    col.codePage = codePage;
                    col.encoding = System.Text.Encoding.GetEncoding(col.codePage);
                }
            }

            if (col.metaType.IsLong && !col.metaType.IsPlp) {
                if (_isYukon) {
                    int  unusedLen = 0xFFFF;      //We ignore this value
                    if (!TryProcessOneTable(stateObj, ref unusedLen, out col.multiPartTableName)) {
                        return false;
                    }
                } else {
                    ushort shortLen;
                    if (!stateObj.TryReadUInt16(out shortLen)) {
                        return false;
                    }
                    string tableName;
                    if (!stateObj.TryReadString(shortLen, out tableName)) {
                        return false;
                    }
                    // with Sql2000 this is returned as an unquoted mix of catalog.owner.table
                    // all of which may contain "." and unable to parse correctly from the string alone
                    // example "select * from pubs..[A.B.C.D.E]" AND only when * will contain a image/text/ntext column
                    // by delay parsing from execute to SqlDataReader.GetSchemaTable to enable more scenarios
                    col.multiPartTableName = new MultiPartTableName(tableName);
                }
            }

            if (!stateObj.TryReadByte(out byteLen)) {
                return false;
            }
            if (!stateObj.TryReadString(byteLen, out col.column)) {
                return false;
            }

            // We get too many DONE COUNTs from the server, causing too meany StatementCompleted event firings.
            // We only need to fire this event when we actually have a meta data stream with 0 or more rows.
            stateObj._receivedColMetaData = true;
            return true;
        }