Exemple #1
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;
        }
Exemple #2
0
        internal bool TryProcessError(byte token, TdsParserStateObject stateObj, out SqlError error)
        {
            ushort shortLen;
            byte byteLen;
            int number;
            byte state;
            byte errorClass;

            error = null;

            if (!stateObj.TryReadInt32(out number))
            {
                return false;
            }
            if (!stateObj.TryReadByte(out state))
            {
                return false;
            }
            if (!stateObj.TryReadByte(out errorClass))
            {
                return false;
            }

            Debug.Assert(((errorClass >= TdsEnums.MIN_ERROR_CLASS) && token == TdsEnums.SQLERROR) ||
                          ((errorClass < TdsEnums.MIN_ERROR_CLASS) && token == TdsEnums.SQLINFO), "class and token don't match!");

            if (!stateObj.TryReadUInt16(out shortLen))
            {
                return false;
            }
            string message;
            if (!stateObj.TryReadString(shortLen, out message))
            {
                return false;
            }

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

            string server;

            // If the server field is not recieved use the locally cached value.
            if (byteLen == 0)
            {
                server = _server;
            }
            else
            {
                if (!stateObj.TryReadString(byteLen, out server))
                {
                    return false;
                }
            }

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

            int line;
            if (!stateObj.TryReadInt32(out line))
            {
                return false;
            }

            error = new SqlError(number, state, errorClass, _server, message, procedure, line);
            return true;
        }
Exemple #3
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;
        }
