Monday, March 06, 2006

I'm writing this just before the start of the Dutch Devdays conference in Amsterdam. The conference promises to a good one, with local speakers as well as guest speakers. I'm going to be presenting four  different in-depth topics, all related to database client applications and/or SQL Server 2005 applications, and how ADO.NET 2.0 and SQL Server 2005 will affect the coding landscape. This will lead right into the talks on language intergrated query (LINQ) an up-and-coming data access technology built into the next release of the C# and VB.NET languages.

I'll try to write back on how things are going but the next two days are going to find me pretty busy. When I'm not giving presentations and available for questions at the forums, I'll be hanging out at the Class-A booth; stop by and say hi, if you're in the neighborhood. Anko Duizer and Astrid Hackenberg are going to be doing some training at Devdays most of Tuesday, as well; knowing their work the sessions will be well worth a listen.

I'll be following up the Devdays conference with two intense (and fun) days on SQLCLR and SQL Server 2005 XML storage and query at the Class-A facility in Woerden. Now that I'm over my (fairly easy, this time) jetlag, I'm looking forward to some late-night discussions and coding in this one. If you like getting your feet wet with SQL Server 2005 by "drinking from a firehose", stop by the booth, there may be a few spots left.

Monday, March 06, 2006 11:25:30 PM (Pacific Standard Time, UTC-08:00)  #    Comments [6]  | 
Friday, March 03, 2006

While teaching SQL Server 2005 to developers, I'd always point out the irony in the fact that the new EVENTDATA() function, used to return information in a DDL trigger or EVENT NOTIFICATION, returns XML and would be used almost exclusively by DBAs. This seems almost like a nefarious plot to force DBAs, who would be the most XML-phobic, to learn XML and XQuery/XPath in order to deal with these in their daily jobs. In fact, I once wrote a SQL statement using XQuery to coerce a common variant of EVENTDATA() output into tabular format.

After spending the last few months wallowing in query plans, deadlock graphs, and the like, I've actually become convinced that XML and XQuery in SQL Server is *primarily a DBA tool*. I knew that would catch your attention. Besides event and query notifications, blocked process events, query plans, deadlock graphs, and EVENTDATA(), Database Tuning Advisor and new bulkload format files also use XML format. XML query plans can be studied by using XQuery/XPath and can then be modified (slightly) for use in "plan forcing" where the XML plan is used as a "query hint", USE PLAN. And there's probably some uses that I missed. SSIS files and Reporting Services RDLs are XML format. I'm becoming convinced that T-SQL error messages should be in XML format too.

So DBAs: if you haven't yet learned XQuery/XPath and the SQL Server XML methods, its not too late. It's there just to make you more productive (well, maybe "just" is an overstatement, but you get the point).

Just to whet your appitite, here's a little stored procedure that uses dynamic management views, the new CROSS APPLY operator and XQuery to look for physical operations in query plans and correlate it with the SQL query. Could be useful, perhaps sorted by execution count. Cheers.

