1. Trang chủ
  2. » Công Nghệ Thông Tin

Hướng dẫn học Microsoft SQL Server 2008 part 72 pps

10 271 0
Tài liệu đã được kiểm tra trùng lặp

Đang tải... (xem toàn văn)

THÔNG TIN TÀI LIỆU

Thông tin cơ bản

Định dạng
Số trang 10
Dung lượng 0,92 MB

Các công cụ chuyển đổi và chỉnh sửa cho tài liệu này

Nội dung

Dynamic SQL and Code Generation IN THIS CHAPTER Executing dynamic SQL Parameterized queries The risk of SQL injection Generating stored procedures Alternatives to dynamic SQL Folks laugh

Trang 1

managers understand that in the long run it will save money — and their job.

Trang 2

Dynamic SQL and Code Generation

IN THIS CHAPTER

Executing dynamic SQL Parameterized queries The risk of SQL injection Generating stored procedures Alternatives to dynamic SQL

Folks laugh when they hear that my favorite project is based on the

notion that T-SQL is a great language for code generation Nordic (New

Object/Relational Design) is essentially a code-generation tool that uses

dynamic SQL to create tables, stored procedures, and views T-SQL works rather

well for code generation, thank you

The term dynamic SQL has a couple of differing definitions Some say it describes

any SQL query submitted by a client other than a stored procedure That’s not

true SQL submitted from the client is better known as ad-hoc SQL

It’s more accurate to say that dynamic SQL describes any SQL DML statement

assembled dynamically at runtime as a string and then submitted

Dynamic SQL is very useful for several tasks:

■ Multiple possible query criteria can be dynamically assembled into

customFROM,WHERE, andORDER BYclauses for flexible queries

■ Code can respond to the schema of the database and generate

appropri-ate triggers, CRUD stored procedures, and views

■ Dynamic code can auto-generate very consistent stored procedures

However, note the following issues when developing dynamic SQL:

■ Dynamic SQL that includes user entries inWHEREclauses can be open

to SQL injection attacks

■ Poorly written dynamic SQL queries often include extra table references

and perform poorly

■ T-SQL code that generates T-SQL code can be tricky to debug

Trang 3

EXEC[UTE] (’T-SQL batch’);

For example, the followingEXECcommand executes a simpleSELECTstatement:

USE Family;

EXEC (’SELECT LastName FROM Person WHERE PersonID = 12;’);

Result:

LastName -Halloway

The security context of executing code should be considered when working with theEXECUTE

command You can control which user account the Database Engine uses to validate permissions on

objects that are referenced by the module The following code uses theEXECUTE ASsyntax to execute

the query as the user Joe:

Use OBXKites EXECUTE AS ‘Joe’ select * from Products

Another aspect of theEXECUTEcommand is the capability to execute the code at a linked server,

instead of at the local server The code is submitted to the linked server and the results are returned to

the local server:

EXECUTE (’Code’) AT MAUI/SYDNEY;

sp_executeSQL

Another method of executing dynamic SQL is to use thesp_executesqlsystem stored procedure

It offers greater compatibility with complex SQL queries than the straightEXECUTEcommand In

several situations I have found that theEXECUTEcommand failed to execute the dynamic SQL, but

sp_executesqlworked flawlessly:

EXEC sp_Executesql

‘T-SQL query’,

‘Parameters Definition’, Parameter, Parameter ;

Parameterized queries

Sometimes it’s easier to create queries based on a number of parameters because it usually avoids the

need for concatenating strings The query and the definition must be Unicode strings

Parameters provide optimization If the T-SQL query has the same parameters for each execution, then

these parameters can be passed tosp_executesqlso the SQL query plan can be stored, and future

executions will be optimized The following example executes the same query from thePersontable

Trang 4

in theFamilydatabase, but this example uses parameters (theNbefore the parameters is necessary

becausesp_executesqlrequires Unicode strings):

EXEC sp_executesql

N’SELECT LastName

FROM Person

WHERE PersonID = @PersonSelect;’,