Exemple #4
0
        private bool TryProcessEnvChange(int tokenLength, TdsParserStateObject stateObj, out SqlEnvChange[] sqlEnvChange)
        {
            // There could be multiple environment change messages following this token.
            byte byteLength;
            int processedLength = 0;
            int nvalues = 0;
            SqlEnvChange[] envarray = new SqlEnvChange[3];  // Why is this hardcoded to 3?

            sqlEnvChange = null;

            while (tokenLength > processedLength)
            {
                if (nvalues >= envarray.Length)
                {
                    // This is a rare path. Most of the time we will have 1 or 2 envchange data streams.
                    SqlEnvChange[] newenvarray = new SqlEnvChange[envarray.Length + 3];

                    for (int ii = 0; ii < envarray.Length; ii++)
                        newenvarray[ii] = envarray[ii];

                    envarray = newenvarray;
                }

                SqlEnvChange env = new SqlEnvChange();

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

                envarray[nvalues] = env;
                nvalues++;

                switch (env.type)
                {
                    case TdsEnums.ENV_DATABASE:
                    case TdsEnums.ENV_LANG:
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            return false;
                        }
                        break;

                    case TdsEnums.ENV_CHARSET:
                        // we copied this behavior directly from luxor - see charset envchange
                        // section from sqlctokn.c
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            return false;
                        }
                        if (env.newValue == TdsEnums.DEFAULT_ENGLISH_CODE_PAGE_STRING)
                        {
                            _defaultCodePage = TdsEnums.DEFAULT_ENGLISH_CODE_PAGE_VALUE;
                            _defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage);
                        }
                        else
                        {
                            Debug.Assert(env.newValue.Length > TdsEnums.CHARSET_CODE_PAGE_OFFSET, "TdsParser.ProcessEnvChange(): charset value received with length <=10");

                            string stringCodePage = env.newValue.Substring(TdsEnums.CHARSET_CODE_PAGE_OFFSET);

                            _defaultCodePage = Int32.Parse(stringCodePage, NumberStyles.Integer, CultureInfo.InvariantCulture);
                            _defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage);
                        }

                        break;

                    case TdsEnums.ENV_PACKETSIZE:
                        // take care of packet size right here
                        Debug.Assert(stateObj._syncOverAsync, "Should not attempt pends in a synchronous call");
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            // Changing packet size does not support retry, should not pend"
                            throw SQL.SynchronousCallMayNotPend();
                        }
                        // Only set on physical state object - this should only occur on LoginAck prior
                        // to MARS initialization!
                        Int32 packetSize = Int32.Parse(env.newValue, NumberStyles.Integer, CultureInfo.InvariantCulture);

                        if (_physicalStateObj.SetPacketSize(packetSize))
                        {
                            // If packet size changed, we need to release our SNIPackets since
                            // those are tied to packet size of connection.
                            _physicalStateObj.ClearAllWritePackets();

                            // Update SNI ConsumerInfo value to be resulting packet size
                            UInt32 unsignedPacketSize = (UInt32)packetSize;
                            UInt32 result = SNINativeMethodWrapper.SNISetInfo(_physicalStateObj.Handle, SNINativeMethodWrapper.QTypes.SNI_QUERY_CONN_BUFSIZE, ref unsignedPacketSize);

                            Debug.Assert(result == TdsEnums.SNI_SUCCESS, "Unexpected failure state upon calling SNISetInfo");
                        }

                        break;

                    case TdsEnums.ENV_LOCALEID:
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            return false;
                        }
                        _defaultLCID = Int32.Parse(env.newValue, NumberStyles.Integer, CultureInfo.InvariantCulture);
                        break;

                    case TdsEnums.ENV_COMPFLAGS:
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            return false;
                        }
                        break;

                    case TdsEnums.ENV_COLLATION:
                        Debug.Assert(env.newLength == 5 || env.newLength == 0, "Improper length in new collation!");
                        if (!stateObj.TryReadByte(out byteLength))
                        {
                            return false;
                        }
                        env.newLength = byteLength;
                        if (env.newLength == 5)
                        {
                            if (!TryProcessCollation(stateObj, out env.newCollation))
                            {
                                return false;
                            }

                            // give the parser the new collation values in case parameters don't specify one
                            _defaultCollation = env.newCollation;
                            int newCodePage = GetCodePage(env.newCollation, stateObj);
                            if (newCodePage != _defaultCodePage)
                            {
                                _defaultCodePage = newCodePage;
                                _defaultEncoding = System.Text.Encoding.GetEncoding(_defaultCodePage);
                            }
                            _defaultLCID = env.newCollation.LCID;
                        }

                        if (!stateObj.TryReadByte(out byteLength))
                        {
                            return false;
                        }
                        env.oldLength = byteLength;
                        Debug.Assert(env.oldLength == 5 || env.oldLength == 0, "Improper length in old collation!");
                        if (env.oldLength == 5)
                        {
                            if (!TryProcessCollation(stateObj, out env.oldCollation))
                            {
                                return false;
                            }
                        }

                        env.length = 3 + env.newLength + env.oldLength;
                        break;

                    case TdsEnums.ENV_BEGINTRAN:
                    case TdsEnums.ENV_COMMITTRAN:
                    case TdsEnums.ENV_ROLLBACKTRAN:

                        if (!stateObj.TryReadByte(out byteLength))
                        {
                            return false;
                        }
                        env.newLength = byteLength;
                        Debug.Assert(env.newLength == 0 || env.newLength == 8, "Improper length for new transaction id!");

                        if (env.newLength > 0)
                        {
                            if (!stateObj.TryReadInt64(out env.newLongValue))
                            {
                                return false;
                            }
                            Debug.Assert(env.newLongValue != SqlInternalTransaction.NullTransactionId, "New transaction id is null?"); // the server guarantees that zero is an invalid transaction id.
                        }
                        else
                        {
                            env.newLongValue = SqlInternalTransaction.NullTransactionId; // the server guarantees that zero is an invalid transaction id.
                        }

                        if (!stateObj.TryReadByte(out byteLength))
                        {
                            return false;
                        }
                        env.oldLength = byteLength;
                        Debug.Assert(env.oldLength == 0 || env.oldLength == 8, "Improper length for old transaction id!");

                        if (env.oldLength > 0)
                        {
                            if (!stateObj.TryReadInt64(out env.oldLongValue))
                            {
                                return false;
                            }
                            Debug.Assert(env.oldLongValue != SqlInternalTransaction.NullTransactionId, "Old transaction id is null?"); // the server guarantees that zero is an invalid transaction id.
                        }
                        else
                        {
                            env.oldLongValue = SqlInternalTransaction.NullTransactionId; // the server guarantees that zero is an invalid transaction id.
                        }

                        // env.length includes 1 byte type token
                        env.length = 3 + env.newLength + env.oldLength;
                        break;

                    case TdsEnums.ENV_LOGSHIPNODE:
                        // env.newBinValue is secondary node, env.oldBinValue is witness node
                        // comes before LoginAck so we can't assert this
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            return false;
                        }
                        break;

                    case TdsEnums.ENV_SPRESETCONNECTIONACK:
                        if (!TryReadTwoBinaryFields(env, stateObj))
                        {
                            return false;
                        }
                        break;

                    case TdsEnums.ENV_USERINSTANCE:
                        if (!TryReadTwoStringFields(env, stateObj))
                        {
                            return false;
                        }
                        break;

                    case TdsEnums.ENV_ROUTING:
                        ushort newLength;
                        if (!stateObj.TryReadUInt16(out newLength))
                        {
                            return false;
                        }
                        env.newLength = newLength;
                        byte protocol;
                        if (!stateObj.TryReadByte(out protocol))
                        {
                            return false;
                        }
                        ushort port;
                        if (!stateObj.TryReadUInt16(out port))
                        {
                            return false;
                        }
                        UInt16 serverLen;
                        if (!stateObj.TryReadUInt16(out serverLen))
                        {
                            return false;
                        }
                        string serverName;
                        if (!stateObj.TryReadString(serverLen, out serverName))
                        {
                            return false;
                        }
                        env.newRoutingInfo = new RoutingInfo(protocol, port, serverName);
                        UInt16 oldLength;
                        if (!stateObj.TryReadUInt16(out oldLength))
                        {
                            return false;
                        }
                        if (!stateObj.TrySkipBytes(oldLength))
                        {
                            return false;
                        }
                        env.length = env.newLength + oldLength + 5; // 5=2*sizeof(UInt16)+sizeof(byte) [token+newLength+oldLength]
                        break;

                    // ENVCHANGE tokens not supported by CoreCLR
                    case TdsEnums.ENV_ENLISTDTC:
                    case TdsEnums.ENV_DEFECTDTC:
                    case TdsEnums.ENV_TRANSACTIONENDED:
                    case TdsEnums.ENV_PROMOTETRANSACTION:
                    case TdsEnums.ENV_TRANSACTIONMANAGERADDRESS:
                        throw SQL.UnsupportedFeatureAndToken(_connHandler, ((TdsEnums.EnvChangeType)env.type).ToString());

                    default:
                        Debug.Assert(false, "Unknown environment change token: " + env.type);
                        break;
                }
                processedLength += env.length;
            }

            sqlEnvChange = envarray;
            return true;
        }
