Microsoft SQL Server 2005 new features [Clr Limited Preview Edition]

Get full details on all the innovative features and benefits available in the release of SQL Server 2005. This authorita

621 77 241KB

English Pages [26] Year 2005

Report DMCA / Copyright

DOWNLOAD FILE

Polecaj historie

Microsoft SQL Server 2005 new features [Clr Limited Preview Edition]

Citation preview

SQL Server Yukon New Features

Chapter 4

10/6/2003

Copyright © 2004 by The McGraw-Hill Companies, Inc. (Publisher). All rights reserved. www.osborne.com SQL Server Yukon New Features By Michael Otey ISBN 0-007-222776-1 400 pages $39.99 Coming soon in 2004 This is a limited edition preview of content from SQL Server Yukon New Features (ISBN: 0072227761). The content is based on the current beta release at the time of writing, and is not a comprehensive representation of the new feature set that will be in the final release of the software and book. We have made every effort to make sure that there are not errors in the text or code as of the writing. However, all of the content is subject to change based on the final release of the software and further editing. Information has been obtained by the Publisher from sources believed to be reliable. However, because of the possibility of human and mechanical error by our sources, Publisher, or others, Publisher does not guarantee to the accuracy, adequacy, or completeness of any information included in this work and is not responsible for any errors or omissions or the results obtained from the use of such information. Summary of Contents Part I: Database Administration Features Chapter 1: Database Administration and Management Features Chapter 2: Architecture and Storage Engine Features Chapter 3: Availability and Recovery Features Part II: Database Development Features Chapter 4: New Development Features Chapter 5: SQL Notification Services page 1 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

Chapter 6: SQL Service Broker Chapter 7: XML Integration Features Part III: Business Intelligence Features Chapter 8: Reporting Services Chapter 9: Data Transformation Services Chapter 10: Data Analysis Services Chapter 11: Data Mining Features Part IV: Appendixes Appendix A: Migration Guide Appendix B: Quick Facts

Chapter 4: New Development Features The new development features that are found in SQL Server Yukon are the accumulation of many years’ worth of effort by both the SQL Server development team and the .NET Framework development team. The most significant of these new development-oriented features is the integration of the .NET Common Language Runtime (CLR). The integration of the CLR brings with it a whole host of new capabilities, including the capability to create database objects by using any of the .NET-compatible languages, such as C#, VB.NET, and Managed C++. This chapter begins by introducing you to those new .NET CLR features and showing you some samples of how they are used. Next, the chapter addresses a topic that’s more familiar to SQL Server DBAs and developers: the new features found in T-SQL. Finally, the chapter takes a walk on the client side and presents some of the new features found in the updated .NET Framework Data Provider for SQL Server that ships with SQL Server Yukon.

Common Language Runtime Integration Undoubtedly the most significant new feature in the SQL Server Yukon release is the integration of the Microsoft CLR. The integration of the CLR with SQL Server extends the page 2 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

capability of SQL Server in several important ways. Although T-SQL, the existing data access and manipulation language, is well suited for set-oriented data access operations, it also has limitations. It was designed more than a decade ago and it is a procedural language rather than an object-oriented language. The integration of the CLR with SQL Server Yukon enables developers to create database objects by using modern object-oriented languages such as VB.NET and C#. While these languages do not have the same strong set-oriented nature as TSQL, they do support complex logic, have better computation capabilities, provide easier access to external resources, facilitate code reuse, and have a first-class development environment that provides much more power than the old Query Analyzer. The integration of the .NET CLR with SQL Server enables the development of stored procedures, user-defined functions, triggers, aggregates, and user-defined types using any of the .NET languages. The integration of the .NET CLR with SQL Server Yukon is more than just skin deep. In fact, the SQL Server engine hosts the CLR in-process. All managed code that executes in the server runs within the confines of the CLR. The managed code accesses the database using ADO.NET in conjunction with the new SQL Server .NET Data Provider. A new construct called an assembly is the unit of deployment for .NET objects with the database. In the following sections, you’ll get a more detailed look at the most important new CLR features found in SQL Server Yukon.

Assemblies To create objects, you must write managed code and compile it into a .NET assembly. The most common way to do this is to use Visual Studio .NET and then create a new class library project and compile it into a DLL assembly. After you create the assembly, you can then load it into SQL Server using the T-SQL CREATE ASSEMBLY command, as shown here: CREATE ASSEMBLY MyCLRDLL FROM ‘\\SERVERNAME\CodeLibrary\MyCLRDLL.dll’

The CREATE ASSEMBLY command takes a parameter that contains the path to the DLL that will be loaded into SQL Server. This can be a local path but more often it is a path to a networked file share. When the CREATE ASSEMBLY command is executed, the DLL is copied into the master database. page 3 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

