Search This Blog

Monday, September 16, 2013

Understanding SQL Server Configuration Manager

By , 15 Sep 2013 on codeproject

Introduction
SQL Server Configuration Manager is a tool to configure the network protocols used by the SQL Server, and to manage network connectivity.
We will find SQL Server Configuration Manager API in the below path:
Start -> Microsoft SQL Server 2008 R2 -> Configuration Tools -> SQL Server Configuration Manager
SQL Server Configuration Manager gets information for WMI (Windows Management Instrumentation) Provider which takes information for “SQLServerManager10.msc” which is located in “C:\Windows\System32\” path. Generally SQL Server Configuration Manager will use to Start, Stop, resume and Configure services of SQL Server.

Left pane has list of configurations we can do for SQL Server.
  • SQL Server Services
  • SQL Server Network Configuration
  • SQL Server Native Client Configuration

Find Which Column in Which Table Updated from logfile

Introduction

Sometimes, database developers need to work with a database in which they don't have any permission to add any procedure or trigger, because that database is for someone else but they need change tracking. In this tip, I will show a solution for this problem.

Background

First of all, I want to appreciate Muhammad Imran for the great information on his site:http://raresql.com/2012/02/01/how-to-recover-modified-records-from-sql-server-part-1.
Then, as a brief history and description: In SQLServer, the log file (LDF) is a Microsoft solution for implementing transactions, and rollback action uses the log file for rolling back, so we can use the LDF file to track data.

Using the Code

SQL Server has undocumented T-function sys.fn_dblog that is used for reading log file and procedure DBCC PAGE that is used for details of data page like allocation_UnitIdFieldsValuesSlotId.
Create PROCEDURE Find_UpdatedColumn_In_Table
@Database_Name NVARCHAR(MAX),
@SchemaName_n_TableName NVARCHAR(MAX),
@Date_From datetime='1900/01/01',
@Date_To datetime ='9999/12/31',
@FeildName nvarchar(max)
AS
begin
DECLARE @parms nvarchar(1024)
DECLARE @Fileid INT
DECLARE @Pageid INT
DECLARE @Slotid INT

DECLARE @ConsolidatedPageID VARCHAR(MAX)
Declare @AllocUnitID as bigint
Declare @TransactionID as VARCHAR(MAX)
Declare @Operation as VARCHAR(MAX)
Declare @DatabaseCollation VARCHAR(MAX)

/*  Pick The actual data
*/
declare @temppagedata table 
(
[ParentObject] sysname,
[Object] sysname,
[Field] sysname,
[Value] sysname)

declare @pagedata table 
(
[Page ID] sysname,
[AllocUnitId] bigint,
[ParentObject] sysname,
[Object] sysname,
[Field] sysname,
[Value] sysname)

    DECLARE Page_Data_Cursor CURSOR FOR 
    /*We need to filter LOP_MODIFY_ROW,LOP_MODIFY_COLUMNS from log 
    for modified records & Get its Slot No, Page ID & AllocUnit ID*/
    SELECT [PAGE ID],[Slot ID],[AllocUnitId]
    FROM    sys.fn_dblog(NULL, NULL)  
    WHERE    
    AllocUnitId IN 
    (Select [Allocation_unit_id] from sys.allocation_units allocunits
    INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)  
    AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 
    AND partitions.partition_id = allocunits.container_id)  
    Where object_id=object_ID('' + @SchemaName_n_TableName + ''))
    AND Operation IN ('LOP_MODIFY_ROW','LOP_MODIFY_COLUMNS')  _
    AND [Context] IN ('LCX_HEAP','LCX_CLUSTERED')
    /*Use this subquery to filter the date*/

    AND [TRANSACTION ID] IN (SELECT DISTINCT _
    [TRANSACTION ID] FROM    sys.fn_dblog(NULL, NULL) 
    WHERE Context IN ('LCX_NULL') AND Operation in ('LOP_BEGIN_XACT')  
    --AND [Transaction Name]='UPDATE'
    AND  CONVERT(NVARCHAR(11),[Begin Time]) BETWEEN @Date_From AND @Date_To)

    /****************************************/

    GROUP BY [PAGE ID],[Slot ID],[AllocUnitId]
    ORDER BY [Slot ID]    
 
    OPEN Page_Data_Cursor

    FETCH NEXT FROM Page_Data_Cursor INTO @ConsolidatedPageID, @Slotid,@AllocUnitID

    WHILE @@FETCH_STATUS = 0
    BEGIN
        DECLARE @hex_pageid AS VARCHAR(Max)
        /*Page ID contains File Number and page number It looks like 0001:00000130.
          In this example 0001 is file Number &  
          00000130 is Page Number & These numbers are in Hex format*/
        SET @Fileid=SUBSTRING(@ConsolidatedPageID,0,CHARINDEX_
        (':',@ConsolidatedPageID)) -- Separate File ID from Page ID
        SET @hex_pageid ='0x'+ SUBSTRING(@ConsolidatedPageID,CHARINDEX_
        (':',@ConsolidatedPageID)+1,Len(@ConsolidatedPageID))  ---Separate the page ID
       
        SELECT @Pageid=Convert(INT,cast('' AS XML).value('xs:hexBinary_
        (substring(sql:variable("@hex_pageid"),sql:column("t.pos")) )', _
        'varbinary(max)')) -- Convert Page ID from hex to integer
        FROM (SELECT CASE substring(@hex_pageid, 1, 2) WHEN '0x' THEN 3 ELSE 0 END) AS t(pos) 
                    
        DELETE @temppagedata
        -- Now we need to get the actual data (After modification) from the page
        INSERT INTO @temppagedata EXEC( 'DBCC PAGE(' + @DataBase_Name + ', ' + _
        @fileid + ', ' + @pageid + ', 3) with tableresults,no_infomsgs;'); 
        -- Add Page Number and allocUnit ID in data to identity which one page it belongs to.                    
        INSERT INTO @pagedata SELECT @ConsolidatedPageID,@AllocUnitID,_
        [ParentObject],[Object],[Field] ,[Value] FROM @temppagedata

        FETCH NEXT FROM Page_Data_Cursor INTO  @ConsolidatedPageID, @Slotid,@AllocUnitID
    END

