Skip to content

Commit

Permalink
First draft of SQL Server Ledger demos for SQL Server 2022
Browse files Browse the repository at this point in the history
  • Loading branch information
rgward committed Jul 4, 2022
1 parent e887535 commit 17332d8
Show file tree
Hide file tree
Showing 18 changed files with 212 additions and 784 deletions.

This file was deleted.

19 changes: 19 additions & 0 deletions demos/sqlserver2022/sqlledger/addlogins.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
USE master;
GO

-- Create a login for bob and make him a sysadmin
IF EXISTS (SELECT * FROM sys.server_principals WHERE NAME = 'bob')
BEGIN
DROP LOGIN bob;
END
CREATE LOGIN bob WITH PASSWORD = N'StrongPassw0rd!';
EXEC sp_addsrvrolemember 'bob', 'sysadmin';
GO

-- Create a login for the app
IF EXISTS (SELECT * FROM sys.server_principals WHERE NAME = 'app')
BEGIN
DROP LOGIN app;
END
CREATE LOGIN app WITH PASSWORD = N'StrongPassw0rd!', DEFAULT_DATABASE = ContosoHR;
GO
17 changes: 17 additions & 0 deletions demos/sqlserver2022/sqlledger/admindropledger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
USE ContosoHR;
GO
-- You cannot turn off versioning for a ledger table
ALTER TABLE Employees SET (SYSTEM_VERSIONING = OFF);
GO
-- You cannot drop the ledger history table
DROP TABLE dbo.MSSQL_LedgerHistoryFor_901578250;
GO
-- You can drop a ledger table
DROP TABLE Employees;
GO
-- But we keep a history of the dropped table
SELECT * FROM sys.objects WHERE name like '%DroppedLedgerTable%';
GO
-- You cannot drop the "dropped ledger table". Substitue the table name from the results from the previous query
DROP TABLE MSSQL_DroppedLedgerTable_Employees_5363A044DD864F90BF64B81441A0B9DC;
GO
8 changes: 8 additions & 0 deletions demos/sqlserver2022/sqlledger/appchangemaryssalary.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
USE ContosoHR;
GO
UPDATE dbo.Employees
SET Salary = Salary + 50000
WHERE EmployeeID = 8;
GO
INSERT INTO dbo.AuditEvents VALUES (getdate(), 'bob', 'UPDATE dbo.Employees SET Salary = Salary + 50000 WHERE EmployeeID = 8');
GO
12 changes: 12 additions & 0 deletions demos/sqlserver2022/sqlledger/createauditledger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
USE ContosoHR;
GO
-- Create an append-only ledger table to track T-SQL commands from the app and the "real" user who initiated the transactkion
DROP TABLE IF EXISTS [dbo].[AuditEvents];
GO
CREATE TABLE [dbo].[AuditEvents](
[Timestamp] [Datetime2] NOT NULL DEFAULT (GETDATE()),
[UserName] [nvarchar](255) NOT NULL,
[Query] [nvarchar](4000) NOT NULL
)
WITH (LEDGER = ON (APPEND_ONLY = ON));
GO
21 changes: 21 additions & 0 deletions demos/sqlserver2022/sqlledger/createdb.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
USE master;
GO

-- Create the ContosoHR database
--
DROP DATABASE IF EXISTS ContosoHR;
GO
CREATE DATABASE ContosoHR;
GO
USE ContosoHR;
GO

-- Enable snapshot isolation to allow ledger to be verified
ALTER DATABASE ContosoHR SET ALLOW_SNAPSHOT_ISOLATION ON
GO

-- Create an app user for the app login
CREATE USER app FROM LOGIN app;
GO
EXEC sp_addrolemember 'db_owner', 'app'
GO
19 changes: 19 additions & 0 deletions demos/sqlserver2022/sqlledger/createemployeeledger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
USE ContosoHR;
GO

-- Create the Employees table and make it an updatetable Ledger table
DROP TABLE IF EXISTS [dbo].[Employees];
GO
CREATE TABLE [dbo].[Employees](
[EmployeeID] [int] IDENTITY(1,1) NOT NULL,
[SSN] [char](11) NOT NULL,
[FirstName] [nvarchar](50) NOT NULL,
[LastName] [nvarchar](50) NOT NULL,
[Salary] [money] NOT NULL
)
WITH
(
SYSTEM_VERSIONING = ON,
LEDGER = ON
);
GO
4 changes: 4 additions & 0 deletions demos/sqlserver2022/sqlledger/generatedigest.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
USE ContosoHR;
GO
EXEC sp_generate_database_ledger_digest;
GO
11 changes: 11 additions & 0 deletions demos/sqlserver2022/sqlledger/getallemployees.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
USE ContosoHR;
GO
-- Use * for all columns
SELECT * FROM dbo.Employees;
GO
-- List out all the columns
SELECT EmployeeID, SSN, FirstName, LastName, Salary,
ledger_start_transaction_id, ledger_end_transaction_id, ledger_start_sequence_number,
ledger_end_sequence_number
FROM dbo.Employees
GO
4 changes: 4 additions & 0 deletions demos/sqlserver2022/sqlledger/getauditledger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
USE ContosoHR;
GO
SELECT * FROM dbo.AuditEvents_Ledger;
GO
4 changes: 4 additions & 0 deletions demos/sqlserver2022/sqlledger/getemployeesledger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
USE ContosoHR;
GO
SELECT * FROM dbo.Employees_Ledger;
GO
4 changes: 4 additions & 0 deletions demos/sqlserver2022/sqlledger/getledgerblocks.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
USE ContosoHR;
GO
SELECT * FROM sys.database_ledger_blocks;
GO
6 changes: 6 additions & 0 deletions demos/sqlserver2022/sqlledger/getledgerobjects.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
USE ContosoHR;
GO
SELECT * FROM sys.ledger_table_history;
GO
SELECT * FROM sys.ledger_column_history;
GO
20 changes: 20 additions & 0 deletions demos/sqlserver2022/sqlledger/populateemployees.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@