If an assembly is updated or becomes deprecated, then you can remove the assembly by using the DROP ASSEMBLY command, as follows: DROP ASSEMBLY MyCLRDLL

Because an assembly is persisted in the database when the source code for that assembly is modified and the assembly is recompiled, the assembly must first be dropped from the database (using the DROP ASSEMBLY command) and then re-added (using the CREATE ASSEMBLY command) before the updates will be reflected in SQL Server database objects.

SQL Server .NET Data Provider If you’re familiar with ADO.NET, you may wonder exactly how these new CLR database procedures will connect with the database. After all, ADO.NET makes its database connection using one client-based .NET data provider such as the .NET Framework Data Provider for SQL Server, which connects to SQL Server databases, or the .NET Framework Data Provider for Oracle, which connects to Oracle databases. While that’s great for a networked application, going through the network libraries isn’t the most efficient connection mode for code that’s running directly on the server. To address this, Microsoft has created the new SQL Server .NET Data Provider, which establishes an in-memory connection to the SQL Server database. At the time of this writing, to create a .NET assembly using Visual Studio 2003 that’s capable of accessing SQL Server via the new SQL Server .NET Data Provider, you must first delete the reference to the older System.Data namespace and then add a reference in your project to the updated version of the System.Data namespace along with a reference to the System.Data.SqlServer namespace. To delete the old reference, open Visual Studio’s Solution Explorer, right-click the old System.Data reference, and select Remove. To add the new references to your Visual Studio .NET project, first select Project | Add References from the Visual Studio .NET IDE to open the Add Reference dialog box. Then, to add the updated System.Data namespace, click the Browse button, navigate to the \Windows\Microsoft.NET\Framework\v1.2.30703 directory, select System.Data.dll, and click OK. To add the reference for the System.Data.SqlServer namespace, page 4 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

open the Add Reference dialog box again (if it is not already open), click the Browse button, navigate to the \Program Files\Microsoft SQL Server\MSSQL.1\MSSQL\Binn directory, select sqlaccess.dll, and click OK. I expect that these steps will be unnecessary in the final version of SQL Server Yukon, because an updated version of Visual Studio.NET will include special SQL Server projects containing the appropriate references that you can load into the Visual Studio .NET IDE. The next step to incorporate the SQL Server .NET Data Provider into your applications is to import the System.Data.SqlServer namespace into your project. The System.Data.SqlServer namespace contains the .NET classes that comprise the SQL Server .NET Data Provider. For a C# project, the import directive is as follows: using System.Data.SqlServer;

For a VB.NET project, you import the System.Data.SqlServer namespace as follows: Imports System.Data.SqlServer

Unlike typical ADO.NET projects, in which you must explicitly open a connection to a named SQL Server instance using the connection object’s Open method, the SQL Server .NET Data Provider implicitly makes a connection to the local SQL Server system and, as you’ll see in the examples in the following sections, there’s no need to invoke the Open method.

.NET Stored Procedures Among the database objects that you’ll most likely want to create using one of the managed .NET languages are stored procedures, because they often contain complex logic and embody business rules that are difficult to express in T-SQL. The following example illustrates the source code required to create a simple CLR stored procedure: using System; using System.Data.SqlServer; namespace MyCLRDLL { /// /// Summary description for Class1. ///

page 5 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

public class PubsDataAccess { public PubsDataAccess(){} public static int GetAuthorsCount() { int iRows; SqlCommand sqlCmd = SqlContext.GetCommand(); sqlCmd.CommandText = "select count(*) as 'Authors Count' from authors"; iRows = (int)sqlCmd.ExecuteScalar(); return iRows; } } }

The first important item to note in this code is the directive that imports the System.Data.SqlServer namespace. This enables the DLL to use the SQL Server .NET Data Provider. Next, you can see that the namespace for this assembly is named MyCLRDLL and that the assemblies’ class name is PubsDataAccess. This class contains a static method named GetAuthorsCount. For C# the method must be defined as static. For VB.NET code the method would need to be defined as Shared. Notice that within the class there is no need to execute the Open method. Instead, the SQL Server .NET Data Provider automatically opens the connection on your behalf. After the code for the CLR stored procedure has been compiled, you can then add its assembly to the database and create the CLR stored procedure. The following code illustrates creating an assembly for MyCLRDLL.dll: CREATE ASSEMBLY MyCLRDLL FROM '\\FILESHARE\Code Library\MyCLRDLL.dll'

When the assembly is created, the DLL is copied into the SQL Server master database and the assembly is registered. The following code illustrates creating a stored procedure that uses the assembly: CREATE PROCEDURE GetAuthorsCount AS