CLOSE Page_Data_Cursor
DEALLOCATE Page_Data_Cursor
DECLARE @Newhexstring VARCHAR(MAX);

--select * from  @PageData
--select * from  @temppagedata
DECLARE @ModifiedRawData TABLE
(
  [ID] INT IDENTITY(1,1),
  [PAGE ID] VARCHAR(MAX),
  [Slot ID] INT,
  [AllocUnitId] BIGINT,
  [RowLog Contents 0_var] VARCHAR(MAX),
  [RowLog Contents 0] VARBINARY(8000)
)
--The modified data is in multiple rows in the page, 
--so we need to convert it into one row as a single hex value.
--This hex value is in string format
INSERT INTO @ModifiedRawData ([PAGE ID],[Slot ID],[AllocUnitId]
,[RowLog Contents 0_var])
SELECT B.[PAGE ID],A.[Slot ID],A.[AllocUnitId]
,
(
SELECT REPLACE(STUFF((SELECT REPLACE(SUBSTRING([VALUE],CHARINDEX(':',[Value])+1,48),'†','')
FROM @pagedata C  
WHERE B.[Page ID]= C.[Page ID] And A.[Slot ID] =LTRIM(RTRIM_
(SUBSTRING(C.[ParentObject],5,3))) And [Object] Like '%Memory Dump%' 
Group By [Value] FOR XML PATH('') ),1,1,'') ,' ','')
) AS [Value]

FROM sys.fn_dblog(NULL, NULL) A
INNER JOIN @pagedata B On A.[PAGE ID]=B.[PAGE ID]
AND A.[AllocUnitId]=B.[AllocUnitId]
AND A.[Slot ID] =LTRIM(RTRIM(Substring(B.[ParentObject],5,3)))
AND B.[Object] Like '%Memory Dump%'
WHERE A.AllocUnitId IN 
(Select [Allocation_unit_id] from sys.allocation_units allocunits
INNER JOIN sys.partitions partitions ON (allocunits.type IN (1, 3)
AND partitions.hobt_id = allocunits.container_id) OR (allocunits.type = 2 
AND partitions.partition_id = allocunits.container_id)  
Where object_id=object_ID('' + @SchemaName_n_TableName + ''))
AND Operation in ('LOP_MODIFY_ROW','LOP_MODIFY_COLUMNS') _
AND [Context] IN ('LCX_HEAP','LCX_CLUSTERED')
/*Use this subquery to filter the date*/

AND [TRANSACTION ID] IN (Select DISTINCT [TRANSACTION ID] FROM sys.fn_dblog(NULL, NULL) 
Where Context IN ('LCX_NULL') AND Operation IN ('LOP_BEGIN_XACT')  
AND [Transaction Name]='UPDATE'
AND  CONVERT(NVARCHAR(11),[Begin Time]) BETWEEN @Date_From AND @Date_To)

/****************************************/
GROUP BY B.[PAGE ID],A.[Slot ID],A.[AllocUnitId]--,[Transaction ID]
ORDER BY [Slot ID]

-- Convert the hex value data in string, convert it into Hex value as well. 
UPDATE @ModifiedRawData  SET [RowLog Contents 0] = cast('' AS XML).value_
('xs:hexBinary(substring(sql:column("[RowLog Contents 0_var]"), 0) )', 'varbinary(max)')
FROM @ModifiedRawData

