Exemplo n.º 1
0
        private void ParseRowContents(byte[] bytes, int rowOffset)
        {
            //normalize the col count
            bool onlyVarCols;

            bytes = NormalizeBytes(bytes, rowOffset, out onlyVarCols);
            //first byte is status
            //second byte is skipped
            //third and fourth is the amount of bytes for fixed width cols
            //  (+4 for the 2 here and the 2 above)
            int posOffset = BitUtil.ToInt16(bytes, 2, true);
            //number of cols is two bytes at the end of this
            int colCount = 1;

            byte[] nullability                 = new byte[(int)Math.Ceiling(colCount / 8d)];
            int    fixedLengthColumnOffset     = 4;
            int    varLengthColumnCount        = -1;
            int    varLengthColumnCountBegin   = -1;
            int    varLengthColumnCurrentCount = -1;
            int    varLengthColumnOffset       = -1;

            if (posOffset != 0 && bytes.Length > posOffset)
            {
                //colCount
                colCount = BitUtil.ToInt16(bytes, posOffset, true);
                if (colCount != _Table.Columns.Count)
                {
                    throw new Exception("Expected " + _Table.Columns.Count + " columns, but received " +
                                        colCount + " columns");
                }
                //nullability is 1 bit per column
                posOffset += 2;
                if (bytes.Length > posOffset)
                {
                    Array.Copy(bytes, posOffset, nullability, 0, nullability.Length);
                    posOffset += nullability.Length;
                    if (bytes.Length > posOffset)
                    {
                        //may not have var length columns (and may show 1-byte 0 or just not be there)
                        varLengthColumnCount = bytes.Length <= posOffset + 1 ? -1 :
                                               BitUtil.ToInt16(bytes, posOffset, true);
                        varLengthColumnCountBegin   = posOffset + 2;
                        varLengthColumnCurrentCount = 0;
                        varLengthColumnOffset       = posOffset + 2 + (varLengthColumnCount * 2);
                    }
                }
            }
            BitArray nullabilityArray = new BitArray(nullability);

            //load up the columns
            foreach (ColumnInfo col in _Table.Columns)
            {
                if (col.IsFixedWidth && !onlyVarCols && bytes.Length > fixedLengthColumnOffset)
                {
                    if (nullabilityArray[col.OrdinalPosition - 1])
                    {
                        _ColumnValues[col] = null;
                    }
                    else
                    {
                        if (!col.DataTypeLength.HasValue)
                        {
                            Console.WriteLine();
                        }
                        int length = col.DataTypeLength.Value;
                        //sometimes, the last column is trimmed to a certain size (e.g. positive bigint can be uint24)
                        if (fixedLengthColumnOffset + length >= bytes.Length)
                        {
                            length = bytes.Length - fixedLengthColumnOffset;
                        }
                        _ColumnValues[col] = col.FromBytes(bytes, fixedLengthColumnOffset, length);
                    }
                    fixedLengthColumnOffset += col.DataTypeLength.Value;
                }
                else if (!col.IsFixedWidth && nullabilityArray[col.OrdinalPosition - 1])
                {
                    _ColumnValues[col] = null;
                    varLengthColumnCurrentCount++;
                }
                else if (varLengthColumnCount > 0 && bytes.Length > varLengthColumnOffset)
                {
                    int end = BitUtil.ToInt16(bytes, varLengthColumnCountBegin +
                                              (varLengthColumnCurrentCount * 2), true);
                    //sometimes, the last column is trimmed to a certain size
                    if (end >= bytes.Length)
                    {
                        end = bytes.Length;
                    }
                    _ColumnValues[col]    = col.FromBytes(bytes, varLengthColumnOffset, end - varLengthColumnOffset);
                    varLengthColumnOffset = end;
                    varLengthColumnCurrentCount++;
                }
            }
        }