Exemple #5
0
        private bool TryReadTwoStringFields(SqlEnvChange env, TdsParserStateObject stateObj)
        {
            // Used by ProcessEnvChangeToken
            byte newLength, oldLength;
            string newValue, oldValue;
            if (!stateObj.TryReadByte(out newLength))
            {
                return false;
            }
            if (!stateObj.TryReadString(newLength, out newValue))
            {
                return false;
            }
            if (!stateObj.TryReadByte(out oldLength))
            {
                return false;
            }
            if (!stateObj.TryReadString(oldLength, out oldValue))
            {
                return false;
            }

            env.newLength = newLength;
            env.newValue = newValue;
            env.oldLength = oldLength;
            env.oldValue = oldValue;

            // env.length includes 1 byte type token
            env.length = 3 + env.newLength * 2 + env.oldLength * 2;
            return true;
        }
        private bool TryProcessLoginAck(TdsParserStateObject stateObj, out SqlLoginAck sqlLoginAck) {
            SqlLoginAck a = new SqlLoginAck();

            sqlLoginAck = null;

            // read past interface type and version
            if (!stateObj.TrySkipBytes(1)) {
                return false;
            }

            byte[] b = new byte[TdsEnums.VERSION_SIZE];
            if (!stateObj.TryReadByteArray(b, 0, b.Length)) {
                return false;
            }
            a.tdsVersion = (UInt32)((((((b[0]<<8)|b[1])<<8)|b[2])<<8)|b[3]); // bytes are in motorola order (high byte first)
            UInt32 majorMinor = a.tdsVersion & 0xff00ffff;
            UInt32 increment  = (a.tdsVersion >> 16) & 0xff;

            // Server responds:
            // 0x07000000 -> Sphinx         // Notice server response format is different for bwd compat
            // 0x07010000 -> Shiloh RTM     // Notice server response format is different for bwd compat
            // 0x71000001 -> Shiloh SP1
            // 0x72xx0002 -> Yukon RTM
            // information provided by S. Ashwin

            switch (majorMinor) {
                case TdsEnums.SPHINXORSHILOH_MAJOR<<24|TdsEnums.DEFAULT_MINOR:    // Sphinx & Shiloh RTM
                    // note that sphinx and shiloh_rtm can only be distinguished by the increment
                    switch (increment) {
                        case TdsEnums.SHILOH_INCREMENT:
                            _isShiloh = true;
                            break;
                        case TdsEnums.SPHINX_INCREMENT:
                            // no flag will be set
                            break;
                        default:
                            throw SQL.InvalidTDSVersion();
                    }
                    break;
                case TdsEnums.SHILOHSP1_MAJOR<<24|TdsEnums.SHILOHSP1_MINOR: // Shiloh SP1
                    if (increment != TdsEnums.SHILOHSP1_INCREMENT) { throw SQL.InvalidTDSVersion(); }
                    _isShilohSP1 = true;
                    break;
                case TdsEnums.YUKON_MAJOR<<24|TdsEnums.YUKON_RTM_MINOR:     // Yukon
                    if (increment != TdsEnums.YUKON_INCREMENT) { throw SQL.InvalidTDSVersion(); }
                    _isYukon = true;
                    break;
                case TdsEnums.KATMAI_MAJOR<<24|TdsEnums.KATMAI_MINOR:
                    if (increment != TdsEnums.KATMAI_INCREMENT) { throw SQL.InvalidTDSVersion(); }
                    _isKatmai = true;
                    break;
                case TdsEnums.DENALI_MAJOR << 24|TdsEnums.DENALI_MINOR:
                    if (increment != TdsEnums.DENALI_INCREMENT) { throw SQL.InvalidTDSVersion(); }
                    _isDenali = true;
                    break;
                default:
                    throw SQL.InvalidTDSVersion();
            }

            _isKatmai       |= _isDenali;
            _isYukon        |= _isKatmai;
            _isShilohSP1    |= _isYukon;            // includes all lower versions
            _isShiloh       |= _isShilohSP1;        //

            a.isVersion8 = _isShiloh;

            stateObj._outBytesUsed = stateObj._outputHeaderLen;
            byte len;
            if (!stateObj.TryReadByte(out len)) {
                return false;
            }

            if (!stateObj.TryReadString(len, out a.programName)) {
                return false;
            }
            if (!stateObj.TryReadByte(out a.majorVersion)) {
                return false;
            }
            if (!stateObj.TryReadByte(out a.minorVersion)) {
                return false;
            }
            byte buildNumHi, buildNumLo;
            if (!stateObj.TryReadByte(out buildNumHi)) {
                return false;
            }
            if (!stateObj.TryReadByte(out buildNumLo)) {
                return false;
            }

            a.buildNum = (short)((buildNumHi << 8) + buildNumLo);

            Debug.Assert(_state == TdsParserState.OpenNotLoggedIn, "ProcessLoginAck called with state not TdsParserState.OpenNotLoggedIn");
            _state = TdsParserState.OpenLoggedIn;

            if (_isYukon) {
                if (_fMARS) {
                    _resetConnectionEvent = new AutoResetEvent(true);
                }
            }

            // Fail if SSE UserInstance and we have not received this info.
            if ( _connHandler.ConnectionOptions.UserInstance && 
                ADP.IsEmpty(_connHandler.InstanceName)) {
                stateObj.AddError(new SqlError(0, 0, TdsEnums.FATAL_ERROR_CLASS, Server, SQLMessage.UserInstanceFailure(), "", 0));
                ThrowExceptionAndWarning(stateObj);
            }

            sqlLoginAck = a;
            return true;
        }