USE ContosoHR;
GO

-- Clear Employees table
DELETE FROM [dbo].[Employees];
GO

-- Insert 10 employees. The names and SSN are completely fictional and not associated with any person
DECLARE @SSN1 char(11) = '795-73-9833'; DECLARE @Salary1 Money = 61692.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN1, 'Catherine', 'Abel', @Salary1);
DECLARE @SSN2 char(11) = '990-00-6818'; DECLARE @Salary2 Money = 990.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN2, 'Kim', 'Abercrombie', @Salary2);
DECLARE @SSN3 char(11) = '009-37-3952'; DECLARE @Salary3 Money = 5684.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN3, 'Frances', 'Adams', @Salary3);
DECLARE @SSN4 char(11) = '708-44-3627'; DECLARE @Salary4 Money = 55415.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN4, 'Jay', 'Adams', @Salary4);
DECLARE @SSN5 char(11) = '447-62-6279'; DECLARE @Salary5 Money = 49744.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN5, 'Robert', 'Ahlering', @Salary5);
DECLARE @SSN6 char(11) = '872-78-4732'; DECLARE @Salary6 Money = 38584.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN6, 'Stanley', 'Alan', @Salary6);
DECLARE @SSN7 char(11) = '898-79-8701'; DECLARE @Salary7 Money = 11918.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN7, 'Paul', 'Alcorn', @Salary7);
DECLARE @SSN8 char(11) = '561-88-3757'; DECLARE @Salary8 Money = 17349.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN8, 'Mary', 'Alexander', @Salary8);
DECLARE @SSN9 char(11) = '904-55-0991'; DECLARE @Salary9 Money = 70796.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN9, 'Michelle', 'Alexander', @Salary9);
DECLARE @SSN10 char(11) = '293-95-6617'; DECLARE @Salary10 Money = 96956.00; INSERT INTO [dbo].[Employees] ([SSN], [FirstName], [LastName], [Salary]) VALUES (@SSN10, 'Marvin', 'Allen', @Salary10);
GO
47 changes: 43 additions & 4 deletions demos/sqlserver2022/sqlledger/readme.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,46 @@
# SQL Ledger in SQL Server 2022
# Demo for SQL Server Ledger for SQL Server 2022

These are demos to demonstrate the capabilities of SQL Ledger for SQL Server 2022
These are demonstrations for SQL Server Ledger for SQL Server 2022

**supplychain**
## Prerequisistes

This folder contains a read-only SQL notebook used to show SQL Ledger in a supply chain scenario.
- SQL Server 2022 Evaluation Edition. You must configure SQL Server for mixed mode authentication.
- Virtual machine or computer with minimum 2 CPUs with 8Gb RAM.
- SQL Server Management Studio (SSMS). The latest SSMS 18.x will work but SSMS 19.x has a new visualization for Ledger tables so the examples in demo 1 were done with the latest SSMS 19.x preview build.

## Demo 1: Using an updatable ledger table

This demo will show you the fundamentals of an updatable ledger table.