CREATE PROCEDURE LookForPhysicalOps (@op VARCHAR(30))
AS
SELECT sql.text, qs.EXECUTION_COUNT, qs.*, p.*
FROM sys.dm_exec_query_stats AS qs
CROSS APPLY sys.dm_exec_sql_text(sql_handle) sql
CROSS APPLY sys.dm_exec_query_plan(plan_handle) p
WHERE query_plan.exist('
declare default element namespace "http://schemas.microsoft.com/sqlserver/2004/07/showplan";
/ShowPlanXML/BatchSequence/Batch/Statements//RelOp/@PhysicalOp[. = sql:variable("@op")]
') = 1
GO

EXECUTE LookForPhysicalOps 'Clustered Index Scan'
EXECUTE LookForPhysicalOps 'Hash Match'
EXECUTE LookForPhysicalOps 'Table Scan'

Friday, March 03, 2006 12:38:32 AM (Pacific Standard Time, UTC-08:00)  #    Comments [2]  | 

If I store XML in an XML data type column its sometimes useful for performance to be able to hoist the value of a particular item to its own persisted computed column. The column can then be used in SQL queries without having to recalculate the XQuery each time its accessed. For example, if I want to use an attribute at the root named orderid:

CREATE TABLE dbo.xml_order (
  id INT PRIMARY KEY IDENTITY, -- to enable XML Index creation
  order_doc XML,
  orderid -- this should be obtained from XML document
)

I must first define a SQL Server UDF to calculate the value.

CREATE FUNCTION dbo.getorderid (@data XML)
RETURNS INT
WITH SCHEMABINDING
AS
BEGIN
  RETURN @data.value('/*[1]/@orderid', 'INT')
END

and then use it:

CREATE TABLE xml_order (
  id INT PRIMARY KEY IDENTITY, -- to enable XML Index creation
  order_doc XML,
  orderid AS dbo.getorderid(order_doc) PERSISTED
)

The "WITH SCHEMABINDING" is needed if I want to the column a persisted computed column. The persisted computed column requires the function to be deterministic (returns same output give same input).

This got me thinking...which types of XQuery statements are deterministic and what determines determinism in an XQuery statement? Turns out that ALL XQuery statements are deterministic, because the current SQL Server XQuery dialect doesn't contain non-deterministic XQuery functions like current-dateTime() and friends. Note that this could change as SQL Server XQuery adds (I hope) more of the standard XQuery functions and operators in future. But for now, all is safe and determnistic.

Friday, March 03, 2006 12:03:01 AM (Pacific Standard Time, UTC-08:00)  #    Comments [1]  | 
Friday, February 10, 2006

I think I got my December update too early. There's an update of the SQL Server 2005 samples on the downloads website. I have (thought I had) the December update, this one actually says "Date published 1/4/2006" and its 20mb instead of the old once (just under 16mb).

The site says: Since its original release, new samples have been added for the following technologies: CLR, SMO, Integration Services, Replication, and Reporting Services. See the SQLServerDatabasesAndSamplesOverview.htm file for descriptions of the new and original samples.

Well, the samples folks (thanks Bonnie and everyone) have really outdone themselves this time. Thanks!

One of the samples that particularly intruiged me was a TVF that returned a resultset from Oracle using System.Data.OracleClient. I was surprised because, although System.Data.OracleClient is on the "approved assemblies" list, the DDL cataloged the assembly as UNSAFE. Hmmm...thought I'd only need EXTERNAL_ACCESS.

So I fired up my combined VPC of SQL Server 2005/Oracle 10g and decided to see for myself. When cataloged as EXTERNAL_ACCESS I got:

Msg 10314, Level 16, State 11, Line 1
An error occurred in the Microsoft .NET Framework while trying to load assembly id 65541. The server may be running out of resources, or the assembly may not be trusted with PERMISSION_SET = EXTERNAL_ACCESS or UNSAFE. Run the query again, or check documentation to see how to solve the assembly trust issues. For more information about this error:
System.IO.FileLoadException: Could not load file or assembly 'OracleTVF, Version=1.0.0.0, Culture=neutral, PublicKeyToken=65071e111a9fd000' or one of its dependencies. Failed to grant minimum permission requests. (Exception from HRESULT: 0x80131417) ---> System.Security.Policy.PolicyException: Required permissions cannot be acquired.

When cataloged as UNSAFE, it worked fine. Well, after I changed it to access the SCOTT.DEPT table. I don't have the "titles" table the sample referred to.

The reason for this (UNSAFE) is most likely that System.Data.OracleClient (which is approved) needs to load Oracle's client libraries. These are written in unmanged code, which makes them unsafe to load, even if System.Data.OracleClient isn't unsafe. BTW, I didn't try ODP.NET. This would have required cataloging my DLL as UNSAFE because Oracle.OracleClient.dll provider isn't on the approved list. But I'm running UNSAFE already. Oh.

Friday, February 10, 2006 3:04:32 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]  | 