Exemple #7
0
        // augments current metadata with table and key information
        private bool TryProcessColInfo(_SqlMetaDataSet columns, SqlDataReader reader, TdsParserStateObject stateObj, out _SqlMetaDataSet metaData)
        {
            Debug.Assert(columns != null && columns.Length > 0, "no metadata available!");

            metaData = null;

            for (int i = 0; i < columns.Length; i++)
            {
                _SqlMetaData col = columns[i];

                byte ignored;
                if (!stateObj.TryReadByte(out ignored))
                { // colnum, ignore
                    return false;
                }
                if (!stateObj.TryReadByte(out ignored))
                { // tablenum, ignore
                    return false;
                }

                // interpret status
                byte status;
                if (!stateObj.TryReadByte(out status))
                {
                    return false;
                }

                col.isDifferentName = (TdsEnums.SQLDifferentName == (status & TdsEnums.SQLDifferentName));
                col.isExpression = (TdsEnums.SQLExpression == (status & TdsEnums.SQLExpression));
                col.isKey = (TdsEnums.SQLKey == (status & TdsEnums.SQLKey));
                col.isHidden = (TdsEnums.SQLHidden == (status & TdsEnums.SQLHidden));

                // read off the base table name if it is different than the select list column name
                if (TdsEnums.SQLDifferentName == (status & TdsEnums.SQLDifferentName))
                {
                    byte len;
                    if (!stateObj.TryReadByte(out len))
                    {
                        return false;
                    }
                    if (!stateObj.TryReadString(len, out col.baseColumn))
                    {
                        return false;
                    }
                }


                if (TdsEnums.SQLExpression == (status & TdsEnums.SQLExpression))
                {
                    col.updatability = 0;
                }
            }

            // set the metadata so that the stream knows some metadata info has changed
            metaData = columns;
            return true;
        }
        // augments current metadata with table and key information
        private bool TryProcessColInfo(_SqlMetaDataSet columns, SqlDataReader reader, TdsParserStateObject stateObj, out _SqlMetaDataSet metaData) {
            Debug.Assert(columns != null && columns.Length > 0, "no metadata available!");

            metaData = null;

            for (int i = 0; i < columns.Length; i++) {
                _SqlMetaData col = columns[i];

                byte ignored;
                if (!stateObj.TryReadByte(out ignored)) { // colnum, ignore
                    return false;
                }
                if (!stateObj.TryReadByte(out col.tableNum)) {
                    return false;
                }

                // interpret status
                byte status;
                if (!stateObj.TryReadByte(out status)) {
                    return false;
                }

                col.isDifferentName = (TdsEnums.SQLDifferentName == (status & TdsEnums.SQLDifferentName));
                col.isExpression = (TdsEnums.SQLExpression == (status & TdsEnums.SQLExpression));
                col.isKey = (TdsEnums.SQLKey == (status & TdsEnums.SQLKey));
                col.isHidden = (TdsEnums.SQLHidden == (status & TdsEnums.SQLHidden));

                // read off the base table name if it is different than the select list column name
                if (col.isDifferentName) {
                    byte len;
                    if (!stateObj.TryReadByte(out len)) {
                        return false;
                    }
                    if (!stateObj.TryReadString(len, out col.baseColumn)) {
                        return false;
                    }
                }

                // Fixup column name - only if result of a table - that is if it was not the result of
                // an expression.
                if ((reader.TableNames != null) && (col.tableNum > 0)) {
                    Debug.Assert(reader.TableNames.Length >= col.tableNum, "invalid tableNames array!");
                    col.multiPartTableName = reader.TableNames[col.tableNum - 1];
                }

                // MDAC 60109: expressions are readonly
                if (col.isExpression) {
                    col.updatability = 0;
                }
            }

            // set the metadata so that the stream knows some metadata info has changed
            metaData = columns;
            return true;
        }
