internal int GetActualSize()
{
MetaType mt = InternalMetaType;
SqlDbType actualType = mt.SqlDbType;
// NOTE: Users can change the Udt at any time, so we may need to recalculate
if ((_actualSize == -1) || (actualType == Data.SqlDbType.Udt))
{
_actualSize = 0;
object val = GetCoercedValue();
bool isSqlVariant = false;
if (IsNull && !mt.IsVarTime)
{
return 0;
}
// if this is a backend SQLVariant type, then infer the TDS type from the SQLVariant type
if (actualType == SqlDbType.Variant)
{
mt = MetaType.GetMetaTypeFromValue(val, streamAllowed: false);
actualType = MetaType.GetSqlDataType(mt.TDSType, 0 /*no user type*/, 0 /*non-nullable type*/).SqlDbType;
isSqlVariant = true;
}
if (mt.IsFixed)
{
_actualSize = mt.FixedLength;
}
else
{
// @hack: until we have ForceOffset behavior we have the following semantics:
// @hack: if the user supplies a Size through the Size property or constructor,
// @hack: we only send a MAX of Size bytes over. If the actualSize is < Size, then
// @hack: we send over actualSize
int coercedSize = 0;
// get the actual length of the data, in bytes
switch (actualType)
{
case SqlDbType.NChar:
case SqlDbType.NVarChar:
case SqlDbType.NText:
case SqlDbType.Xml:
{
coercedSize = ((!_isNull) && (!_coercedValueIsDataFeed)) ? (StringSize(val, _coercedValueIsSqlType)) : 0;
_actualSize = (ShouldSerializeSize() ? Size : 0);
_actualSize = ((ShouldSerializeSize() && (_actualSize <= coercedSize)) ? _actualSize : coercedSize);
if (_actualSize == -1)
_actualSize = coercedSize;
_actualSize <<= 1;
}
break;
case SqlDbType.Char:
case SqlDbType.VarChar:
case SqlDbType.Text:
{
// for these types, ActualSize is the num of chars, not actual bytes - since non-unicode chars are not always uniform size
coercedSize = ((!_isNull) && (!_coercedValueIsDataFeed)) ? (StringSize(val, _coercedValueIsSqlType)) : 0;
_actualSize = (ShouldSerializeSize() ? Size : 0);
_actualSize = ((ShouldSerializeSize() && (_actualSize <= coercedSize)) ? _actualSize : coercedSize);
if (_actualSize == -1)
_actualSize = coercedSize;
}
break;
case SqlDbType.Binary:
case SqlDbType.VarBinary:
case SqlDbType.Image:
case SqlDbType.Timestamp:
coercedSize = ((!_isNull) && (!_coercedValueIsDataFeed)) ? (BinarySize(val, _coercedValueIsSqlType)) : 0;
_actualSize = (ShouldSerializeSize() ? Size : 0);
_actualSize = ((ShouldSerializeSize() && (_actualSize <= coercedSize)) ? _actualSize : coercedSize);
if (_actualSize == -1)
_actualSize = coercedSize;
break;
case SqlDbType.Udt:
throw ADP.DbTypeNotSupported(SqlDbType.Udt.ToString());
case SqlDbType.Structured:
coercedSize = -1;
break;
case SqlDbType.Time:
_actualSize = (isSqlVariant ? 5 : MetaType.GetTimeSizeFromScale(GetActualScale()));
break;
case SqlDbType.DateTime2:
// Date in number of days (3 bytes) + time
_actualSize = 3 + (isSqlVariant ? 5 : MetaType.GetTimeSizeFromScale(GetActualScale()));
break;
case SqlDbType.DateTimeOffset:
// Date in days (3 bytes) + offset in minutes (2 bytes) + time
_actualSize = 5 + (isSqlVariant ? 5 : MetaType.GetTimeSizeFromScale(GetActualScale()));
break;
default:
Debug.Assert(false, "Unknown variable length type!");
break;
} // switch
// don't even send big values over to the variant
if (isSqlVariant && (coercedSize > TdsEnums.TYPE_SIZE_LIMIT))
throw SQL.ParameterInvalidVariant(this.ParameterName);
}
}
return _actualSize;
}