-- 
select Field, Value  from @temppagedata t
inner join @ModifiedRawData m on LTRIM(RTRIM(SUBSTRING_
(t.[ParentObject],5,3)))  = cast(m.[Slot ID] as nvarchar(1000))
where t.Field =  @FeildName

end

EXEC Find_UpdatedColumn_In_Table  'Test','dbo.Test','2000/01/01','9999/12/31',N'id'

Note

Something to note is that this proc just works with the current log, and if we need to work with log back up, we need to restore.
By 13 Sep 2013

Thursday, August 1, 2013

How To Create an ADO.NET Data Access Utility Class for SQL Server


By:  

Problem

I am a .NET developer and I typically write applications that use a SQL Server database.  I'm looking for a really simple, reusable class that encapsulates my ADO.NET database access code for create, read, update and delete (CRUD).  As I see it I need two methods in the class: one that executes a stored procedure that returns a result set and another that executes a stored procedure that does an insert, update or a delete.  Can you provide an example of how to do it?

Solution

While there are many code samples readily available to encapsulate ADO.NET database access, I prefer the simple, bare-bones approach that satisfies your requirements of a method that executes a query and another that executes a command.  In this tip I will review a solution that has a class library for the database utility and a console application that uses the class library.
I will assume that the reader is familiar with creating .NET applications using Visual Studio.
Connection Strings
When you write ADO.NET code to access a database, you need a connection string to specify the database that you want to access.  The connection string can be stored in your application's app.config file or web.config file (for a web application).  The following is an example of an app.config file:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5" />
    </startup>
  <connectionStrings>
    <add name="mssqltips"
         connectionString="data source=localhost;initial catalog=mssqltips;Integrated Security=SSPI;"
         providerName="System.Data.SqlClient" />
  </connectionStrings>
</configuration>
The following are the main points about the app.config file:
  • mssqltips is the name of the connection string; we will use the name mssqltips to access the connection string
  • Data source is the server name of the SQL Server database instance
  • Initial catalog is the database name
  • Integrated Security=SSPI means we are using windows authentication to connect to the database
  • Provider name is the ADO.NET data provider for SQL Server
You can specify many more settings in the connection string than I have shown here.  Take a look atSqlConnection.ConnectionString Property for the details.
Database Utility Class
I will use a class library project named DataAccessUtility to implement the database access utility class.  When a class library is compiled it generates a dynamic link library (.DLL) which can then be referenced from any .NET application.  The class library will have a single class named SqlDatabaseUtility with the following methods:
  • GetConnection() opens a database connection
  • ExecuteQuery() executes a stored procedure that performs a query
  • ExecuteCommand() executes a stored procedure that performs an insert, update or delete
Before I get to reviewing the code in the methods, here are a couple of things that need to be done:
  • Add a reference to System.Configuration to the class library project; I need this to access the connection string in the app.config file
  • Add using statements to the SqlDatabaseUtility class for the namespaces System.Configuration, System.Data and System.Data.SqlClient; I am using classes from these namespaces
The GetConnection() method has the following code:
public SqlConnection GetConnection(string connectionName)
{
  string cnstr = ConfigurationManager.ConnectionStrings[connectionName].ConnectionString;
  SqlConnection cn = new SqlConnection(cnstr);
  cn.Open();
  return cn;
}
The main points about the GetConnection() method are:
  • Reads the connection string from the app.config (or web.config) file
  • Creates an instance of a SqlConnection object passing the connection string into the constructor
  • Calls the Open() method on the SqlConnection object which "opens" a database connection
  • Returns the SqlConnection object to the caller
The ExecuteQuery() method has the following code:
 public DataSet ExecuteQuery(
  string connectionName,
  string storedProcName,
  Dictionary procParameters
)
{
  DataSet ds = new DataSet();
  using(SqlConnection cn = GetConnection(connectionName))
  {
      using(SqlCommand cmd = cn.CreateCommand())
      {
          cmd.CommandType = CommandType.StoredProcedure;
          cmd.CommandText = storedProcName;
          // assign parameters passed in to the command
          foreach (var procParameter in procParameters)
          {
            cmd.Parameters.Add(procParameter.Value);
          }
          using (SqlDataAdapter da = new SqlDataAdapter(cmd))
          {
            da.Fill(ds);
          }
      }
 }
 return ds;
}
The main points about the ExecuteQuery() method are:
  • Creates a Dataset that will be used to return the query results to the caller
  • Calls the GetConnection() method to open a database connection
  • Creates a SqlCommand object from the Connection, and sets the CommandType and CommandText properties
  • Adds any parameters passed in to the SqlCommand parameter collection
  • Creates a SqlDataAdapter for the SqlCommand, and calls the Fill method to execute the query and populate a dataset
  • Returns the Dataset to the caller
  • The SqlConnection, SqlCommand, and SqlDataAdapter objects are wrapped with a "using" statement which ensures that the objects are disposed; the caller is not responsible for "freeing" these objects
