diff --git a/Build/Build.ssmssqlproj b/Build/Build.ssmssqlproj
index a18b2220d..07d36eead 100644
--- a/Build/Build.ssmssqlproj
+++ b/Build/Build.ssmssqlproj
@@ -103,6 +103,12 @@
GrantBuildPermissions.sql
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ GrantUserAccessToRemoteDatabase.sql
+
8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
Dev_tSQLt
diff --git a/Build/GrantUserAccessToRemoteDatabase.sql b/Build/GrantUserAccessToRemoteDatabase.sql
new file mode 100644
index 000000000..99aabfa37
--- /dev/null
+++ b/Build/GrantUserAccessToRemoteDatabase.sql
@@ -0,0 +1,7 @@
+IF EXISTS ( SELECT 1
+ FROM sys.databases
+ WHERE name = 'tSQLt_RemoteSynonymsTestDatabase' )
+ BEGIN
+
+ EXEC dbo.sp_changedbowner @loginame = N'tSQLt.Build';
+ END;
\ No newline at end of file
diff --git a/Build/tSQLt.build b/Build/tSQLt.build
index fc96ac43e..0fd6e9e8a 100644
--- a/Build/tSQLt.build
+++ b/Build/tSQLt.build
@@ -261,6 +261,7 @@
+
@@ -286,6 +287,7 @@
+
diff --git a/Build/tSQLt.build.xml b/Build/tSQLt.build.xml
index b39bd865a..ac65e01bc 100644
--- a/Build/tSQLt.build.xml
+++ b/Build/tSQLt.build.xml
@@ -275,6 +275,7 @@
+
@@ -300,6 +301,7 @@
+
diff --git a/Build/tSQLt.validatebuild b/Build/tSQLt.validatebuild
index 36349b27b..a8cfa2569 100644
--- a/Build/tSQLt.validatebuild
+++ b/Build/tSQLt.validatebuild
@@ -238,6 +238,10 @@
+
+
+
+
diff --git a/Build/tSQLt.validatebuild.xml b/Build/tSQLt.validatebuild.xml
index af001c0f6..6b85835a0 100644
--- a/Build/tSQLt.validatebuild.xml
+++ b/Build/tSQLt.validatebuild.xml
@@ -341,6 +341,12 @@
+
+
+
+
+
+
diff --git a/Source/BuildOrder.txt b/Source/BuildOrder.txt
index fb97a1066..59a4d771f 100644
--- a/Source/BuildOrder.txt
+++ b/Source/BuildOrder.txt
@@ -4,10 +4,20 @@ tSQLt.Private_Bin2Hex.sfn.sql
tSQLt.Private_NewTestClassList.tbl.sql
tSQLt.Private_ResetNewTestClassList.ssp.sql
tSQLt.Private_SysTypes.svw.sql
+tSQLt.Private_SysColumns.svw.sql
+tSQLt.Private_SysComputedColumns.svw.sql
+tSQLt.Private_SysDefaultConstraints.svw.sql
+tSQLt.Private_SysIdentityColumns.svw.sql
+tSQLt.Private_SysObjects.svw.sql
+tSQLt.Private_SysSchemas.svw.sql
tSQLt.Private_GetFullTypeName.sfn.sql
tSQLt.Private_DisallowOverwritingNonTestSchema.ssp.sql
+tSQLt.Private_CreateRemoteSysObjects.ssp.sql
+tSQLt.Private_GetRemoteObjectId.ssp.sql
+tSQLt.Private_AlterSysObjectForRemote.ssp.sql
tSQLt.Private_QuoteClassNameForNewTestClass.sfn.sql
tSQLt.Private_MarkSchemaAsTestClass.ssp.sql
+tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable.ssp.sql
tSQLt.NewTestClass.ssp.sql
tSQLt.Fail.ssp.sql
tSQLt.class.sql
@@ -48,6 +58,7 @@ tSQLt.Private_GetDataTypeOrComputedColumnDefinition.sfn.sql
tSQLt.Private_GetIdentityDefinition.sfn.sql
tSQLt.Private_GetDefaultConstraintDefinition.sfn.sql
tSQLt.Private_GetUniqueConstraintDefinition.sfn.sql
+tSQLt.Private_CreateRemoteUserDefinedDataTypes.ssp.sql
tSQLt.Private_CreateFakeOfTable.ssp.sql
tSQLt.Private_MarkFakeTable.ssp.sql
tSQLt.FakeTable.ssp.sql
diff --git a/Source/Source.ssmssqlproj b/Source/Source.ssmssqlproj
index 01b2d9a4d..0ee169c6a 100644
--- a/Source/Source.ssmssqlproj
+++ b/Source/Source.ssmssqlproj
@@ -205,6 +205,12 @@
tSQLt.NewTestClass.ssp.sql
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_AlterSysObjectForRemote.ssp.sql
+
8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
Dev_tSQLt
@@ -241,6 +247,18 @@
tSQLt.Private_CreateFakeFunction.ssp.sql
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_CreateRemoteSysObjects.ssp.sql
+
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_CreateRemoteUserDefinedDataTypes.ssp.sql
+
8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
Dev_tSQLt
@@ -295,6 +313,12 @@
tSQLt.Private_GetForeignKeyDefinition.sfn.sql
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_GetRemoteObjectId.ssp.sql
+
8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
Dev_tSQLt
@@ -421,12 +445,48 @@
tSQLt.Private_SqlVersion.sfn.sql
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_SysColumns.svw.sql
+
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_SysComputedColumns.svw.sql
+
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_SysDefaultConstraints.svw.sql
+
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_SysIdentityColumns.svw.sql
+
8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
Dev_tSQLt
tSQLt.Private_SysIndexes.svw.sql
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_SysObjects.svw.sql
+
+
+ 8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
+ Dev_tSQLt
+
+ tSQLt.Private_SysSchemas.svw.sql
+
8c91a03d-f9b4-46c0-a305-b5dcc79ff907:Dev_tSQLt:True
Dev_tSQLt
@@ -528,7 +588,7 @@
Dev_tSQLt
tSQLtCLR_CreateProcs.sql
-
+
diff --git a/Source/tSQLt.FakeTable.ssp.sql b/Source/tSQLt.FakeTable.ssp.sql
index a2635edba..680ee3f26 100644
--- a/Source/tSQLt.FakeTable.ssp.sql
+++ b/Source/tSQLt.FakeTable.ssp.sql
@@ -13,15 +13,17 @@ BEGIN
DECLARE @OrigTableName NVARCHAR(MAX);
DECLARE @NewNameOfOriginalTable NVARCHAR(4000);
DECLARE @OrigTableFullName NVARCHAR(MAX); SET @OrigTableFullName = NULL;
-
+ DECLARE @RemoteObjectID INT;
+ DECLARE @SynonymObjectId INT;
+
SELECT @OrigSchemaName = @SchemaName,
@OrigTableName = @TableName
IF(@OrigTableName NOT IN (PARSENAME(@OrigTableName,1),QUOTENAME(PARSENAME(@OrigTableName,1)))
AND @OrigSchemaName IS NOT NULL)
- BEGIN
- RAISERROR('When @TableName is a multi-part identifier, @SchemaName must be NULL!',16,10);
- END
+ BEGIN
+ RAISERROR('When @TableName is a multi-part identifier, @SchemaName must be NULL!',16,10);
+ END
SELECT @SchemaName = CleanSchemaName,
@TableName = CleanTableName
@@ -31,25 +33,27 @@ BEGIN
EXEC tSQLt.Private_RenameObjectToUniqueName @SchemaName, @TableName, @NewNameOfOriginalTable OUTPUT;
- SELECT @OrigTableFullName = S.base_object_name
- FROM sys.synonyms AS S
- WHERE S.object_id = OBJECT_ID(@SchemaName + '.' + @NewNameOfOriginalTable);
- IF(@OrigTableFullName IS NOT NULL)
- BEGIN
- IF(COALESCE(OBJECT_ID(@OrigTableFullName,'U'),OBJECT_ID(@OrigTableFullName,'V')) IS NULL)
- BEGIN
- RAISERROR('Cannot fake synonym %s.%s as it is pointing to %s, which is not a table or view!',16,10,@SchemaName,@TableName,@OrigTableFullName);
- END;
- END;
- ELSE
- BEGIN
- SET @OrigTableFullName = @SchemaName + '.' + @NewNameOfOriginalTable;
- END;
+ SET @OrigTableFullName = @SchemaName + '.' + @NewNameOfOriginalTable;
+ SET @SynonymObjectId = OBJECT_ID(@OrigTableFullName, 'SN');
+ IF ( @SynonymObjectId > 0)
+ BEGIN
+ EXEC tSQLt.Private_GetRemoteObjectId @SynonymObjectId = @SynonymObjectId ,
+ @RemoteObjectId = @RemoteObjectID OUTPUT,
+ @OrigTableFullName = @OrigTableFullName OUTPUT
- EXEC tSQLt.Private_CreateFakeOfTable @SchemaName, @TableName, @OrigTableFullName, @Identity, @ComputedColumns, @Defaults;
+ EXEC tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable @TableName, @SchemaName, @OrigTableFullName;
+ END;
+
+ EXEC tSQLt.Private_CreateFakeOfTable @SchemaName, @TableName, @OrigTableFullName, @Identity, @ComputedColumns, @Defaults, @RemoteObjectID;
EXEC tSQLt.Private_MarkFakeTable @SchemaName, @TableName, @NewNameOfOriginalTable;
+
+ IF (@RemoteObjectID IS NOT NULL)
+ BEGIN
+ EXEC tSQLt.Private_CreateRemoteSysObjects @Instance = NULL, @Database = NULL;
+ END
+
END
---Build-
GO
diff --git a/Source/tSQLt.Private_AlterSysObjectForRemote.ssp.sql b/Source/tSQLt.Private_AlterSysObjectForRemote.ssp.sql
new file mode 100644
index 000000000..3f966576e
--- /dev/null
+++ b/Source/tSQLt.Private_AlterSysObjectForRemote.ssp.sql
@@ -0,0 +1,49 @@
+IF OBJECT_ID('tSQLt.Private_AlterSysObjectForRemote') IS NOT NULL
+ DROP PROCEDURE tSQLt.Private_AlterSysObjectForRemote;
+GO
+---Build+
+CREATE PROCEDURE tSQLt.Private_AlterSysObjectForRemote
+ @Instance NVARCHAR(MAX) ,
+ @Database NVARCHAR(MAX) ,
+ @SysObject NVARCHAR(MAX) ,
+ @PrivateViewName NVARCHAR(MAX)
+AS
+ BEGIN
+ DECLARE @sql NVARCHAR(MAX);
+ SET @sql = 'ALTER VIEW tSQLt.' + @PrivateViewName + ' AS
+ SELECT ' +
+ CASE WHEN @SysObject = 'types' THEN '
+ name ,
+ system_type_id ,
+ user_type_id ,
+ CASE WHEN is_user_defined = 1 THEN 1
+ ELSE schema_id
+ END AS schema_id ,
+ principal_id ,
+ max_length ,
+ precision ,
+ scale ,
+ collation_name ,
+ is_nullable ,
+ is_user_defined ,
+ is_assembly_type ,
+ default_object_id ,
+ rule_object_id ,
+ is_table_type
+ ' ELSE '* ' END
+ + CASE WHEN CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR(MAX)) LIKE '9.%'
+ AND @SysObject = 'types' THEN ',0 is_table_type'
+ ELSE ''
+ END + ' FROM ' + COALESCE(QUOTENAME(@Instance) + '.', '')
+ + COALESCE(QUOTENAME(@Database) + '.', '') + 'sys.' + @SysObject
+ + ';';
+
+
+
+
+ EXEC (@sql);
+
+ RETURN 0;
+ END;
+---Build-
+GO
\ No newline at end of file
diff --git a/Source/tSQLt.Private_CreateFakeOfTable.ssp.sql b/Source/tSQLt.Private_CreateFakeOfTable.ssp.sql
index af732fd63..3039ccbd4 100644
--- a/Source/tSQLt.Private_CreateFakeOfTable.ssp.sql
+++ b/Source/tSQLt.Private_CreateFakeOfTable.ssp.sql
@@ -7,11 +7,17 @@ CREATE PROCEDURE tSQLt.Private_CreateFakeOfTable
@OrigTableFullName NVARCHAR(MAX),
@Identity BIT,
@ComputedColumns BIT,
- @Defaults BIT
+ @Defaults BIT,
+ @RemoteObjectID INT
AS
BEGIN
DECLARE @Cmd NVARCHAR(MAX);
DECLARE @Cols NVARCHAR(MAX);
+
+ IF (@RemoteObjectID IS NOT NULL)
+ BEGIN
+ EXEC tSQLt.Private_CreateRemoteUserDefinedDataTypes @RemoteObjectID = @RemoteObjectID
+ END
SELECT @Cols =
(
@@ -25,11 +31,11 @@ BEGIN
THEN ''
ELSE ' NULL'
END
- FROM sys.columns c
+ FROM tSQLt.Private_SysColumns c
CROSS APPLY tSQLt.Private_GetDataTypeOrComputedColumnDefinition(c.user_type_id, c.max_length, c.precision, c.scale, c.collation_name, c.object_id, c.column_id, @ComputedColumns) cc
CROSS APPLY tSQLt.Private_GetDefaultConstraintDefinition(c.object_id, c.column_id, @Defaults) AS dc
CROSS APPLY tSQLt.Private_GetIdentityDefinition(c.object_id, c.column_id, @Identity) AS id
- WHERE object_id = OBJECT_ID(@OrigTableFullName)
+ WHERE object_id = COALESCE(@RemoteObjectID, OBJECT_ID(@OrigTableFullName))
ORDER BY column_id
FOR XML PATH(''), TYPE
).value('.', 'NVARCHAR(MAX)');
diff --git a/Source/tSQLt.Private_CreateRemoteSysObjects.ssp.sql b/Source/tSQLt.Private_CreateRemoteSysObjects.ssp.sql
new file mode 100644
index 000000000..8cbb84a6d
--- /dev/null
+++ b/Source/tSQLt.Private_CreateRemoteSysObjects.ssp.sql
@@ -0,0 +1,52 @@
+IF OBJECT_ID('tSQLt.Private_CreateRemoteSysObjects') IS NOT NULL
+ DROP PROCEDURE tSQLt.Private_CreateRemoteSysObjects;
+GO
+---Build+
+CREATE PROCEDURE tSQLt.Private_CreateRemoteSysObjects
+ @Instance NVARCHAR(MAX) ,
+ @Database NVARCHAR(MAX)
+AS
+ BEGIN
+ DECLARE @SysObject NVARCHAR(MAX);
+ DECLARE @ViewName NVARCHAR(MAX);
+
+
+ DECLARE @SysObjects AS TABLE
+ (
+ SysObject NVARCHAR(MAX) ,
+ ViewName NVARCHAR(MAX)
+ );
+ INSERT INTO @SysObjects
+ VALUES ( 'types', 'Private_SysTypes' ),
+ ( 'computed_columns', 'Private_SysComputedColumns' ),
+ ( 'default_constraints', 'Private_SysDefaultConstraints' ),
+ ( 'identity_columns', 'Private_SysIdentityColumns' ),
+ ( 'columns', 'Private_SysColumns' ),
+ ( 'objects', 'Private_SysObjects' ),
+ ( 'schemas', 'Private_SysSchemas' );
+
+ DECLARE @cursor AS CURSOR;
+
+ SET @cursor = CURSOR FOR
+SELECT SysObject, ViewName
+ FROM @SysObjects;
+
+ OPEN @cursor;
+ FETCH NEXT FROM @cursor INTO @SysObject, @ViewName;
+
+ WHILE @@FETCH_STATUS = 0
+ BEGIN
+ EXEC tSQLt.Private_AlterSysObjectForRemote @Instance = @Instance,
+ @Database = @Database, @SysObject = @SysObject,
+ @PrivateViewName = @ViewName;
+
+ FETCH NEXT FROM @cursor INTO @SysObject, @ViewName;
+ END;
+
+ CLOSE @cursor;
+ DEALLOCATE @cursor;
+
+ RETURN 0;
+ END;
+---Build-
+GO
diff --git a/Source/tSQLt.Private_CreateRemoteUserDefinedDataTypes.ssp.sql b/Source/tSQLt.Private_CreateRemoteUserDefinedDataTypes.ssp.sql
new file mode 100644
index 000000000..ec805c1b5
--- /dev/null
+++ b/Source/tSQLt.Private_CreateRemoteUserDefinedDataTypes.ssp.sql
@@ -0,0 +1,58 @@
+IF OBJECT_ID('tSQLt.Private_CreateRemoteUserDefinedDataTypes') IS NOT NULL
+ DROP PROCEDURE tSQLt.Private_CreateRemoteUserDefinedDataTypes;
+GO
+---Build+
+CREATE PROCEDURE tSQLt.Private_CreateRemoteUserDefinedDataTypes @RemoteObjectID INT
+AS
+ BEGIN
+
+ DECLARE @UDDTs NVARCHAR(MAX) = '';
+
+ SELECT @UDDTs = @UDDTs + N'CREATE TYPE ' + QUOTENAME(sch.[name])
+ + N'.' + QUOTENAME(typ.[name]) + N' FROM ' + styp.[name]
+ + CASE WHEN typ.[system_type_id] IN ( 41, 42, 43, 106, 108,
+ 165, 167, 173, 175, 231,
+ 239 )
+ THEN N'('
+ + CASE WHEN typ.[max_length] = -1 -- for: VARCHAR, NVARCHAR, VARBINARY
+ THEN N'MAX'
+ WHEN typ.[system_type_id] IN ( 165, 167,
+ 173, 175 )
+ -- VARBINARY, VARCHAR, BINARY, CHAR
+ THEN CONVERT(NVARCHAR(5), typ.[max_length])
+ WHEN typ.[system_type_id] IN ( 231, 239 ) -- NVARCHAR, NCHAR
+ THEN CONVERT(NVARCHAR(5), ( typ.[max_length]
+ / 2 ))
+ WHEN typ.[system_type_id] IN ( 41, 42, 43 )
+ -- TIME, DATETIME2, DATETIMEOFFSET
+ THEN CONVERT(NVARCHAR(5), typ.[scale])
+ WHEN typ.[system_type_id] IN ( 106, 108 ) -- DECIMAL, NUMERIC
+ THEN CONVERT(NVARCHAR(5), typ.[precision])
+ + N', '
+ + CONVERT(NVARCHAR(5), typ.[scale])
+ END + N')'
+ ELSE N''
+ END + CASE typ.[is_nullable]
+ WHEN 1 THEN N' NULL'
+ ELSE ' NOT NULL'
+ END + N';'
+ FROM tSQLt.Private_SysTypes typ
+ INNER JOIN tSQLt.Private_SysSchemas sch ON sch.[schema_id] = typ.[schema_id]
+ INNER JOIN tSQLt.Private_SysTypes styp ON styp.[user_type_id] = typ.[system_type_id]
+ JOIN tSQLt.Private_SysColumns AS c ON c.user_type_id = typ.user_type_id
+ JOIN tSQLt.Private_SysObjects t ON t.object_id = c.object_id
+ WHERE typ.[is_user_defined] = 1
+ AND typ.[is_assembly_type] = 0
+ AND typ.[is_table_type] = 0
+ AND t.object_id = @RemoteObjectID
+ AND NOT EXISTS ( SELECT 1
+ FROM sys.types t
+ JOIN sys.schemas s ON s.schema_id = t.schema_id
+ AND t.[name] COLLATE SQL_Latin1_General_CP1_CI_AS = typ.[name] COLLATE SQL_Latin1_General_CP1_CI_AS
+ AND s.[name] COLLATE SQL_Latin1_General_CP1_CI_AS = sch.[name] COLLATE SQL_Latin1_General_CP1_CI_AS );
+
+ EXEC (@UDDTs);
+
+ END;
+---Build-
+GO
diff --git a/Source/tSQLt.Private_GetDataTypeOrComputedColumnDefinition.sfn.sql b/Source/tSQLt.Private_GetDataTypeOrComputedColumnDefinition.sfn.sql
index 50a397bb1..e06e9b50e 100644
--- a/Source/tSQLt.Private_GetDataTypeOrComputedColumnDefinition.sfn.sql
+++ b/Source/tSQLt.Private_GetDataTypeOrComputedColumnDefinition.sfn.sql
@@ -14,7 +14,7 @@ RETURN SELECT
' AS '+ cci.definition + CASE WHEN cci.is_persisted = 1 THEN ' PERSISTED' ELSE '' END AS ComputedColumnDefinition,
cci.object_id,
cci.column_id
- FROM sys.computed_columns cci
+ FROM tSQLt.Private_SysComputedColumns cci
)cc
ON cc.object_id = V.ObjectId
AND cc.column_id = V.ColumnId
diff --git a/Source/tSQLt.Private_GetDefaultConstraintDefinition.sfn.sql b/Source/tSQLt.Private_GetDefaultConstraintDefinition.sfn.sql
index 9c759c7a0..9ec2f30ff 100644
--- a/Source/tSQLt.Private_GetDefaultConstraintDefinition.sfn.sql
+++ b/Source/tSQLt.Private_GetDefaultConstraintDefinition.sfn.sql
@@ -9,7 +9,7 @@ RETURN SELECT
COALESCE(DefaultDefinition, '') AS DefaultDefinition
FROM (SELECT 1) X(X)
LEFT JOIN (SELECT 1 AS IsDefault,' DEFAULT '+ definition AS DefaultDefinition,parent_object_id,parent_column_id
- FROM sys.default_constraints
+ FROM tSQLt.Private_SysDefaultConstraints
)dc
ON dc.parent_object_id = @ObjectId
AND dc.parent_column_id = @ColumnId
diff --git a/Source/tSQLt.Private_GetIdentityDefinition.sfn.sql b/Source/tSQLt.Private_GetIdentityDefinition.sfn.sql
index 05cbf178e..5ec9831ff 100644
--- a/Source/tSQLt.Private_GetIdentityDefinition.sfn.sql
+++ b/Source/tSQLt.Private_GetIdentityDefinition.sfn.sql
@@ -12,7 +12,7 @@ RETURN SELECT
' IDENTITY(' + CAST(seed_value AS NVARCHAR(MAX)) + ',' + CAST(increment_value AS NVARCHAR(MAX)) + ')' AS IdentityDefinition,
object_id,
column_id
- FROM sys.identity_columns
+ FROM tSQLt.Private_SysIdentityColumns
) AS id
ON id.object_id = @ObjectId
AND id.column_id = @ColumnId
diff --git a/Source/tSQLt.Private_GetRemoteObjectId.ssp.sql b/Source/tSQLt.Private_GetRemoteObjectId.ssp.sql
new file mode 100644
index 000000000..aff4db86a
--- /dev/null
+++ b/Source/tSQLt.Private_GetRemoteObjectId.ssp.sql
@@ -0,0 +1,47 @@
+IF OBJECT_ID('tSQLt.Private_GetRemoteObjectId') IS NOT NULL
+ DROP PROCEDURE tSQLt.Private_GetRemoteObjectId;
+GO
+---Build+
+GO
+CREATE PROCEDURE tSQLt.Private_GetRemoteObjectId
+ @SynonymObjectId INT ,
+ @RemoteObjectId INT OUTPUT ,
+ @OrigTableFullName sysname OUTPUT
+AS
+ BEGIN
+ DECLARE @Database NVARCHAR(MAX);
+ DECLARE @Instance NVARCHAR(MAX);
+
+ SELECT @OrigTableFullName = S.base_object_name ,
+ @Database = PARSENAME(S.base_object_name, 3) ,
+ @Instance = PARSENAME(S.base_object_name, 4)
+ FROM sys.synonyms AS S
+ WHERE S.object_id = @SynonymObjectId;
+
+ DECLARE @RemotePath NVARCHAR(MAX) = COALESCE(QUOTENAME(PARSENAME(@OrigTableFullName,
+ 4)) + '.', '')
+ + QUOTENAME(PARSENAME(@OrigTableFullName, 3));
+ DECLARE @Cmd NVARCHAR(MAX);
+ DECLARE @params NVARCHAR(MAX) = '@RemoteObjectID INT OUT, @OrigTableFullName NVARCHAR(MAX)';
+ SET @Cmd = '
+ SELECT @RemoteObjectID = o.object_id
+ FROM ' + @RemotePath + '.sys.objects o
+ JOIN ' + @RemotePath
+ + '.sys.schemas s ON s.schema_id = o.schema_id
+ WHERE s.name = PARSENAME(@OrigTableFullName, 2)
+ AND o.name = PARSENAME(@OrigTableFullName, 1)
+ AND o.type IN ( ''U'', ''V'' );';
+
+ EXEC sp_executesql @Cmd, @params, @RemoteObjectID OUT,
+ @OrigTableFullName;
+
+
+ IF ( @RemoteObjectID > 0 )
+ BEGIN
+ EXEC tSQLt.Private_CreateRemoteSysObjects @Instance = @Instance,
+ @Database = @Database;
+ END;
+ END;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_SysColumns.svw.sql b/Source/tSQLt.Private_SysColumns.svw.sql
new file mode 100644
index 000000000..e594f34bd
--- /dev/null
+++ b/Source/tSQLt.Private_SysColumns.svw.sql
@@ -0,0 +1,8 @@
+IF OBJECT_ID('tSQLt.Private_SysColumns') IS NOT NULL DROP VIEW tSQLt.Private_SysColumns;
+GO
+---Build+
+GO
+CREATE VIEW tSQLt.Private_SysColumns AS SELECT * FROM sys.columns AS cc;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_SysComputedColumns.svw.sql b/Source/tSQLt.Private_SysComputedColumns.svw.sql
new file mode 100644
index 000000000..13414a842
--- /dev/null
+++ b/Source/tSQLt.Private_SysComputedColumns.svw.sql
@@ -0,0 +1,8 @@
+IF OBJECT_ID('tSQLt.Private_SysComputedColumns') IS NOT NULL DROP VIEW tSQLt.Private_SysComputedColumns;
+GO
+---Build+
+GO
+CREATE VIEW tSQLt.Private_SysComputedColumns AS SELECT * FROM sys.computed_columns AS cc;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_SysDefaultConstraints.svw.sql b/Source/tSQLt.Private_SysDefaultConstraints.svw.sql
new file mode 100644
index 000000000..e6250e2bc
--- /dev/null
+++ b/Source/tSQLt.Private_SysDefaultConstraints.svw.sql
@@ -0,0 +1,8 @@
+IF OBJECT_ID('tSQLt.Private_SysDefaultConstraints') IS NOT NULL DROP VIEW tSQLt.Private_SysDefaultConstraints;
+GO
+---Build+
+GO
+CREATE VIEW tSQLt.Private_SysDefaultConstraints AS SELECT * FROM sys.default_constraints AS cc;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_SysIdentityColumns.svw.sql b/Source/tSQLt.Private_SysIdentityColumns.svw.sql
new file mode 100644
index 000000000..202df612e
--- /dev/null
+++ b/Source/tSQLt.Private_SysIdentityColumns.svw.sql
@@ -0,0 +1,8 @@
+IF OBJECT_ID('tSQLt.Private_SysIdentityColumns') IS NOT NULL DROP VIEW tSQLt.Private_SysIdentityColumns;
+GO
+---Build+
+GO
+CREATE VIEW tSQLt.Private_SysIdentityColumns AS SELECT * FROM sys.identity_columns AS cc;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_SysObjects.svw.sql b/Source/tSQLt.Private_SysObjects.svw.sql
new file mode 100644
index 000000000..7a8240f2f
--- /dev/null
+++ b/Source/tSQLt.Private_SysObjects.svw.sql
@@ -0,0 +1,8 @@
+IF OBJECT_ID('tSQLt.Private_SysObjects') IS NOT NULL DROP VIEW tSQLt.Private_SysObjects;
+GO
+---Build+
+GO
+CREATE VIEW tSQLt.Private_SysObjects AS SELECT * FROM sys.objects AS cc;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_SysSchemas.svw.sql b/Source/tSQLt.Private_SysSchemas.svw.sql
new file mode 100644
index 000000000..2ef39844a
--- /dev/null
+++ b/Source/tSQLt.Private_SysSchemas.svw.sql
@@ -0,0 +1,8 @@
+IF OBJECT_ID('tSQLt.Private_SysSchemas') IS NOT NULL DROP VIEW tSQLt.Private_SysSchemas;
+GO
+---Build+
+GO
+CREATE VIEW tSQLt.Private_SysSchemas AS SELECT * FROM sys.schemas AS cc;
+GO
+---Build-
+GO
diff --git a/Source/tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable.ssp.sql b/Source/tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable.ssp.sql
new file mode 100644
index 000000000..aaaf34bb4
--- /dev/null
+++ b/Source/tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable.ssp.sql
@@ -0,0 +1,24 @@
+IF OBJECT_ID('tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable') IS NOT NULL
+ DROP PROCEDURE tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable;
+GO
+---Build+
+GO
+CREATE PROCEDURE tSQLt.Private_ValidateSynonymCompatibilityWithFakeTable
+ @TableName sysname ,
+ @SchemaName sysname ,
+ @OrigTableFullName sysname
+AS
+ BEGIN
+
+ IF NOT EXISTS ( SELECT 1
+ FROM tSQLt.Private_SysObjects o
+ JOIN tSQLt.Private_SysSchemas s ON s.schema_id = o.schema_id
+ WHERE o.type IN ( 'U', 'V' )
+ AND o.name = PARSENAME(@OrigTableFullName, 1)
+ AND s.name = PARSENAME(@OrigTableFullName, 2) )
+ BEGIN
+ RAISERROR('Cannot fake synonym %s.%s as it is pointing to %s, which is not a table or view!',16,10,@SchemaName,@TableName,@OrigTableFullName);
+ END;
+ END;
+GO
+
\ No newline at end of file
diff --git a/TestUtil/BuildOrder.txt b/TestUtil/BuildOrder.txt
index 161d9d007..a89126bf7 100644
--- a/TestUtil/BuildOrder.txt
+++ b/TestUtil/BuildOrder.txt
@@ -3,3 +3,4 @@ tSQLt_testutil.class.sql
../Build/temp/GetUnsignedEmptyBytes.sql
tSQLtTestUtilCLR_CreateItems.sql
tSQLt_testutil_test.class.sql
+tSQLt_RemoteSynonymsTestDatabase.db.sql
\ No newline at end of file
diff --git a/TestUtil/tSQLt_RemoteSynonymsTestDatabase.db.sql b/TestUtil/tSQLt_RemoteSynonymsTestDatabase.db.sql
new file mode 100644
index 000000000..40388ef28
--- /dev/null
+++ b/TestUtil/tSQLt_RemoteSynonymsTestDatabase.db.sql
@@ -0,0 +1,123 @@
+IF NOT EXISTS ( SELECT *
+ FROM sys.databases
+ WHERE name = 'tSQLt_RemoteSynonymsTestDatabase' )
+ BEGIN
+ CREATE DATABASE tSQLt_RemoteSynonymsTestDatabase;
+ END;
+GO
+USE tSQLt_RemoteSynonymsTestDatabase
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.tables t
+ JOIN sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tbl'
+ AND s.name = 'MyTestClass' )
+ BEGIN
+ DROP TABLE MyTestClass.tbl;
+ END;
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.tables t
+ JOIN sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tbli'
+ AND s.name = 'MyTestClass' )
+ BEGIN
+ DROP TABLE MyTestClass.tbli;
+ END;
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.types t
+ JOIN sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'UDT'
+ AND s.name = 'MyTestClass' )
+ BEGIN
+ DROP TYPE MyTestClass.UDT;
+ END;
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.types t
+ JOIN sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'UDTi'
+ AND s.name = 'MyTestClass' )
+ BEGIN
+ DROP TYPE MyTestClass.UDTi;
+ END;
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.schemas
+ WHERE name = 'MyTestClass' )
+ BEGIN
+ DROP SCHEMA MyTestClass;
+ END;
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.objects o
+ JOIN sys.schemas s ON s.schema_id = o.schema_id
+ WHERE o.name = 'TestView'
+ AND s.name = 'dbo' )
+ BEGIN
+ DROP VIEW dbo.TestView;
+ END;
+
+
+IF EXISTS ( SELECT *
+ FROM sys.tables t
+ JOIN sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'TestTable'
+ AND s.name = 'dbo' )
+ BEGIN
+ DROP TABLE dbo.TestTable;
+ END;
+GO
+
+IF EXISTS ( SELECT *
+ FROM sys.objects o
+ JOIN sys.schemas s ON s.schema_id = o.schema_id
+ WHERE o.name = 'NotATable'
+ AND s.name = 'dbo' )
+ BEGIN
+ DROP PROCEDURE dbo.NotATable;
+ END;
+GO
+
+CREATE TABLE dbo.TestTable
+ (
+ c1 INT NULL ,
+ c2 BIGINT NULL ,
+ c3 VARCHAR(MAX) NULL
+ );
+GO
+CREATE VIEW dbo.TestView
+AS
+ SELECT *
+ FROM dbo.TestTable;;
+GO
+
+CREATE PROCEDURE dbo.NotATable
+AS
+ RETURN;
+GO
+
+CREATE SCHEMA MyTestClass;
+GO
+
+CREATE TYPE MyTestClass.UDT FROM NVARCHAR(20);
+GO
+
+CREATE TABLE MyTestClass.tbl(i MyTestClass.UDT)
+GO
+
+CREATE TYPE MyTestClass.UDTi FROM INT;
+GO
+
+CREATE TABLE MyTestClass.tbli(i MyTestClass.UDTi)
+GO
+
+USE $(NewDbName)
+GO
\ No newline at end of file
diff --git a/Tests/FakeTableTests.class.sql b/Tests/FakeTableTests.class.sql
index 2b6c1c3d7..8d938b21a 100644
--- a/Tests/FakeTableTests.class.sql
+++ b/Tests/FakeTableTests.class.sql
@@ -190,6 +190,18 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test FakeTable works with remote 2 part names in first parameter]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT);
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+END;
+GO
+
CREATE PROC FakeTableTests.[test a faked table has no check constraints]
AS
BEGIN
@@ -202,6 +214,19 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test a faked remote table has no check constraints]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT CHECK(i > 5));
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (5);
+END;
+GO
+
CREATE PROC FakeTableTests.[test a faked table has no foreign keys]
AS
BEGIN
@@ -215,6 +240,22 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test a faked remote table has no foreign keys]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable0(i INT PRIMARY KEY);
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT REFERENCES tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable0(i));
+
+ CREATE SYNONYM FakeTableTests.TempTable0 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable0;
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (5);
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable: a faked table has any defaults removed]
AS
BEGIN
@@ -233,6 +274,25 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable: a faked table has any defaults removed]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT DEFAULT(77));
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+ INSERT INTO FakeTableTests.TempTable1 (i) DEFAULT VALUES;
+
+ DECLARE @value INT;
+ SELECT @value = i
+ FROM FakeTableTests.TempTable1;
+
+ EXEC tSQLt.AssertEquals NULL, @value;
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable: a faked table has any unique constraints removed]
AS
BEGIN
@@ -246,6 +306,20 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable: a faked table has any unique constraints removed]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT UNIQUE);
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (1);
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (1);
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable: a faked table has any unique indexes removed]
AS
BEGIN
@@ -260,6 +334,21 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable: a faked table has any unique indexes removed]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT);
+ CREATE UNIQUE INDEX UQ_tSQLt_test_TempTable1_i ON tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i);
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (1);
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (1);
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable: a faked table has any not null constraints removed]
AS
BEGIN
@@ -272,6 +361,19 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable: a faked table has any not null constraints removed]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1(i INT NOT NULL);
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempTable1';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+ INSERT INTO FakeTableTests.TempTable1 (i) VALUES (NULL);
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable works on referencedTo tables]
AS
BEGIN
@@ -293,6 +395,27 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable works on referencedTo tables]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(i INT PRIMARY KEY);
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst2(i INT PRIMARY KEY, tst1i INT REFERENCES tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(i));
+
+ BEGIN TRY
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1';
+ END TRY
+ BEGIN CATCH
+ DECLARE @ErrorMessage NVARCHAR(MAX);
+ SELECT @ErrorMessage = ERROR_MESSAGE()+'{'+ISNULL(ERROR_PROCEDURE(),'NULL')+','+ISNULL(CAST(ERROR_LINE() AS VARCHAR),'NULL')+'}';
+
+ EXEC tSQLt.Fail 'FakeTable threw unexpected error:', @ErrorMessage;
+ END CATCH;
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable doesn't produce output]
AS
BEGIN
@@ -314,6 +437,28 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable doesn't produce output]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst(i INT);
+ CREATE SYNONYM FakeTableTests.tst FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst;
+
+ EXEC tSQLt.CaptureOutput 'EXEC tSQLt.FakeTable ''FakeTableTests.tst''';
+
+ SELECT OutputText
+ INTO #actual
+ FROM tSQLt.CaptureOutputLog;
+
+ SELECT TOP(0) *
+ INTO #expected
+ FROM #actual;
+
+ INSERT INTO #expected(OutputText)VALUES(NULL);
+
+ EXEC tSQLt.AssertEqualsTable '#expected','#actual';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable doesn't preserve identity if @Identity parameter is not specified]
AS
BEGIN
@@ -330,6 +475,21 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable doesn't preserve identity if @Identity parameter is not specified]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(i INT IDENTITY(1,1));
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1';
+
+ EXEC('INSERT INTO FakeTableTests.tst1(i) VALUES(1)');
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable doesn't preserve identity if @identity parameter is 0]
AS
BEGIN
@@ -346,6 +506,19 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable doesn't preserve identity if @identity parameter is 0]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(i INT IDENTITY(1,1));
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1',@Identity=0;
+
+ EXEC('INSERT INTO FakeTableTests.tst1(i) VALUES(1)');
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves identity if @identity parameter is 1]
AS
BEGIN
@@ -362,6 +535,27 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves identity if @identity parameter is 1]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 ( i INT IDENTITY(1, 1) );
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1', @Identity = 1;
+ BEGIN TRY
+ EXEC('INSERT INTO FakeTableTests.tst1(i) VALUES(1)');
+ EXEC tSQLt.Fail @Message0 = N'Fake table has no identity column!';
+ END TRY
+ BEGIN CATCH
+ DECLARE @ErrorMessage NVARCHAR(4000);
+ SET @ErrorMessage = ERROR_MESSAGE();
+ EXEC tSQLt.AssertEquals @Expected = 'Cannot insert explicit value for identity column in table ''tst1'' when IDENTITY_INSERT is set to OFF.',
+ @Actual = @ErrorMessage;
+ END CATCH
+END;
+GO
CREATE PROC FakeTableTests.[test FakeTable works with more than one column]
AS
@@ -386,6 +580,37 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable works with more than one column]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(i1 INT,i2 INT,i3 INT,i4 INT,i5 INT,i6 INT,i7 INT,i8 INT);
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ CREATE TABLE #Actual (column_id INT, [name] NVARCHAR(500));
+ CREATE TABLE #Expected (column_id INT, [name] NVARCHAR(500));
+
+ INSERT INTO #Expected
+ SELECT column_id ,
+ c.name
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns c
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables t ON t.object_id = c.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst1'
+ AND s.name = 'dbo';
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1';
+
+ INSERT INTO #Actual
+ SELECT column_id ,
+ name
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('FakeTableTests.tst1');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected', '#Actual';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable works with ugly column and table names]
AS
BEGIN
@@ -408,6 +633,37 @@ BEGIN
EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
END;
GO
+
+CREATE PROC FakeTableTests.[test remote FakeTable works with ugly column and table names]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.[tst!@#$%^&*()_+ 1]([col!@#$%^&*()_+ 1] INT);
+ CREATE SYNONYM FakeTableTests.[tst!@#$%^&*()_+ 1] FOR tSQLt_RemoteSynonymsTestDatabase.dbo.[tst!@#$%^&*()_+ 1];
+
+ CREATE TABLE #Actual (column_id INT, [name] NVARCHAR(500));
+ CREATE TABLE #Expected (column_id INT, [name] NVARCHAR(500));
+
+ INSERT INTO #Expected
+ SELECT column_id ,
+ c.name
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns c
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables t ON t.object_id = c.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst!@#$%^&*()_+ 1'
+ AND s.name = 'dbo';
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.[tst!@#$%^&*()_+ 1]';
+
+ INSERT INTO #Actual
+ SELECT column_id ,
+ name
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('FakeTableTests.[tst!@#$%^&*()_+ 1]');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected', '#Actual';
+END;
+GO
CREATE PROC FakeTableTests.[test FakeTable preserves identity base and step-size]
AS
@@ -432,6 +688,29 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves identity base and step-size]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (i INT IDENTITY(42,13));
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ INSERT INTO FakeTableTests.tst1 DEFAULT VALUES;
+ INSERT INTO FakeTableTests.tst1 DEFAULT VALUES;
+
+ SELECT i
+ INTO #Expected
+ FROM FakeTableTests.tst1;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1',@Identity=1;
+
+ INSERT INTO FakeTableTests.tst1 DEFAULT VALUES;
+ INSERT INTO FakeTableTests.tst1 DEFAULT VALUES;
+
+ EXEC tSQLt.AssertEqualsTable '#Expected', 'FakeTableTests.tst1';
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves data type of identity column with @Identity=0]
AS
BEGIN
@@ -456,6 +735,36 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves data type of identity column with @Identity=0]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 ( i INT );
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ CREATE TABLE #Expected(type_name NVARCHAR(500));
+ CREATE TABLE #Actual (type_name NVARCHAR(500));
+
+ INSERT INTO #Expected
+ SELECT tp.name type_name
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns c
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.types tp ON tp.user_type_id = c.user_type_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables t ON t.object_id = c.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst1'
+ AND s.name = 'dbo';
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1', @Identity = 0;
+
+ INSERT INTO #Actual
+ SELECT TYPE_NAME(user_type_id) type_name
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('FakeTableTests.tst1');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual'
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves data type of identity column with @Identity=1]
AS
BEGIN
@@ -480,6 +789,37 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves data type of identity column with @Identity=1]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 ( i [DECIMAL](4) IDENTITY(1,1) );
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ CREATE TABLE #Expected(type_name NVARCHAR(500), max_length INT, precision INT, scale INT);
+ CREATE TABLE #Actual(type_name NVARCHAR(500), max_length INT, precision INT, scale INT);
+
+ INSERT INTO #Expected
+ SELECT tp.name type_name, c.max_length, c.precision, c.scale
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns c
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.types tp ON tp.user_type_id = c.user_type_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables t ON t.object_id = c.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst1'
+ AND s.name = 'dbo';
+
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1',@Identity = 1;
+
+ INSERT INTO #Actual
+ SELECT TYPE_NAME(user_type_id) type_name,max_length,precision,scale
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('FakeTableTests.tst1');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable works if IDENTITYCOL is not the first column (with @Identity=1)]
AS
BEGIN
@@ -504,6 +844,42 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable works if IDENTITYCOL is not the first column (with @Identity=1)]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(x INT, i INT IDENTITY(1,1), y VARCHAR(30));
+ CREATE TABLE #Actual
+ (
+ name VARCHAR(500) ,
+ is_identity BIT
+ );
+ CREATE TABLE #Expected
+ (
+ name VARCHAR(500) ,
+ is_identity BIT
+ );
+ INSERT INTO #Expected
+ SELECT c.name, is_identity
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns c
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables t ON t.object_id = c.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst1' AND s.name = 'dbo';
+
+ CREATE SYNONYM dbo.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC tSQLt.FakeTable 'dbo.tst1',@Identity = 1;
+
+ INSERT INTO #Actual
+ SELECT name, is_identity
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('dbo.tst1');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable works if there is no IDENTITYCOL and @Identity = 1]
AS
BEGIN
@@ -528,33 +904,92 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable works if there is no IDENTITYCOL and @Identity = 1]
+AS
+BEGIN
+
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1(x INT, y VARCHAR(30));
+ CREATE SYNONYM dbo.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ CREATE TABLE #Actual
+ (
+ name VARCHAR(500) ,
+ is_identity BIT
+ );
+ CREATE TABLE #Expected
+ (
+ name VARCHAR(500) ,
+ is_identity BIT
+ );
+ INSERT INTO #Expected
+ SELECT c.name, is_identity
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns c
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables t ON t.object_id = c.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst1' AND s.name = 'dbo';
+
+ EXEC tSQLt.FakeTable 'dbo.tst1',@Identity = 1;
+
+ INSERT INTO #Actual
+ SELECT name, is_identity
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('dbo.tst1');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
+
+END;
+GO
+
CREATE PROC FakeTableTests.AssertTableStructureBeforeAndAfterCommandForComputedCols
@TableName NVARCHAR(MAX),
@Cmd NVARCHAR(MAX),
@ClearComputedCols INT
AS
BEGIN
+
+ DECLARE @Database NVARCHAR(MAX),
+ @Instance NVARCHAR(MAX),
+ @Schema NVARCHAR(MAX),
+ @Table NVARCHAR(MAX);
+
+ SELECT @Instance = PARSENAME(S.base_object_name, 4),
+ @Database = PARSENAME(S.base_object_name, 3),
+ @Schema = PARSENAME(S.base_object_name, 2),
+ @Table = PARSENAME(S.base_object_name, 1)
+ FROM sys.synonyms AS S
+ WHERE S.object_id = OBJECT_ID(@TableName);
+
+ IF (@Database IS NOT NULL)
+ BEGIN
+ EXEC tSQLt.Private_CreateRemoteSysObjects @Instance = @Instance, @Database = @Database;
+ END
+ CREATE TABLE #Expected(column_id INT, IsComputedColumn BIT, is_persisted BIT, name NVARCHAR(MAX), definition NVARCHAR(MAX), user_type_id INT)
+ CREATE TABLE #Actual(column_id INT, IsComputedColumn BIT, is_persisted BIT, name NVARCHAR(MAX), definition NVARCHAR(MAX), user_type_id INT)
+
+ INSERT INTO #Expected
SELECT c.column_id, CASE WHEN cc.column_id IS NULL THEN 0 ELSE 1 END AS IsComputedColumn, cc.is_persisted, c.name, cc.definition, c.user_type_id
- INTO #Expected
- FROM sys.columns c
- LEFT OUTER JOIN sys.computed_columns cc ON cc.object_id = c.object_id
+ FROM tSQLt.Private_SysColumns c
+ JOIN tSQLt.Private_SysObjects o ON o.object_id = c.object_id
+ JOIN tSQLt.Private_SysSchemas s ON s.schema_id = o.schema_id
+ LEFT OUTER JOIN tSQLt.Private_SysComputedColumns cc ON cc.object_id = c.object_id
AND cc.column_id = c.column_id
AND @ClearComputedCols = 0
- WHERE c.object_id = OBJECT_ID('dbo.tst1');
+ WHERE o.name = COALESCE(@Table,PARSENAME(@TableName, 1)) AND s.name = COALESCE(@Schema, PARSENAME(@TableName, 2));
EXEC (@Cmd);
-
+
+ INSERT INTO #Actual
SELECT c.column_id, CASE WHEN cc.column_id IS NULL THEN 0 ELSE 1 END AS IsComputedColumn, cc.is_persisted, c.name, cc.definition, c.user_type_id
- INTO #Actual
FROM sys.columns c
LEFT OUTER JOIN sys.computed_columns cc ON cc.object_id = c.object_id
AND cc.column_id = c.column_id
- WHERE c.object_id = OBJECT_ID('dbo.tst1');
+ WHERE c.object_id = OBJECT_ID(@TableName);
EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
END;
GO
+
CREATE PROC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForComputedCols
@TableName NVARCHAR(MAX),
@Cmd NVARCHAR(MAX)
@@ -584,6 +1019,16 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves computed columns if @ComputedColumns = 1]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT, y AS x + 5 PERSISTED);
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForComputedCols 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @ComputedColumns = 1;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves persisted computed columns if @ComputedColumns = 1]
AS
BEGIN
@@ -595,6 +1040,16 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves persisted computed columns if @ComputedColumns = 1]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT, y AS x + 5 PERSISTED);
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForComputedCols 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @ComputedColumns = 1;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable does not preserve persisted computed columns if @ComputedColumns = 0]
AS
BEGIN
@@ -606,6 +1061,16 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable does not preserve persisted computed columns if @ComputedColumns = 0]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT, y AS x + 5 PERSISTED);
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableAfterCommandHasNoComputedCols 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @ComputedColumns = 0;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable does not preserve persisted computed columns if @ComputedColumns is not specified]
AS
BEGIN
@@ -617,6 +1082,16 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable does not preserve persisted computed columns if @ComputedColumns is not specified]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT, y AS x + 5 PERSISTED);
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableAfterCommandHasNoComputedCols 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'';';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves multiple mixed persisted computed columns if @ComputedColumns = 1]
AS
BEGIN
@@ -628,28 +1103,62 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves multiple mixed persisted computed columns if @ComputedColumns = 1]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (NotComputed INT, ComputedAndPersisted AS (NotComputed + 5) PERSISTED, ComputedNotPersisted AS (NotComputed + 7), AnotherComputed AS (GETDATE()));
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForComputedCols 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @ComputedColumns = 1;';
+END;
+GO
+
CREATE PROC FakeTableTests.AssertTableStructureBeforeAndAfterCommandForDefaults
@TableName NVARCHAR(MAX),
@Cmd NVARCHAR(MAX),
@ClearDefaults INT
AS
BEGIN
+
+ DECLARE @Database NVARCHAR(MAX),
+ @Instance NVARCHAR(MAX),
+ @Schema NVARCHAR(MAX),
+ @Table NVARCHAR(MAX);
+
+ SELECT @Instance = PARSENAME(S.base_object_name, 4),
+ @Database = PARSENAME(S.base_object_name, 3),
+ @Schema = PARSENAME(S.base_object_name, 2),
+ @Table = PARSENAME(S.base_object_name, 1)
+ FROM sys.synonyms AS S
+ WHERE S.object_id = OBJECT_ID(@TableName);
+
+ IF (@Database IS NOT NULL)
+ BEGIN
+ EXEC tSQLt.Private_CreateRemoteSysObjects @Instance = @Instance, @Database = @Database;
+ END
+ CREATE TABLE #Expected(column_id INT, IsComputedColumn BIT, name NVARCHAR(MAX), definition NVARCHAR(MAX), user_type_id INT)
+ CREATE TABLE #Actual(column_id INT, IsComputedColumn BIT, name NVARCHAR(MAX), definition NVARCHAR(MAX), user_type_id INT)
+
+ INSERT INTO #Expected
SELECT c.column_id, CASE WHEN dc.parent_column_id IS NULL THEN 0 ELSE 1 END AS IsComputedColumn, c.name, dc.definition, c.user_type_id
- INTO #Expected
- FROM sys.columns c
- LEFT OUTER JOIN sys.default_constraints dc ON dc.parent_object_id = c.object_id
+ FROM tSQLt.Private_SysColumns c
+ JOIN tSQLt.Private_SysObjects o ON o.object_id = c.object_id
+ JOIN tSQLt.Private_SysSchemas s ON s.schema_id = o.schema_id
+ LEFT OUTER JOIN tSQLt.Private_SysDefaultConstraints dc ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
AND @ClearDefaults = 0
- WHERE c.object_id = OBJECT_ID('dbo.tst1');
-
+ WHERE o.name = COALESCE(@Table,PARSENAME(@TableName, 1)) AND s.name = COALESCE(@Schema, PARSENAME(@TableName, 2));
+
+ IF NOT EXISTS (SELECT 1 FROM #Expected) EXEC tSQLt.Fail;
+
EXEC (@Cmd);
+ INSERT INTO #Actual
SELECT c.column_id, CASE WHEN dc.parent_column_id IS NULL THEN 0 ELSE 1 END AS IsComputedColumn, c.name, dc.definition, c.user_type_id
- INTO #Actual
FROM sys.columns c
LEFT OUTER JOIN sys.default_constraints dc ON dc.parent_object_id = c.object_id
AND dc.parent_column_id = c.column_id
- WHERE c.object_id = OBJECT_ID('dbo.tst1');
+ WHERE c.object_id = OBJECT_ID(@TableName);
EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
END;
@@ -684,6 +1193,17 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remoteFakeTable does not preserve defaults if @Defaults is not specified]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT DEFAULT(5));
+
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableAfterCommandHasNoDefaults 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1''';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable does not preserve defaults if @Defaults = 0]
AS
BEGIN
@@ -695,6 +1215,17 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable does not preserve defaults if @Defaults = 0]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT DEFAULT(5));
+
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableAfterCommandHasNoDefaults 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @Defaults = 0;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves defaults if @Defaults = 1]
AS
BEGIN
@@ -706,6 +1237,17 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves defaults if @Defaults = 1]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x INT DEFAULT(5));
+
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForDefaults 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @Defaults = 1;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves defaults if @Defaults = 1 when multiple columns exist on table]
AS
BEGIN
@@ -720,6 +1262,18 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves defaults if @Defaults = 1 when multiple columns exist on table]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 ( ColWithNoDefault CHAR(3),
+ ColWithDefault DATETIME DEFAULT(GETDATE()));
+
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForDefaults 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @Defaults = 1;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves defaults if @Defaults = 1 when multiple varied columns exist on table]
AS
BEGIN
@@ -735,6 +1289,19 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves defaults if @Defaults = 1 when multiple varied columns exist on table]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 ( ColWithNoDefault CHAR(3),
+ ColWithDefault DATETIME DEFAULT(GETDATE()),
+ ColWithDiffDefault INT DEFAULT(-3));
+
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ EXEC FakeTableTests.AssertTableStructureBeforeAndAfterCommandIsSameForDefaults 'FakeTableTests.tst1', 'EXEC tSQLt.FakeTable ''FakeTableTests.tst1'', @Defaults = 1;';
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves the collation of a column]
AS
BEGIN
@@ -760,6 +1327,35 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves the collation of a column]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.tst1 (x VARCHAR(30) COLLATE Latin1_General_BIN,
+ y VARCHAR(40));
+ CREATE SYNONYM FakeTableTests.tst1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.tst1;
+
+ CREATE TABLE #Expected (name NVARCHAR(MAX), collation_name NVARCHAR(MAX));
+ CREATE TABLE #Actual (name NVARCHAR(MAX), collation_name NVARCHAR(MAX));
+
+ INSERT INTO #Expected
+ SELECT C.name ,C.collation_name
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns AS C
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables AS t ON t.object_id = C.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas AS s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tst1' AND s.name = 'dbo';
+
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.tst1';
+ INSERT INTO #Actual
+ SELECT name, collation_name
+ FROM sys.columns
+ WHERE object_id = OBJECT_ID('FakeTableTests.tst1');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
+
+END;
+GO
+
CREATE PROCEDURE FakeTableTests.[test Private_ResolveFakeTableNamesForBackwardCompatibility returns quoted schema when schema and table provided]
AS
BEGIN
@@ -914,6 +1510,32 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves UDTd]
+AS
+BEGIN
+ CREATE SYNONYM dbo.tbl FOR tSQLt_RemoteSynonymsTestDatabase.MyTestClass.tbli;
+
+ CREATE TABLE #Expected (name NVARCHAR(255), system_type_id INT, max_length INT, precision INT, scale INT, is_nullable BIT);
+ CREATE TABLE #Actual (name NVARCHAR(255), system_type_id INT, max_length INT, precision INT, scale INT, is_nullable BIT);
+
+ INSERT INTO #Expected
+ SELECT C.name ,C.system_type_id,C.max_length,C.precision,C.scale,C.is_nullable
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns AS C
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables AS t ON t.object_id = C.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas AS s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tbli' AND s.name = 'MyTestClass';
+
+ EXEC tSQLt.FakeTable @TableName = 'dbo.tbl';
+
+ INSERT INTO #Actual
+ SELECT C.name ,C.system_type_id,C.max_length,C.precision,C.scale,C.is_nullable
+ FROM sys.columns AS C WHERE C.object_id = OBJECT_ID('dbo.tbl');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test FakeTable preserves UDTd based on char type]
AS
BEGIN
@@ -936,6 +1558,32 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable preserves UDTd based on char type]
+AS
+BEGIN
+ CREATE SYNONYM dbo.tbl FOR tSQLt_RemoteSynonymsTestDatabase.MyTestClass.tbl;
+
+ CREATE TABLE #Expected (name NVARCHAR(255), system_type_id INT, max_length INT, precision INT, scale INT, is_nullable BIT);
+ CREATE TABLE #Actual (name NVARCHAR(255), system_type_id INT, max_length INT, precision INT, scale INT, is_nullable BIT);
+
+ INSERT INTO #Expected
+ SELECT C.name ,C.system_type_id,C.max_length,C.precision,C.scale,C.is_nullable
+ FROM tSQLt_RemoteSynonymsTestDatabase.sys.columns AS C
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.tables AS t ON t.object_id = C.object_id
+ JOIN tSQLt_RemoteSynonymsTestDatabase.sys.schemas AS s ON s.schema_id = t.schema_id
+ WHERE t.name = 'tbl' AND s.name = 'MyTestClass';
+
+ EXEC tSQLt.FakeTable @TableName = 'dbo.tbl';
+
+ INSERT INTO #Actual
+ SELECT C.name ,C.system_type_id,C.max_length,C.precision,C.scale,C.is_nullable
+ FROM sys.columns AS C WHERE C.object_id = OBJECT_ID('dbo.tbl');
+
+ EXEC tSQLt.AssertEqualsTable '#Expected','#Actual';
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test can fake local synonym of table]
AS
BEGIN
@@ -960,6 +1608,17 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test raises appropriate error if synonym is remote but not of a table]
+AS
+BEGIN
+ CREATE SYNONYM FakeTableTests.TempSynonym1 FOR tSQLt_RemoteSynonymsTestDatabase.FakeTableTests.NotATable;
+
+ EXEC tSQLt.ExpectException @ExpectedMessage = 'Cannot fake synonym [FakeTableTests].[TempSynonym1] as it is pointing to [tSQLt_RemoteSynonymsTestDatabase].[FakeTableTests].[NotATable], which is not a table or view!';
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempSynonym1';
+
+END;
+GO
+
CREATE PROC FakeTableTests.[test can fake view]
AS
BEGIN
@@ -972,6 +1631,20 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test can fake view to remote table]
+AS
+BEGIN
+
+ SELECT TOP(0) * INTO #actual FROM tSQLt_RemoteSynonymsTestDatabase.dbo.TestTable;
+
+ EXEC('CREATE VIEW FakeTableTests.TempView1 AS SELECT * FROM tSQLt_RemoteSynonymsTestDatabase.dbo.TestTable;');
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempView1';
+
+ EXEC tSQLt.AssertEqualsTableSchema @Expected = 'FakeTableTests.TempTable1', @Actual = #actual;
+END;
+GO
+
CREATE PROC FakeTableTests.[test can fake local synonym of view]
AS
BEGIN
@@ -985,6 +1658,18 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test can fake remote synonym of view]
+AS
+BEGIN
+
+ CREATE SYNONYM FakeTableTests.TempSynonym1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TestView;
+
+ EXEC tSQLt.FakeTable 'FakeTableTests.TempSynonym1';
+
+ EXEC('INSERT INTO FakeTableTests.TempSynonym1 VALUES (1,2,NULL)');
+END;
+GO
+
CREATE PROC FakeTableTests.[test raises error if @TableName is multi-part and @SchemaName is not NULL]
AS
BEGIN
@@ -1017,6 +1702,19 @@ BEGIN
END;
GO
+CREATE PROC FakeTableTests.[test remote FakeTable works with two parameters, if they are quoted]
+AS
+BEGIN
+ CREATE TABLE tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1 ( i INT NOT NULL );
+ CREATE SYNONYM FakeTableTests.TempTable1 FOR tSQLt_RemoteSynonymsTestDatabase.dbo.TempTable1;
+
+ EXEC tSQLt.FakeTable '[FakeTableTests]','[TempTable1]';
+
+ EXEC FakeTableTests.AssertTableIsNewObjectThatHasNoConstraints 'FakeTableTests.TempTable1';
+
+END;
+GO
+
--CREATE PROC FakeTableTests.[test FakeTable works with cross database synonym]
--AS
--BEGIN