page 6 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

EXTERNAL NAME MyCLRDLL:[MyCLRDLL.PubsDataAccess]::GetAuthorsCount

The EXTERNAL NAME statement is new to SQL Server Yukon. In the preceding example, the EXTERNAL NAME statement specifies that the stored procedure will be created using a .NET assembly. An assembly can contain multiple namespaces and methods, and the EXTERNAL NAME statement uses the following syntax to identify the correct code to use from within the assembly: Assembly Name:[AssemblyNamespace.TypeName]::MethodName In the previous example, the registered assembly is named MyCLRDLL. The namespace within the assembly is MyCLRDLL and the class within that namespace is PubsDataAccess. Finally, the method within the class that will be executed is GetAuthorsCount. After the CLR stored procedure has been created, it can be called like any stored procedure, as the following example illustrates: DECLARE @authorcount INT EXEC @authorcount = GetAuthorsCount PRINT @authorcount

.NET User-Defined Functions Creating .NET-based user-defined functions is another new feature that’s enabled by the integration of the .NET CLR. User-defined functions that return scalar types must return a .NET data type that can be implicitly converted to a SQL Server data type. Scalar functions written with the .NET Framework can significantly outperform T-SQL in certain scenarios because, unlike T-SQL, .NET functions are created using compiled code. User-defined functions can also return table types, in which case the function must return a result set. The following example extends the assembly that was used in the earlier example by adding a class named DateRoutines that contains a method named GetDateAsString that performs a basic date-to-string conversion: using System; using System.Data.SqlServer; namespace MyCLRDLL {

page 7 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

public class DateRoutines { public DateRoutines(){} public static string GetDateAsString() { DateTime CurrentDate = new DateTime(); return CurrentDate.ToString(); } } public class PubsDataAccess { public PubsDataAccess(){} public static int GetAuthorCount() { int iRows; SqlCommand sqlCmd = SqlContext.GetCommand(); sqlCmd.CommandText = "select count(*) as 'Authors Count' from authors"; iRows = (int)sqlCmd.ExecuteScalar(); return iRows; } } }

The important point to note is that the DateRoutines class’s GetDateAsString method. takes the system date and time and returns them as a string value. Note: Before you modify an assembly that has been used to create SQL Server objects, you must first drop the dependant objects. Then, you can modify the assembly and re-create the dependant objects. To create the function, the assembly must first be created, as you saw previously in the stored procedure example. Then, the CREATE FUNCTION statement is used to create a new SQL Server function that executes the appropriate method in the assembly. The following example illustrates how the CREATE FUNCTION statement can create a .NET user-defined function:

page 8 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

CREATE FUNCTION GetDateAsString() RETURNS nvarchar(256) EXTERNAL NAME MyCLRDLL:[MyCLRDLL.DateRoutines]::GetDateAsString SELECT dbo.GetDateAsString()

For user-defined functions, the CREATE FUNCTION statement has been extended with the EXTERNAL NAME clause, which essentially links the user-defined function name to the appropriate method in the .NET assembly. In this example, the GetDateAsString function is using the assembly named MyCLRDLL. Within that assembly, it’s using the MyCRLDLL namespace, the DateRoutines class, and the GetDateAsString method within that class.

.NET Extended Triggers In addition to stored procedures and user-defined functions, the new .NET integration capabilities in SQL Server Yukon also enable you to create .NET extended triggers. The following example shows an extended trigger class that was added to the MyCLRDLL assembly: public static void MyTrigger() { SqlTriggerContext oTriggerContext = SqlContext.GetTriggerContext(); SqlPipe sPipe = SqlContext.GetPipe(); SqlCommand sqlCmd = SqlContext.GetCommand(); if (oTriggerContext.TriggerAction == System.Data.Sql.TriggerAction.Insert) sqlCmd.CommandText = "SELECT * FROM INSERTED"; sPipe.Execute(sqlCmd); }

The SqlContext object enables the code to access the virtual table that’s created during the execution of the trigger. This virtual table stores the data that caused the trigger to fire. The SqlPipe object enables the extended trigger to communicate with the external caller. In this example, the SqlContext object is used to first determine if the trigger action was an insert operation. If so, then the contents of the virtual trigger table are retrieved and sent to the caller page 9 Features_CLR.doc

SQL Server Yukon New

SQL Server Yukon New Features

Chapter 4

10/6/2003

using the SqlPipe object’s Execute method in conjunction with a SELECT command that reads the contents of the virtual table. The following code shows how to create the extended trigger: CREATE TRIGGER MyTrigger ON Jobs FOR INSERT AS EXTERNAL NAME MyCLRDLL:[MyCLRDLL.PubsDataAccess]::MyTrigger

