diff --git a/App.config b/App.config index bae5d6d..ecdcf8a 100644 --- a/App.config +++ b/App.config @@ -1,6 +1,6 @@ - + diff --git a/CAMOsoft/CAMOsoft.DbUtils/CAMOsoft.DbUtils.csproj b/CAMOsoft/CAMOsoft.DbUtils/CAMOsoft.DbUtils.csproj index 73d61f6..bf6d47e 100644 --- a/CAMOsoft/CAMOsoft.DbUtils/CAMOsoft.DbUtils.csproj +++ b/CAMOsoft/CAMOsoft.DbUtils/CAMOsoft.DbUtils.csproj @@ -10,7 +10,7 @@ Properties CAMOsoft.DbUtils CAMOsoft.DbUtils - v4.6.1 + v4.7.2 512 @@ -85,8 +85,12 @@ + + + ..\..\packages\Microsoft.SqlServer.Types.14.0.1016.290\lib\net40\Microsoft.SqlServer.Types.dll + @@ -109,4 +113,22 @@ true + + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + + + \ No newline at end of file diff --git a/CAMOsoft/CAMOsoft.DbUtils/SqlServerTypes/Loader.cs b/CAMOsoft/CAMOsoft.DbUtils/SqlServerTypes/Loader.cs new file mode 100644 index 0000000..ce606cf --- /dev/null +++ b/CAMOsoft/CAMOsoft.DbUtils/SqlServerTypes/Loader.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace SqlServerTypes +{ + /// + /// Utility methods related to CLR Types for SQL Server + /// + public class Utilities + { + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr LoadLibrary(string libname); + + /// + /// Loads the required native assemblies for the current architecture (x86 or x64) + /// + /// + /// Root path of the current application. Use Server.MapPath(".") for ASP.NET applications + /// and AppDomain.CurrentDomain.BaseDirectory for desktop applications. + /// + public static void LoadNativeAssemblies(string rootApplicationPath) + { + var nativeBinaryPath = IntPtr.Size > 4 + ? Path.Combine(rootApplicationPath, @"SqlServerTypes\x64\") + : Path.Combine(rootApplicationPath, @"SqlServerTypes\x86\"); + + LoadNativeAssembly(nativeBinaryPath, "msvcr120.dll"); + LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial140.dll"); + } + + private static void LoadNativeAssembly(string nativeBinaryPath, string assemblyName) + { + var path = Path.Combine(nativeBinaryPath, assemblyName); + var ptr = LoadLibrary(path); + if (ptr == IntPtr.Zero) + { + throw new Exception(string.Format( + "Error loading {0} (ErrorCode: {1})", + assemblyName, + Marshal.GetLastWin32Error())); + } + } + } +} \ No newline at end of file diff --git a/CAMOsoft/CAMOsoft.DbUtils/SqlServerTypes/readme.htm b/CAMOsoft/CAMOsoft.DbUtils/SqlServerTypes/readme.htm new file mode 100644 index 0000000..02d9ac8 --- /dev/null +++ b/CAMOsoft/CAMOsoft.DbUtils/SqlServerTypes/readme.htm @@ -0,0 +1,61 @@ + + + + Microsoft.SqlServer.Types + + + +
+

Action required to load native assemblies

+

+ To deploy an application that uses spatial data types to a machine that does not have 'System CLR Types for SQL Server' installed you also need to deploy the native assembly SqlServerSpatial140.dll. Both x86 (32 bit) and x64 (64 bit) versions of this assembly have been added to your project under the SqlServerTypes\x86 and SqlServerTypes\x64 subdirectories. The native assembly msvcr120.dll is also included in case the C++ runtime is not installed. +

+

+ You need to add code to load the correct one of these assemblies at runtime (depending on the current architecture). +

+

ASP.NET Web Sites

+

+ For ASP.NET Web Sites, add the following block of code to the code behind file of the Web Form where you have added Report Viewer Control: +

+    Default.aspx.cs:
+        
+    public partial class _Default : System.Web.UI.Page
+    {
+        static bool _isSqlTypesLoaded = false;
+
+        public _Default()
+        {
+            if (!_isSqlTypesLoaded)
+            {
+                SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~"));
+                _isSqlTypesLoaded = true;
+            }
+            
+        }
+    }
+
+

+

ASP.NET Web Applications

+

+ For ASP.NET Web Applications, add the following line of code to the Application_Start method in Global.asax.cs: +

    SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~/bin"));
+

+

Desktop Applications

+

+ For desktop applications, add the following line of code to run before any spatial operations are performed: +

    SqlServerTypes.Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory);
+

