Please start any new threads on our new site at https://forums.sqlteam.com. We've got lots of great SQL Server experts to answer whatever question you can come up with.

 All Forums
 SQL Server 2008 Forums
 SQL Server Administration (2008)
 Detecting that QUOTED_IDENTIFIER is OFF

Author  Topic 

Kristen
Test

22859 Posts

Posted - 2011-10-28 : 11:55:08
I'm fed up with QUOTED_IDENTIFIER accidentally getting set to OFF.

We don't have a SET QUOTED_IDENTIFIER ON in every single Sproc create script that we have, and I don't want to clutter them up by putting it there.

Is there a way that I can detecting if QUOTED_IDENTIFIER is OFF? All our scripts run an Sproc that logs the version of the script being run, and I could put the test into that so I at least get a warning when this happens.

I've looked in BoL, but obviously not in the right place

Thanks.

robvolk
Most Valuable Yak

15732 Posts

Posted - 2011-10-28 : 11:59:05
Look at the SESSIONPROPERTY() function. I wrote about another method here:

http://weblogs.sqlteam.com/robv/archive/2010/09/22/handy-sql-server-function-you-may-not-have-known-about.aspx
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2011-10-28 : 12:09:51
Perfect! Many thanks Rob. Here's what I have so far:

SELECT *
FROM
(
SELECT name,
[Status] = CASE WHEN (@@OPTIONS & number) = 0 THEN 'OFF' ELSE 'ON' END
FROM master.dbo.spt_values
WHERE type='SOP'
AND number > 0
) AS X
WHERE
(
([name]='ansi_null_dflt_off' AND [Status] <> 'OFF')
OR ([name]='ansi_null_dflt_on' AND [Status] <> 'ON')
OR ([name]='ansi_nulls' AND [Status] <> 'ON')
OR ([name]='ansi_padding' AND [Status] <> 'ON')
OR ([name]='ansi_warnings' AND [Status] <> 'ON')
OR ([name]='arithabort' AND [Status] <> 'ON')
OR ([name]='arithignore' AND [Status] <> 'OFF')
OR ([name]='concat_null_yields_null' AND [Status] <> 'ON')
OR ([name]='cursor_close_on_commit' AND [Status] <> 'OFF')
OR ([name]='disable_def_cnst_check' AND [Status] <> 'OFF')
OR ([name]='implicit_transactions' AND [Status] <> 'OFF')
OR ([name]='nocount' AND [Status] <> 'OFF')
OR ([name]='numeric_roundabort' AND [Status] <> 'OFF')
OR ([name]='quoted_identifier' AND [Status] <> 'ON')
OR ([name]='xact_abort' AND [Status] <> 'OFF')
)
--
ORDER BY [name]
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2011-10-28 : 12:52:12
Keep in mind that QUOTED_IDENTIFIER is a setting on the procedure declaration, not just a statement within its body. (In fact SET QUOTED_IDENTIFIER should not appear in a procedure body, as its effects can be detrimental)

You can determine which procedures do not have that setting with the following:

select OBJECT_NAME(object_id), * from sys.sql_modules where uses_quoted_identifier=0

Once you find them, you can reset QUOTED_IDENTIFIER and use ALTER PROCEDURE to recreate them with the correct settings.

Another best practice is to remove all double quotes from your code, ensure strings are delimited only with single quotes, and (optionally) delimit all object identifiers with square brackets. Yeah it's a lot of work, but doing so renders the QUOTED_IDENTIFIER setting moot.
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2011-10-28 : 13:42:09
Following a standard that I didn't know 8-)

Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx


Want to help yourself?

http://msdn.microsoft.com/en-us/library/ms130214.aspx

http://weblogs.sqlteam.com/brettk/

http://brettkaiser.blogspot.com/


Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2011-10-28 : 14:25:50
quote:
Originally posted by robvolk