Much like the other .NET examples, the extended trigger is created using the CREATE TRIGGER statement. The CREATE TRIGGER statement has been extended with the AS EXTERNAL NAME clause, which associates the trigger to a method in an assembly. In the preceding example, the EXTERNAL NAME clause points to the assembly named MyCLRDLL, which contains the namespace MyCLRDLL. Within the PubsDataAccess class of that namespace, the MyTrigger method contains the code that will be executed when this extended trigger is fired.

CLR User-Defined Data Types Another important new feature in SQL Server Yukon that is enabled by the integration of the .NET CLR is the ability to create true user-defined types (UDTs). Using UDTs, you can extend the raw types provided by SQL Server and add data types that are specialized to your application or environment. In the following example, you’ll see how to create a UDT that represents a gender code: either M for male or F for female. While you could store this data in a standard 1-byte character field, using a UDT ensures that the field will accept only these two values, with no additional need for triggers, constraints, or other data-validation techniques. [Serializable(), System.Data.Sql.SqlUserDefinedType

(System.Data.Sql.Format.SerializedDataWithMetadata, MaxByteSize=8000)] public class MFCode : System.Data.SqlTypes.INullable { private bool is_Null = false;

page 10 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

private string m_size; private string m_type; public bool IsNull { get { return (is_Null); } } public override string ToString() { if(this.IsNull) return "NULL"; else return this.ToString(); } public static MFCode Parse(System.Data.SqlTypes.SqlString s) { if (s.IsNull) return null; else { MFCode mf = new MFCode(); mf.Size = s.ToString(); return (mf); } } public static MFCode Null { get { MFCode mf = new MFCode(); mf.is_Null = true; return (mf); } } public string Size { get { return(this.m_size);

page 11 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

} set { m_size = value; } } public string Type { get { return(this.m_size); } set { if (value == "M" || value == "F") m_type = value; else throw new ArgumentException("Type must be M or F"); } } }

The first section of this code is essentially a template that’s required by all UDTs. The class’s attributes must be serializable, the class must implement the INullable interface, and the class name is set to the name of the UDT—in this example, MFCode. The public properties of IsNull, Null, and Parse are required for all UDTs. The Parse property must be declared as static or, if you’re using VB.NET, must be a Shared property. The custom Size and Type properties are specific to this implementation. The Type property is responsible for editing the allowable values. In this case, only the values of M or F are permitted. After the assembly has been created, you can add the UDT to a database by using the CREATE TYPE statement: CREATE TYPE MFCode EXTERNAL NAME MyCLRDLL:[MyCLRDLL.MFCode]

Much like the other .NET database objects, the EXTERNAL NAME clause is used to specify the assembly, the namespace, and the class for the UDT. Once the UDT is created, you page 12 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

can use it very much like SQL Server’s native data types. The following example creates a table that uses the new MFCode UDT: CREATE TABLE Contact (ContactID int, FirstName varchar(25), LastName varchar(25), Gender MFCode)

Assigning values to the UDT is a bit different than the standard column assignment. To assign a value to a UDT, you need to set its custom property. This example shows the value of M being assigned to a variable that’s declared as an MFCode UDT: insert into contact

(ContactID, FirstName) values(1, 'Mike')

declare @mf MFCode set @mf = CONVERT(MFCode, ' ') set @mf::Size = 1 set @mf::Type='M' UPDATE contact SET Gender = @mf WHERE contactid = 1

CLR User-Defined Aggregates A user-defined aggregate is another new type of .NET database object that is introduced in SQL Server Yukon. Essentially, a user-defined aggregate is an extensibility function that enables you to aggregate values over a group during the processing of a query. SQL Server has always provided a basic set of aggregation functions, like MIN, MAX, and SUM, that you can use over a query. User-defined aggregates enable you to extend this group of aggregate functions with your own custom aggregations. When you create a user-defined function, you supply the logic that will perform the aggregation.

.NET Database Object Security No discussion of the new CLR features would be complete without a mention of the security associated with the .NET assemblies that are used. Unlike T-SQL, which doesn’t have any native facilities for referencing resources outside the database, .NET assemblies are fully capable of assessing both system and network resources. Therefore, securing them is an page 13 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

important aspect of their development. With SQL Server Yukon, Microsoft has integrated the user-based SQL Server security model with the permissions-based CLR security model. Following the SQL Server security model, users are able to access only database objects— including those created from .NET assemblies—to which they have user rights. The CLR security extends the standard SQL Server security model by providing control over the type of system resources that can be accessed by .NET code running on the server. CLR security permissions are specified at the time the assembly is created by using the WITH PERMISSION_SET clause of the CREATE ASSEMBLY statement. The following table summarizes the options for CLR database security permissions that can be applied to SQL Server database objects. CLR Security

