Welcome to MSDN Blogs Sign in | Join | Help

VSDB uses the the ($DefaultDataPath) SQLCMD variable to represent the location where you would place your data and log file of your database. The deployment engine sets the value of SQLCMD variable by querying SQL Server using the following query:

   1:  DECLARE @value nvarchar(512),
   2:          @rc    int;
   3:  EXEC    @rc = [master].[dbo].[xp_instance_regread] N'HKEY_LOCAL_MACHINE',N'Software\Microsoft\MSSQLServer\MSSQLServer',N'DefaultData', @value output-- , 'no_output'; 
   4:  SELECT  @value AS [Value]

 

The problem is that this value by default is not getting populated when you install SQL Server! You have to set it using SQL Server Management Studio, using the Server properties dialog, on the Database Settings tab,  you will find the “Database default locations”.

image

You can programmatically set it using the following query:

   1:  EXEC xp_instance_regwrite N'HKEY_LOCAL_MACHINE', N'Software\Microsoft\MSSQLServer\MSSQLServer', N'DefaultData', REG_SZ, N'd:\dbs\MSSQL10.MSSQLSERVER\MSSQL\DATA'

This brings up the next question, what does VSDB return as the value if the DefaultData location Registry entry is not set? It returns the location of the master.mdf file. If you would turn on SQL tracing you will see the following query fly by:

   1:  DECLARE @filepath nvarchar(260),
   2:          @rc int
   3:   
   4:  EXEC master.dbo.xp_instance_regread N'HKEY_LOCAL_MACHINE',N'Software\Microsoft\MSSQLServer\MSSQLServer',N'DefaultData', @filepath output, 'no_output' 
   5:   
   6:  IF ((@filepath IS NOT NULL) AND (CHARINDEX(N'\', @filepath, len(@filepath)) = 0))
   7:      SELECT     @filepath = @filepath + N'\'
   8:   
   9:  IF (@filepath IS NULL)
  10:      SELECT     @filepath = [sdf].[physical_name]
  11:      FROM       [master].[sys].[database_files] AS [sdf]
  12:      WHERE      [file_id] = 1
  13:   
  14:  SELECT @filepath AS FilePath

 

Now this still does not mean it works, because SQL Server or SQL Server Management Studio not validate if this location actually exists and is accessible from within SQL Server.

So the question becomes how can you protect yourself against this inside my deployment?

The following script can be helpful as a pre-deployment script to check if the $(DefaultDataPath) location actually exists and take action accordingly.

DataPathExistsCheck.sql

   1:  -- If we raise an error we want to stop execution of the deployment engine
   2:  :ON ERROR EXIT
   3:   
   4:  SET NOCOUNT ON
   5:  DECLARE @value nvarchar(512),
   6:          @rc    int;
   7:  EXEC    @rc = [master].[dbo].[xp_instance_regread] N'HKEY_LOCAL_MACHINE',N'Software\Microsoft\MSSQLServer\MSSQLServer',N'DefaultData', @value output-- , 'no_output'; 
   8:  -- debug: shows the output
   9:  -- SELECT  @value AS [Value], @rc as [RC];
  10:   
  11:  DECLARE @result int
  12:  DECLARE @table as table(FileExists int, DirExist int, ParentDirExists int)
  13:  -- debug: shows the output
  14:  -- EXEC [master].[dbo].[xp_fileexist] @value
  15:  INSERT  @table EXEC [master].[dbo].[xp_fileexist] @value
  16:   
  17:  IF EXISTS (SELECT * FROM @table WHERE DirExist = 1)
  18:  BEGIN
  19:      PRINT ' DIRECTORY ' + @value + ' EXISTS'
  20:  END
  21:  ELSE
  22:  BEGIN
  23:      PRINT ' DIRECTORY ' + @value + ' DOES NOT EXIST'
  24:      RAISERROR('DIRECTORY DOES NOT EXIST', 16, 1)
  25:  END
  26:   
  27:  :ON ERROR IGNORE 

 

I hope this is helpful and builds a better understanding on how VSDB works under the covers,
GertD @ www.DBProj.com

Now that SQL Server 2008 R2 November CTP is available, I found some time to install it and test the existing Visual Studio 2008 Team System Database Edition GDR R2 release with it. The only thing that is really different from a SQL Server point of view besides two changes to the SQL parser, is that the version number changed from 10.00.xxxx to 10.50.yyyy (10.00.2531 for the November CTP). As we will see enough to confuse the VSDB 2008 GDR R2 release.

First step, is to create a connection inside Solution Explorer, no problems here, I can create a connection, navigate the schema using Solution Explorer, use the table and query designer tools. Next step is to create a project. In this case I created a SQL Server 2008 Database project named sql2008r2.

Import Database Schema

The next step is to import a schema from the SQL Server 2008 R2 instance, using the Import Database Schema option, beforehand I created an instance of the good old Northwind database on the SQL Server 2008 R2 instance, named Northwind.

image

The problems start after hitting the Start option, or if you were using the new project wizard to create the project and import the schema in a single step, you would face the problem after hitting the Start button inside the wizard.

The problem manifests itself as follows:

image

The change in version number blocks the Import Database Schema code to connect to the SQL Server 2008 R2 instance, since it presents itself with a 10.50.yyyy instead of the 10.00.xxxx version number.

 

Schema Compare

Now we have an empty project, so lets attempt to use Schema Compare, and compare the SQL Server 2008 R2 database (as the source) with the project as the target.

image

This works great, not problems! You only need to make sure that you select all the object types you want to include. By default permissions and extended properties are excluded from the comparison and would therefore not get imported.

Deploy

Now we have a project, lets deploy it to a new database. In first instance this failed, because Schema Compare does not parameterize the file definitions of the database, so I had to update these, as shown below.

Updated file definitions:

   1:  ALTER DATABASE [$(DatabaseName)]
   2:      ADD FILE (NAME = [$(DatabaseName)_data], FILENAME = '$(DefaultDataPath)\$(DatabaseName).mdf', SIZE = 3328 KB, MAXSIZE = UNLIMITED, FILEGROWTH = 1024 KB) TO FILEGROUP [PRIMARY];
   3:   
   4:  ALTER DATABASE [$(DatabaseName)]
   5:      ADD LOG FILE (NAME = [$(DatabaseName)_log], FILENAME = '$(DefaultDataPath)\$(DatabaseName).ldf', SIZE = 832 KB, MAXSIZE = 2097152 MB, FILEGROWTH = 10 %);
   6:   

After this deploy and incremental deploy works as expected, without any problems. Next steps were to test Data Compare, Data Generation and Database Unit Testing, which all worked as expected as well.

So besides the glitch in Import Database Schema, SQL Server 2008 R2 and the VS 2008 Database Edition GDR R2 get along just fine, good to know.

GertD @ www.DBProj.com

Visual Studio makes it relatively easy to hook in to pre and post build events, by using the Project properties tab named Build Events. However when using Database Projects (.dbproj) you more often need to do something at deployment time. The good news is that the standard MSBuild framework, already defines these events, the bad news is that you manually have to update the project file yourself.

The steps are pretty simple:

  • Unload the project, by right clicking on the project node inside Solution Explorer and selecting the “Unload Project” option
  • This will grey-out the project node inside Solution Explorer and mark it (unavailable). Now you can right click on it again and select the “Edit <your project file name>.dbproj” option. This will load the project file inside the XML editor.
  • Next you have to add the target elements for the PreDeployEvent and PostDeployEvent, like below:
   1:  <Target Name="PreDeployEvent">
   2:      <Message Importance="high" Text="Pre deployment event"/>
   3:  </Target>
   4:   
   5:  <Target Name="PostDeployEvent" >
   6:      <Message Importance="high" Text="Post deployment event"/>
   7:  </Target>

 

  • After you made all the changes, you save and close the project file and reload the project, by right clicking on the project node again and choosing the “Reload Project” option.
    • If you forgot to close the editor, you will be asked if it can be closed and saved. Only after you confirmed this is OK, the project will be reloaded.
  • Now you can test if your pre and post-deployment events are firing by deploying your project. If everything works you should see the pre and post build event messages in the output window like on lines 9 and 14.
   1:  ------ Build started: Project: nw, Configuration: Debug Any CPU ------
   2:      Loading project references...
   3:      Loading project files...
   4:      Building the project model and resolving object interdependencies...
   5:      Validating the project model...
   6:      Writing model to nw.dbschema...
   7:    nw -> D:\demo\nw\sql\debug\nw.dbschema
   8:  ------ Deploy started: Project: nw, Configuration: Debug Any CPU ------
   9:    Pre deployment event
  10:      Deployment script generated to:
  11:  D:\demo\nw\sql\debug\nw.sql
  12:   
  13:      The deployment script was generated, but was not deployed. You can change the deploy action on the Deploy tab of the project properties.
  14:    Post deployment event
  15:  ========== Build: 1 succeeded or up-to-date, 0 failed, 0 skipped ==========
  16:  ========== Deploy: 1 succeeded, 0 failed, 0 skipped ==========

Now you should be able to hook-up your events to the pre and post deployment events. Please keep in mind that pre-deployment scripts do not change the outcome of deployments like discussed earlier in this blog post.

Success,
GertD @ DBProj.com

Pre-deployment script do not change the outcome of deployments!

The above statements is something that most users do not realize when using pre-deployment scripts. Since the pre-deployment script is included in to the deployment script, it therefore by definition runs after the comparison the the source model with the target database (model), and therefore cannot change the behavior of the deployment.

For example:

If you know you have an orphaned object that is blocking a certain upgrade scenario,  most users expect that when you would drop the offending object in a pre-deployment script, that this would take care of things. However the deployment engine has already performed the comparison between the source model and the target database (model) and generated the deployment script based on the results.

In order to gain a better understanding about what is going on, lets step through the flow of activities inside the deployment engine.

  1. The deployment engine takes as input the result of a build. It will de-serialize the source model (.dbschema) file to hydrate the source model representation in memory. It will take in to account the settings provided through the various configuration files, like Database.sqldeployment, Database.sqlsettings and Database.sqlcmdvars.
  2. The second step is to create a target model representation, by importing the target database.
    Note: when the deployment engine detects that the target database does not exists, it will create a target model based on the model database, since SQL Server inherits all settings and objects inside the model database when creating a new database.
  3. If a “Transaction.refactorlog” file is present, the refactorting operation will be applied to the models, by making changes to the target model to yield the correct outcome.
  4. Then the two models are compared, in order to determine the differences between the source and target. Internally this results in to a set of all the differences, which are then represented in a tokenized format to represent each change, after which the tokenized stream of difference operations is ordered and optimized by folding/collapsing operations together. All this results in the actual deployment part of the script.
  5. Once the previous step has been completed the single file deployment script representation is generated, which contains the following code blocks:
    image
    1. The database code block contains the statements that either creates the database or checks if the database exists, based on the determination of the deployment engine.
    2. The pre-deployment code block, contains the consolidated code, by flattening all the include statements (:r filename) inside the pre-deployment master script file.
    3. The deployment code block is the code generated based on the model diff
    4. The post-deployment code block, contains the consolidated code, by flattening all the include statements (:r filename) inside the post-deployment master script file.
    5. The refactoring code block is maintaining the __RefactorLog table to indicate that a certain refactoring operation has been deployed to this instance.

Now that we better understand the order in which operations take place, we can conclude that “pre-deployment scripts can never change the outcome of a deployment”, and that we really need a pre-pre-deployment script that runs before the model comparison is taking place in order to influence the outcome of the comparison and therefore the outcome of the deployment engine.

GertD @ www.DBProj.com (aetk39ypwb)

Last week, September 10, I was invited by the New England SQL Server User Group to present about my favorite topic “Declarative Database Development”.

I posted the slides of the presentation at DBProj.com.

GertD @ www.DBProj.com

image

The DevConnections conference organization (Tech Conferences Inc.), just released the latest issue of the magazine accompanying the conferences, named: MyDevConnections. In this edition (volume 2, issue 1) you will find an article that I wrote about “Declarative Database Development – Define What You Want, Not How You Get There!” (see page 68-71). If you did not receive the printed edition of the magazine, don’t worry since you can download the PDF version.

During the Spring 2009 SQL Connections show in Orlando, I was invited by Richard Campbell of .NET Rocks, to talk about DataDude (aka. Visual Studio Team System 2008 Database Edition GDR), who it’s for, why Microsoft created it, and other things. Check it out!

Watch this interview in its entirety at
Part 1: www.devconnections.com/mydevconnections/Drapers1_Orlando09
Part 2: www.devconnections.com/mydevconnections/Drapers2_Orlando09

Enjoy,
GertD @ www.DBProj.com

This post announces the availability of a small helper utility that will allow you to maintain your database.sqlcmdvars files from a command line tool.

Description:

What is the scenario? If you are using vsdbcmd.exe to deploy your schema, you include the Database.sqlcmdvars, however vsdbcmd.exe does not have an option to override the values of the SQLCMD variables used at the command line level like you can do when using MSBuild (assuming you chained the SQLCMD variable to a MSBuild property).

This little tool, named SqlCmdVars.exe, lets you update you Database.sqlcmdvars file from the command line, dump its content, query the existence of variables, delete an existing variable, update the value of an existing variable and add new variable with value if required.

Usage:

The tool has a couple command line switches, if you no longer know you can always do SqlCmdVars.exe –? and it will provide you the list of command line parameters available. You can interchange the forward slash and dash as the parameter prefix, so /? and –? have the same effect.

Parameter Short form parameter Description
/Input:<string> /i:<string> Defines the input file, this is the only mandatory parameter. You provide an absolute or relative file path to the input file. You have to include the full file name, so name plus file extension.

/Input:d:\demo\dbproj\Northwind\Properties\database.sqlcmdvars

/i:..\dbproj\Northwind\Properties\database.sqlcmdvars

If there are spaces in the path, you place double quotes around the file path and name like this:

/i:”d:\users\gertd\Documents\Visual Studio 2008\Projectsj\Northwind\Properties\database.sqlcmdvars”

NOTE: If you are updating the content of the sqlcmdvars file which you are pointing to, using the /Property or /Delete command and you did not specify a explicit output file using the /Output command, you are implicitly updating the input file!
/Output:<string> /o:<string> Defines the output file. If the output file already exists, it will be overwritten. You can provide an absolute or relative file path to the output file.

NOTE: You have to make sure you can write to the file and directory location you specified.
/Property:<string> /p:<string> The /Property command adds or updates a variable name-value pair. The syntax is equivalent to the MSBuild task properties

/Property:<variable name>=<property value>

For example when you want to add or update a variable named DefaultLogPath you use this:

/p:DefaultLogPath=”D:\dbs\MSSQL10.MSSQLSERVER\MSSQL\DATA”

If you want to delete a variable you can do this by assigning an empty value like this

/p:DefaultLogPath=

You can have multiple /Property commands on a single command line invocation, but the command must be unique. This means you can provide values for the same variable multiple times like this:

/p:prop1=value1 /p:prop2=newValue2 /p:prop1= /p:prop1=value2

The final result of this is that variable named prop1 will have the value2, the last assignment wins.

NOTE: In order to delete a variable you must include the equal sign (=), omitting the = sign will result in an error.

NOTE: Variable names are matched case-insensitively, the casing of variable values is preserved.

NOTE: Each /Property command must be unique, for example the following will generate an error “Duplicate 'Property' argument 'prop1=value1'”

/p:prop1=value1 /p:prop1= /p:prop1=value1
/Delete:<string> /d:<string> The /Delete command allows you to explicitly delete a variable given a variable name. For example to delete a variable with name prop1 you write:

/Delete:prop1

or

/d:prop1

You can have multiple /Delete commands on a single command line invocation. However the commands must be unique.

NOTE: Variable names are matched case-insensitive.
/Query:<string> /q:<string> The /Query command lets you search the input file for a given variable name and when found it will return its current value.

For example:

/Query:DefaultLogPath

or

-q:DefaultLogPath

Will return the value: D:\dbs\MSSQL10.MSSQLSERVER\MSSQL\DATA

The /Query command also sets the exitcode when a property is found, so it can be used inside a batch file using ERRORLEVEL to determine if a property is defined or not.

@echo off
SqlCmdVars.exe %*
IF ERRORLEVEL 2 @echo NOT FOUND
IF ERRORLEVEL 1 @echo FOUND

The default ERRORLEVEL for other operations is 0 (zero), errors are indicated through error levels 99 and up.

/List[+|-] /l[+|-] The /List command dumps all name value pairs of all the variables defined inside the file.

The output looks like this:

BuildVersion = 2009.07.31.01
DefaultLogPath = d:\dbs\MSSQL10.MSSQLSERVER\MSSQL\DATA

@<file> N/A You can use a response file to make it easier to handle multiple or large parameters. The response file contains the parameters in the format described above.
/Help[+|-] /? Show the command line help information

 

Download:

You can download SqlCmdVars.zip from the DBProj.com website.

We frequently get asked how to identify the version a user is running with, so here is the list of Visual Studio Team System 2008 Database Edition releases. The information is retrieved using Help => About Microsoft Visual Studio inside the Visual Studio shell (devenv.exe). Alternatively you can copy the information to the clipboard using the “Copy Info” button.

 

When you are on the latest versions it should look like this:

image

 

Release Visual Studio version information Database Edition version information

2008 RTM

Microsoft Visual Studio 2008
Version 9.0.21022.8 RTM

Microsoft Visual Studio Team System 2008 Database Edition

2008 SP1

Microsoft Visual Studio 2008
Version 9.0.30729.1 SP

Microsoft Visual Studio Team System 2008 Database Edition

2008 SP1 + GDR

Microsoft Visual Studio 2008
Version 9.0.30729.1 SP

Microsoft Visual Studio Team System 2008 Database Edition GDR Version 9.1.31124.01

2008 SP1 + GDR R2

Microsoft Visual Studio 2008
Version 9.0.30729.1 SP

Microsoft Visual Studio Team System 2008 Database Edition GDR Version 9.1.40413.00

As you can see, the RTM and SP1 releases, before the GDR, do not show a separate version number for the Database Edition. This is because they are an integral part of the Visual Studio 2008 release, so they inherit the version numbering from that release.

 

An other method is to look at the file version information of the package that loads Database Edition in to the Visual Studio shell.

Release File name File version

2008 RTM

C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\
Microsoft.VisualStudio.TeamSystem.DataPackage.dll

9.0.21022.8

2008 SP1

C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\
Microsoft.VisualStudio.TeamSystem.DataPackage.dll

9.0.30729.1

2008 SP1 + GDR

C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\
Microsoft.VisualStudio.Data.Schema.Project.dll

9.1.31124.01

2008 SP1 + GDR R2

C:\Program Files (x86)\Microsoft Visual Studio 9.0\Common7\IDE\PrivateAssemblies\
Microsoft.VisualStudio.Data.Schema.Project.dll

9.1.40413.00

Please note that the file location changed between RTM and the GDR release. RTM and RTM+SP1 Database Edition files are installed in the “C:\Program Files\Microsoft Visual Studio 9.0\DBPro\…” directory, while the GDR and GDR+R2 bits are installed in the “C:\Program Files\Microsoft Visual Studio 9.0\VSTSDB\…” directory. When you install the GDR release the DBPro directory is not removed.

Also note that the file names were changed to reflect the underlying namespace name changes from Microsoft.VisualStudio.TeamSystem.Data* to Microsoft.VisualStudio.Data.* and Microsoft.Data.Schema.*. The first group Microsoft.VisualStudio.Data.* are the files which are Visual Studio specific, the second group, Microsoft.VisualStudio.Data.* are host agnostic. The second naming convention in the GDR is to indicate if a file is provider agnostic or not. Microsoft.VisualStudio.Data.Schema.Project.dll is provider agnostic and Microsoft.VisualStudio.Data.Schema.Project.Sql.dll is provider specific.

Also published on: http://dbproj.com/Tutorials/tabid/62/TID/17/cid/2/Default.aspx

Quick one based on a forum question where somebody asked how to detect if VSDBCMD.EXE failed or succeeded inside a batch file.

VSDBCMD.EXE does not return a very elaborate amount of information, there are just two return values 0 and 1, where zero indicates success and 1 failure. So in order to test for this you simply check the ERRORLEVEL inside your batch file.

This is a simple wrapper that I use that shells out to VSDBCMD.EXE and passes all the parameters, so I do not have to place the Deploy directory on the PATH.

   1:  @echo off
   2:  setlocal
   3:   
   4:  if "%PROCESSOR_ARCHITECTURE%"=="x86" call "%ProgramFiles%\Microsoft Visual Studio 9.0\VSTSDB\Deploy\vsdbcmd.exe" %*
   5:  if "%PROCESSOR_ARCHITECTURE%"=="AMD64" call "%ProgramFiles(x86)%\Microsoft Visual Studio 9.0\VSTSDB\Deploy\vsdbcmd.exe" %*
   6:   
   7:  if errorlevel 1 @echo vsdbcmd.exe failed&goto end
   8:  if errorlevel 0 @echo vsdbcmd.exe succeeded&goto end
   9:   
  10:  endlocal
  11:   
  12:  :end
  13:   

The checks for PROCESSOR_ARCHITECTURE make sure I can find the executable in the right location depending on the fact if I am running with a x32 or x64 CMD.EXE instance.

Also published on: http://www.dbproj.com/Tutorials/tabid/62/TID/16/cid/21/Default.aspx

Have fun,

GertD @ www.DBProj.com

I am happy to announce that there is a new class dedicated to VSDB. “Agile Database Techniques”, is a 3-days course that provides students with the knowledge and skills to properly manage the SQL Server database development lifecycle in an agile environment. You will learn how to manage changes to the database structure, ensuring quality through T-SQL unit testing, and how to automate the building and deploying of SQL Server databases. Intended for developers and administrators already comfortable with the concepts of designing, programming, testing, and deploying SQL Server databases, this course focuses on using Visual Studio Team System 2008 Database Edition to maximize productivity while minimizing mistakes.

The dates and locations for the first 3 events are:

  • Aug 5-7, 2009, Atlanta, GA
  • Aug 24-26, 2009, Seattle, WA
  • Sep 7-9, 2009, Chicago, IL

The class will be taught by Richard Hundhausen, who is a Visual Studio Team System MVP and has been following the VSDB developments from day one.

GertD @ www.DBProj.com

I am receiving the following question a lot: How do I propagate MSBuild properties to SQLCMD variables. In order to make the Visual Studio 2008 Team System Database Edition GDR release use the data from an MSBuild property inside a SQLCMD variable you need to do three things:

  1. Add the variable to the Database.sqlcmdvars file
  2. Add a XML fragment to the database project (.dbproj) file
  3. Use the SQLCMD variable

First you need to add a SQLCMD variable to the Database.sqlcmdvars file, in this example we will add the $(ProjectDirectory) variable, which we want to use the reflect the MSBuild $(MSBuildProjectDirectory) property. Set the value to something that you can recognize as not being set, you cannot leave it empty, so I will use “notset”.

image

Now that we have set the variable, we need to add some information to the database project file to map the value from the MSBuild property to the SQLCMD variable we just defined.

In order to achieve this we need to add an ItemGroup to the project file. There is no UI support for doing this, so you manually need to edit the database project file. There are multiple ways of doing this, I will describe one, which assumes you have the project loaded inside Visual Studio as a starting point.

  1. Right click on the database project node inside the Visual Studio Solution Explorer, this will show the following menu, where you choose the “Unload Project” option
    image
  2. Now the project is unloaded and the Solution Explorer windows only shows the project node as “(unavailable)”.
    image
  3. Now right click on the project node again and choose the “Edit <project name>.dbproj” options
    image
  4. Go to the end of the project file and add the following ItemGroup before the end of the </Project> element
       1:    <ItemGroup>
       2:      <SqlCommandVariableOverride Include="ProjectDirectory=$(MSBuildProjectDirectory)" />
       3:    </ItemGroup>
  5. The ItemGroup defines an element of type SqlCommandVariableOverride and contains an attribute which is a string that has on the left hand side of the equation the SQLCMD variable name and on the right hand side the MSBuild property name. Now you have mapped the MSBuild property to the SQLCMD variable
  6. Right click on the database node inside Solution Explorer again, now choose the “Reload Project” option. This will close the project file inside the XML editor and open the project again. If you did not close the editor, Visual Studio will tell you this action will close the project file inside the editor.
    image 
  7. Now we can use the variable, and to test we first add the following statement to the Script.PreDeplomenent.sql file.
       1:  print N'SQLCMD ProjectDirectory = $(ProjectDirectory)'
  8. To test it we need to deploy the project, to the database, not just to script, otherwise the pre-deployment script will not get executed. The result should like something like this inside the Output window:
    image

Now that we know the variable assignment works, we can use the variable in other more interesting places.

 

In the next post I will cover how to make the variable assignment conditional.

GertD @ www.DBProj.com

Based on a customer request I created a .dbschema file which contains the definitions of all the extended stored procedures used by SQL LiteSpeed 5.0 that live inside the master database. Since schema import does not import the definition of extended stored procedures, the user could no resolve the reference to the extended stored procedures.

The following 39 extended stored procedures are defined inside the dbschema file:

Extended Stored Procedure name

[dbo].[xp_append_file]
[dbo].[xp_backup_database]
[dbo].[xp_backup_log]
[dbo].[xp_delete_tsmfile]
[dbo].[xp_encrypt_decrypt]
[dbo].[xp_file_search]
[dbo].[xp_get_temp_filename]
[dbo].[xp_memory_size]
[dbo].[xp_objectrecovery]
[dbo].[xp_objectrecovery_createscript]
[dbo].[xp_objectrecovery_executeselect]
[dbo].[xp_objectrecovery_viewcontents]
[dbo].[xp_procedure]
[dbo].[xp_read_file]
[dbo].[xp_rebind_tsmmc]
[dbo].[xp_remove_file]
[dbo].[xp_replicate_activity_statistics]
[dbo].[xp_replicate_job_statistics]
[dbo].[xp_restore_attachedfilesonly]
[dbo].[xp_restore_checkpassword]
[dbo].[xp_restore_checksumonly]
[dbo].[xp_restore_database]
[dbo].[xp_restore_filelistonly]
[dbo].[xp_restore_headeronly]
[dbo].[xp_restore_log]
[dbo].[xp_restore_setinfo]
[dbo].[xp_restore_verifyonly]
[dbo].[xp_sls_bcp]
[dbo].[xp_slsAddRegMultiString]
[dbo].[xp_slsReadProgress]
[dbo].[xp_slsRemoveRegMultiString]
[dbo].[xp_slssqlmaint]
[dbo].[xp_sqllitespeed_debug]
[dbo].[xp_sqllitespeed_licenseinfo]
[dbo].[xp_sqllitespeed_version]
[dbo].[xp_view_sls_auditlog]
[dbo].[xp_view_tsmcontents]
[dbo].[xp_view_tsmfilespaces]
[dbo].[xp_view_tsmmc]

You can download the dbschema files from the following SkyDrive location:
http://cid-526eb9977609d51e.skydrive.live.com/self.aspx/DBProj.com/DBSchema/SQLLiteSpeed/SQLLiteSpeed.dbschema.zip

There are 3 dbschema files, one for each version:

I hope this helps others who need to reference SQL LiteSpeed procedures.

GertD @ www.DBProj.com

Today a user send me a question how to resolve reference of system objects inside tempdb?

My first thought was this should get resolved by loading the master.dbschema file. However this did not resolve the issue, so time to ask for an example, which slightly altered looks something like this:

   1:  CREATE PROC [dbo].[testproc]
   2:  AS
   3:      SET NOCOUNT ON
   4:      -- code simplified for this example    
   5:      SELECT [object_id],
   6:                   [name]
   7:      FROM   [tempdb].[sys].[objects] 

When you add the stored procedure above to a project you will get the following 3 warnings:

image

When you add a reference to the master.dbschema file, found in:
%ProgramFiles%\Microsoft Visual Studio 9.0\VSTSDB\Extensions\SqlServer\<200?>\DBSchemas\master.dbschema

You will get the following 3 warnings, can you spot the difference or improvements?image

Very good, there are no differences, this did not resolve anything.

The reason being that you are referencing a 3-part name, where the database name is not master. So the only way to resolve this issue is to change the database reference literal from master to tempdb. When you are adding the database reference to the master.dbschema file, it defaults to use "master” as the literal database variable.

image image

You need to change the database literal variable from master in to tempdb. And then it will resolve the 3-part names to tempdb.sys.objects in this example.

After making this change the warnings are gone, as you can see in the error list.

image

 

You can always validate you database reference settings by double clicking on the reference inside Solution Explorer.

image

If you have to resort to using this trick, I advice you to copy the master.dbschema to tempdb.dbschema and optionally purge the objects in the dbschema that you do not need in order to speed up the loading of you project.

GertD @ www.DBProj.com

Define What You Want, Not How You Get There!

 

If Not Exists…

Database development is many aspects behind in comparison to regular application development. If you look how database development is integrated with regular application development or development processes it becomes even more obvious that there is room for improvement in this area. When asked, you will find that many database developers are spending their valuable time writing, maintaining, and testing database deployment scripts. The practices may vary, some write them by hand, some use schema comparison tools to generate the script and modify that, and some went all the way to create their own tools to generate these kinds of deployment scripts.

However, the outcome of these efforts is all the same, a set of SQL statements captured inside .SQL script files or embedded as SQL statements inside some application or installer program like WiX. In general they all look like this:

   1:  --
   2:  -- [dbo].[DataLoading]
   3:  --
   4:  IF (OBJECT_ID('[dbo].[DataLoading]', 'U') IS NULL)
   5:  BEGIN
   6:  CREATE TABLE [dbo].[DataLoading]
   7:  (
   8:      [TableName]    SYSNAME NOT NULL,
   9:      [MultiValue]    TINYINT NOT NULL,
  10:      [RowCount]    BIGINT    NOT NULL,
  11:      PRIMARY KEY CLUSTERED
  12:      (
  13:          [TableName], 
  14:          [MultiValue]
  15:      )
  16:  )
  17:  END
  18:  GO

Fig 1: A typical fragment of a manually written deployment script

 

Most scripts are significantly more complicated, especially when you start dealing with incremental version updates. If you ever wrote or maintained one of these scripts you know this is when the problems with this approach become clear. For the simple cases it is all straightforward—check if the object exists, if not create it—this is even true when adding constraints, etc., since the object is easily identifiable. How about adding a column, changing its data type, and renaming a column name or changing the column order inside an index without changing the index name? As soon as you have multiple changes on a single aspect of an object, ordering and the ability to detect which change needs to be made gets very complicated.

Some database developers therefore stamp each and every object, using an extend property or by maintaining a version table, with versioning information about the object. This works great, as long as you are the only one and/or only tool that makes the changes to the schema, since SQL Server can and will not enforce the versioning information.

The fact that SQL Server does not maintain and expose enough useful information when it comes to versioning of the database schema, nor can it make any guarantees that the schema has been changed or tempered with, only compounds the problem.

The next problem with this approach is that the execution time of the deployment will grow over time. What most database developers will do is maintain two scripts, a new deployment and an incremental deployment, in the same fashion as described above. When time progresses you are accumulating lots of changes, which all have to be executed in the same time order to guarantee the right results. This might also lead to having to touch or rebuild objects multiple times, because dependencies between objects cannot be honored between change scripts across time periods. In other words change script v4 to v5 needs to be independent of v7 to v8 and therefore cannot collapse operations together for efficiency sake.

This brings me to the last obstacle for this approach; your script can only reflect your knowledge of the system as you understand at the time you are writing the script. What do I mean by that? Say you are distributing an application; the user has a need for some additional reporting and adds VIEWs to the system inside their own schema, providing abstraction and isolation from your schema. Great practice! They are very happy and add an index over the view, which makes the VIEW schema bound. Now it is time for you to update your schema and you happen to have a need to update one of the tables that is covered by a schema-bound view from the user. You do not know about this view, so the reality is that most deployments will fail at this time.

 

The Alternative Approach

So what is the alternative you might ask? If you analyze the problems described above there are a couple of conclusions you can draw:

  • SQL Server does not provide any guarantees about the schema version deployed.
  • You cannot rely on your knowledge about the state of the system; the system might have changed underneath you, or might be on a different version or is in some weird state.
  • The number of permutations to validate inside your deployment script is therefore endless and you cannot compensate for all possible cases.

The root cause, however, is the fact that you are encoding state transitions inside your deployment script that are based on a state of the system at time T. When you are deploying this at time T+5 the world might look and be in fact different and all you could do is “fail” the deployment since the outcome of your deployment is now in doubt.

Now what if you describe how you want your schema to look, instead of encoding inside a script how to implement it? This is what declarative database development is about. You define what you want, not how you get there or physically implement the database.

Let’s dive into how the Visual Studio 2008 Team System Database Edition GDR product leverages declarative database development to produce a model-driven deployment of database schemas.

 

Let There Be a Model

The first thing you need is a model representation of the database schema. The model describes all the objects inside your database schema; this is the “what you want” part. In order to create and fill the model, the system needs a description of the objects. Normally this is provided through a DSL (Domain Specific Language); VSDB uses the regular T-SQL DDL language to define the shape of schema objects, so there is no need to learn a new language or representation. So the model is fed a collection of DDL statements, which are living inside .SQL files, held together by a project file (.DBPROJ), which functions as the container for the source code files.

image

Fig 2: Database projects are containers of SQL files, which are compiled in to the schema model

The fact that the model is built based on a source-code representation of the database is a huge differentiator. This enables a true offline development experience and better integration with source code control systems and with aspects like build servers, etc. It also means that your model is allowed to be in an inconsistent or incomplete state; you can break dependencies inside the schema and the compiler will immediately flag those.

clip_image002

Fig 3: The Visual Studio error list indicates that your model is in an inconsistent state.

The underlying engine inside VSDB will perform the following actions on top of the source code when building the model:

  • Parse the source code, this will enforce the syntactic validity and transform the source code into a programmatically accessible representation, which is used to store the object inside the model.
  • Interpretation, will wire up all the object relationships.
  • Validation rules, this is the stage where semantic validation is performed, for example an object that has an instead of trigger is not allowed to be part of a transactional replication publication. Two in themselves valid and correct DDL statements, but together mutually exclusive.
  • Optionally you can enforce more rules over the model through the use of T-SQL Static Code Analysis.

When the model is in a valid and consistent state, you can now perform a build. This will perform all the steps described above, excluding running T-SQL Static Code Analysis since this is an optional step. When no errors are detected, it will persist the resulting model to disk, as a .DBSCHEMA file. The .DBSCHEMA file is effectively an XML serialized format of the database model, which functions as your database schema “blueprint,” this is the manifest that describes what you want inside the database.

How Do I Deploy this Puppy?

Now that you have a model representation, the question is how does it help solve the deployment problem? The easiest way to explain this is to describe the deployment process using the following diagram.

image

Fig 4: The VSDB deployment engine in action

  1. The first step is to load the source model, if this is provided in the form of a .DBSCHEMA file this is simply deserializing the model.
  2. The second step is to produce a model representation of the target database. This is done by importing the schema the same way you created the initial project representation, except it does not persist the resulting source code representation in this case.
  3. Now that there are two models, compare the two models, taking into account the deployment settings and additional information like the .REFACTORINGLOG file. The deployment settings determine the rules and settings used to compare and to generate the deployment script. The rafactoringlog file is providing additional information to deploy changes that cannot be determined using a difference-based deployment engine. One of the key examples is a rename column operation, which cannot be distinguished from a drop-and-add column of the same type with a different name; however, since there is state associated with the change, it is very important to preserve this information.
  4. The result of the model comparison is a list of differences. The deployment engine will then represent each atomic change as an individual action. Then the optimizer will take the collection of actions, fold them together where possible, separate them if needed, and place them in the correct dependency order.
  5. This information is then used to generate the deployment script, which is a regular .SQL script that can be executed normally using tools like SQLCMD.EXE or SSMS (SQL Server Management Studio).
  6. Optionally you can tell the deployment engine to directly update the target database, but by default only the deployment script is generated, since most people want to validate that it meets the expectations before actually executing.

The end result is that you create a deployment script taking into consideration the state of the schema as it exists in time, based on the “blueprint” of the schema that you provided.

 

The Icing on the Cake

Since most SQL Server deployments do not have Visual Studio installed, or you simply do not have access from your Visual Studio environment to the database that needs to get updated, there is a fully standalone command-line-based deployment engine that allows you to deploy the results of a build. This command-line engine is XCOPY deployable, so you can copy it onto a memory stick or server share and deploy your database from there.

   1:  "%programfiles%\microsoft visual studio 9.0\vstsdb\deploy\vsdbcmd.exe" 
   2:  /a:Deploy 
   3:  /manifest:MyDatabase.deploymanifest 
   4:  /p:DeploymentConfigurationFile=MyDatabase.sqldeployment 
   5:  /p:SqlCommandVariablesFile=MyDatabase.sqlcmdvars 
   6:  /cs:"Data Source=MyServer\sql2008;Integrated Security=true"

Fig 5: Deploying from the command line using VSDBCMD.EXE

Using VSDBCMD.EXE is as easy as pointing it to the .DEPLOYMENTMANIFEST file, which is a container that holds all the build output together, but the tool allows you to override every part of the manifest.

This includes which deployment settings or variable files are to be used by the deployment engine.

You can also use VSDBCMD.EXE to create a model file from an existing database by using the import option like this:

   1:  "%programfiles%\microsoft visual studio 9.0\vstsdb\deploy\vsdbcmd.exe" 
   2:  /a:Import 
   3:  /cs:"Data Source=(local);Integrated Security=true;Initial Catalog=MySourceDB" 
   4:  /dsp:sql 
   5:  /model:MySourceDB.dbschema

Fig 6: Creating a model representation from a target database using VSDBCMD.EXE

The resulting file can now be used as the import file for the Schema Comparison tool, which will allow you to perform the visual comparison between two database schemas presented as a .DBSCHEMA file, a Database Project, or a connection to a database. This is an ideal support tool if you need to troubleshoot the differences between two database schemas.

 

Summary

Declarative database development and Visual Studio 2008 Team System Database Edition GDR can help you streamline your processes and integration of database development tasks and ease the deployment of your database schema, through a great standalone and redistributable deployment engine.

GertD @ www.DBProj.com

The QFE rollup release for the Visual Studio Team System 2008 Database Edition GDR release is now available.

You can download the SETUP.EXE from the regular location. (http://www.microsoft.com/downloads/details.aspx?FamilyID=bb3ad767-5f69-4db9-b1c9-8f55759846ed)

If you have the VS2008 RTM version of the Database Edition or the RTM version of the VSDB 2008 GDR release installed, this setup will automatically upgrade your installation. If you have the RC installed of the QFE rollup, you have to uninstall first and then re-install the GDR.

For more detail on what got fixed in the QFE rollup, please see my previous posting: http://blogs.msdn.com/gertd/archive/2009/03/26/release-candidate-of-gdr-qfe.aspx

 

The final version number of the is 9.1.40413.00, so you can check in your Help->About  to see if you have the latest version installed.

image

GertD @ www.DBProj.com

More Posts Next page »
 
Page view tracker