--- title: "Support for Large UDTs | Microsoft Docs" ms.custom: "" ms.date: "03/17/2017" ms.prod: sql ms.prod_service: "database-engine, sql-database, sql-data-warehouse, pdw" ms.reviewer: "" ms.technology: native-client ms.topic: "reference" ms.assetid: 621b6d13-10f1-47d0-b63c-7adb6ab904e0 author: markingmyname ms.author: maghan monikerRange: ">=aps-pdw-2016||=azuresqldb-current||=azure-sqldw-latest||>=sql-server-2016||=sqlallproducts-allversions||>=sql-server-linux-2017||=azuresqldb-mi-current" --- # Support for Large UDTs [!INCLUDE[appliesto-ss-asdb-asdw-pdw-md](../../includes/appliesto-ss-asdb-asdw-pdw-md.md)] This sample solution contains two projects. One project creates an assembly (DLL) from C# source code. This assembly contains the CLR type. A table will be added to the database. A column in the table will be of a type defined in the assembly, By default, this sample will use the master database. The second project is a native C application that reads data from the table. This sample will not work with any version of [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] earlier than [!INCLUDE[ssKatmai](../../includes/sskatmai-md.md)]. For more information about support for large UDTs, see [Large CLR User-Defined Types (ODBC)](../../relational-databases/native-client/odbc/large-clr-user-defined-types-odbc.md). ## Example The first code listing is C# source code. Paste it into a file called LargeStringUDT.cs and compile it to a DLL. Copy LargeStringUDT.dll to the root directory of your C drive. The second ( [!INCLUDE[tsql](../../includes/tsql-md.md)]) code listing creates the assembly in the master database. Compile the second (C++) code listing with odbc32.lib and user32.lib. Make sure your INCLUDE environment variable includes the directory that contains sqlncli.h. If you will build and run this sample as a 32-bit application on a 64-bit operating system, you must create the ODBC data source with the ODBC Administrator in %windir%\SysWOW64\odbcad32.exe. This sample connects to your computer's default [!INCLUDE[ssNoVersion](../../includes/ssnoversion-md.md)] instance. To connect to a named instance, change the definition of the ODBC data source to specify the instance using the following format: server\namedinstance. By default, [!INCLUDE[ssExpress](../../includes/ssexpress-md.md)] installs to a named instance. The fourth ( [!INCLUDE[tsql](../../includes/tsql-md.md)]) code listing deletes the assembly from the master database. ``` // LargeStringUDT.cs // compile with: /target:library using System; using System.Data; using System.Data.SqlTypes; using Microsoft.SqlServer.Server; using System.Text; [assembly: System.CLSCompliantAttribute(true)] [Serializable] [Microsoft.SqlServer.Server.SqlUserDefinedType(Format.UserDefined, IsFixedLength = false, MaxByteSize = -1, IsByteOrdered = true)] public class LargeStringUDT : INullable, IBinarySerialize { private bool _isNull; private string _largeString; public bool IsNull { get { return (_isNull); } } public static LargeStringUDT Null { get { LargeStringUDT lsUDT = new LargeStringUDT(); lsUDT._isNull = true; return lsUDT; } } public override string ToString() { if (IsNull) return "NULL"; else return _largeString; } [SqlMethod(OnNullCall = false)] public static LargeStringUDT Parse(SqlString s) { if (s.IsNull) return Null; LargeStringUDT lsUDT = new LargeStringUDT(); lsUDT._largeString = s.Value; return lsUDT; } public String LargeString { get { return _largeString; } set { _largeString = value; } } public void Read(System.IO.BinaryReader r) { _isNull = r.ReadBoolean(); if (!_isNull) _largeString = new String(r.ReadChars(r.ReadInt32())); } public void Write(System.IO.BinaryWriter w) { w.Write(_isNull); if (!_isNull) { w.Write(_largeString.Length); for (int i = 0; i < _largeString.Length; ++i) w.Write(_largeString[i]); } } } ``` ``` USE [MASTER] IF EXISTS (SELECT * FROM sys.objects WHERE name = 'LargeStringUDTs') DROP TABLE LargeStringUDTs GO IF EXISTS (SELECT * FROM sys.types WHERE name = 'LargeStringUDT') DROP TYPE dbo.LargeStringUDT GO IF EXISTS (SELECT * FROM sys.assemblies WHERE name = 'LargeStringUDT') DROP ASSEMBLY LargeStringUDT GO CREATE ASSEMBLY LargeStringUDT FROM 'C:\LargeStringUDT.dll' WITh PERMISSION_SET=SAFE; GO CREATE TYPE dbo.LargeStringUDT EXTERNAL NAME LargeStringUDT.[LargeStringUDT]; GO CREATE TABLE dbo.LargeStringUDTs (ID int IDENTITY(1,1) PRIMARY KEY, LargeString LargeStringUDT) GO INSERT INTO dbo.LargeStringUDTs (LargeString) VALUES (CONVERT(LargeStringUDT, 'This is the first string')); INSERT INTO dbo.LargeStringUDTs (LargeString) VALUES (CONVERT(LargeStringUDT, 'This is the second string')); INSERT INTO dbo.LargeStringUDTs (LargeString) VALUES (Convert(LargeStringUDT, 'This is the third string')); GO ``` ``` // compile with: odbc32.lib #include #include #include #include #define ODBCVER 0x0350 #include #include #include #define _SQLNCLI_ODBC #include "sqlncli.h" int main() { // The command to execute. SQLTCHAR* szCmdString = (SQLTCHAR *)_T("SELECT ID, LargeString FROM dbo.LargeStringUDTs"); int ret = 0; SQLRETURN rc; SQLHENV hEnv = NULL; SQLHDBC hDbc = NULL; SQLHSTMT hStmt = NULL; SQLTCHAR szConn[256]; BYTE DataBuf[15]; SQLSMALLINT iLen = 0; SQLLEN iDataLen = 0; rc = SQLAllocHandle(SQL_HANDLE_ENV, SQL_NULL_HANDLE, &hEnv); if (rc != SQL_SUCCESS) { printf("Failed to get HENV\n"); return -1; } rc = SQLSetEnvAttr (hEnv, SQL_ATTR_ODBC_VERSION, (SQLPOINTER)SQL_OV_ODBC3, 0); if (rc != SQL_SUCCESS) { printf("Failed to SetEnvAttr\n"); SQLFreeHandle(SQL_HANDLE_ENV, hEnv); return -1; } rc = SQLAllocHandle(SQL_HANDLE_DBC, hEnv, &hDbc); if (rc != SQL_SUCCESS) { printf("Failed to get HDBC\n"); SQLFreeHandle(SQL_HANDLE_ENV, hEnv); return -1; } rc = SQLDriverConnect(hDbc, NULL, (SQLTCHAR *)_T("DRIVER={SQL Server Native Client 10.0};SERVER=(local);Trusted_Connection=Yes;database=master"), SQL_NTS, szConn, 255, &iLen, SQL_DRIVER_NOPROMPT); if (rc != SQL_SUCCESS && rc != SQL_SUCCESS_WITH_INFO) { printf("Failed to connect\n"); ret = -1; goto End; } rc = SQLAllocHandle(SQL_HANDLE_STMT, hDbc, &hStmt); if (rc != SQL_SUCCESS) { printf("Failed to get hstmt\n"); ret = -1; goto End; } // Execute the command. rc = SQLExecDirect(hStmt, szCmdString, SQL_NTS); if (rc != SQL_SUCCESS) { printf("Failed to get hstmt\n"); ret = -1; goto End; } // Process the result set. SQLSMALLINT paramType; SQLTCHAR szData[100], szData2[100]; SQLSMALLINT NameLengthPtr = 0, DataTypePtr, DecimalDigitsPtr, NullablePtr; SQLULEN ColumnSizePtr[2]; rc = SQLDescribeCol(hStmt, 1, szData, sizeof(szData), &NameLengthPtr, &DataTypePtr, &ColumnSizePtr[0], &DecimalDigitsPtr, &NullablePtr); _tprintf(_T("%s"), szData); rc = SQLDescribeCol(hStmt, 2, szData2, sizeof(szData2), &NameLengthPtr, &DataTypePtr, &ColumnSizePtr[1], &DecimalDigitsPtr, &NullablePtr); _tprintf(_T(" %s\n"), szData2); while ( ( rc = SQLFetch(hStmt ) ) == SQL_SUCCESS ) { rc = SQLGetData(hStmt, 1, SQL_C_SHORT, ¶mType, sizeof(SQL_C_SHORT), NULL); printf("%d ", paramType); bool ifFirst = true; while ( ( rc = SQLGetData(hStmt, 2 , SQL_C_BINARY, DataBuf, sizeof(DataBuf) ,&iDataLen ) ) != SQL_NO_DATA) { // process number of bytes in the DataBuf; int NumBytes = (iDataLen > sizeof(DataBuf)) || (iDataLen == SQL_NO_TOTAL) ? sizeof(DataBuf): iDataLen; for ( int i = ifFirst?5:0 ; i