Exemple #9
0
         private bool TryProcessUDTMetaData(SqlMetaDataPriv metaData, TdsParserStateObject stateObj) {

            ushort shortLength;
            byte byteLength;

            if (!stateObj.TryReadUInt16(out shortLength)) { // max byte size
                return false;
            }
            metaData.length = shortLength;

            // database name
            if (!stateObj.TryReadByte(out byteLength)) {
                return false;
            }
            if (byteLength != 0) {
                if (!stateObj.TryReadString(byteLength, out metaData.udtDatabaseName)) {
                    return false;
                }
            }

            // schema name
            if (!stateObj.TryReadByte(out byteLength)) {
                return false;
            }
            if (byteLength != 0) {
                if (!stateObj.TryReadString(byteLength, out metaData.udtSchemaName)) {
                    return false;
                }
            }

            // type name
            if (!stateObj.TryReadByte(out byteLength)) {
                return false;
            }
            if (byteLength != 0) {
                if (!stateObj.TryReadString(byteLength, out metaData.udtTypeName)) {
                    return false;
                }
            }

            if (!stateObj.TryReadUInt16(out shortLength)) {
                return false;
            }
            if (shortLength != 0) {
                if (!stateObj.TryReadString(shortLength, out metaData.udtAssemblyQualifiedName)) {
                    return false;
                }
            }

            return true;
        }       
        private bool TryProcessTypeInfo (TdsParserStateObject stateObj, SqlMetaDataPriv col, UInt32 userType) {
            byte byteLen;
            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);
                }
            }

            return true;
        }
        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;
        }
        /// <summary>
        /// <para> Parses the TDS message to read single CIPHER_INFO entry.</para>
        /// </summary>
        internal bool TryReadCipherInfoEntry (TdsParserStateObject stateObj, out SqlTceCipherInfoEntry entry) {
            byte cekValueCount = 0;
            entry = new SqlTceCipherInfoEntry(ordinal: 0);

            // Read the DB ID
            int dbId;
            if (!stateObj.TryReadInt32(out dbId)) {
                return false;
            }

            // Read the keyID
            int keyId;
            if (!stateObj.TryReadInt32(out keyId)) {
                return false;
            }

            // Read the key version
            int keyVersion;
            if (!stateObj.TryReadInt32(out keyVersion)) {
                return false;
            }

            // Read the key MD Version
            byte[] keyMDVersion = new byte[8];
            if (!stateObj.TryReadByteArray(keyMDVersion, 0, 8)) {
                return false;
            }

            // Read the value count
            if (!stateObj.TryReadByte (out cekValueCount)) {
                return false;
            }

            for (int i = 0; i < cekValueCount; i++) {
                // Read individual CEK values
                byte[] encryptedCek;
                string keyPath;
                string keyStoreName;
                byte algorithmLength;
                string algorithmName;
                ushort shortValue;
                byte byteValue;
                int length;

                // Read the length of encrypted CEK 
                if (!stateObj.TryReadUInt16 (out shortValue)) {
                    return false; 
                }

                length = shortValue;
                encryptedCek = new byte[length];

                // Read the actual encrypted CEK
                if (!stateObj.TryReadByteArray (encryptedCek, 0, length)) {
                    return false;
                }

                // Read the length of key store name
                if (!stateObj.TryReadByte (out byteValue)) {
                    return false;
                }

                length = byteValue;

                // And read the key store name now
                if (!stateObj.TryReadString(length, out keyStoreName)) {
                    return false;
                }

                // Read the length of key Path
                if (!stateObj.TryReadUInt16 (out shortValue)) {
                    return false;
                }

                length = shortValue;

                // Read the key path string
                if (!stateObj.TryReadString(length, out keyPath)) {
                    return false;
                }

                // Read the length of the string carrying the encryption algo
                if (!stateObj.TryReadByte(out algorithmLength)) {
                    return false;
                }

                length = (int)algorithmLength;

                // Read the string carrying the encryption algo  (eg. RSA_PKCS_OAEP)
                if (!stateObj.TryReadString(length, out algorithmName)) {
                    return false;
                }

                // Add this encrypted CEK blob to our list of encrypted values for the CEK
                entry.Add(encryptedCek, 
                    databaseId: dbId, 
                    cekId: keyId, 
                    cekVersion: keyVersion, 
                    cekMdVersion: keyMDVersion, 
                    keyPath: keyPath, 
                    keyStoreName: keyStoreName, 
                    algorithmName: algorithmName);
            }

            return true;
        }
        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;
        }
        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;
        }