N’@PersonSelect INT’,

@PersonSelect = 12;

Result:

LastName

-Halloway

Developing dynamic SQL code

Building a dynamic SQL string usually entails combining aSELECTcolumn’s literal string with a

more fluidFROMclause andWHEREclause While any part of the query can be dynamic, normally the

SELECT@columnsis not

Once the SQL string is complete, the SQL statement is executed by means of thesp_executesql

command The example that follows builds both customFROMandWHEREclauses based on the user’s

requirements

Within the batch, theNeedsAndbit variable tracks the need for anAndseparator betweenWHERE

clause conditions If the product category is specified, then the initial portion of theSELECTstatement

includes the required joins to fetch theProductCategorytable TheWHEREclause portion of the

batch examines each possible user criterion If the user has specified a criterion for that column, then

the column, with its criterion, is added to the @SQLWherestring

Real-world dynamic SQL sometimes includes dozens of complex options The following code listing uses

three possible columns for optional user criteria:

USE OBXKites;

DECLARE

@SQL NVARCHAR(1024),

@SQLWhere NVARCHAR(1024),

@NeedsAnd BIT,

User Parameters

@ProductName VARCHAR(50),

@ProductCode VARCHAR(10),

@ProductCategory VARCHAR(50);

Initialize Variables

SET @NeedsAnd = 0;

SET @SQLWhere = ‘’;

Trang 5

Set up initial SQL Select

IF @ProductCategory IS NULL SET @SQL = ‘Select ProductName from Product’;

ELSE SET @SQL = ‘Select ProductName

from Product Join ProductCategory

on Product.ProductCategoryID

= ProductCategory.ProductCategoryID’;

Build the Dynamic Where Clause

IF @ProductName IS NOT NULL BEGIN;

SET @SQLWhere = ‘ProductName = ’ + @ProductName;

SET @NeedsAnd = 1;

END;

IF @ProductCode IS NOT NULL BEGIN;

IF @NeedsAnd = 1 SET @SQLWhere = @SQLWhere + ‘ and ’;

SET @SQLWhere = ‘Code = ’ + @ProductCode;

SET @NeedsAnd = 1;

END;

IF @ProductCategory IS NOT NULL BEGIN;

IF @NeedsAnd = 1 SET @SQLWhere = @SQLWhere + ‘ and ’;

SET @SQLWhere = ‘ProductCategory = ’ + @ProductCategory;

SET @NeedsAnd = 1;

END;

Assemble the select and the where portions of the dynamic SQL

IF @SQLWhere <> ‘’

SET @SQL = @SQL + ‘ where ’ + @SQLWhere + ‘;’;

∼∼Use this for testing and debug use only

PRINT @SQL;

EXEC sp_executesql @SQL

Trang 6

The results shown are both the printed text of the dynamic SQL and the data returned from the

execu-tion of the dynamic SQL statement:

Select ProductName from Product where Code = 1001;

Name

-Basic Box Kite 21 inch

Code generation

The following example may seem a bit complex, but it’s a great real-world demonstration of T-SQL

code generation It’s from the Nordic database and this is the piece of code that actually generates the

stored procedures and views for each class This procedure is called every time a new class or attribute

is added or changed

A few points in the code worth noting:

■ + CHAR(13) + CHAR(10)are added to the generated code to make it more readable

■ The columns (attributes) are built up in the@SQLStrvariable first, then the dynamicFROM

clause is added

■ A cursor is used to iterate through the columns and tables to build up the custom stored

procedure and view

■ The@SQLStris assembled once and the@GenStris modified to first create the view and

then create the stored procedure

■ The dynamic SQL variables@SQLStrand@GenStrare both declared asNVARCHAR(MAX)

■ Any custom columns are automatically enclosed in square brackets to avoid any syntax errors

Here’s the code:

Gen Class

CREATE

alter

PROC dbo.GenClass

(@ClassName NVARCHAR(50))

AS

SET NoCount ON

EXEC IncVersion ‘Class Design’

DECLARE @GenStr NVARCHAR(MAX),