The ExeuteCommand() method has the following code:
public int ExecuteCommand(
  string connectionName,
  string storedProcName,
  Dictionary<string, SqlParameter> procParameters
)
{
  int rc;

  using (SqlConnection cn = GetConnection(connectionName))
  {
    // create a SQL command to execute the stored procedure
    using (SqlCommand cmd = cn.CreateCommand())
    {
      cmd.CommandType = CommandType.StoredProcedure;
      cmd.CommandText = storedProcName;

      // assign parameters passed in to the command
      foreach (var procParameter in procParameters)
      {
        cmd.Parameters.Add(procParameter.Value);
      }

      rc = cmd.ExecuteNonQuery();
    }
  }

  return rc;
}
The main points about the ExecuteCommand() method are:
  • Calls the GetConnection() method to open a database connection; the using construct is used to close the database connection automatically
  • Creates a SqlCommand object from the Connection and sets the CommandType and CommandText properties
  • Adds any parameters passed in to the SqlCommand parameter collection
  • Calls the SqlCommand ExecuteNonQuery method to call the stored procedure; the return value is the number of rows affected; e.g. the number of rows inserted, update or deleted by the command
  • The SqlConnection and SqlCommand objects are wrapped with a "using" statement which ensures that the objects are disposed; the caller is not responsible for "freeing" these objects
Console Application
In this section I will review a .NET console application that will access a SQL Server database by using the SqlDatabaseUtility  class.  Here is a T-SQL script that creates a table, and two stored procedures - one that inserts a row and another that performs a query:
use mssqltips
go

create table [dbo].[customer] (
 [id] [int] identity(1,1) NOT NULL,
 [name] [varchar](50) NOT NULL,
 [state] [varchar](2) NOT NULL,
 constraint [pk_customer] primary key clustered ([id] asc)
)
go

create procedure dbo.AddCustomer
 @name  varchar(50)
,@state char(2)
as
begin
 insert into dbo.customer
  ([name], [state])
 values
  (@name, @state)
end
go

create procedure dbo.GetCustomerList
as
begin
 select [id], [name], [state]
 from dbo.customer
end
go
Before I get to reviewing the code in the console application, here are a couple of things that need to be done:
  • Add a reference to the DataAccessUtility class library to the console application; I need this to call the methods in the SqlDatabaseUtility class
  • Add a using statement for the DataAccessUtility, System.Data and System.Data.SqlClient namespaces
  • Create an mssqltips database and run the above T-SQL script in it
  • Put the connectionStrings element (shown in the Connection Strings section above) into the app.config file in the console application project
Here is the code to call the AddCustomer stored procedure:
SqlDatabaseUtility dbutility = new SqlDatabaseUtility();
            
// add a customer
Dictionary cmdParameters = new Dictionary();
cmdParameters["name"] = new SqlParameter("name", "Smith");
cmdParameters["state"] = new SqlParameter("state", "MD");
dbutility.ExecuteCommand("mssqltips", "dbo.AddCustomer", cmdParameters);
The main points about the above code are:
  • Create an instance of the SqlDatabaseUtility class
  • Create a Dictionary collection for parameters; it's like a name-value pair
  • Add parameters to the collection; parameter names must match the stored procedure parameters
  • Call the SqlDatabaseUtility ExecuteCommand method passing in the connection name, stored procedure name, and the parameter collection
Here is the code to call the GetCustomerList stored procedure:
Dictionary<string, SqlParameter> queryParameters = new Dictionary<string, SqlParameter>();
DataSet ds = dbutility.ExecuteQuery("mssqltips", "dbo.GetCustomerList", queryParameters);
DataTable t = ds.Tables[0];
foreach(DataRow r in t.Rows)
{
  Console.WriteLine(string.Format("{0}\t{1}\t{2}", 
    r[0].ToString(), 
    r[1].ToString(), 
    r[2].ToString()));
}
The main points about the above code are:
  • Create a Dictionary collection for parameters; even though the GetCustomerList does not take any parameters, you still have to pass an empty collection
  • Call the SqlDatabaseUtility ExecuteQuery method passing the connection name, stored procedure name, and empty parameter collection
  • ExecuteQuery returns a Dataset which is a collection of DataTables
  • Get the first Datatable from the Dataset, iterate through the rows and print the column values to the console

Next Steps

  • The above code is an example of a very simple approach to calling stored procedures from .NET code.
  • To keep the code as simple as possible, there is no exception handling shown.  You do need try/catch blocks around your database calls.  Take a look at the SqlCommand methods to see the kinds of exceptions that you need to catch. 
  • Download the sample code here to experiment on your own.