Exemple #15
0
        private bool TryProcessOneTable(TdsParserStateObject stateObj, ref int length, out MultiPartTableName multiPartTableName)
        {
            ushort tableLen;
            MultiPartTableName mpt;
            string value;

            multiPartTableName = default(MultiPartTableName);

            mpt = new MultiPartTableName();
            byte nParts;

            // Find out how many parts in the TDS stream
            if (!stateObj.TryReadByte(out nParts))
            {
                return false;
            }
            length--;
            if (nParts == 4)
            {
                if (!stateObj.TryReadUInt16(out tableLen))
                {
                    return false;
                }
                length -= 2;
                if (!stateObj.TryReadString(tableLen, out value))
                {
                    return false;
                }
                mpt.ServerName = value;
                nParts--;
                length -= (tableLen * 2); // wide bytes
            }
            if (nParts == 3)
            {
                if (!stateObj.TryReadUInt16(out tableLen))
                {
                    return false;
                }
                length -= 2;
                if (!stateObj.TryReadString(tableLen, out value))
                {
                    return false;
                }
                mpt.CatalogName = value;
                length -= (tableLen * 2); // wide bytes
                nParts--;
            }
            if (nParts == 2)
            {
                if (!stateObj.TryReadUInt16(out tableLen))
                {
                    return false;
                }
                length -= 2;
                if (!stateObj.TryReadString(tableLen, out value))
                {
                    return false;
                }
                mpt.SchemaName = value;
                length -= (tableLen * 2); // wide bytes
                nParts--;
            }
            if (nParts == 1)
            {
                if (!stateObj.TryReadUInt16(out tableLen))
                {
                    return false;
                }
                length -= 2;
                if (!stateObj.TryReadString(tableLen, out value))
                {
                    return false;
                }
                mpt.TableName = value;
                length -= (tableLen * 2); // wide bytes
                nParts--;
            }
            Debug.Assert(nParts == 0, "ProcessTableName:Unidentified parts in the table name token stream!");

            multiPartTableName = mpt;
            return true;
        }