@SQLStr NVARCHAR(MAX),

@ClassStr NVARCHAR(MAX),

@CurrentClass CHAR(100),

Trang 7

+ CHAR(13) + CHAR(10) + ‘ sc.ClassName + ’‘:’‘ + StateName as [State],’

+ CHAR(13) + CHAR(10) + ‘ ObjectCode as [Object:ObjectCode], Name1 as [Object:Name1], Name2 as [Object:Name2],’

+ CHAR(13) + CHAR(10) + ‘ NULL as [Object:Description],’ + CHAR(13) + CHAR(10)

+ ‘ o.Created as [Object:Created], o.Modified as [Object:Modified], o.Version as [Object:Version] ’

+ CHAR(13) + CHAR(10)

Walk through custom attributes DECLARE cAttributes CURSOR FAST_FORWARD FOR SELECT REPLACE(ClassName, ‘ ’, ‘’), AttributeName FROM dbo.Attributes(@ClassName)

OPEN cAttributes prime the cursor FETCH cAttributes INTO @CurrentClass, @CurrentAttrib WHILE @@Fetch_Status = 0

BEGIN SET @SQLStr = @SQLStr + ‘ , CC’ + RTRIM(@CurrentClass) + ‘.’

+ RTRIM(@CurrentAttrib) + ‘ as [’ + RTRIM(@CurrentClass) + ‘:’

+ RTRIM(@CurrentAttrib) + ‘]’ + CHAR(13) + CHAR(10) fetch next

FETCH cAttributes INTO @CurrentClass, @CurrentAttrib END

CLOSE cAttributes DEALLOCATE cAttributes

FROM base metadata tables SET @SQLStr = @SQLStr + ‘ FROM dbo.Object AS o’ + CHAR(13) + CHAR(10) + ‘ JOIN dbo.Class AS c’ + CHAR(13) + CHAR(10)

+ ‘ ON o.ClassID = c.ClassID’ + CHAR(13) + CHAR(10) + ‘ LEFT JOIN dbo.State AS s’ + CHAR(13) + CHAR(10) + ‘ ON o.StateID = s.StateID’ + CHAR(13) + CHAR(10) + ‘ LEFT JOIN dbo.Class AS sc’ + CHAR(13) + CHAR(10) + ‘ ON s.ClassID = sc.ClassID’ + CHAR(13) + CHAR(10)

FROM dynamic classes DECLARE cClasses CURSOR FAST_FORWARD

Set Difference Query FOR SELECT REPLACE(ClassName, ‘ ’, ‘’)

Trang 8

FROM SuperClasses(dbo.GetClassID(@ClassName))

ORDER BY ClassID DESC

OPEN cClasses

FETCH cClasses INTO @CurrentClass prime the cursor

WHILE @@Fetch_Status = 0

BEGIN

SET @SQLStr = @SQLStr + ‘ JOIN dbo.Obj’

+ RTRIM(@CurrentClass) + ‘ CC’

+ RTRIM(@CurrentClass) + CHAR(13) + CHAR(10)

+ ‘ ON o.ObjectID = CC’

+ RTRIM(@CurrentClass) + ‘.ObjectID’ + CHAR(13) + CHAR(10)

FETCH cClasses INTO @CurrentClass fetch next

END

CLOSE cClasses

DEALLOCATE cClasses

Drop and Create View

SET @GenStr = ‘IF OBJECT_ID(’’v’ + RTRIM(REPLACE(@ClassName, ‘ ’, ‘’))

+ ‘’’)’ + ‘ IS NOT NULL DROP VIEW dbo.v’

+ RTRIM(REPLACE(@ClassName, ‘ ’, ‘’))

EXEC sp_executesql @GenStr

SET @GenStr = ‘CREATE VIEW dbo.v’

+ RTRIM(REPLACE(@ClassName, ‘ ’, ‘’))

+ CHAR(13) + CHAR(10)

+ ‘ AS ’ + CHAR(13) + CHAR(10) + @SQLStr

EXEC sp_executesql @GenStr