1. Create logins by executing the script **addlogins.sql** from SSMS as the default sysadmin for the SQL Server instance.
2. Login with the 'bob' sysadmin user created in step #1.
2. Create the database schema with users by executing the script **createdb.sql** from SSMS.
3. Create an updateable ledger table for Employees by executing the script **createemployeeledger.sql** from SSMS.
4. Create an append-only ledger table for auditing of the application by executing the script **createauditledger.sql** from SSMS. This table will be used later in the demonstration.
5. Populate initial employee data using the script **populateemployees.sql** from SSMS. Use SSMS Object Explorer to see the tables have properties next to their name that they are ledger tables and a new visual icon to indicate it is a ledger table.
6. Examine the data in the employee table using the script **getallemployees.sql**. Notice there are "hidden" columns that are not shown if you execute a SELECT *. Some of these columns are NULL or 0 because no updates have been made to the data. You normally will not use these columns but use the *ledger view* to see information about changes to the employees table.
7. Look at the employees "ledger" by executing the script **getemployeesledger.sql**. This is a view from the Employees table and a ledger *history* table. Notice the ledger has the transaction information from hidden columns in the table plus an indication of what type of operation was performed on the ledger for a specific row.
8. Examine the definition of the ledger view by executing **getemployeesledgerview.sql**. The ledger history table uses the name**MSSQL_LedgerHistoryFor_[objectid of table]**. Notice the view is a union of the original table (for new inserts) and updates from the history table (insert/delete pair).
9. You can combine the ledger view with a system table to get more auditing information. Execute the script **viewemployeesledgerhistory.sql** to see an example. You can see that 'bob' inserted all the data along with a timestamp.
10. To verify the integrity of the ledger let's generate a digest by executing the script **generatedigest.sql**. **Save the output value (including the brackets) to be used for verifying the ledger.**
11. You can now see blocks generated for the ledger table by executing the script **getledgerblocks.sql**
10. Try to update Jay Adam's salary to see if no one will notice by executing the script **updatejayssalary.sql**.
11. Execute the script **getallemployees.sql** to see that it doesn't look anyone updated the data. But notice in the 2nd query result, the **ledger_start_transaction_id** is different than from the 1st insert.
12. Execute the script **viewemployeesledgerhistory.sql** to see the audit of the changes and who made them.
13. Let's verify the ledger just to verify the integrity of the data. Edit the script **verifyledger.sql** by substituting the JSON value from **step 10** from the **generatedigest.sql** script (include the brackets inside the quotes). Execute the script. The **last_verified_block_id** should match the block_id in the digest and in **sys.database_ledger_blocks**. I now know the ledger is verified as of the time the digest was captured. By using this digest I know that 1) The data is valid based on the time the digest was captured 2) The internal blocks match the current data changes for the update to jay's salary. If someone had to fake out the data for the Employees table without doing a T-SQL UPDATE to make the system "think" Jay's current salary was 50,000 more than it really is, the system would have raised an error that hashes of the changes don't match the current data.

## Demo 2: Using an append-only ledger

Now see you can use an append-only ledger to capture application information. To ensure we captured what person was responsible for changes even if an application uses an "application login" we can use an append-only ledger table which was created earlier then you ran the script **createauditledger.sql**.

1. To simulate a user using the application to change someone else's salary **connect to SSMS as the app login** created with the **addlogins.sql** script in step 1 and execute the script **appchangemaryssalary.sql**
1. **Logging back in as bob or the local sysadmin login**, look at the ledger by executing the script **viewemployeesledgerhistory.sql**. All you can see is that the "app" changed Mary's salary.
1. Look at the audit ledger by executing the script **getauditledger.sql**. This ledger cannot be updated so the app must "log" all operations and the originating user from the app who initiated the operation. So I can see from the ledger at the SQL level that the app user changed Mary's salary but the app ledger shows bob was the actual person who used the app to make the change.

## Demo 3: Protecting Ledger tables from DDL changes.

Let's see how admin trying to change ledger table properties or drop ledger tables

1. You can also view which tables and columns have been created for SQL Server ledger by executing the script **getledgerobjects.sql**
1. Admins are restricted from altering certain aspects of a ledger table, removing the ledger history table, and there is a record kept of any dropped ledger table (which you cannot drop). See these aspects of ledger by executing the script **admindropledger.sql**
1. Execute **getledgerobjects.sql** again to see the dropped ledger table.
6 changes: 6 additions & 0 deletions demos/sqlserver2022/sqlledger/updatejayssalary.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
USE ContosoHR;
GO
UPDATE dbo.Employees
SET Salary = Salary + 50000
WHERE EmployeeID = 4;
GO
5 changes: 5 additions & 0 deletions demos/sqlserver2022/sqlledger/verifyledger.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
USE ContosoHR;
GO
EXECUTE sp_verify_database_ledger
N'{"database_name":"ContosoHR","block_id":0,"hash":"0xC8125753E3CFE79A1B396BC257364B27698151A3A41A86F8FDF64ABA39D1CCD1","last_transaction_commit_time":"2022-07-04T11:25:55.1966667","digest_time":"2022-07-04T18:27:32.9950501"}'
GO
9 changes: 9 additions & 0 deletions demos/sqlserver2022/sqlledger/viewemployeesledgerhistory.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
USE ContosoHR;
GO
SELECT e.EmployeeID, e.FirstName, e.LastName, e.Salary,
dlt.transaction_id, dlt.commit_time, dlt.principal_name, e.ledger_operation_type_desc, dlt.table_hashes
FROM sys.database_ledger_transactions dlt
JOIN dbo.Employees_Ledger e
ON e.ledger_transaction_id = dlt.transaction_id
ORDER BY dlt.commit_time DESC;
GO

0 comments on commit 17332d8

Please sign in to comment.