External Access Allowed

Calls to Unmanaged Code

SAFE

No external access allowed

No calls to unmanaged code allowed

EXTERNAL_ACCESS

External access allowed via

No calls to unmanaged code allowed

management APIs UNSAFE

External access allowed

Calls to unmanaged code allowed

Using the SAFE permission restricts all external access. The EXTERNAL_ACCESS permission enables some external access of resources using managed APIs. SQL Server impersonates the caller in order to access external resources. You must have the new EXTERNAL_ACCESS permission in order to create objects with this permission set. The UNSAFE permission is basically an “anything goes” type of permission. All system resource can be access and calls to both managed and unmanaged code are allowed. Only system administrators can create objects with UNSAFE permissions.

When to Use CLR Database Objects Database objects created using the CLR are best suited for objects that either require complex logic or are transportable between the database and data-tier layer of an application. They are not as well suited as T-SQL to raw-data access and update functions.

page 14 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

T-SQL Enhancements With all the new .NET-related features, you may wonder whether Microsoft is planning to drop support for T-SQL—definably not. T-SQL is still the best language to use for raw-data access (as you probably noticed, T-SQL syntax was used in the previous examples). So rest assured that T-SQL will be around for the foreseeable future. In fact, Microsoft has made a number of important enhancements to T-SQL that you’ll learn about in this section.

IntelliSense Support One very welcome enhancement to the T-SQL side of SQL Server Yukon is the inclusion of full IntelliSense support for T-SQL. IntelliSense provides interactive parameter prompting and smart command completion for all T-SQL commands edited using the SQL Workbench.

New Date/Time Data Types At a deeper level, T-SQL also provides support for several new language enhancements. Some of the more important of these new features are the new date/time data types: •

UtcDateTime



Date A calendar date



Time 24-hour time

Universal Time from Greenwich Time

These new data types are implemented as system UDTs and are part of the System.Data.SqlTypes namespace. This implementation makes them familiar to users who know the base class library. The following table lists the new data types and their characteristics. New Date/Time Data Type

Precision

Range

Time Zone Aware

UtcDateTime

100 ns

1-1-1 through 9999-12-31

Yes

Date

1 day

1-1-1 through 9999-12-31

No

Time

100 ns

1900-1-1 through 2079-6-6

No

One notable point about UtcDateTime is that its aware of the different time zones, which enables you to compare and align events that occur across time boundaries. The data type also page 15 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

has properties that allow you to extract the different parts of the date. For instance, the following example extracts the year: utcDateCol::Year

The UtcDateTime date type also provides a number of conversion and formatting methods. For instance, to return a date character string, you can use utcDateCol::CovertToString(“mmddyyyy”)

New Varchar(max) Data Type The new Varchar(max) data type provides an alternative to text/image data types. The new Varchar(max) data type is an extension to the Varchar, Nvarchar, and Varbinary data types. Like the Text, Ntext, and Image data types, the Varchar(max) data type supports up to 2GB of data. However, unlike the existing Text, Ntext, and Image data types, the Varchar(max) data type can contain both character and binary data. Also unlike the Text, Ntext, and Image data types, it provides no support for text pointers. Microsoft introduced the new Varchar(max) data type to make working with these large data types more like working with standard string data. This allows you to use the same programming model for Varchar(max) data that you use to work with standard Varchar data. All string functions work on Varchar(max) data types, and the SUBSTRING functions can be used to read chunks of data. In addition, the T-SQL UPDATE statement has been enhanced to support updating chunks within a Varchar(max) data type. You can create a column using the new Varchar(max) data type, as shown here: CREATE TABLE NewBLOB ( DataID INT IDENTITY NOT NULL, BLOBData VARCHAR(MAX) NOT NULL )

TOP Enhancements Another area of T-SQL that has been improved is the TOP clause. In SQL Server 2000, you were forced to use a constant value in conjunction with the TOP clause. In other words, you could select the TOP 5 or the TOP 10 rows where the value of 5 or 10 was a constant. With SQL page 16 SQL Server Yukon New Features_CLR.doc

SQL Server Yukon New Features

Chapter 4

10/6/2003

Server Yukon, the TOP function now enables the use of an expression in conjunction with the TOP clause. An expression can be any allowed T-SQL expression including a variable or a scalar subquery. The TOP clause is also supported in the INSERT, UPDATE, and DELETE statements. This gives the TOP clause a great deal more flexibility than ever before. Here is an example of using the new TOP clause: DECLARE @MyTop INT SET @MyTop = 15 SELECT TOP (@MyTop) CustomerID, CompanyName FROM customers

