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