November 21, 2012 at 8:59 am
I was writing some code to check out the check_constraints of tables spread out accross multiple DBs in a partitioned view
My idea was to use a parameterized query.
Turns out you cannot use parameters for object names.
Is this correct or is there another way to do this?
Something to do with SQL Injection? (No fear of)
Also, is it no longer necesseay to use + in dynamic SQL? (See test 4)
DECLARE
@SQL NVarchar(1000),
@DBName NVarchar(50),
@CKName NVarchar(50),
@Tbl NVarchar(50)
SET @DBName = 'Master'
SET @CKName = 'FakeName'
SET @Tbl = 'Check_Constraints'
-- 1: Works
SET @SQL = 'SELECT * FROM ' + @DBName + '.sys.Check_Constraints'
EXEC (@SQL)
-- 2: Works
SET @SQL = 'SELECT * FROM ' + @DBName + '.sys.Check_Constraints WHERE Name = ''@CK'''
EXEC sp_ExecuteSQL
@Stmt = @SQL,
@Parms = N'@CK NVarchar(50)', @ck = @CKName
-- 3: Works
SET @SQL = 'SELECT * FROM ' + @DBName + '.sys.Check_Constraints WHERE Name = @ck'
EXEC sp_ExecuteSQL
@Stmt = @SQL,
@Parms = N'@CK NVarchar(50)', @ck = @CKName
-- 4: Works ?? Same as WHERE Name = ''' + @CKName + '''' ??
SET @SQL = 'SELECT * FROM ' + @DBName + '.sys.Check_Constraints WHERE Name = ''@CKName'''
EXEC sp_ExecuteSQL
@Stmt = @SQL,
@Parms = N'@CK NVarchar(50)', @ck = @CKName
-- 5: Doesn't work
SET @SQL = 'SELECT * FROM ' + @DBName + '.sys.Check_Constraints WHERE Name = @CKName'
EXEC sp_ExecuteSQL
@Stmt = @SQL,
@Parms = N'@CK NVarchar(50)', @ck = @CKName
/*
Msg 137, Level 15, State 2, Line 1
Must declare the scalar variable "@CKName".
*/
-- 6: Doesn't work
SET @SQL = N'SELECT * FROM Master.sys.@Tbl2 WHERE Name = @CK2'
EXEC sp_ExecuteSQL
@Stmt = @SQL,
@params =N'@Tbl2 NVarchar(50), @CK2 NVarchar(50)', @CK2 = @CKName, @Tbl2 = @Tbl
/*
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '@Tbl2'.
*/
-- 7: Doesn't work
SET @SQL = N'SELECT * FROM @DBName2.sys.Check_Constraints'
EXEC sp_ExecuteSQL
@Stmt = @SQL,
@params =N'@DBName2 NVarchar(50)', @DBName2 = @DBName
/* Error
Msg 102, Level 15, State 1, Line 1
Incorrect syntax near '.'.
*/
Thanks
November 21, 2012 at 10:52 pm
Would this work?
DECLARE @DB VARCHAR(100) = 'MyDB'
SELECT *
FROM @DB.sys.check_constraints
If not, why would it work in dynamic SQL?
Obviously, you've found an approach that does work though.
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
November 21, 2012 at 11:14 pm
dwain.c (11/21/2012)
Would this work?
DECLARE @DB VARCHAR(100) = 'MyDB'
SELECT *
FROM @DB.sys.check_constraints
If not, why would it work in dynamic SQL?
Obviously, you've found an approach that does work though.
I haven't fired up 2k12 yet but I'd just bet that won't work. You cannot use variables for object names like that.
The @ck thing being used in the queries is a pass through variable which is a trait of using sp_Execute SQL. Notice that where it's being used is not an object but acts just like what a variable would do in a norma query.
--Jeff Moden
November 21, 2012 at 11:24 pm
Jeff Moden (11/21/2012)
dwain.c (11/21/2012)
Would this work?
DECLARE @DB VARCHAR(100) = 'MyDB'
SELECT *
FROM @DB.sys.check_constraints
If not, why would it work in dynamic SQL?
Obviously, you've found an approach that does work though.
I haven't fired up 2k12 yet but I'd just bet that won't work. You can use variables for object names like that.
The @ck thing being used in the queries is a pass through variable which is a trait of using sp_Execute SQL. Notice that where it's being used is not an object but acts just like what a variable would do in a norma query.
Did you mean "You cannot use variables for object names like that." ?
I know. But wouldn't it be cool if you could. Think about it - naming columns on the fly! God what we could do with that to confuse the masses! :w00t:
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
November 21, 2012 at 11:27 pm
D.Post (11/21/2012)
Is this correct or is there another way to do this?Something to do with SQL Injection? (No fear of)
No. No way to stipulate the database name in a variable without using dynamic SQL of some sort.
So far as SQL injection goes, your code is wide open for it the way @DBName is currently used. The best way around it is to check that the content of @DBName actually exists in sys.databases or throw a fatal error.
Items 2 and 4 may run but they don't actually work the way you would expect. Since you double single-quoted the @ck variable names, the variable names become quoted literals rather than variables.
--Jeff Moden
November 21, 2012 at 11:31 pm
dwain.c (11/21/2012)
Jeff Moden (11/21/2012)
dwain.c (11/21/2012)
Would this work?
DECLARE @DB VARCHAR(100) = 'MyDB'
SELECT *
FROM @DB.sys.check_constraints
If not, why would it work in dynamic SQL?
Obviously, you've found an approach that does work though.
I haven't fired up 2k12 yet but I'd just bet that won't work. You can use variables for object names like that.
The @ck thing being used in the queries is a pass through variable which is a trait of using sp_Execute SQL. Notice that where it's being used is not an object but acts just like what a variable would do in a norma query.
Did you mean "You cannot use variables for object names like that." ?
I know. But wouldn't it be cool if you could. Think about it - naming columns on the fly! God what we could do with that to confuse the masses! :w00t:
Yes... that's what I meant. I went back and corrected the original post. Thanks for the catch on my phat phingering.
Not only would it be cool to be able to name object names with a variable but it would also be cool if we could use variables and column names in the same SELECT like we can with UPDATE. Instead of "quirky updates", we could use "not so quirky SELECTs" were we can use an ORDER BY and the whole shebang!
--Jeff Moden
November 21, 2012 at 11:36 pm
Jeff Moden (11/21/2012)
Not only would it be cool to be able to name object names with a variable but it would also be cool if we could use variables and column names in the same SELECT like we can with UPDATE. Instead of "quirky updates", we could use "not so quirky SELECTs" were we can use an ORDER BY and the whole shebang!
Somewhere, somewhen I saw an article where someone had interviewed you and asked what you thought should be included in the next version of SQL or what your biggest gripes were. Add that one to the list.
For the record, yeah that would also be way cool!
The only question would be, if CELKO sits on the ISO standards committee would he approve of it? He might consider it a "hillbilly dialect." :hehe:
My thought question: Have you ever been told that your query runs too fast?
My advice:
INDEXing a poor-performing query is like putting sugar on cat food. Yeah, it probably tastes better but are you sure you want to eat it?
The path of least resistance can be a slippery slope. Take care that fixing your fixes of fixes doesn't snowball and end up costing you more than fixing the root cause would have in the first place.
Need to UNPIVOT? Why not CROSS APPLY VALUES instead?[/url]
Since random numbers are too important to be left to chance, let's generate some![/url]
Learn to understand recursive CTEs by example.[/url]
[url url=http://www.sqlservercentral.com/articles/St
November 22, 2012 at 1:50 am
Ok, so we have to use dynamic queries for object names.
Make sure to check the object against the sys views.
DECLARE
@DBName NVarchar(50)
SET @DBName = 'Master1'
IF NOT EXISTS (SELECT * FROM sys.Databases WHERE Name = @DBName)
BEGIN
PRINT 'Database : ' + @DBName + ' does not exist'
RETURN
END
I'm assuming here that no injection is possible using PRINT.
People could inject another valid object name though.
Could cause a bit of a hassle when using DELETE or TRUNCATE.
November 22, 2012 at 5:21 am
D.Post (11/22/2012)
Ok, so we have to use dynamic queries for object names.Make sure to check the object against the sys views.
DECLARE
@DBName NVarchar(50)
SET @DBName = 'Master1'
IF NOT EXISTS (SELECT * FROM sys.Databases WHERE Name = @DBName)
BEGIN
PRINT 'Database : ' + @DBName + ' does not exist'
RETURN
END
I'm assuming here that no injection is possible using PRINT.
People could inject another valid object name though.
Could cause a bit of a hassle when using DELETE or TRUNCATE.
That is not dynamic SQL...
But if you build an SQL string like that and execute it using sp_executesql or EXEC() command, you can inject terrible code into it. Here is your code implemented as Dynamic SQL:
DECLARE
@DBName NVarchar(50)
SET @DBName = 'Master1'
IF NOT EXISTS (SELECT * FROM sys.Databases WHERE Name = @DBName)
BEGIN
-- example of dynamic sql
DECLARE @sql NVARCHAR(1000)
SET @sql = 'PRINT ''Database : ' + @DBName + ' does not exist'''
EXEC (@sql)
END
Now let's try to inject something to it (taking @DBName is input parameter):
CREATE TABLE check_injection (i int)
GO
-- Check for sql injection
select * from check_injection
go
DECLARE
@DBName NVarchar(50)
-- SET @DBName = 'Master1'
-- Someone injected this bit:
SET @DBName = ''';DROP TABLE check_injection; PRINT ''bb:-)'';--'
IF NOT EXISTS (SELECT * FROM sys.Databases WHERE Name = @DBName)
BEGIN
-- example of dynamic sql
select QUOTENAME(@DBName)
DECLARE @sql NVARCHAR(1000)
SET @sql = 'PRINT ''Database : ' + @DBName + ' does not exist'''
EXEC (@sql)
END
select * from check_injection
With enough rights, you may drop the whole database 🙂
November 22, 2012 at 7:35 am
Thanks for the input guys! 😀
@Eugene
That is not dynamic SQL...
I know. I was just demonstrating Jeffs suggestion of checking for a valid object and stopping if it isn't valid.
So far as SQL injection goes, your code is wide open for it the way @DBName is currently used. The best way around it is to check that the content of @DBName actually exists in sys.databases or throw a fatal error.
Thanks for the injection example!!
Time to test some of my apps and SPs! 😛
Viewing 10 posts - 1 through 9 (of 9 total)
You must be logged in to reply to this topic. Login to reply