private void WriteTvpOrderUnique(MSS.SmiExtendedMetaData metaData, TdsParserStateObject stateObj) { // TVP_ORDER_UNIQUE token (uniqueness and sort order) // Merge order and unique keys into a single token stream MSS.SmiOrderProperty orderProperty = (MSS.SmiOrderProperty)metaData.ExtendedProperties[MSS.SmiPropertySelector.SortOrder]; MSS.SmiUniqueKeyProperty uniqueKeyProperty = (MSS.SmiUniqueKeyProperty)metaData.ExtendedProperties[MSS.SmiPropertySelector.UniqueKey]; // Build list from List<TdsOrderUnique> columnList = new List<TdsOrderUnique>(metaData.FieldMetaData.Count); for (int i = 0; i < metaData.FieldMetaData.Count; i++) { // Add appropriate SortOrder flag byte flags = 0; MSS.SmiOrderProperty.SmiColumnOrder columnOrder = orderProperty[i]; if (SortOrder.Ascending == columnOrder.Order) { flags = TdsEnums.TVP_ORDERASC_FLAG; } else if (SortOrder.Descending == columnOrder.Order) { flags = TdsEnums.TVP_ORDERDESC_FLAG; } // Add unique key flage if appropriate if (uniqueKeyProperty[i]) { flags |= TdsEnums.TVP_UNIQUE_FLAG; } // Remember this column if any flags were set if (0 != flags) { columnList.Add(new TdsOrderUnique(checked((short)(i + 1)), flags)); } } // Write flagged columns to wire... if (0 < columnList.Count) { stateObj.WriteByte(TdsEnums.TVP_ORDER_UNIQUE_TOKEN); WriteShort(columnList.Count, stateObj); foreach (TdsOrderUnique column in columnList) { WriteShort(column.ColumnOrdinal, stateObj); stateObj.WriteByte(column.Flags); } } }
// Write a single TvpColumnMetaData stream to the server private void WriteTvpColumnMetaData(MSS.SmiExtendedMetaData md, bool isDefault, TdsParserStateObject stateObj) { // User Type if (SqlDbType.Timestamp == md.SqlDbType) { WriteUnsignedInt(TdsEnums.SQLTIMESTAMP, stateObj); } else { WriteUnsignedInt(0, stateObj); } // Flags ushort status = TdsEnums.Nullable; if (isDefault) { status |= TdsEnums.TVP_DEFAULT_COLUMN; } WriteUnsignedShort(status, stateObj); // Type info WriteSmiTypeInfo(md, stateObj); // Column name // per spec, "ColName is never sent to server or client for TVP, it is required within a TVP to be zero length." WriteIdentifier(null, stateObj); }
// Write a TypeInfo stream // Devnote: we remap the legacy types (text, ntext, and image) to SQLBIGVARCHAR, SQLNVARCHAR, and SQLBIGVARBINARY private void WriteSmiTypeInfo(MSS.SmiExtendedMetaData metaData, TdsParserStateObject stateObj) { switch (metaData.SqlDbType) { case SqlDbType.BigInt: stateObj.WriteByte(TdsEnums.SQLINTN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.Binary: stateObj.WriteByte(TdsEnums.SQLBIGBINARY); WriteUnsignedShort(checked((ushort)metaData.MaxLength), stateObj); break; case SqlDbType.Bit: stateObj.WriteByte(TdsEnums.SQLBITN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.Char: stateObj.WriteByte(TdsEnums.SQLBIGCHAR); WriteUnsignedShort(checked((ushort)(metaData.MaxLength)), stateObj); WriteUnsignedInt(_defaultCollation.info, stateObj); stateObj.WriteByte(_defaultCollation.sortId); break; case SqlDbType.DateTime: stateObj.WriteByte(TdsEnums.SQLDATETIMN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.Decimal: stateObj.WriteByte(TdsEnums.SQLNUMERICN); stateObj.WriteByte(checked((byte)MetaType.MetaDecimal.FixedLength)); // SmiMetaData's length and actual wire format's length are different stateObj.WriteByte(0 == metaData.Precision ? (byte)1 : metaData.Precision); stateObj.WriteByte(metaData.Scale); break; case SqlDbType.Float: stateObj.WriteByte(TdsEnums.SQLFLTN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.Image: stateObj.WriteByte(TdsEnums.SQLBIGVARBINARY); WriteUnsignedShort(unchecked((ushort)MSS.SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); break; case SqlDbType.Int: stateObj.WriteByte(TdsEnums.SQLINTN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.Money: stateObj.WriteByte(TdsEnums.SQLMONEYN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.NChar: stateObj.WriteByte(TdsEnums.SQLNCHAR); WriteUnsignedShort(checked((ushort)(metaData.MaxLength * 2)), stateObj); WriteUnsignedInt(_defaultCollation.info, stateObj); stateObj.WriteByte(_defaultCollation.sortId); break; case SqlDbType.NText: stateObj.WriteByte(TdsEnums.SQLNVARCHAR); WriteUnsignedShort(unchecked((ushort)MSS.SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); WriteUnsignedInt(_defaultCollation.info, stateObj); stateObj.WriteByte(_defaultCollation.sortId); break; case SqlDbType.NVarChar: stateObj.WriteByte(TdsEnums.SQLNVARCHAR); if (MSS.SmiMetaData.UnlimitedMaxLengthIndicator == metaData.MaxLength) { WriteUnsignedShort(unchecked((ushort)MSS.SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); } else { WriteUnsignedShort(checked((ushort)(metaData.MaxLength * 2)), stateObj); } WriteUnsignedInt(_defaultCollation.info, stateObj); stateObj.WriteByte(_defaultCollation.sortId); break; case SqlDbType.Real: stateObj.WriteByte(TdsEnums.SQLFLTN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.UniqueIdentifier: stateObj.WriteByte(TdsEnums.SQLUNIQUEID); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.SmallDateTime: stateObj.WriteByte(TdsEnums.SQLDATETIMN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.SmallInt: stateObj.WriteByte(TdsEnums.SQLINTN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.SmallMoney: stateObj.WriteByte(TdsEnums.SQLMONEYN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.Text: stateObj.WriteByte(TdsEnums.SQLBIGVARCHAR); WriteUnsignedShort(unchecked((ushort)MSS.SmiMetaData.UnlimitedMaxLengthIndicator), stateObj); WriteUnsignedInt(_defaultCollation.info, stateObj); stateObj.WriteByte(_defaultCollation.sortId); break; case SqlDbType.Timestamp: stateObj.WriteByte(TdsEnums.SQLBIGBINARY); WriteShort(checked((int)metaData.MaxLength), stateObj); break; case SqlDbType.TinyInt: stateObj.WriteByte(TdsEnums.SQLINTN); stateObj.WriteByte(checked((byte)metaData.MaxLength)); break; case SqlDbType.VarBinary: stateObj.WriteByte(TdsEnums.SQLBIGVARBINARY); WriteUnsignedShort(unchecked((ushort)metaData.MaxLength), stateObj); break; case SqlDbType.VarChar: stateObj.WriteByte(TdsEnums.SQLBIGVARCHAR); WriteUnsignedShort(unchecked((ushort)metaData.MaxLength), stateObj); WriteUnsignedInt(_defaultCollation.info, stateObj); stateObj.WriteByte(_defaultCollation.sortId); break; case SqlDbType.Variant: stateObj.WriteByte(TdsEnums.SQLVARIANT); WriteInt(checked((int)metaData.MaxLength), stateObj); break; case SqlDbType.Xml: stateObj.WriteByte(TdsEnums.SQLXMLTYPE); // Is there a schema if (ADP.IsEmpty(metaData.TypeSpecificNamePart1) && ADP.IsEmpty(metaData.TypeSpecificNamePart2) && ADP.IsEmpty(metaData.TypeSpecificNamePart3)) { stateObj.WriteByte(0); // schema not present } else { stateObj.WriteByte(1); // schema present WriteIdentifier(metaData.TypeSpecificNamePart1, stateObj); WriteIdentifier(metaData.TypeSpecificNamePart2, stateObj); WriteIdentifierWithShortLength(metaData.TypeSpecificNamePart3, stateObj); } break; case SqlDbType.Udt: stateObj.WriteByte(TdsEnums.SQLUDT); WriteIdentifier(metaData.TypeSpecificNamePart1, stateObj); WriteIdentifier(metaData.TypeSpecificNamePart2, stateObj); WriteIdentifier(metaData.TypeSpecificNamePart3, stateObj); break; case SqlDbType.Structured: if (metaData.IsMultiValued) { WriteTvpTypeInfo(metaData, stateObj); } else { Debug.Assert(false, "SUDTs not yet supported."); } break; case SqlDbType.Date: stateObj.WriteByte(TdsEnums.SQLDATE); break; case SqlDbType.Time: stateObj.WriteByte(TdsEnums.SQLTIME); stateObj.WriteByte(metaData.Scale); break; case SqlDbType.DateTime2: stateObj.WriteByte(TdsEnums.SQLDATETIME2); stateObj.WriteByte(metaData.Scale); break; case SqlDbType.DateTimeOffset: stateObj.WriteByte(TdsEnums.SQLDATETIMEOFFSET); stateObj.WriteByte(metaData.Scale); break; default: Debug.Assert(false, "Unknown SqlDbType should have been caught earlier!"); break; } }
private void WriteTvpTypeInfo(MSS.SmiExtendedMetaData metaData, TdsParserStateObject stateObj) { Debug.Assert(SqlDbType.Structured == metaData.SqlDbType && metaData.IsMultiValued, "Invalid metadata for TVPs. Type=" + metaData.SqlDbType); // Type token stateObj.WriteByte((byte)TdsEnums.SQLTABLE); // 3-part name (DB, Schema, TypeName) WriteIdentifier(metaData.TypeSpecificNamePart1, stateObj); WriteIdentifier(metaData.TypeSpecificNamePart2, stateObj); WriteIdentifier(metaData.TypeSpecificNamePart3, stateObj); // TVP_COLMETADATA if (0 == metaData.FieldMetaData.Count) { WriteUnsignedShort((ushort)TdsEnums.TVP_NOMETADATA_TOKEN, stateObj); } else { // COUNT of columns WriteUnsignedShort(checked((ushort)metaData.FieldMetaData.Count), stateObj); // TvpColumnMetaData for each column (look for defaults in this loop MSS.SmiDefaultFieldsProperty defaults = (MSS.SmiDefaultFieldsProperty)metaData.ExtendedProperties[MSS.SmiPropertySelector.DefaultFields]; for (int i = 0; i < metaData.FieldMetaData.Count; i++) { WriteTvpColumnMetaData(metaData.FieldMetaData[i], defaults[i], stateObj); } // optional OrderUnique metadata WriteTvpOrderUnique(metaData, stateObj); } // END of optional metadata stateObj.WriteByte(TdsEnums.TVP_END_TOKEN); }
// Writes metadata portion of parameter stream from an SmiParameterMetaData object. private void WriteSmiParameterMetaData(MSS.SmiParameterMetaData metaData, bool sendDefault, TdsParserStateObject stateObj) { // Determine status byte status = 0; if (ParameterDirection.Output == metaData.Direction || ParameterDirection.InputOutput == metaData.Direction) { status |= TdsEnums.RPC_PARAM_BYREF; } if (sendDefault) { status |= TdsEnums.RPC_PARAM_DEFAULT; } // Write everything out WriteParameterName(metaData.Name, stateObj); stateObj.WriteByte(status); WriteSmiTypeInfo(metaData, stateObj); }