I've always been slightly puzzled by the permission "EXECUTE" on an XML SCHEMA COLLECTION. Say I have an XML SCHEMA COLLECTION named MySchemas and a table that uses it:

CREATE TABLE MyDocuments (
  id INT PRIMARY KEY IDENTITY,
  thexml XML (MySchemas)
)

And suppose I have a user named FRED that I grant access to the TABLE:

GRANT SELECT, INSERT, UPDATE, DELETE on MyDocuments to FRED

Now FRED can DELETE and SELECT from the table, but because he does not have EXECUTE permission on the XML SCHEMA COLLECTION, he can't INSERT or UPDATE the column that uses it with a schema-valid document. He also can't use typed parameters or variables. UNLESS the value of the XML column, variable, or parameter is NULL. So this works for FRED...

INSERT MyDocuments VALUES(NULL) -- INSERTing a non-NULL would fail.

So does this:

DECLARE @x XML (MySchemas)

But assignment of a document that corresponds to the XML SCHEMA COLLECTION to the variable @x fails unless FRED has EXECUTE on the XML SCHEMA COLLECTION. You grant the permission like this:

GRANT EXECUTE ON XML SCHEMA COLLECTION::MySchemas TO FRED

I can only guess that the reason for this privilege is to keep folks from "probing" the XML SCHEMA COLLECTION (perhaps there is sensitive information in the restrictions) by seeing what works on a column insert or variable assignment and what doesn't. And following the validation error messages. Perhaps.

BTW, the Books Online (I have the December update) gets it right except for SELECT. It says:

Denying the EXECUTE permission denies the principal the ability to insert or update the values in columns, variables, and parameters that are typed or constrained by the XML schema collection. It also denies the principal the ability to query the values in those same xml type columns and variables.

Friday, February 10, 2006 12:28:04 AM (Pacific Standard Time, UTC-08:00)  #    Comments [5]  | 
Thursday, February 09, 2006

System.Configuration.dll was the last assembly added to the "SQL Server 2005 approved assembly" list, that is, the list of BCL assemblies approved for SQL Server consumption. These are loaded from the GAC, rather than having to be explicitly added to the database by the user. System.Configuration was added SO late that it doesn't show up in a Visual Studio Database assembly project in the "Add References" dialog with all of its collegues. You have to use a normal Visual Studio Class Library project (or other means) to reference it.

When students in my beta classes would try and fiddle with the config file information used to determine which version of an assembly should be loaded by putting these settings in a file aptly named sqlservr.exe.config, these would be ignored. I'd thought that the entire config file was discarded, and rebuilt so that SQL Server would have its own version configuration information. Just before SQL Server 2005 shipped, the ability to run CREATE ASSEMBLY on multiple versions of the same user assembly was dropped (you can still have multiple language-specific resource sattelite assemblies cataloged).

So what do these two things have to do with one another?

Someone asked me recently if you could access configuration strings by making a sqlservr.exe.config unrelated to assembly loading I didn't think so, but if not, what is System.Configuration doing on the approved list? Let's try it in a .NET user-defined function...

public static string GetConfigString()
{
  // This statement requires referencing System.Configuration.dll
  ConnectionStringSettings s = ConfigurationManager.ConnectionStrings["pubs"];
  if (s != null)
    return s;
  else
    return "no config";
}

This works fine. The .NET UDF can even be cataloged and run as SAFE. So now that we've gone this far, a better question might be "why do you want to put configuration strings in files"? You're running IN A DATABASE after all, how 'bout storing them in a TABLE? Perhaps so that the same code would work inside SQL Server or in middle tier server? OK, I'll buy that.

Thursday, February 09, 2006 12:03:53 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]  | 
Wednesday, February 08, 2006

Dynamic SQL executed in a stored procedure executes by default using the security context of the CALLER of the procedure rather than the OWNER. That's the way SQL Server has always worked, and although SQL Server 2005 lets you EXECUTE AS OWNER (among other choices), EXECUTE AS CALLER is still the default.

