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 datatypes, 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)
{
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 (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;
}