internal bool TryReadSqlVariant(SqlBuffer value, int lenTotal, TdsParserStateObject stateObj)
{
// get the SQLVariant type
byte type;
if (!stateObj.TryReadByte(out type))
{
return false;
}
ushort lenMax = 0; // maximum lenData of value inside variant
// read cbPropBytes
byte cbPropsActual;
if (!stateObj.TryReadByte(out cbPropsActual))
{
return false;
}
MetaType mt = MetaType.GetSqlDataType(type, 0 /*no user datatype*/, 0 /* no lenData, non-nullable type */);
byte cbPropsExpected = mt.PropBytes;
int lenConsumed = TdsEnums.SQLVARIANT_SIZE + cbPropsActual; // type, count of propBytes, and actual propBytes
int lenData = lenTotal - lenConsumed; // length of actual data
// read known properties and skip unknown properties
Debug.Assert(cbPropsActual >= cbPropsExpected, "cbPropsActual is less that cbPropsExpected!");
//
// now read the value
//
switch (type)
{
case TdsEnums.SQLBIT:
case TdsEnums.SQLINT1:
case TdsEnums.SQLINT2:
case TdsEnums.SQLINT4:
case TdsEnums.SQLINT8:
case TdsEnums.SQLFLT4:
case TdsEnums.SQLFLT8:
case TdsEnums.SQLMONEY:
case TdsEnums.SQLMONEY4:
case TdsEnums.SQLDATETIME:
case TdsEnums.SQLDATETIM4:
case TdsEnums.SQLUNIQUEID:
if (!TryReadSqlValueInternal(value, type, lenData, stateObj))
{
return false;
}
break;
case TdsEnums.SQLDECIMALN:
case TdsEnums.SQLNUMERICN:
{
Debug.Assert(cbPropsExpected == 2, "SqlVariant: invalid PropBytes for decimal/numeric type!");
byte precision;
if (!stateObj.TryReadByte(out precision))
{
return false;
}
byte scale;
if (!stateObj.TryReadByte(out scale))
{
return false;
}
// skip over unknown properties
if (cbPropsActual > cbPropsExpected)
{
if (!stateObj.TrySkipBytes(cbPropsActual - cbPropsExpected))
{
return false;
}
}
if (!TryReadSqlDecimal(value, TdsEnums.MAX_NUMERIC_LEN, precision, scale, stateObj))
{
return false;
}
break;
}
case TdsEnums.SQLBIGBINARY:
case TdsEnums.SQLBIGVARBINARY:
//Debug.Assert(TdsEnums.VARNULL == lenData, "SqlVariant: data length for Binary indicates null?");
Debug.Assert(cbPropsExpected == 2, "SqlVariant: invalid PropBytes for binary type!");
if (!stateObj.TryReadUInt16(out lenMax))
{
return false;
}
Debug.Assert(lenMax != TdsEnums.SQL_USHORTVARMAXLEN, "bigvarbinary(max) in a sqlvariant");
// skip over unknown properties
if (cbPropsActual > cbPropsExpected)
{
if (!stateObj.TrySkipBytes(cbPropsActual - cbPropsExpected))
{
return false;
}
}
goto case TdsEnums.SQLBIT;
case TdsEnums.SQLBIGCHAR:
case TdsEnums.SQLBIGVARCHAR:
case TdsEnums.SQLNCHAR:
case TdsEnums.SQLNVARCHAR:
{
Debug.Assert(cbPropsExpected == 7, "SqlVariant: invalid PropBytes for character type!");
SqlCollation collation;
if (!TryProcessCollation(stateObj, out collation))
{
return false;
}
if (!stateObj.TryReadUInt16(out lenMax))
{
return false;
}
Debug.Assert(lenMax != TdsEnums.SQL_USHORTVARMAXLEN, "bigvarchar(max) or nvarchar(max) in a sqlvariant");
// skip over unknown properties
if (cbPropsActual > cbPropsExpected)
{
if (!stateObj.TrySkipBytes(cbPropsActual - cbPropsExpected))
{
return false;
}
}
Encoding encoding = Encoding.GetEncoding(GetCodePage(collation, stateObj));
if (!TryReadSqlStringValue(value, type, lenData, encoding, false, stateObj))
{
return false;
}
break;
}
case TdsEnums.SQLDATE:
if (!TryReadSqlDateTime(value, type, lenData, 0, stateObj))
{
return false;
}
break;
case TdsEnums.SQLTIME:
case TdsEnums.SQLDATETIME2:
case TdsEnums.SQLDATETIMEOFFSET:
{
Debug.Assert(cbPropsExpected == 1, "SqlVariant: invalid PropBytes for time/datetime2/datetimeoffset type!");
byte scale;
if (!stateObj.TryReadByte(out scale))
{
return false;
}
// skip over unknown properties
if (cbPropsActual > cbPropsExpected)
{
if (!stateObj.TrySkipBytes(cbPropsActual - cbPropsExpected))
{
return false;
}
}
if (!TryReadSqlDateTime(value, type, lenData, scale, stateObj))
{
return false;
}
break;
}
default:
Debug.Assert(false, "Unknown tds type in SqlVariant!" + type.ToString(CultureInfo.InvariantCulture));
break;
} // switch
return true;
}