So how does this relate to SQL statements execute in a .NET stored procedure, function, or trigger? Do these execute as caller or owner? Turns out it depends on what statement you are executing. Executing an "ordinary" SQL statement like this:

public static void GetAuthorsNET {
using (SqlConnection conn = new SqlConnection("context connection=true"))
using (SqlCommand cmd = new SqlCommand("select * from dbo.authors", conn)
{
  conn.Open();
  SqlContext.Pipe.ExecuteAndSend(cmd);
}
}

GRANT someuser EXECUTE on dbo.GetAuthorsNET

EXECUTE AS USER='someuser'
EXEC dbo.GetAuthorsNET
GO
REVERT

executes the SELECT statement in the .NET code as CALLER and throws a permission denied error if the caller doesn't have direct SELECT access to the authors table. The same contruct in a T-SQL procedure:

CREATE PROCEDURE dbo.GetAuthorsSQL
AS
SELECT * FROM dbo.authors

GRANT someuser EXECUTE on dbo.GetAuthorsSQL

would execute the SELECT as the OWNER of the stored procedure, not the caller and the SELECT succeeds.

OK. How about the following .NET code? Does it execute dbo.byroyalty as the OWNER of the stored procedure?

public static void ExecByRoyalty {
using (SqlConnection conn = new SqlConnection("context connection=true"))
using (SqlCommand cmd = new SqlCommand("dbo.byroyalty", conn)
{
  cmd.CommandType = CommandType.StoredProcedure;
  cmd.Parameters.AddWithValue("@percentage", 50);
  conn.Open();
  SqlContext.Pipe.ExecuteAndSend(cmd);
}
}

GRANT someuser EXECUTE on dbo.ExecByRoyalty -- grant on calling proc (owner by dbo)
DENY someuser EXECUTE on dbo.ByRoyalty -- deny on called proc

This executes the ByRoyalty proc AS the OWNER of the ExecByRoyalty proc, ownership chain intact. Even if someuser executes ExecByRoyalty. Oh.

Time for a tiebreaker. How about this one?

public static void ExecByRoyaltyAsString {
using (SqlConnection conn = new SqlConnection("context connection=true"))
using (SqlCommand cmd = new SqlCommand("exec dbo.byroyalty @perc", conn)
{
  cmd.CommandType = CommandType.Text; // not a sproc, a textual execute statement, does it matter?
  cmd.Parameters.AddWithValue("@perc", 50);
  conn.Open();
  SqlContext.Pipe.ExecuteAndSend(cmd);
}
}

This executes the ByRoyalty proc AS the OWNER of the ExecByRoyaltyAsString proc, ownership chain intact. The sproc works even when 'someuser' executes it. Interesting.

Wednesday, February 08, 2006 11:26:46 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]  | 
Monday, January 30, 2006

I've answered a few questions lately on setting up SqlDependency or ASP.NET SQL Server dependency with SQL Server 2005. Folks have gone by the instructions on the DataWorks Weblog posting and still receive the error "either schema dbo does not exist or you do not have permission to access it". This is caused by the separation or users and schemas in SQL Server 2005.

The instructions don't show creating 'startUser' (the principal that creates procedures, queues, and services), so folks create it, using the new DDL, like this:

CREATE LOGIN startUser WITH PASSWORD = 'SomeStrongPW1'
CREATE USER startUser FOR LOGIN startUser

Problem is, CREATE USER doesn't assign a default database schema (its not supposed to) and when startUser attempts to create database objects, it creates them in the "default default_schema" which is dbo. The quick fix is to create a schema for (owned by) the user and make that schema its default schema.

CREATE SCHEMA startUserSchema AUTHORIZATION startUser
ALTER USER startUser WITH DEFAULT_SCHEMA = startUserSchema

A better alternative might be to create a database role for this function and create the default schema owned by the role. Then add startUser to the role. You still have to alter the user's default_schema in this case, because database roles cannot have default schemas. Roles cannot have default_schemas themselves because if one user was a member of 3 different roles and each role had a different default_schemas which one would "win"?

A less attractive (actually unattractive) alternative is to give startUser CREATE (actually ALTER) privilege on the DBO schema.

GRANT ALTER ON SCHEMA::dbo to startUser

DON'T do this, you've just given startUser much more privilege than it really needs.

Three more comments:
1. If you used sp_adduser instead of CREATE USER, you "got lucky". For backward compatibility sp_adduser actually does:

CREATE USER startUser WITH DEFAULT_SCHEMA = startUser
GO
-- create schema must be first statement in the batch
CREATE SCHEMA startUser AUTHORIZATION startUser

When/if that backward compatibility mode is removed, your luck runs out.

2. With the new separation of users and schemas granting CREATE TABLE permission doesn't give the user enough to create a TABLE, nowadays. The user also needs a *container* to create tables (or other database objects) in. The user needs a database schema. Resist the temptation to make a schema for the user; rather make a schema for a role the user is a member of. The fact that schemas can be owned by a role is one of their best features.

3. Technically, Service Broker SERVICEs (as well as MESSAGE_TYPEs and CONTACTs) don't live at schema scope. They live at database scope, so you don't need a schema for them. CREATE privilege is enough. But QUEUEs (and most database objects) do live at schema scope. QUEUEs are just tables with special semantics, after all.

Monday, January 30, 2006 10:35:25 AM (Pacific Standard Time, UTC-08:00)  #    Comments [4]  | 
Saturday, January 21, 2006

I've been confirmed to present some talks at DevDays Netherlands on March 7-8. I'll be talking about my favorite subjects, SQL Server 2005 and ADO.NET 2.0. It will be good to catch up with the folks from Class-A. Anko, Astrid, and Alex will also be presenting. I'm trying to line up some advance copies of A Developer's Guide to SQL Server 2005 , but that may be pushing the scheduled publication date a bit.

After DevDays I'll be giving an Immersion Event in the area covering SQL Server 2005 in depth, from a development perspective. I'll even be talking about best practices now that folks, especially the early adopters who developed products to be released along with the SQL Server release itself, have had a chance to practice.  If you've not had a chance to explore SQL Server 2005, now's your chance. See you there.

Saturday, January 21, 2006 10:50:19 PM (Pacific Standard Time, UTC-08:00)  #    Comments [6]  | 
Monday, January 16, 2006

I've been getting some mail messages that the sample chapter of our latest book that we uploaded on the SQLskills website is not readable. Or in some cases, not downloadable. The error messages indicate that you need the latest version of Acrobat Reader (downloadable from Adobe) to read the chapter. The “not downloadable” message may be an indication of not having the latest version of the plugin. If you still have problems after getting the latest version, please let me know.

Monday, January 16, 2006 8:37:33 AM (Pacific Standard Time, UTC-08:00)  #    Comments [3]  | 
Friday, January 13, 2006

I've been intruiged for a while with the idea of using SQL Server Express edition as a gateway from HTTP messaging to Service Broker messaging. That is, receiving web service messages through HTTP endpoints and turning them into Service Broker messages to take advantage of the robustness of the Service Broker protocol. Went to set one of these up today...but...HTTP endpoints are not supported on Express edition. Or on Workgroup edition for that matter, you must have Standard edition to define and use them. So you must have at least Standard edition to setup such a gateway.

Friday, January 13, 2006 2:16:52 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]  | 
Thursday, January 12, 2006

I don't know anyone that likes to wait for an application to respond. This is especially a concern with web applications; you start to wonder if the web infrastructure has a problem. Should you hit by "Order" button again?

Because waiting is subjective it's nice to be able to know, when a user calls, how long they have actually been waiting. Or at least how long the database has been waiting. SQL Server 2005 will tell you, at least when locking is involved.

There is a configuration parameter "blocked process threshold" that controls if and when to send notifications whenever a process is blocked for N seconds. You set this through sp_configure; its an advanced option so show advanced options must be on too. It's set to 0 (never notify) by default. You can catch these notifications through WMI/SQLAgent alerts or the new event notifications. Very cool.

So now when a user reports "I've been waiting for this database query for 10 minutes" but the query response is immediate when you check it (the "works for me" answer that users hate), you can see (after the fact) if its lock contention that caused the waiting. “Well, you weren't waiting for locks” might be a better answer. Maybe. 

Thursday, January 12, 2006 2:53:15 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]  | 
Monday, January 09, 2006