Exemple #16
0
        internal bool TryProcessError(byte token, TdsParserStateObject stateObj, out SqlError error)
        {
            ushort shortLen;
            byte byteLen;
            int number;
            byte state;
            byte errorClass;

            error = null;

            if (!stateObj.TryReadInt32(out number))
            {
                return false;
            }
            if (!stateObj.TryReadByte(out state))
            {
                return false;
            }
            if (!stateObj.TryReadByte(out errorClass))
            {
                return false;
            }

            Debug.Assert(((errorClass >= TdsEnums.MIN_ERROR_CLASS) && token == TdsEnums.SQLERROR) ||
                          ((errorClass < TdsEnums.MIN_ERROR_CLASS) && token == TdsEnums.SQLINFO), "class and token don't match!");

            if (!stateObj.TryReadUInt16(out shortLen))
            {
                return false;
            }
            string message;
            if (!stateObj.TryReadString(shortLen, out message))
            {
                return false;
            }

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

            string server;

            // If the server field is not received use the locally cached value.
            if (byteLen == 0)
            {
                server = _server;
            }
            else
            {
                if (!stateObj.TryReadString(byteLen, out server))
                {
                    return false;
                }
            }

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

            int line;
            if (_isYukon)
            {
                if (!stateObj.TryReadInt32(out line))
                {
                    return false;
                }
            }
            else
            {
                ushort shortLine;
                if (!stateObj.TryReadUInt16(out shortLine))
                {
                    return false;
                }
                line = shortLine;
                // If we haven't yet completed processing login token stream yet, we may be talking to a Yukon server
                // In that case we still have to read another 2 bytes
                if (_state == TdsParserState.OpenNotLoggedIn)
                {
                    // Login incomplete
                    byte b;
                    if (!stateObj.TryPeekByte(out b))
                    {
                        return false;
                    }
                    if (b == 0)
                    {
                        // This is an invalid token value
                        ushort value;
                        if (!stateObj.TryReadUInt16(out value))
                        {
                            return false;
                        }
                        line = (line << 16) + value;
                    }
                }
            }

            error = new SqlError(number, state, errorClass, _server, message, procedure, line);
            return true;
        }