Exemplo n.º 2
0
        internal object FromBytes(byte[] bytes, int offset, int length)
        {
            switch (_DataType)
            {
            case SqlDbType.BigInt:
                switch (length)
                {
                case 1: return((long)bytes[offset]);

                case 2: return((long)BitUtil.ToUInt16(bytes, offset, true));

                case 3: return((long)BitUtil.ToUInt24(bytes, offset, true));

                case 4: return((long)BitUtil.ToUInt32(bytes, offset, true));

                case 8: return(BitUtil.ToInt64(bytes, offset, true));

                default: throw new Exception("Unrecognized length for bigint: " + length);
                }

            case SqlDbType.Binary:
                byte[] binaryBytes = new byte[DataTypeLength.Value];
                Array.Copy(bytes, offset, binaryBytes, 0, length);
                return(binaryBytes);

            case SqlDbType.VarBinary:
                byte[] varBinaryBytes = new byte[length];
                Array.Copy(bytes, offset, varBinaryBytes, 0, length);
                return(varBinaryBytes);

            case SqlDbType.Bit: return((bytes[offset] & 1) != 0);

            case SqlDbType.Char:
                byte[] charBytes = new byte[DataTypeLength.Value];
                Array.Copy(bytes, offset, charBytes, 0, length);
                //go ahead and set each extra 32's (spaces) if length is shorted
                for (int i = length; i < DataTypeLength.Value; i++)
                {
                    charBytes[i] = 32;
                }
                return(Encoding.UTF8.GetString(charBytes));

            case SqlDbType.VarChar:
                byte[] varCharBytes = new byte[length];
                Array.Copy(bytes, offset, varCharBytes, 0, length);
                return(Encoding.UTF8.GetString(varCharBytes));

            case SqlDbType.Date: return(new DateTime().AddDays(BitUtil.ToInt32(bytes, offset + 4, true)));

            case SqlDbType.DateTime:
                if (length < 8)
                {
                    byte[] dateBytes = new byte[8];
                    for (int i = 0; i < 8; i++)
                    {
                        if (i < length)
                        {
                            dateBytes[i] = bytes[offset + i];
                        }
                        else
                        {
                            dateBytes[i] = 0;
                        }
                    }
                    return(new DateTime(1900, 1, 1).AddDays(BitUtil.ToInt32(dateBytes, 4, true)).
                           AddMilliseconds(THREE_AND_ONE_THIRD * BitUtil.ToInt32(dateBytes, 0, true)));
                }
                else
                {
                    return(new DateTime(1900, 1, 1).AddDays(BitUtil.ToInt32(bytes, offset + 4, true)).
                           AddMilliseconds(THREE_AND_ONE_THIRD * BitUtil.ToInt32(bytes, offset, true)));
                }

            case SqlDbType.DateTime2:
                return(new DateTime().AddDays(BitUtil.ToInt32(bytes, offset + 8, true)).
                       AddMilliseconds(1000d / Math.Pow(10, Scale.Value) * BitUtil.ToInt64(bytes, offset, true)));

            case SqlDbType.DateTimeOffset: return("DateTimeOffset not supported");

            case SqlDbType.Decimal:
                //when data type length is less than the data type length, we must pad with zeroes
                if (length < DataTypeLength.Value)
                {
                    byte[] decimalBytes = new byte[offset + DataTypeLength.Value];
                    Array.Copy(bytes, offset, decimalBytes, offset, length);
                    bytes  = decimalBytes;
                    length = DataTypeLength.Value;
                }
                int[] bits = new int[4];
                bits[0] = BitUtil.ToInt32(bytes, offset + 1, true);
                bits[1] = length >= 9 ? BitUtil.ToInt32(bytes, offset + 5, true) : 0;
                bits[2] = length >= 13 ? BitUtil.ToInt32(bytes, offset + 9, true) : 0;
                bits[3] = length >= 17 ? BitUtil.ToInt32(bytes, offset + 13, true) : 0;
                //sometimes this is bigger than C#'s max precision/scale of 28 so just return SqlDecimal
                if (_Precision > 28 || _Scale > 28)
                {
                    return(new SqlDecimal(_Precision.Value, (byte)_Scale, bytes[offset] == 1, bits));
                }
                else
                {
                    return(new SqlDecimal(_Precision.Value, (byte)_Scale, bytes[offset] == 1, bits).Value);
                }

            case SqlDbType.Float:
                switch (length)
                {
                case 7:
                    return(BitUtil.ToDouble(new byte[] {
                        bytes[offset], bytes[offset + 1], bytes[offset + 2], bytes[offset + 3],
                        bytes[offset + 4], bytes[offset + 5], bytes[offset + 6], 64
                    }, 0, true));

                case 8: return(BitUtil.ToDouble(bytes, offset, true));

                default: throw new Exception("Unrecognized float length: " + length);
                }

            case SqlDbType.Image: return("Image not supported");

            case SqlDbType.Int:
                switch (length)
                {
                case 1: return((int)bytes[offset]);

                case 2: return((int)BitUtil.ToUInt16(bytes, offset, true));

                case 3: return((int)BitUtil.ToUInt24(bytes, offset, true));

                case 4: return(BitUtil.ToInt32(bytes, offset, true));

                default: throw new Exception("Unrecognized int length : " + length);
                }

            case SqlDbType.Money:
                if (length < 8)
                {
                    byte[] moneyBytes = new byte[8];
                    for (int i = 0; i < 8; i++)
                    {
                        if (i < length)
                        {
                            moneyBytes[i] = bytes[offset + i];
                        }
                        else
                        {
                            moneyBytes[i] = (byte)(i == 2 ? 1 : 0);
                        }
                    }
                    return(BitUtil.ToInt64(moneyBytes, 0, true) / 10000d);
                }
                return(BitUtil.ToInt64(bytes, offset, true) / 10000d);

            case SqlDbType.NChar:
                byte[] ncharBytes = new byte[DataTypeLength.Value];
                Array.Copy(bytes, offset, ncharBytes, 0, length);
                //go ahead and set each extra 32's (spaces) if length is shorted
                for (int i = length; i < DataTypeLength.Value; i++)
                {
                    ncharBytes[i] = (byte)(i % 2 == 1 ? 0 : 32);
                }
                return(Encoding.Unicode.GetString(ncharBytes));

            case SqlDbType.NVarChar:
                //if it's an odd number, we have to add a zero to the end
                int    nvarCharLength = length + (length % 2);
                byte[] nvarCharBytes  = new byte[nvarCharLength];
                Array.Copy(bytes, offset, nvarCharBytes, 0, length);
                return(Encoding.Unicode.GetString(nvarCharBytes));

            case SqlDbType.NText: return("NText not supported");

            case SqlDbType.Real: return(BitUtil.ToSingle(bytes, offset, true));

            case SqlDbType.SmallDateTime:
                return(new DateTime(1900, 1, 1).AddDays(BitUtil.ToUInt16(bytes, offset + 2, true)).
                       AddMinutes(BitUtil.ToUInt16(bytes, offset, true)));

            case SqlDbType.SmallInt:
                return(length == 1 ? (short)bytes[offset] : BitUtil.ToInt16(bytes, offset, true));

            case SqlDbType.SmallMoney:
                switch (length)
                {
                case 3: return(BitUtil.ToInt32(new byte[] {
                        bytes[offset], bytes[offset + 1], bytes[offset + 2], 0
                    }, 0, true) / 10000d);

                case 4: return(BitUtil.ToInt32(bytes, offset, true) / 10000d);

                default: throw new Exception("Unrecognized length for small money: " + length);
                }

            case SqlDbType.Structured: return("Structured not supported");

            case SqlDbType.Text: return("Text not supported");

            case SqlDbType.Time:
                return(TimeSpan.FromMilliseconds(1000d / Math.Pow(10, Scale.Value) * BitUtil.ToInt64(bytes, offset, true)));

            case SqlDbType.Timestamp: return("Timestamp not supported");

            case SqlDbType.TinyInt: return(bytes[offset]);

            case SqlDbType.Udt: return("UDT's not supported");

            case SqlDbType.UniqueIdentifier:
                byte[] guid = new byte[16];
                Array.Copy(bytes, offset, guid, 0, 16);
                return(new Guid(guid));

            case SqlDbType.Variant: return("Variant not supported");

            case SqlDbType.Xml: return("Xml not supported");

            default: throw new NotImplementedException(_DataType + " not implemented");
            }
        }