Dan and I have been permitted to post a sample draft-quality chapter and the table of contents our upcoming book, "SQL Server 2005 Developer's Guide". They're available on the SQLskills website as links from the Resources/Books menu entry on the homepage. The sample chapter discusses using the SqlClient data provider in SQL Server procedural code. Feedback appreciated. Book becoming available on shelves (relatively) soon. Enjoy.

Special thanks to our astute technical reviewers.

Now, back to work for me...

Monday, January 09, 2006 2:52:10 PM (Pacific Standard Time, UTC-08:00)  #    Comments [9]  | 
Tuesday, January 03, 2006

With apologies to Johnny Winter. Long time, no postings. You might have guessed why I disappeared, but Dan and I just finished and handed in the sequel (pun intended) to the "First Look" book, entitled "A Developer's Guide to SQL Server 2005". How I spent my winter "vacation"... Whew.

We've got everything updated to RTM, LOTS of new/updated material on every topic (especially on security) and a new chapter on SMO. Those SQL Server 2005 folks were busy since beta2. Now we'll see how long copyedits, production, etc, takes. Should be on shelves by late Q1-early Q2. We'll be posting a sample chapter shortly.

Now to figure out what to do with the rest of this year. Started to look at some different ways to "stretch out". Took a quick glance at the new JDBC driver last week. More content coming soon...feel free to send suggestions.