+
+ + \ No newline at end of file diff --git a/CAMOsoft/CAMOsoft.DbUtils/packages.config b/CAMOsoft/CAMOsoft.DbUtils/packages.config new file mode 100644 index 0000000..94d3422 --- /dev/null +++ b/CAMOsoft/CAMOsoft.DbUtils/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/ChangesLog.txt b/ChangesLog.txt index 7a3ea4f..57cd03b 100644 --- a/ChangesLog.txt +++ b/ChangesLog.txt @@ -1,6 +1,11 @@ SQLPlayer Data Script Writer - Changes Log ========================================== +ver.2.3 @ 02/12/2020 +- Support for Temporal tables (#10) +- Support for Time data type (#14) +- Fixed: Showing the wrong number of rows in a table (#12) + ver.2.2 @ 12/06/2020 - Support for Binary and Varbinary diff --git a/DataScriptWriter.csproj b/DataScriptWriter.csproj index dc7d432..a1be3e5 100644 --- a/DataScriptWriter.csproj +++ b/DataScriptWriter.csproj @@ -9,7 +9,7 @@ Properties DataScriptWriter DataScriptWriter - v4.6.1 + v4.7.2 512 SAK SAK @@ -50,6 +50,9 @@ + + packages\Microsoft.SqlServer.Types.14.0.1016.290\lib\net40\Microsoft.SqlServer.Types.dll + @@ -85,6 +88,7 @@ + ConnectDbForm.cs @@ -105,6 +109,7 @@ Resources.resx True + SettingsSingleFileGenerator Settings.Designer.cs @@ -126,6 +131,19 @@ + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + + + PreserveNewest + diff --git a/OUTPUT/Application.TransactionTypes.sql b/OUTPUT/Application.TransactionTypes.sql new file mode 100644 index 0000000..9cdbd6e --- /dev/null +++ b/OUTPUT/Application.TransactionTypes.sql @@ -0,0 +1,44 @@ +CREATE PROCEDURE [dbo].[Populate_Application_TransactionTypes] +AS +BEGIN +/* + Table's data: [Application].[TransactionTypes] + Data Source: [DEV19].[WideWorldImporters] + Created on: 02/12/2020 00:13:12 + Scripted by: DEV19\Administrator + Generated by: Data Script Writer - ver. 2.3.0.0 + GitHub repo URL: https://github.com/SQLPlayer/DataScriptWriter/ +*/ +PRINT 'Populating data into [Application].[TransactionTypes]'; + +IF NOT EXISTS (SELECT TOP (1) * FROM [Application].[TransactionTypes]) +BEGIN + + ;WITH cte_data + as (SELECT [TransactionTypeID], [TransactionTypeName], [LastEditedBy] FROM + (VALUES + (1, N'Customer Invoice', 1) + , (2, N'Customer Credit Note', 1) + , (3, N'Customer Payment Received', 1) + , (4, N'Customer Refund', 1) + , (5, N'Supplier Invoice', 1) + , (6, N'Supplier Credit Note', 1) + , (7, N'Supplier Payment Issued', 1) + , (8, N'Supplier Refund', 1) + , (9, N'Stock Transfer', 1) + , (10, N'Stock Issue', 1) + , (11, N'Stock Receipt', 1) + , (12, N'Stock Adjustment at Stocktake', 1) + , (13, N'Customer Contra', 9) + ) as v ([TransactionTypeID], [TransactionTypeName], [LastEditedBy]) +) + INSERT INTO [Application].[TransactionTypes] + ([TransactionTypeID], [TransactionTypeName], [LastEditedBy]) + SELECT [TransactionTypeID], [TransactionTypeName], [LastEditedBy] + FROM cte_data; + +END + +-- End data of table: [Application].[TransactionTypes] -- +END +GO diff --git a/OUTPUT/Person.AddressType_INSERT.sql b/OUTPUT/Person.AddressType_INSERT.sql new file mode 100644 index 0000000..80214f6 --- /dev/null +++ b/OUTPUT/Person.AddressType_INSERT.sql @@ -0,0 +1,36 @@ +CREATE PROCEDURE [dbo].[Populate_Person_AddressType] +AS +BEGIN +/* + Table's data: [Person].[AddressType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:00:40 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[AddressType]'; + +IF NOT EXISTS (SELECT TOP (1) * FROM [Person].[AddressType]) +BEGIN + + ;WITH cte_data + as (SELECT [AddressTypeID], [Name], [rowguid], [ModifiedDate] FROM + (VALUES + (1, 'Billing', 'b84f78b1-4efe-4a0e-8cb7-70e9f112f886', '20080430 00:00:00.000') + , (2, 'Home', '41bc2ff6-f0fc-475f-8eb9-cec0805aa0f2', '20080430 00:00:00.000') + , (3, 'Main Office', '8eeec28c-07a2-4fb9-ad0a-42d4a0bbc575', '20080430 00:00:00.000') + , (4, 'Primary', '24cb3088-4345-47c4-86c5-17b535133d1e', '20080430 00:00:00.000') + , (5, 'Shipping', 'b29da3f8-19a3-47da-9daa-15c84f4a83a5', '20080430 00:00:00.000') + , (6, 'Archive', 'a67f238a-5ba2-444b-966c-0467ed9c427f', '20080430 00:00:00.000') + ) as v ([AddressTypeID], [Name], [rowguid], [ModifiedDate]) +) + INSERT INTO [Person].[AddressType] + ([AddressTypeID], [Name], [rowguid], [ModifiedDate]) + SELECT [AddressTypeID], [Name], [rowguid], [ModifiedDate] + FROM cte_data; + +END + +-- End data of table: [Person].[AddressType] -- +END +GO diff --git a/OUTPUT/Person.AddressType_MERGE.sql b/OUTPUT/Person.AddressType_MERGE.sql new file mode 100644 index 0000000..78068b6 --- /dev/null +++ b/OUTPUT/Person.AddressType_MERGE.sql @@ -0,0 +1,48 @@ +CREATE PROCEDURE [dbo].[Populate_Person_AddressType] +AS +BEGIN +/* + Table's data: [Person].[AddressType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 14:59:12 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[AddressType]'; + +IF OBJECT_ID('tempdb.dbo.#Person_AddressType') IS NOT NULL DROP TABLE #Person_AddressType; +SELECT * INTO #Person_AddressType FROM [Person].[AddressType] WHERE 0=1; + +INSERT INTO #Person_AddressType + ([AddressTypeID], [Name], [rowguid], [ModifiedDate]) +SELECT CAST([AddressTypeID] AS int) AS [AddressTypeID], [Name], [rowguid], [ModifiedDate] FROM +(VALUES + (1, 'Billing', 'b84f78b1-4efe-4a0e-8cb7-70e9f112f886', '20080430 00:00:00.000') + , (2, 'Home', '41bc2ff6-f0fc-475f-8eb9-cec0805aa0f2', '20080430 00:00:00.000') + , (3, 'Main Office', '8eeec28c-07a2-4fb9-ad0a-42d4a0bbc575', '20080430 00:00:00.000') + , (4, 'Primary', '24cb3088-4345-47c4-86c5-17b535133d1e', '20080430 00:00:00.000') + , (5, 'Shipping', 'b29da3f8-19a3-47da-9daa-15c84f4a83a5', '20080430 00:00:00.000') + , (6, 'Archive', 'a67f238a-5ba2-444b-966c-0467ed9c427f', '20080430 00:00:00.000') +) as v ([AddressTypeID], [Name], [rowguid], [ModifiedDate]); + + + +WITH cte_data as (SELECT CAST([AddressTypeID] AS int) AS [AddressTypeID], [Name], [rowguid], [ModifiedDate] FROM [#Person_AddressType]) +MERGE [Person].[AddressType] as t +USING cte_data as s + ON t.[AddressTypeID] = s.[AddressTypeID] +WHEN NOT MATCHED BY target THEN + INSERT ([AddressTypeID], [Name], [rowguid], [ModifiedDate]) + VALUES (s.[AddressTypeID], s.[Name], s.[rowguid], s.[ModifiedDate]) +WHEN MATCHED THEN + UPDATE SET + [Name] = s.[Name], [rowguid] = s.[rowguid], [ModifiedDate] = s.[ModifiedDate] +WHEN NOT MATCHED BY source THEN + DELETE +; + +DROP TABLE #Person_AddressType; + +-- End data of table: [Person].[AddressType] -- +END +GO diff --git a/OUTPUT/Person.ContactType.sql b/OUTPUT/Person.ContactType.sql new file mode 100644 index 0000000..9fa7b25 --- /dev/null +++ b/OUTPUT/Person.ContactType.sql @@ -0,0 +1,62 @@ +CREATE PROCEDURE [dbo].[Populate_Person_ContactType] +AS +BEGIN +/* + Table's data: [Person].[ContactType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:02:26 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[ContactType]'; + +IF OBJECT_ID('tempdb.dbo.#Person_ContactType') IS NOT NULL DROP TABLE #Person_ContactType; +SELECT * INTO #Person_ContactType FROM [Person].[ContactType] WHERE 0=1; + +INSERT INTO #Person_ContactType + ([ContactTypeID], [Name], [ModifiedDate]) +SELECT CAST([ContactTypeID] AS int) AS [ContactTypeID], [Name], [ModifiedDate] FROM +(VALUES + (1, 'Accounting Manager', '20080430 00:00:00.000') + , (2, 'Assistant Sales Agent', '20080430 00:00:00.000') + , (3, 'Assistant Sales Representative', '20080430 00:00:00.000') + , (4, 'Coordinator Foreign Markets', '20080430 00:00:00.000') + , (5, 'Export Administrator', '20080430 00:00:00.000') + , (6, 'International Marketing Manager', '20080430 00:00:00.000') + , (7, 'Marketing Assistant', '20080430 00:00:00.000') + , (8, 'Marketing Manager', '20080430 00:00:00.000') + , (9, 'Marketing Representative', '20080430 00:00:00.000') + , (10, 'Order Administrator', '20080430 00:00:00.000') + , (11, 'Owner', '20080430 00:00:00.000') + , (12, 'Owner/Marketing Assistant', '20080430 00:00:00.000') + , (13, 'Product Manager', '20080430 00:00:00.000') + , (14, 'Purchasing Agent', '20080430 00:00:00.000') + , (15, 'Purchasing Manager', '20080430 00:00:00.000') + , (16, 'Regional Account Representative', '20080430 00:00:00.000') + , (17, 'Sales Agent', '20080430 00:00:00.000') + , (18, 'Sales Associate', '20080430 00:00:00.000') + , (19, 'Sales Manager', '20080430 00:00:00.000') + , (20, 'Sales Representative', '20080430 00:00:00.000') +) as v ([ContactTypeID], [Name], [ModifiedDate]); + + + +WITH cte_data as (SELECT CAST([ContactTypeID] AS int) AS [ContactTypeID], [Name], [ModifiedDate] FROM [#Person_ContactType]) +MERGE [Person].[ContactType] as t +USING cte_data as s + ON t.[ContactTypeID] = s.[ContactTypeID] +WHEN NOT MATCHED BY target THEN + INSERT ([ContactTypeID], [Name], [ModifiedDate]) + VALUES (s.[ContactTypeID], s.[Name], s.[ModifiedDate]) +WHEN MATCHED THEN + UPDATE SET + [Name] = s.[Name], [ModifiedDate] = s.[ModifiedDate] +WHEN NOT MATCHED BY source THEN + DELETE +; + +DROP TABLE #Person_ContactType; + +-- End data of table: [Person].[ContactType] -- +END +GO diff --git a/OUTPUT/Person.PhoneNumberType.sql b/OUTPUT/Person.PhoneNumberType.sql new file mode 100644 index 0000000..c180505 --- /dev/null +++ b/OUTPUT/Person.PhoneNumberType.sql @@ -0,0 +1,33 @@ +CREATE PROCEDURE [data].[Populate_Person_PhoneNumberType] +AS +BEGIN +/* + Table's data: [Person].[PhoneNumberType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:07:03 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[PhoneNumberType]'; + +IF NOT EXISTS (SELECT TOP (1) * FROM [Person].[PhoneNumberType]) +BEGIN + + ;WITH cte_data + as (SELECT [PhoneNumberTypeID], [Name], [ModifiedDate] FROM + (VALUES + (1, 'Cell', '20171213 13:19:22.273') + , (2, 'Home', '20171213 13:19:22.273') + , (3, 'Work', '20171213 13:19:22.273') + ) as v ([PhoneNumberTypeID], [Name], [ModifiedDate]) +) + INSERT INTO [Person].[PhoneNumberType] + ([PhoneNumberTypeID], [Name], [ModifiedDate]) + SELECT [PhoneNumberTypeID], [Name], [ModifiedDate] + FROM cte_data; + +END + +-- End data of table: [Person].[PhoneNumberType] -- +END +GO diff --git a/OUTPUT/Person.PhoneNumberType_INSERT.sql b/OUTPUT/Person.PhoneNumberType_INSERT.sql new file mode 100644 index 0000000..c180505 --- /dev/null +++ b/OUTPUT/Person.PhoneNumberType_INSERT.sql @@ -0,0 +1,33 @@ +CREATE PROCEDURE [data].[Populate_Person_PhoneNumberType] +AS +BEGIN +/* + Table's data: [Person].[PhoneNumberType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:07:03 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[PhoneNumberType]'; + +IF NOT EXISTS (SELECT TOP (1) * FROM [Person].[PhoneNumberType]) +BEGIN + + ;WITH cte_data + as (SELECT [PhoneNumberTypeID], [Name], [ModifiedDate] FROM + (VALUES + (1, 'Cell', '20171213 13:19:22.273') + , (2, 'Home', '20171213 13:19:22.273') + , (3, 'Work', '20171213 13:19:22.273') + ) as v ([PhoneNumberTypeID], [Name], [ModifiedDate]) +) + INSERT INTO [Person].[PhoneNumberType] + ([PhoneNumberTypeID], [Name], [ModifiedDate]) + SELECT [PhoneNumberTypeID], [Name], [ModifiedDate] + FROM cte_data; + +END + +-- End data of table: [Person].[PhoneNumberType] -- +END +GO diff --git a/OUTPUT/Person.PhoneNumberType_MERGE.sql b/OUTPUT/Person.PhoneNumberType_MERGE.sql new file mode 100644 index 0000000..9e4e9b5 --- /dev/null +++ b/OUTPUT/Person.PhoneNumberType_MERGE.sql @@ -0,0 +1,45 @@ +CREATE PROCEDURE [data].[Populate_Person_PhoneNumberType] +AS +BEGIN +/* + Table's data: [Person].[PhoneNumberType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:06:49 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[PhoneNumberType]'; + +IF OBJECT_ID('tempdb.dbo.#Person_PhoneNumberType') IS NOT NULL DROP TABLE #Person_PhoneNumberType; +SELECT * INTO #Person_PhoneNumberType FROM [Person].[PhoneNumberType] WHERE 0=1; + +INSERT INTO #Person_PhoneNumberType + ([PhoneNumberTypeID], [Name], [ModifiedDate]) +SELECT CAST([PhoneNumberTypeID] AS int) AS [PhoneNumberTypeID], [Name], [ModifiedDate] FROM +(VALUES + (1, 'Cell', '20171213 13:19:22.273') + , (2, 'Home', '20171213 13:19:22.273') + , (3, 'Work', '20171213 13:19:22.273') +) as v ([PhoneNumberTypeID], [Name], [ModifiedDate]); + + + +WITH cte_data as (SELECT CAST([PhoneNumberTypeID] AS int) AS [PhoneNumberTypeID], [Name], [ModifiedDate] FROM [#Person_PhoneNumberType]) +MERGE [Person].[PhoneNumberType] as t +USING cte_data as s + ON t.[PhoneNumberTypeID] = s.[PhoneNumberTypeID] +WHEN NOT MATCHED BY target THEN + INSERT ([PhoneNumberTypeID], [Name], [ModifiedDate]) + VALUES (s.[PhoneNumberTypeID], s.[Name], s.[ModifiedDate]) +WHEN MATCHED THEN + UPDATE SET + [Name] = s.[Name], [ModifiedDate] = s.[ModifiedDate] +WHEN NOT MATCHED BY source THEN + DELETE +; + +DROP TABLE #Person_PhoneNumberType; + +-- End data of table: [Person].[PhoneNumberType] -- +END +GO diff --git a/OUTPUT/Person.PhoneNumberType_MERGE_NEW_ONLY.sql b/OUTPUT/Person.PhoneNumberType_MERGE_NEW_ONLY.sql new file mode 100644 index 0000000..faa0b84 --- /dev/null +++ b/OUTPUT/Person.PhoneNumberType_MERGE_NEW_ONLY.sql @@ -0,0 +1,40 @@ +CREATE PROCEDURE [data].[Populate_Person_PhoneNumberType] +AS +BEGIN +/* + Table's data: [Person].[PhoneNumberType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:08:00 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[PhoneNumberType]'; + +IF OBJECT_ID('tempdb.dbo.#Person_PhoneNumberType') IS NOT NULL DROP TABLE #Person_PhoneNumberType; +SELECT * INTO #Person_PhoneNumberType FROM [Person].[PhoneNumberType] WHERE 0=1; + +INSERT INTO #Person_PhoneNumberType + ([PhoneNumberTypeID], [Name], [ModifiedDate]) +SELECT CAST([PhoneNumberTypeID] AS int) AS [PhoneNumberTypeID], [Name], [ModifiedDate] FROM +(VALUES + (1, 'Cell', '20171213 13:19:22.273') + , (2, 'Home', '20171213 13:19:22.273') + , (3, 'Work', '20171213 13:19:22.273') +) as v ([PhoneNumberTypeID], [Name], [ModifiedDate]); + + + +WITH cte_data as (SELECT CAST([PhoneNumberTypeID] AS int) AS [PhoneNumberTypeID], [Name], [ModifiedDate] FROM [#Person_PhoneNumberType]) +MERGE [Person].[PhoneNumberType] as t +USING cte_data as s + ON t.[PhoneNumberTypeID] = s.[PhoneNumberTypeID] +WHEN NOT MATCHED BY target THEN + INSERT ([PhoneNumberTypeID], [Name], [ModifiedDate]) + VALUES (s.[PhoneNumberTypeID], s.[Name], s.[ModifiedDate]) +; + +DROP TABLE #Person_PhoneNumberType; + +-- End data of table: [Person].[PhoneNumberType] -- +END +GO diff --git a/OUTPUT/Person.PhoneNumberType_MERGE_without_DELETE.sql b/OUTPUT/Person.PhoneNumberType_MERGE_without_DELETE.sql new file mode 100644 index 0000000..0974074 --- /dev/null +++ b/OUTPUT/Person.PhoneNumberType_MERGE_without_DELETE.sql @@ -0,0 +1,43 @@ +CREATE PROCEDURE [data].[Populate_Person_PhoneNumberType] +AS +BEGIN +/* + Table's data: [Person].[PhoneNumberType] + Data Source: [DEV19].[AdventureWorks2014] + Created on: 18/10/2019 15:07:40 + Scripted by: DEV19\Administrator + Generated by Data Script Writer - ver. 2.0.0.0 +*/ +PRINT 'Populating data into [Person].[PhoneNumberType]'; + +IF OBJECT_ID('tempdb.dbo.#Person_PhoneNumberType') IS NOT NULL DROP TABLE #Person_PhoneNumberType; +SELECT * INTO #Person_PhoneNumberType FROM [Person].[PhoneNumberType] WHERE 0=1; + +INSERT INTO #Person_PhoneNumberType + ([PhoneNumberTypeID], [Name], [ModifiedDate]) +SELECT CAST([PhoneNumberTypeID] AS int) AS [PhoneNumberTypeID], [Name], [ModifiedDate] FROM +(VALUES + (1, 'Cell', '20171213 13:19:22.273') + , (2, 'Home', '20171213 13:19:22.273') + , (3, 'Work', '20171213 13:19:22.273') +) as v ([PhoneNumberTypeID], [Name], [ModifiedDate]); + + + +WITH cte_data as (SELECT CAST([PhoneNumberTypeID] AS int) AS [PhoneNumberTypeID], [Name], [ModifiedDate] FROM [#Person_PhoneNumberType]) +MERGE [Person].[PhoneNumberType] as t +USING cte_data as s + ON t.[PhoneNumberTypeID] = s.[PhoneNumberTypeID] +WHEN NOT MATCHED BY target THEN + INSERT ([PhoneNumberTypeID], [Name], [ModifiedDate]) + VALUES (s.[PhoneNumberTypeID], s.[Name], s.[ModifiedDate]) +WHEN MATCHED THEN + UPDATE SET + [Name] = s.[Name], [ModifiedDate] = s.[ModifiedDate] +; + +DROP TABLE #Person_PhoneNumberType; + +-- End data of table: [Person].[PhoneNumberType] -- +END +GO diff --git a/Program.cs b/Program.cs index 646421f..cbfc229 100644 --- a/Program.cs +++ b/Program.cs @@ -14,6 +14,8 @@ static class Program [STAThread] static void Main() { + SqlServerTypes.Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory); + Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new frmMain()); diff --git a/Properties/AssemblyInfo.cs b/Properties/AssemblyInfo.cs index 7c186b2..51f3087 100644 --- a/Properties/AssemblyInfo.cs +++ b/Properties/AssemblyInfo.cs @@ -31,5 +31,5 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("2.2.0.0")] -[assembly: AssemblyFileVersion("2.2.0.0")] +[assembly: AssemblyVersion("2.3.0.0")] +[assembly: AssemblyFileVersion("2.3.0.0")] diff --git a/Properties/Resources.Designer.cs b/Properties/Resources.Designer.cs index 2cab982..fa35389 100644 --- a/Properties/Resources.Designer.cs +++ b/Properties/Resources.Designer.cs @@ -120,6 +120,27 @@ internal static string LoadColumnInfo { } } + /// + /// Looks up a localized string similar to DECLARE @Tablename nvarchar(100) = '{0}'; + ///DECLARE @oid BIGINT = ( + ///SELECT o.object_id from sys.objects o + ///INNER JOIN sys.schemas s on s.schema_id = o.schema_id + ///WHERE o.name = parsename(@TableName, 1) and s.name = parsename(@TableName, 2) + ///); + ///WITH cc as ( + /// SELECT c.name as COLUMN_NAME, c.is_identity, c.generated_always_type + /// from sys.objects o + /// INNER JOIN sys.columns c ON c.object_id = o.object_id + /// WHERE o.object_id = @oid + ///) + ///select c.ORDINAL_POSITION, c.COLUMN_NAME, c.DATA_TYPE, co.c [rest of string was truncated]";. + /// + internal static string LoadColumnInfo2016andLater { + get { + return ResourceManager.GetString("LoadColumnInfo2016andLater", resourceCulture); + } + } + /// /// Looks up a localized string similar to ;WITH tbs AS /// ( @@ -129,7 +150,7 @@ internal static string LoadColumnInfo { /// FROM sys.tables t (NOLOCK) /// INNER JOIN sys.schemas s (NOLOCK) ON s.schema_id = t.schema_id /// INNER JOIN sys.partitions p (NOLOCK) ON p.object_id = t.object_id - /// WHERE t.is_ms_shipped = 0 + /// WHERE t.is_ms_shipped = 0 and p.index_id <= 1 /// ) ///SELECT SchemaName, TableName, SUM(rows) AS RowCnt ///FROM tbs diff --git a/Properties/Resources.resx b/Properties/Resources.resx index 896e0c6..ad3c9c9 100644 --- a/Properties/Resources.resx +++ b/Properties/Resources.resx @@ -139,7 +139,7 @@ FROM sys.tables t (NOLOCK) INNER JOIN sys.schemas s (NOLOCK) ON s.schema_id = t.schema_id INNER JOIN sys.partitions p (NOLOCK) ON p.object_id = t.object_id - WHERE t.is_ms_shipped = 0 + WHERE t.is_ms_shipped = 0 and p.index_id <= 1 ) SELECT SchemaName, TableName, SUM(rows) AS RowCnt FROM tbs @@ -173,4 +173,34 @@ LEFT JOIN cc ON cc.COLUMN_NAME = c.COLUMN_NAME where c.table_name = parsename(@TableName, 1) and c.table_schema = parsename(@TableName, 2) ; + + DECLARE @Tablename nvarchar(100) = '{0}'; +DECLARE @oid BIGINT = ( +SELECT o.object_id from sys.objects o +INNER JOIN sys.schemas s on s.schema_id = o.schema_id +WHERE o.name = parsename(@TableName, 1) and s.name = parsename(@TableName, 2) +); +WITH cc as ( + SELECT c.name as COLUMN_NAME, c.is_identity, c.generated_always_type + from sys.objects o + INNER JOIN sys.columns c ON c.object_id = o.object_id + WHERE o.object_id = @oid +) +select c.ORDINAL_POSITION, c.COLUMN_NAME, c.DATA_TYPE, co.constraint_type, quotename(c.COLUMN_NAME) as Q_COLUMN_NAME, cc.is_identity, cc.generated_always_type +from information_schema.columns c +LEFT JOIN ( + select tc.TABLE_SCHEMA, tc.TABLE_NAME, kcu.COLUMN_NAME, tc.constraint_type + from information_schema.table_constraints tc + join information_schema.key_column_usage kcu on + tc.table_name = kcu.table_name and + tc.constraint_name = kcu.constraint_name + where tc.table_name = parsename(@TableName, 1) and + tc.table_schema = parsename(@TableName, 2) and + tc.constraint_type = 'PRIMARY KEY' +) as co on co.TABLE_SCHEMA = c.TABLE_SCHEMA and co.TABLE_NAME = c.TABLE_NAME and co.COLUMN_NAME = c.COLUMN_NAME +LEFT JOIN cc ON cc.COLUMN_NAME = c.COLUMN_NAME +where c.table_name = parsename(@TableName, 1) +and c.table_schema = parsename(@TableName, 2) +and cc.generated_always_type = 0 + \ No newline at end of file diff --git a/Properties/Settings.Designer.cs b/Properties/Settings.Designer.cs index 7facb07..47846d9 100644 --- a/Properties/Settings.Designer.cs +++ b/Properties/Settings.Designer.cs @@ -12,7 +12,7 @@ namespace DataScriptWriter.Properties { [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "15.9.0.0")] + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("Microsoft.VisualStudio.Editors.SettingsDesigner.SettingsSingleFileGenerator", "16.6.0.0")] internal sealed partial class Settings : global::System.Configuration.ApplicationSettingsBase { private static Settings defaultInstance = ((Settings)(global::System.Configuration.ApplicationSettingsBase.Synchronized(new Settings()))); diff --git a/README.md b/README.md index 3611c2d..17da80b 100644 --- a/README.md +++ b/README.md @@ -9,3 +9,7 @@ https://github.com/SQLPlayer/DataScriptWriter/releases/ Blog post & video: - [Script and deploy the data for database from SSDT project](https://sqlplayer.net/2019/10/script-deploy-the-data-for-database-from-ssdt-project/) - [SSDT: Scripting static data from SQL Server (video)](https://sqlplayer.net/2020/04/ssdt-scripting-static-data-from-sql-server-video/) + + +# Screenshot +![](.\images\data-script-writer-selecting.png) \ No newline at end of file diff --git a/ScriptWriter.cs b/ScriptWriter.cs index 5cb1ea6..dc9e0ee 100644 --- a/ScriptWriter.cs +++ b/ScriptWriter.cs @@ -21,7 +21,7 @@ public ScriptWriter(CAMOsoft.DbUtils.MsSqlSession db, string outputFolder) { _db = db; _OutputFolder = outputFolder; - string sql = "SELECT @@SPID AS SPID, SUSER_NAME() AS UserName, DB_NAME() AS DbName, @@SERVERNAME AS ServerName;"; + string sql = "SELECT @@SPID AS SPID, SUSER_NAME() AS UserName, DB_NAME() AS DbName, @@SERVERNAME AS ServerName, @@VERSION as ServerVersion;"; _ServerInfoRow = _db.SelectRow(sql); InitTable(); } @@ -88,12 +88,19 @@ private string GetColListWithCastForPK(DataTable dt) private DataTable LoadColumnsInfo(ScriptObject so) { - string sql = Properties.Resources.ResourceManager.GetString("LoadColumnInfo"); + string queryDef = "LoadColumnInfo"; + if (IsSQLServer2016orLater()) queryDef = "LoadColumnInfo2016andLater"; + string sql = Properties.Resources.ResourceManager.GetString(queryDef); sql = sql.Replace("{0}", so.FullName); DataTable dt = _db.SelectTable(sql, "ColumnInfo"); return dt; } + private bool IsSQLServer2016orLater() + { + return (this.ServerVersion.StartsWith("Microsoft SQL Azure") || this.ServerVersion.CompareTo("Microsoft SQL Server 2016") > 0); + } + private StringBuilder SerializeRowValues(DataRow row, DataTable colInfoTable, string prefix, string suffix) { StringBuilder sb = new StringBuilder(); @@ -283,7 +290,7 @@ private void ScriptTableMerge(ScriptObject so, DataTable colInfoTable, DataTable bool useIdentity = hasIdentity(colInfoTable); w.WriteLine(String.Format("IF OBJECT_ID('tempdb.dbo.{0}') IS NOT NULL DROP TABLE {0};", tmpTableName)); - w.WriteLine(String.Format("SELECT * INTO {1} FROM {0} WHERE 0=1;", so.FullQuoted, tmpTableName)); + w.WriteLine(String.Format("SELECT {2} INTO {1} FROM {0} WHERE 0=1;", so.FullQuoted, tmpTableName, colList)); w.WriteLine(_BatchSeparator); if (useIdentity) @@ -439,6 +446,14 @@ public string ServerName } } + public string ServerVersion + { + get + { + return _ServerInfoRow["ServerVersion"].ToString(); + } + } + public DataTable TableList { get diff --git a/SqlServerTypes/Loader.cs b/SqlServerTypes/Loader.cs new file mode 100644 index 0000000..ce606cf --- /dev/null +++ b/SqlServerTypes/Loader.cs @@ -0,0 +1,45 @@ +using System; +using System.IO; +using System.Runtime.InteropServices; + +namespace SqlServerTypes +{ + /// + /// Utility methods related to CLR Types for SQL Server + /// + public class Utilities + { + [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)] + private static extern IntPtr LoadLibrary(string libname); + + /// + /// Loads the required native assemblies for the current architecture (x86 or x64) + /// + /// + /// Root path of the current application. Use Server.MapPath(".") for ASP.NET applications + /// and AppDomain.CurrentDomain.BaseDirectory for desktop applications. + /// + public static void LoadNativeAssemblies(string rootApplicationPath) + { + var nativeBinaryPath = IntPtr.Size > 4 + ? Path.Combine(rootApplicationPath, @"SqlServerTypes\x64\") + : Path.Combine(rootApplicationPath, @"SqlServerTypes\x86\"); + + LoadNativeAssembly(nativeBinaryPath, "msvcr120.dll"); + LoadNativeAssembly(nativeBinaryPath, "SqlServerSpatial140.dll"); + } + + private static void LoadNativeAssembly(string nativeBinaryPath, string assemblyName) + { + var path = Path.Combine(nativeBinaryPath, assemblyName); + var ptr = LoadLibrary(path); + if (ptr == IntPtr.Zero) + { + throw new Exception(string.Format( + "Error loading {0} (ErrorCode: {1})", + assemblyName, + Marshal.GetLastWin32Error())); + } + } + } +} \ No newline at end of file diff --git a/SqlServerTypes/readme.htm b/SqlServerTypes/readme.htm new file mode 100644 index 0000000..02d9ac8 --- /dev/null +++ b/SqlServerTypes/readme.htm @@ -0,0 +1,61 @@ + + + + Microsoft.SqlServer.Types + + + +
+

Action required to load native assemblies

+

+ To deploy an application that uses spatial data types to a machine that does not have 'System CLR Types for SQL Server' installed you also need to deploy the native assembly SqlServerSpatial140.dll. Both x86 (32 bit) and x64 (64 bit) versions of this assembly have been added to your project under the SqlServerTypes\x86 and SqlServerTypes\x64 subdirectories. The native assembly msvcr120.dll is also included in case the C++ runtime is not installed. +

+

+ You need to add code to load the correct one of these assemblies at runtime (depending on the current architecture). +

+

ASP.NET Web Sites

+

+ For ASP.NET Web Sites, add the following block of code to the code behind file of the Web Form where you have added Report Viewer Control: +

+    Default.aspx.cs:
+        
+    public partial class _Default : System.Web.UI.Page
+    {
+        static bool _isSqlTypesLoaded = false;
+
+        public _Default()
+        {
+            if (!_isSqlTypesLoaded)
+            {
+                SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~"));
+                _isSqlTypesLoaded = true;
+            }
+            
+        }
+    }
+
+

+

ASP.NET Web Applications

+

+ For ASP.NET Web Applications, add the following line of code to the Application_Start method in Global.asax.cs: +

    SqlServerTypes.Utilities.LoadNativeAssemblies(Server.MapPath("~/bin"));
+

+

Desktop Applications

+

+ For desktop applications, add the following line of code to run before any spatial operations are performed: +

    SqlServerTypes.Utilities.LoadNativeAssemblies(AppDomain.CurrentDomain.BaseDirectory);
+

+
+ + \ No newline at end of file diff --git a/images/data-script-writer-selecting.png b/images/data-script-writer-selecting.png new file mode 100644 index 0000000..4c87c65 Binary files /dev/null and b/images/data-script-writer-selecting.png differ diff --git a/packages.config b/packages.config new file mode 100644 index 0000000..e4120d3 --- /dev/null +++ b/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file