Keep in mind that QUOTED_IDENTIFIER is a setting on the procedure declaration, not just a statement within its body. (In fact SET QUOTED_IDENTIFIER should not appear in a procedure body, as its effects can be detrimental)


Yeah, been-there and done-that. And I now find that my euphoria is slightly sort-lived. I'll knock up an example shortly.
quote:

You can determine which procedures do not have that setting with the following:



Yup, done that too ... it was my first action when I discovered that we had a problem. About 50% of the Sprocs are wrong-QUOTED_IDENTIFIER, but it varies from DB to DB (probably according to what something else set at the time that the rollout scripts were run
quote:

Another best practice is to remove all double quotes from your code, ensure strings are delimited only with single quotes, and (optionally) delimit all object identifiers with square brackets. Yeah it's a lot of work, but doing so renders the QUOTED_IDENTIFIER setting moot.


and that's my final annoyance. We did this years ago, so we have (as far as I know) none of these issues in our code, in practice. However, we have recently introduced some indexed views, to improve performance in some areas, and now Sprocs that were created with QUOTED_IDENTIFER OFF give error when run.

We can fix that at the next rollout by re-creating EVERY Sproc (which is a PITA as that will take a long time to run the script, and 99% of them won't actually have changed materially. Or we could custom-build rollout scripts to only have specific SProcs in them, but I can't even be sure that TEST and PRODUCTION DBs are the same in this regard, and I don't really want to have custom rollout scripts for each Client/Database as that is a "hybrid" method of working compared to our carefully crafted, tested and rehearsed "only this has changed since last time" rollout process, so it runs the risk that we trip over some other never-before-seen issue compared to doing it "how we always do".

As a knee-jerk reaction our rollout scripts now have a SET-the-whole-world at the top that guarantees there are no mavericks - but, even then, we might have a script in the middle that was generated with SSMS that has prefixed the script with a helpful SET QUOTED_IDENTIFIER ON but then cavalierly added a SET QUOTED_IDENTIFIER OFF to the end of the script, creating a train-wreck for the rest of the concatenated rollout script.

So ... because each of our scripts, that we concatenate to make the master-rollout-script, has a "Log this NAME and VERSION" Sproc call I thought adding a check for all the correct SET values (to the "log this" Sproc) would mean that at least we would get an alert when the wrong SETting was in place.
Go to Top of Page

Kristen
Test

22859 Posts

Posted - 2011-10-28 : 14:56:32
I don't seem to be able to detect some values, e.g. QUOTED_IDENTIFIER, within an Sproc:


--
IF EXISTS (SELECT * FROM INFORMATION_SCHEMA.ROUTINES WHERE ROUTINE_NAME = 'Test_SET_Values')
DROP PROCEDURE dbo.Test_SET_Values
GO

CREATE PROCEDURE dbo.Test_SET_Values
AS
/*
* Test_SET_Values Test SET values are set to Default Values
*
*/
DECLARE @intOPTIONS int

SELECT @intOPTIONS = @@OPTIONS -- Store current value

SET NOCOUNT ON
SET XACT_ABORT ON
SET ARITHABORT ON

DECLARE @intRetVal int -- Return value

SELECT @intRetVal = 0 -- Assume no error

-- ... all sorts of code removed ...

SELECT *
INTO #Test_SET_Values_01
FROM
(
SELECT name,
[Status] = CASE WHEN (@intOPTIONS & number) = 0 THEN 'OFF' ELSE 'ON' END
FROM master.dbo.spt_values
WHERE type='SOP'
AND number > 0
) AS X
WHERE
(
([name]='ansi_null_dflt_off' AND [Status] <> 'OFF')
OR ([name]='ansi_null_dflt_on' AND [Status] <> 'ON')
OR ([name]='ansi_nulls' AND [Status] <> 'ON')
OR ([name]='ansi_padding' AND [Status] <> 'ON')
OR ([name]='ansi_warnings' AND [Status] <> 'ON')
OR ([name]='arithabort' AND [Status] <> 'ON')
OR ([name]='arithignore' AND [Status] <> 'OFF')
OR ([name]='concat_null_yields_null' AND [Status] <> 'ON')
OR ([name]='cursor_close_on_commit' AND [Status] <> 'OFF')
OR ([name]='disable_def_cnst_check' AND [Status] <> 'OFF')
OR ([name]='implicit_transactions' AND [Status] <> 'OFF')
OR ([name]='nocount' AND [Status] <> 'OFF')
OR ([name]='numeric_roundabort' AND [Status] <> 'OFF')
OR ([name]='quoted_identifier' AND [Status] <> 'ON')
OR ([name]='xact_abort' AND [Status] <> 'OFF')
)
--
ORDER BY [name]

IF @@ROWCOUNT <> 0
BEGIN
SELECT [Error] = '****** WARNING: Unexpected SET values ******'

SELECT [name], [Status]
FROM #Test_SET_Values_01
ORDER BY [name]
END

DROP TABLE #Test_SET_Values_01

-- ... more code removed ...

SET NOCOUNT OFF

RETURN @intRetVal
GO


-- TEST RIG

-- Set all properties to inappropriate values
SET ansi_null_dflt_off ON
SET ansi_null_dflt_on OFF
SET ansi_nulls OFF
SET ansi_padding OFF
SET ansi_warnings OFF
SET arithabort OFF
SET arithignore ON
SET concat_null_yields_null OFF
SET cursor_close_on_commit ON
-- SET disable_def_cnst_check ON
SET implicit_transactions ON
SET nocount ON
SET numeric_roundabort ON
SET quoted_identifier OFF
SET xact_abort ON
GO

EXEC dbo.Test_SET_Values
GO

-- Reinstate appropriate values
SET ansi_null_dflt_off OFF
SET ansi_null_dflt_on ON
SET ansi_nulls ON
SET ansi_padding ON
SET ansi_warnings ON
SET arithabort ON
SET arithignore OFF
SET concat_null_yields_null ON
SET cursor_close_on_commit OFF
-- SET disable_def_cnst_check OFF
SET implicit_transactions OFF
SET nocount OFF
SET numeric_roundabort OFF
SET quoted_identifier ON
SET xact_abort OFF
GO
Go to Top of Page

robvolk
Most Valuable Yak

15732 Posts

Posted - 2011-10-28 : 15:01:14
Ahhhh yeah, indexed views. You can mitigate some of the pain by making all the database settings consistent, and making sure all your devs have consistent settings.

Then my next suggestion is....source control. Never build or deploy ANYTHING that doesn't come out of source control, and preferably from an automated build process.

If source control's not feasible, at least use a consistent method, i.e. SSMS only, or custom deployment only. Mixing SSMS scripts with scripts from other sources is really painful because the script output is not consistent. I filed a Connect item with MS about it but they closed it:

https://connect.microsoft.com/SQLServer/feedback/details/583013/provide-consistent-database-script-output-across-all-microsoft-products#

One last thing you might want to consider is a DDL and/or Logon trigger that can detect invalid settings and roll back the event. So if someone logs on with the wrong setting they're disconnected (not sure this will work). You can also query sys.dm_exec_sessions for some of the settings on existing connections, and possibly kill them.
Go to Top of Page

X002548
Not Just a Number

15586 Posts

Posted - 2011-10-28 : 15:18:46
bhwahahahaha

trouble maker...I like it



Brett

8-)

Hint: Want your questions answered fast? Follow the direction in this link
http://weblogs.sqlteam.com/brettk/archive/2005/05/25/5276.aspx


Want to help yourself?

http://msdn.microsoft.com/en-us/library/ms130214.aspx

http://weblogs.sqlteam.com/brettk/

http://brettkaiser.blogspot.com/


Go to Top of Page
   

- Advertisement -