Standard Where Clause

SET @SQLStr = @SQLStr + CHAR(13) + CHAR(10)

+ ‘ WHERE o.ObjectID = @ObjectID weirdness aboundeth’

Drop and Create Proc

SET @GenStr = ‘IF OBJECT_ID(’’p’ + RTRIM(REPLACE(@ClassName, ‘ ’, ‘’))

+ ‘’’)’ + ‘ IS NOT NULL DROP PROC dbo.p’

+ RTRIM(REPLACE(@ClassName, ‘ ’, ‘’))

EXEC sp_executesql @GenStr

SET @GenStr = ‘CREATE PROC dbo.p’

+ RTRIM(REPLACE(@ClassName, ‘ ’, ‘’))

+ ‘ (@ObjectID INT) AS SET NoCount ON ’ + @SQLStr

EXEC sp_executesql @GenStr

RETURN

Trang 9

SQL injection is a hacker technique that appends SQL code to a parameter that is later executed as

dynamic SQL What makes SQL injection so dangerous is that anyone with access to the organization’s

website who can enter data into a text field can attempt an SQL injection attack There are several

malicious techniques that involve appending code or modifying theWHEREclause Before learning how

to prevent it, it’s important to understand how it works, as the following sections explain

Appending malicious code

Adding a statement terminator, another SQL command, and a comment, a hacker can pass code into the

execute string For example, if the parameter passed in is

123’; Delete OrderDetail

the parameter, including thedeleteDDL command, placed within a dynamic SQL string would

execute as a batch:

SELECT * FROM Customers

WHERE CustomerID = ‘123’; Delete OrderDetail ’

The statement terminator ends the intended code and the delete command looks to SQL Server like

nothing more than the second line in the batch The quotes would normally cause a syntax error, but

the comment line solves that problem for the hacker The result? An emptyOrderDetailtable

Other popular appended commands include runningxp_commandshellor setting thesapassword

Or 1 =1

Another SQL injection technique is to modify theWHEREclause so that more rows are selected than

intended

If the user enters the following string into the user text box:

123’ or 1=1

then the1=1(always true) condition is injected into theWHEREclause The injected hyphens comment

out the closing quote:

SELECT * FROM Customers

WHERE CustomerID = ‘123’ or 1=1 ’

With every row selected by the SQL statement, what happens next depends on how the rest of the

sys-tem handles multiple rows Regardless, it’s not what should happen

Trang 10

Password? What password?

Another creative use of SQL injection is to comment out part of the intended code Suppose the user

enters the following in the web form:

UserName: Joe’

Password : who cares

The resulting SQL statement might read as follows:

SELECT USerID

FROM Users

WHERE UserName = ‘Joe’ ’ AND Password = ‘who cares’

The comment in the username causes SQL Server to ignore the rest of theWHEREclause, including the

password condition

Preventing SQL Server injection attacks

Several development techniques can prevent SQL injection:

■ UseEXECUTE ASand carefully define the roles so that statements don’t have permission to

drop tables

■ Use DRI referential integrity to prevent deleting primary table rows with dependent secondary

table rows

■ Never let user input mixed with dynamic SQL in a web form execute as submitted SQL

Always pass all parameters through a stored procedure

■ Check for and reject parameters that include statement terminators, comments, orxp_

■ Test your database using the SQL injection techniques described above

SQL injection is a real threat If your application is exposed to entry from the Internet and you haven’t

taken steps to prevent SQL injection, it’s only a matter of time before your database is attacked

Best Practice

For a flexible search procedure in Nordic, I’ve started using a new practice of parsing and joining Rather

than build a dynamic SQL WHERE clause, I allow the application to pass in a multiple-word search string

This is parsed into a table with each word becoming a row The search table is then joined with the various

data points that can be searched For an example of this technique, turn back to Chapter 28, ‘‘Building Out

the Data Abstraction Layer,’’ or download the latest version of Nordic from CodePlex.com

Ngày đăng: 04/07/2014, 09:20

TỪ KHÓA LIÊN QUAN