Common Table Expressions Another new T-SQL feature is support for Common Table Expressions (CTE). CTE are a lot like views, but they are embedded in a query. The main reason Microsoft introduced CTE to SQL Server Yukon is to provide a mechanism for handling recursive queries. Recursion is achieved by the fact that CTE is allowed to refer to itself. To avoid possibly overwhelming the system from a poorly constructed recursive query, SQL Server implements a server-wide limit on the maximum level of recursion that is allowed, with a default maximum of 100 levels. CTE is implemented as a part of the WITH keyword and can be used in front of the SELECT, INSERT, UPDATE, and DELETE statements. To implement recursive queries using the new CTE, you must use a special syntax, as shown in this simple code example: WITH My_CTE AS (SELECT1 UNION ALL SELECT2)

To use CTE, you first write a WITH clause that names the CTE. This example shows the CTE named My_CTE. Then you bind the CTE to columns or a SELECT statement. The first SELECT statement, called the Anchor Member, must not refer to itself. The second SELECT statement references the CTE and is called the Recursive Member. There must be a semicolon in front of the WITH keyword if this is not the first statement in a batch.

Transaction Abort Handling Another important advance embodied by T-SQL in SQL Server Yukon is improved transaction abort handling. With SQL Server Yukon, a new Try/Catch model has been added to the transaction. The new Try/Catch structure enables transaction abort errors to be captured with page 17 SQL Server Yukon New Features_CLR.doc

SQL Server Yukon New Features

Chapter 4

10/6/2003

no loss of the transaction context. With SQL Server 2000, although you can abort a transaction, there’s no way to maintain the context of the transaction so that you can completely recover the aborted transaction. SQL Server Yukon’s new Try/Catch transaction abort handling enables you to maintain the complete context of the aborted transaction, giving you the option of re-creating the transaction. The following code shows the basic T-SQL Try/Catch structure: BEGIN TRY

END TRY BEGIN CATCH TRAN_ABORT

END CATCH

The transaction is attempted in the Try block. If the RAISERROR with TRAN_ABORT statement is issued in theTry block, control is transferred to the Catch block. Within the Catch block, the @@error variable can be evaluated to determine the error condition.

When to Use T-SQL Database Objects T-SQL database objects are not being phased out in SQL Server Yukon. In fact, T-SQL is still the best choice for objects that need to perform raw-data access operations. For instance, if you have stored procedures whose main function is to insert, update, or delete rows of data, then these objects should be developed using T-SQL rather than any of the .NET languages.

Client Development and Enhancements to .NET Framework Data Provider for SQL Server In addition to the new CLR and T-SQL features, the SQL Server Yukon release also provides some extensive improvements on the client side by bundling an update to ADO.NET. As ADO.NET continues to mature, it’s finally getting those missing features that were present in its predecessor, the COM-based ADO, along with a couple of brand-new features. As you’ll discover as you read this section, many of the new features that Microsoft has added to ADO.NET expose some of the new capabilities that have been added to the SQL Server database engine. In addition to the major new features described in this section, the new ADO.NET also page 18 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

supports new T-SQL data types: Varchar(max), UtcDataTime, Date, and Time. These new data types were described earlier in the chapter, in the sections “New Date/Time Data Types” and “New Varchar(max) Data Type.” To begin using the new .NET Data Provider for SQL Server in your Visual Studio .NET projects, you first need to make sure that your project is using the updated version of the .NET Framework. At the time of this writing, you must first delete the reference to the older System.Data version and then add a reference to the new version. To delete the reference to the older version, open Visual Studio’s Solution Explorer, right-click the old System.Data reference, and select Remove. To add a reference to the new System.Data namespace, select Project | Add References from Visual Studio .NET to open the Add Reference dialog box. Then, click the Browse button, navigate to the \Windows\Microsoft.NET\Framework\v1.2.30703 directory, select System.Data.dll, and click OK. The next step to incorporate the .NET Data Provider for SQL Server into your applications is to import the System.Data.SqlClient namespace into your project. The System.Data.SqlClient namespace contains the .NET classes that comprise the .NET Data Provider for SQL Server. For a C# project, the import directive is as follows: using System.Data.SqlClient;

For a VB.NET project, you import the System.Data.SqlClient namespace as follows: Imports System.Data.SqlClient