Exemple #17
0
        private bool TryReadSqlStringValue(SqlBuffer value, byte type, int length, Encoding encoding, bool isPlp, TdsParserStateObject stateObj)
        {
            switch (type)
            {
                case TdsEnums.SQLCHAR:
                case TdsEnums.SQLBIGCHAR:
                case TdsEnums.SQLVARCHAR:
                case TdsEnums.SQLBIGVARCHAR:
                case TdsEnums.SQLTEXT:
                    // If bigvarchar(max), we only read the first chunk here,
                    // expecting the caller to read the rest
                    if (encoding == null)
                    {
                        // if hitting 7.0 server, encoding will be null in metadata for columns or return values since
                        // 7.0 has no support for multiple code pages in data - single code page support only
                        encoding = _defaultEncoding;
                    }
                    string stringValue;
                    if (!stateObj.TryReadStringWithEncoding(length, encoding, isPlp, out stringValue))
                    {
                        return false;
                    }
                    value.SetToString(stringValue);
                    break;

                case TdsEnums.SQLNCHAR:
                case TdsEnums.SQLNVARCHAR:
                case TdsEnums.SQLNTEXT:
                    {
                        String s = null;

                        if (isPlp)
                        {
                            char[] cc = null;

                            if (!TryReadPlpUnicodeChars(ref cc, 0, length >> 1, stateObj, out length))
                            {
                                return false;
                            }
                            if (length > 0)
                            {
                                s = new String(cc, 0, length);
                            }
                            else
                            {
                                s = ADP.StrEmpty;
                            }
                        }
                        else
                        {
                            if (!stateObj.TryReadString(length >> 1, out s))
                            {
                                return false;
                            }
                        }

                        value.SetToString(s);
                        break;
                    }

                default:
                    Debug.Assert(false, "Unknown tds type for SqlString!" + type.ToString(CultureInfo.InvariantCulture));
                    break;
            }

            return true;
        }
        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;
        }