One of the most useful, and potentially dangerous, extended stored procedures provided with SQL Server 2008 isxp_cmdshell.. SQL Server Profiler extended procedures Are used by SQL Server
Trang 1CHAPTER 44 Advanced Stored Procedure Programming and Optimization
Table 44.2 lists the general categories of extended stored procedures
One of the most useful, and potentially dangerous, extended stored procedures provided
with SQL Server 2008 isxp_cmdshell xp_cmdshellcan execute any operating system
command or program available on the SQL Server system, as long as it is a console program
that doesn’t require user input.xp_cmdshellaccepts avarchar(8000)(ornvarchar(4000))
value as the command string to be executed, and it returns the results of the command as a
singlenvarchar(255)column The full syntax ofxp_cmdshellis as follows:
xp_cmdshell { ‘command_string’ } [ , no_output ]
If the no_outputoption is specified, the results from the command are not displayed
The following example uses xp_cmdshellto list the files in a directory on the SQL Server
computer’s hard disk:
EXEC xp_cmdshell ‘DIR c:\*.*’
xp_cmdshellruns synchronously Control is not returned to the SQL Server user session
until the shell command completes This is why you have to ensure that the shell
command invoked via xp_cmdshelldoes not prompt for user input Commands invoked
viaxp_cmdshelldo not run interactively, so there is no way to respond to the user input
prompt The SQL Server session waits indefinitely for a command invoked via
xp_cmdshellto return
TABLE 44.2 Extended Stored Procedures Categories
Category Description
General extended
proce-dures
Provide general functionality Perhaps the most useful is xp_cmdshell, which executes external programs and returns the output from them as a result set
SQL Mail extended
proce-dures
Enable you to perform email operations from within SQL Server
SQL Server Profiler
extended procedures
Are used by SQL Server Profiler They can also be used directly, for instance, to create a trace queue and start the trace from within a stored procedure
OLE automation procedures Allow SQL Server to create and use OLE automation objects
API system stored
proce-dures
Are undocumented extended stored procedures used by the API libraries The server cursor functionality, for instance, is imple-mented as a set of extended stored procedures
Trang 2Using Extended Stored Procedures
CAUTION
After SQL Server passes off the xp_cmdshellcommand to the operating system, SQL
Server cannot interact with the command If the command requires user input, the
process waits indefinitely, and it usually doesn’t go away without a fight Killing the
process in SQL Server usually just leaves it in a KILLED/ROLLBACKstate Closing the
session that invoked the xp_cmdshellstatement doesn’t help either Sometimes, you
might have to stop and restart SQL Server to make the process finally go away
Alternatively, you may be able to use Task Manager on the system where SQL Server is
running to identify the system process that corresponds to the process invoked by
xp_cmdshelland end the process
Ifxp_cmdshellis invoked from another database, it has to be fully qualified as
master xp_cmdshell Unlike with system procedures, SQL Server doesn’t automatically
look for extended stored procedures in the masterdatabase
Because of the potentially dangerous nature of xp_cmdshell(it essentially allows a user to
run operating system–level commands on the SQL Server machine), it is disabled by
default To enable xp_cmdshell, you must run the following commands:
EXEC sp_configure ‘show advanced options’, 1
GO
RECONFIGURE
GO
To enable the feature.
EXEC sp_configure ‘xp_cmdshell’, 1
GO
RECONFIGURE
GO
As an additional security measure in SQL Server 2008, by default, permission to execute
xp_cmdshellis limited to users with CONTROL SERVERpermission The Windows process
spawned by xp_cmdshellruns within the security context of the account under which the
SQL Server service is running Essentially, it has the same security rights as the SQL Server
service account
Whenxp_cmdshellis invoked by a user who is not a member of the sysadminfixed server
role, it fails unless a proxy account has been set up A proxy account is a Windows account
that a system administrator defines and sets a security context for within the Windows
environment When a user who is not a member of the sysadmingroup runs xp_cmdshell,
the commands are run within the security context of the defined proxy account
The proxy account for xp_cmdshellcan be created by executing
sp_xp_cmdshell_proxy_account The syntax of this command is as follows:
sp_xp_cmdshell_proxy_account [ NULL | { ‘account_name’ , ’password’ } ]
Trang 3CHAPTER 44 Advanced Stored Procedure Programming and Optimization
For example, the following command creates a proxy credential for the Windows domain
userDeveloper\tomthat has the Windows password ss2k5Unl:
sp_xp_cmdshell_proxy_account ‘Developer/tom’ , ‘ss2k5Unl’
IfNULLis passed as account_name, the proxy credential is deleted
CAUTION
Because of the potential havoc that could be wreaked on your database server if
xp_cmdshellgot into the wrong hands, it is recommended that the capability to run
xp_cmdshellbe left disabled If you must use xp_cmdshell, be very careful about
who has access to it by limiting it to only those with sysadminpermissions if at all
possible If for some reason xp_cmdshellmust be made available to all users, be
sure that the permissions granted to the proxy account are restricted to the minimum
permissions required to perform the commands that need to be invoked via
xp_cmdshell.
Summary
Stored procedures in SQL Server can be very powerful, especially when they take
advan-tage of the many features of the T-SQL language Very complex tasks can be simplified
into a single stored procedure call The guidelines and tips presented in this chapter
should help you create more powerful, efficient, and robust stored procedures
Additionally, with the ability to create NET CLR stored procedures, you can write even
more powerful stored procedures in languages other than T-SQL to further expand the
capabilities and power of the stored procedures that reside in SQL Server
Trang 4SQL Server and the
.NET Framework
IN THIS CHAPTER
What’s New in SQL Server
2008 and the NET Framework
Getting Comfortable with ADO.NET 3.5 and SQL Server 2008
Developing with LINQ to SQL
Using ADO.NET Data Services
Leveraging the Microsoft Sync Framework
This chapter examines the deep integration of the NET
Framework with SQL Server 2008 It first teaches the
essen-tials of programming with ADO.NET 3.5, then it
jump-starts your LINQ to SQL skills, and finally it delves into
ADO.NET Data Services (formerly Astoria) and the Microsoft
Sync Framework
What’s New in SQL Server 2008
and the NET Framework
The release of the NET Framework 3.5 includes a number
of exciting new SQL Server features, the most compelling of
which is Language-Integrated Query (LINQ) LINQ to SQL is
a timesaving and powerful technology that enables
devel-opers to write code in either C# or VB NET, rather than
T-SQL, to query SQL Server databases
ADO.NET Data Services is another new technology that
makes it easy to work with SQL Server data in web
applica-tions, websites, Rich Internet Applications (RIAs), and other
programs that need to consume data from the Web This
chapter shows you how to get started with a simple web
application that exposes your data over HTTP
Finally, this chapter covers the Microsoft Sync Framework
and how to use it for your occasionally connected
applica-tions
Trang 5CHAPTER 45 SQL Server and the NET Framework
Getting Comfortable with ADO.NET 3.5 and SQL
Server 2008
You need to familiarize yourself with the following primary NET Framework namespaces
to be able to program against SQL Server 2008:
System.Data—This is the root namespace, which contains essential data access
classes, such as DataSet,DataTable,andDataRow.
System.Data.SqlClient—This namespace contains classes specialized for SQL Server
access, such as SqlConnection,SqlCommand, and SqlParameter.
System.Xml—This namespace holds most of the objects you need to be able to work
with SQL Server XML
System.LinqandSystem.Data.Linq—These namespaces hold classes essential for
working with LINQ to SQL (stored in the new Sytem.Coreassembly)
The easiest way to immerse yourself in the code is to walk through some typical usage
scenarios, which we do in the following sections
ADO.NET: Advanced Basics
To start coding with ADO.NET and SQL Server, you first need to connect to an instance of
SQL Server To do this, you need a connection string A connection string is simply a string
literal that contains all the parameters necessary to locate and log in to a server in a
semi-colon-delimited format The following is an example:
”Data Source=(SQLServer001);Initial Catalog=AdventureWorks2008;Integrated
Security=True”
This connection string tells ADO.NET to connect to a server called SQLServer001, change
to the AdventureWorks2008database context, and use integrated Windows security to
connect, which means it should use the credentials of the currently authenticated user (in
web applications, this is usually ASPNET, unless impersonation is used) You typically want
to store this connection string in your application’s configfile, preferably encrypted
There are too many different connection string parameters to list here; you can check the
MSDN “Connection Strings” topic for full information
The managed object that represents a SQL Server connection is
System.Data.SqlClient.SqlConnection.
This chapter takes you through a simple C# Windows application built with Visual Studio
2008 (VS) It contains every manager’s dream: a form with a magic button on it that does
everything with one click To create this application, open Visual Studio and create a new
C# Windows Forms application (illustrated in Figure 45.1) Right-click the file called
Form1.csin Solution Explorer (SE) and select Rename Change the name to MainForm.cs
Trang 6Getting Comfortable with ADO.NET 3.5 and SQL Server 2008
FIGURE 45.1 Creating a new C# Windows Forms application with Visual Studio 2008
and accept the rename warning Next, right-click MainForm.csagain and select View Code
Then type the following namespaces into the usingarea at the top left:
using System.Data.SqlClient;
using System.Configuration;
Next, right-click the Referencesfolder in the Solution Explorer and choose Add Reference
On the ensuing Add Reference dialog, click on the NET tab and then scroll down until
you find System.Configuration Select this entry and click OK Next, right-click the
project in the Solution Explorer and choose Add New Item; then scroll though the choices
that appear in the Add New Item dialog until you find Application Configuration File
This file is the place where you typically store connection strings and other configurable
parameters Open your new App.Configfile and enter the following elements, substituting
your server name for (local)in the connection string itself:
<?xml version=”1.0” encoding=”utf-8” ?>
<configuration>
<appSettings>
<add
key=”SqlConn”
value=”Data Source=(local);Initial Catalog=AdventureWorks2008;
Integrated Security=True”/>
</appSettings>
</configuration>
Trang 7CHAPTER 45 SQL Server and the NET Framework
Switching back to MainForm.cs, right-click the file in Solution Explorer and then select
View Designer, which launches the Visual Studio WinForms designer Drag a Button
control from the Toolbox onto the form and name it btnGo Next, drag a DataGridView
control onto the form and name it GridView(ignore the form designer’s SmartTag); this
control will be used to display the data returned when you execute your SqlCommand The
SqlCommandobject allows you to execute T-SQL, including stored procedures, functions,
and other expressions from within the context of an active SQL Server connection
SqlCommandhas several execution methods, each of which behaves differently and returns
a different type of object:
ExecuteNonQuery—Executes the T-SQL statements and returns an Int32that
indi-cates the number of rows affected It also populates any output parameters This
capability is especially useful when you are executing INSERTandUPDATEqueries
ExecuteScalar—Executes the T-SQL statements and returns an object (of type
Object) that contains the value of the first column of the first row returned The
object returned is castable to one of the native NET types (for example, Int32,
String[even for returned xmlcolumns],Boolean).
ExecuteReader—Executes the T-SQL statements and returns a SqlDataReaderobject
SqlDataReaderobjects are useful when you want to perform some behavior on the
returned result set on a per-row and/or per-column basis (usually using a looping
construct)
ExecuteXmlReader—Executes the T-SQL statements and returns a
System.Xml.XmlReader, which you can use to iterate through the nodes in selected
XML (or to instantiate otherSystem.Xmlobjects, such as
System.Xml.XPath.XPathDocument), produced either via SELECT FOR XMLor from
a column or variable of the newxmldata type
TIP
System.Data.SqlClientalso provides asynchronous versions of the preceding
method calls in begin-call/end-call pairs that take a handy callback method parameter,
includingBeginExecuteReader, EndExecuteReader, BeginExecuteNonQuery, and
EndExecuteNonQuery Note that there is no
BeginExecuteScalar/EndExecuteScalar.
To wire up the data returned from the SqlCommandinto a System.Data.DataSet(the
storage object for returned results), you need to use an object of type
System.Data.SqlClient.SqlDataAdapter Developers frequently use SqlDataAdapter
objects to map data coming from SQL Server into DataSetobjects and back, using its
Fill()andUpdate()methods, respectively
Trang 8Getting Comfortable with ADO.NET 3.5 and SQL Server 2008
You may also want to include in your code a try-catchexception-handling block that
catches any SqlExceptionobjects thrown during your code’s execution
To test the many classes we’ve just mentioned, add the code in Listing 45.1 to the
btnGo_Click()event handler To generate the event handler, simply view your form in
the Visual Studio designer and then double-click your button
LISTING 45.1 A Button Event Handler That Illustrates the Use of Several ADO.NET Objects
private void btnGo_Click(object sender, EventArgs e)
{
using (SqlConnection Connection =
new SqlConnection(ConfigurationManager.AppSettings[“SqlConn”]))
{
using (SqlCommand Command =
new SqlCommand(
@”SELECT TOP 10 * FROM Person.Person”
, Connection))
{
try
{
using (SqlDataAdapter Adapter =
new SqlDataAdapter(Command)) {
using (DataSet Set = new DataSet())
{
Connection.Open();
Adapter.Fill(Set);
GridView.DataSource = Set.Tables[0];
}
}
}
catch (SqlException SqlEx)
{
foreach (SqlError SqlErr in SqlEx.Errors)
{
MessageBox.Show(
“The following SQL Error occurred: “ + SqlErr.Message,
“SqlError”);
}
}
}
}
}
Trang 9CHAPTER 45 SQL Server and the NET Framework
FIGURE 45.2 Using ADO.NET in a simple Windows Forms application
Next, run your Windows Forms application (press F5) and then clickbtnGo Your form
should look something like the one in Figure 45.2
This code in your form executes as follows: a connection to SQL Server is made via
SqlConnectionand the subsequent call to Connection.Open()(which, by the way, is
unnecessary because SqlDataAdapter.Fill()implicitly opens the closed connection) The
SqlCommandobjectCommandis set to use this connection via its constructor The constructor
also takes a string parameter that contains the text of the query It can also take the name
of a stored procedure, for example When using a stored procedure name, you change its
CommandTypeproperty from the default of CommandType.Textto
CommandType.StoredProcedure.
Next, you instantiate a SqlDataAdapterobject that registers the Commandobject as what it
will execute on the call to Fill() You also create a DataSetobject to hold the returned
data In the simplest respect, DataSetobjects are collections of DataTableobjects, which
map directly to SQL Server query results Each DataTableobject, as you may guess, holds
an array of DataRowobjects, each of which in turn holds an array of DataColumnvalues
accessible by indexers
You bind the DataGridViewobject to the filled DataSetobject’s first table (Tables[0]), and
you can rest assured that the catchblock will notify you with a message box about each
SqlErrorcontained in the Errorscollection of any raised SqlException
NOTE
One convention used in the code in this chapter is nested usingstatements with
these objects When you use this C# syntax convention, you don’t have to set up a
finallyblock that calls Dispose()for every object; usingdoes that implicitly for you
Trang 10Developing with LINQ to SQL
Many of the database classes provided in ADO.NET have aDispose()method because,
under the covers, they utilize unmanaged (COM) resources The objects you most
commonly use for database applications that provideDispose()areSqlConnection,
SqlCommand, SqlDataAdapter, SqlDataReader, and DataSet.
Now that you’ve had a taste of working with some of the traditional ADO.NET objects, it’s
time to forge ahead into the new world of LINQ
Developing with LINQ to SQL
LINQ enables developers to write code in either C# or VB.NET using the same set of
syntactic conventions to query object collections (known as LINQ to Objects), XML
docu-ments (known as LINQ to XML), SQL Server data (known as LINQ to SQL), and other
queryable resources The focus in the following sections is exclusively on LINQ to SQL
A LINQ to SQL statement is translated into an in-memory data structure known as an
expression tree An expression tree is an abstract representation of executable code These
trees provide a means for translating LINQ expressions into something else—in the case of
LINQ to SQL, T-SQL statements Once translated into T-SQL, the code is executed on SQL
Server (not in NET) This point is important because it highlights the fact that LINQ is
independent from its various data providers
Another important point is that the T-SQL produced by LINQ is not executed until the
moment in your NET code when your LINQ to SQL query is first utilized, not where it is
first defined You may, for example, declare a LINQ to SQL statement near the top of your
.NET method but then only actually use it in one branch of an if-elseblock This
provides enormous efficiency
We should also mention that a certain amount of trust is involved in using LINQ to SQL
because it requires you to accept the fact that Microsoft’s LINQ team has made most of the
right decisions in doing this translation work (and it has) This does not mean that, as a
.NET developer, you no longer need to learn T-SQL; on the contrary, there is much more
to T-SQL that LINQ simply doesn’t do, and you will run into its limitations if you use it a
lot It does mean, however, that you can save an immense amount of time in developing
data-driven applications because you no longer have to do the repetitive work of writing
T-SQL stored procedures for every simple create, retrieve, update, and delete (CRUD) query
Getting Started
To start with LINQ to SQL, launch Visual Studio 2008, then right-click your sample project
in Solution Explorer, and choose Add New Item Click on the Datafolder on the left side
of the ensuing dialog and then select the LINQ to SQL Classes item on the right Name
your new file AdventureWorks2008and click OK (illustrated in Figure 45.3)