Server-Side Cursor Support Using SqlResultSet One of the most important new features provided in the new ADO.NET is support for server-side cursors. This is one of the areas where ADO.NET was missing features found in COM-based ADO. Prior versions of ADO.NET supported only client-side cursors, requiring the client platform to do the work of maintaining the result set. With server-side cursors, you can shift that work to the server. The main reason that Microsoft added this new feature was for the new in-process SQL Server .NET Data Provider. Microsoft added them to support in-process server-side database because on the server there’s a need to dynamically scroll through the results of short-lived result sets and there’s little user interaction. Server-side cursors do hold page 19 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

state, which decreases scalability and increases the need for round-trips to the server. It’s important to note that Microsoft strongly recommends that even though they added this support to the client side to facilitate code compatibility between the midtier and data-tier layers of an application, you should never use server-side cursors for client-side development With the SQL Server Yukon version of ADO.NET, the new SqlResultSet object exposes server-side cursors to your application. These cursors are both updateable and dynamically scrollable. Server-side cursors are implemented by the new ExecuteResultSet method in the SqlCommand object. The following example demonstrates the use of the ADO.NET SqlResultSet object: SqlConnection cn = new SqlConnection ("SERVER=MyServer;INTEGRATED SECURITY=True;DATABASE=Northwind"); SqlCommand cmd = new SqlCommand("SELECT * FROM Customers", cn); cmd.CommandType = CommandType.Text; try { cn.Open(); SqlResultSet result = cmd.ExecuteResultSet (ResultSetOptions.Scrollable | ResultSetOptions.Updatable); result.ScrollAbsolute(1); // Scroll forward/backward or update... // Always be sure to close result.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { cn.Close(); }

page 20 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

In the preceding code, you can see the new SqlResultSet object used in the Try block. Much like the SqlDataReader object, the SqlResultSet object is instantiated using a call from the Command object. In this case, the cursor is opened using the ExecuteResultSet method, which takes an argument that specifies what type of cursor will be opened. This example opens a scrollable, updateable cursor. After the cursor is opened, your application can scroll forward and backward and make updates. Since server-side cursors hold state and consume server resources for as long as they’re open, it’s very important to be sure to close them when they’re no longer needed.

Asynchronous Support Another feature that was present in ADO but missing in the earlier releases of ADO.NET is support for asynchronous queries. Asynchronous queries enable client applications to submit queries without blocking the user interference. In the midtier layer of applications, the new ADO.NET asynchronous support enables server applications to issue multiple database requests on different threads without blocking the threads. This new asynchronous support will also work with prior versions of SQL Server, including SQL Server 7 and 2000. With SQL Server Yukon, ADO.NET provides asynchronous support both for opening a connection and for executing commands. The implementation is the same as other asynchronous operations found in the .NET Framework. The asynchronous operation is started by using the object’s BEGINxxx method and is ended by using the ENDxxx method. The IAsyncResult object is used to check the completion status of the command. The following example shows how to execute an asynchronous query. SqlConnection cn = new SqlConnection ("SERVER=myServer;INTEGRATED SECURITY=True;DATABASE=Pubs"); SqlCommand cmd = new SqlCommand("SELECT * FROM authors"); cmd.CommandType = CommandType.Text; try { cn.Open(); IAsyncResult myResult = cmd.BeginExecuteReader(); while(!myResult.IsCompleted) { // Perform other code actions

page 21 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

} SqlDataReader rdr = cmd.EndExecuteReader(myResult); // Process the contents of the reader } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { cn.Close(); }

The important point to note in this example is the code within the Try block. The SqlCommand object’s BeginExecuteReader method is used to start an asynchronous query that returns all of the rows in the authors table. Control is returned to the application immediately after the statement is executed. The application doesn’t need to wait for the query to finish. Next, a While loop is used to check the status of the IAsyncResult object. When the asynchronous command completes, the IsCompleted property is set to true. At this point, the While loop completes and the EndExecuteReader command is used to assign the asynchronous query to a SqlDataReader object for processing.

Multiple Active Result Sets The ability to take advantage of SQL Server Yukon’s new multiple active result sets (MARS) feature is another enhancement found in the new ADO.NET version. In prior versions of ADO.NET and SQL Server, you were limited to one active result set per connection. And while COM-based ADO and OLE DB had a feature that allowed the application to process multiple results sets, under the covers, that feature was actually spawning new connections on your behalf in order to process the additional commands. The new MARS feature in ADO.NET takes advantage of SQL Server Yukon’s ability to have multiple active commands on a single connection. In this model you can open a connection to the database, then open the first command and process some results, then open the second command and process results, then go back to the first command and process more results. You page 22 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

can freely switch back and forth between the different active commands. There’s no blocking between the commands, and both commands share a single connection to the database. The feature provides a big performance and scalability gain for ADO.NET applications. Since this feature relies on a SQL Server Yukon database, it can be used only with SQL Server Yukon databases and doesn’t work with prior versions of SQL Server. The following example illustrates using MARS: SqlConnection cn = new SqlConnection ("SERVER=myServer;INTEGRATED SECURITY=True;DATABASE=Northwind"); SqlCommand cmd1 = new SqlCommand("SELECT * FROM products", cn); cmd1.CommandType = CommandType.Text; SqlCommand cmd2 = new SqlCommand ("delete from products where ProductID = @ProductID",cn); cmd2.CommandType = CommandType.Text; cmd2.Parameters.Add("@ProductID", SqlDbType.Int); try { cn.Open(); SqlDataReader rdr = cmd1.ExecuteReader(); while (rdr.Read()) { if (rdr["ProductName"].ToString() == "Chai" ) { cmd2.Parameters["@ProductID"].Value = rdr["ProductID"]; cmd2.ExecuteNonQuery(); } } rdr.Close(); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { cn.Close(); }

page 23 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

In this example, you can see that both cmd1 and cmd2 share the same SqlConnection object named cn, and the SqlCommand named cmd2 is able to execute without first closing the SqlDataReader, which is already active.

Paging Integrated support for paging is another welcome new feature found in the SQL Server Yukon version of ADO.NET. Paging is always one of the difficult areas to work with in client applications. The new ADO.NET provides the basic support for paging by enabling the application to select and bind to a range of rows from a result set. For scalability, the new paging implementation doesn’t hold any state on the server. However, this also means that it’s possible for the membership of the paging set to change between executions. Therefore, the new paging feature is best suited to data that’s fairly stable and doesn’t change frequently. The paging support in the new ADO.NET is ordinal-based, and to use it, you must specify a starting row in the result set and the number of rows to include in the page. The rows of the page set are read using the standard SqlDataReader object. The following example illustrates using the new ADO.NET paging function: private SqlDataReader PageProductsTable(int nStartRow, int nPageSize) { SqlConnection cn = new SqlConnection ("SERVER=myServer;INTEGRATED SECURITY=True;DATABASE=Northwind"); SqlCommand cmd = new SqlCommand("SELECT * FROM Products", cn); cmd.CommandType = CommandType.Text; try { cn.Open(); return cmd.ExecutePageReader (CommandBehavior.CloseConnection, nStartRow, nPageSize); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally

page 24 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

{ cn.Close(); } return null; }

In this example, the PageProducts method takes as arguments two integers that define the starting position and the paging size of the rows to be read. It returns an ADO.NET SqlDataReader object. Inside the routine, the SqlConnection and SqlCommand objects are created as normal. However, you can see where there is a difference in the Try block. After the SqlConnection object is opened, the SqlCommand object’s ExecutePageReader method is called to retrieve a page of results. The first argument of the ExecutePageReader method is an ordinal that identifies the starting row. The second argument specifies the number of rows to be returned. The third argument is the CommandBehavior.CloseConnection enumerator that tells the SqlCommand object to close the connection when the operation is finished.

SqlDataTable Support SqlDataTable is a new object added to the ADO.NET Framework that ships with SQL Server Yukon. Prior versions of the ADO.NET Framework required you to use a full DataSet and DataAdapter even if you only wanted to access a single table. This resulted in more overhead and more complexity than was necessary simply to access a single table. The new SqlDataTable object enables that type of single-table access to be handled in a more efficient and simpler fashion. SqlDataTable is like a standard DataTable in that it can be a part of a DataSet. However, SqlDataTable is an extended version of the DataTable in that it embodies several DataAdatper-like functions. For instance, the new SqlDataTable object has a Fill method and also generates INSERT, UPDATE, and DELETE commands. The following example shows you how the new SqlDataTable object is used: SqlConnection cn = new SqlConnection ("SERVER=MyServer;INTEGRATED SECURITY=True;DATABASE=Northwind"); SqlDataTable EmpTable =

new SqlDataTable

("SELECT * FROM employees WHERE ReportTo = 2", cn); try {

page 25 New Features_CLR.doc

SQL Server Yukon

SQL Server Yukon New Features

Chapter 4

10/6/2003

EmpTable.Fill(); // Update the data here... // Call Update to post the changes EmpTable.Update(); } catch (Exception ex) { MessageBox.Show(ex.Message); } finally { cn.Close(); }

You can see that the SqlDataTable object is used to contain the rows from the employees table where the ReportTo column contains the value of 2. SqlDataTable is populated using the Fill method. As you can see, there’s no need for either a DataAdapter or DataSet. After SqlDataTable is populated, your code can modify its contents and any changes will be posted to the database by calling the Update method.

page 26 New Features_CLR.doc

SQL Server Yukon