Tuesday, January 03, 2006 3:57:45 PM (Pacific Standard Time, UTC-08:00)  #    Comments [5]  | 
Monday, December 05, 2005

Got the word today. Officially supported. Error in readme file. Reference this blog entry.  Good to hear this.

Monday, December 05, 2005 4:06:04 PM (Pacific Standard Time, UTC-08:00)  #    Comments [2]  | 
Thursday, December 01, 2005

I'm sure there's something about this in BOL somewhere, but this cost me a few more than a few ticks yesterday. Hoping to save you a few ticks. This one deals with semantic models used by Report Builder (part of SSRS 2005).

Suppose you have a semantic model deployed on server A that you want to move to server B. You don't have the source code. Perhaps it "arrived" pre-deployed on a VPC, as an example. You need the .smdl file. But it doesn't exist standalone, its been deployed to the Report Server. Or at least I didn't find it. I could probably write a program to extract it using the admin web service interface. But I'm too lazy.

So, eventually, I brought up the web interface, selected the model, then, under "Model Definition" chose "Edit". A nice dialog box asked me where I wanted to put the .smdl file. Great, just what I wanted.

BTW, bringing up SSMS, and browsing to the model in Object Browser, the model had a nice dropdown menu item, "Script As...". Problem was, it didn't seem to script anything. I tried all three script options, nothing happened.

Thursday, December 01, 2005 12:55:17 PM (Pacific Standard Time, UTC-08:00)  #    Comments [1]  | 
Monday, November 21, 2005

Service Broker security is the subject of confusion even among people who think they know how it works. Some of the confusion occurs because security was tightened up in the last few CTPs.

I've read in two different places that Service Broker conversations always need to have a master key in the database(s) where the services run. Not so. You don't need a database master key (and this is in RTM) if:

1. Both services (initiator and target) live in the same database
2. You begin the conversation using ENCRYPTED = OFF in the BEGIN DIALOG statement

ENCRYPTED = ON is the default, and you do need a database master key in this case, hence the confusion.

Monday, November 21, 2005 7:58:29 AM (Pacific Standard Time, UTC-08:00)  #    Comments [18]  | 

Theme design by Jelle Druyts

Pick a theme: