Freigeben über


Unterstützung für große UDTs

Diese Beispielprojektmappe umfasst zwei Projekte. Ein Projekt erstellt eine Assembly (DLL) aus C#-Quellcode. Diese Assembly enthält den CLR-Typ. Der Datenbank wird eine Tabelle hinzugefügt. Eine Spalte in der Tabelle ist von einem in der Assembly definierten Typ. Standardmäßig wird in diesem Beispiel die master-Datenbank verwendet. Das zweite Projekt ist eine systemeigene C-Anwendung, die Daten aus der Tabelle liest.

In einer SQL Server-Version vor SQL Server 2008 kann das Beispiel nicht ausgeführt werden.

Weitere Informationen über die Unterstützung von großen UDTs finden Sie unter Große benutzerdefinierte CLR-Typen (ODBC).

Beispiel

Das erste Codelisting ist der C#-Quellcode. Fügen Sie den Code in eine Datei mit dem Namen LargeStringUDT.cs ein, und kompilieren Sie ihn zu einer DLL. Kopieren Sie LargeStringUDT.dll in das Stammverzeichnis des Laufwerks C.

Das zweite Codelisting (Transact-SQL) erstellt die Assembly in der master-Datenbank.

Kompilieren Sie das zweite Codelisting (C++) mit odbc32.lib und user32.lib. Stellen Sie sicher, dass die INCLUDE-Umgebungsvariable das Verzeichnis einschließt, das sqlncli.h enthält.

Wenn Sie dieses Beispiel als 32-Bit-Anwendung entwickeln und unter einem 64-Bit-Betriebssystem ausführen, müssen Sie die ODBC-Datenquelle mit dem ODBC-Administrator in %windir%\SysWOW64\odbcad32.exe erstellen.

In diesem Beispiel wird eine Verbindung mit der SQL Server-Standardinstanz des Computers hergestellt. Ändern Sie zum Herstellen einer Verbindung mit einer benannten Instanz die Definition der ODBC-Datenquelle, um die Instanz im folgenden Format anzugeben: Server\benannteInstanz. Standardmäßig wird SQL Server Express in einer benannten Instanz installiert.

Das vierte Codelisting (Transact-SQL) löscht die Assembly aus der master-Datenbank.

// 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 <stdio.h>
#include <tchar.h>
#include <stddef.h>
#include <windows.h>
#define ODBCVER 0x0350
#include <sql.h>
#include <sqlext.h>
#include <sqltypes.h>
#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, &paramType, 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 <NumBytes ; i++ )
            putchar((char)DataBuf[i]);
         ifFirst = false;
      };
      printf("\n");
   }

   if ( rc != SQL_NO_DATA ) {
      printf("Failed to fetch data\n");
      ret= -1;
   }

End:
   if (hStmt) {
      SQLFreeStmt(hStmt,SQL_CLOSE);
      SQLFreeStmt(hStmt,SQL_DROP);
   }

   if (hDbc) {
      SQLDisconnect(hDbc);
      SQLFreeConnect(hDbc);
   }

   if (hEnv)
      SQLFreeHandle(SQL_HANDLE_ENV, hEnv);
};

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