SQL Server error 4928 - no replication or CDC - sql-server

I'm trying to rename a column but I'm getting this error:
Msg 4928, Level 16, State 1, Procedure sp_rename, Line 547
Cannot alter column 'appraisal_id' because it is 'enabled for Replication or Change Data Capture'.
Msg 0, Level 20, State 0, Line 0
A severe error occurred on the current command. The results, if any, should be discarded.
No replication is configured. At some point CDC was enabled on the database and a few tables (including the table I'm trying to rename a column on), but it is currently disabled on the database. I'm assuming it was disabled on the database without first disabling it on each table, and that's causing this problem. I would say this is a SQL Server bug.
As a workaround, I can re-enable CDC on the database, disable it on the table, and then disable it on the database, then I can rename the column.
I'm trying to find out which tables have this problem (our database has 3500 tables), so I can fix this once and for all and avoid this in future. I don't see anything in any of the system tables (I checked sys.tables, sys.objects, sysobject, sys.columns, syscolumns) that indicates this table has CDC enabled. All the relevant columns (is_published, is_schema_published, is_merge_published, is_tracked_by_cdc) have value 0.
Any idea where SQL Server stores this information ?
I'm using SQL 2008 and 2008 R2; the problem occurs on both.
You can reproduce the problem with the script below:
CREATE DATABASE TestCDC
GO
USE TestCDC
GO
CREATE TABLE dbo.fish(
fish_id int NOT NULL
, name nvarchar(100) NOT NULL
, CONSTRAINT XPKfish PRIMARY KEY (fish_id))
GO
EXECUTE sp_cdc_enable_db
GO
EXECUTE sys.sp_cdc_enable_table
#source_schema = N'dbo'
, #source_name = 'fish'
, #capture_instance = 'my_capture'
, #role_name = NULL
, #filegroup_name = NULL
GO
EXECUTE sp_cdc_disable_db
GO
EXECUTE sp_rename 'dbo.fish.name', 'fish_name'

I'm assuming you have figured this out since but I just came across this problem again and perhaps people would like a good answer on this thread.
It seems that if you disable CDC on the database level it does disable it everywhere but these errors keep occurring.
In order to overcome this problem the trick is to:
Activate CDC on the DB level
EXECUTE sp_cdc_enable_db
GO
Activate CDC on the table
EXEC sys.sp_cdc_enable_table
#source_schema = N'dbo',
#source_name = N'MyTable',
#role_name = N'MyRole',
#supports_net_changes = 1
GO
Disable CDC on the table
EXEC sys.sp_cdc_disable_table
#source_schema = N'dbo',
#source_name = N'MyTable',
#capture_instance = N'dbo_MyTable'
GO
Disable CDC on the DB level
EXECUTE sp_cdc_disable_db
GO

I don't have access to an instance with CDC enabled to test this, but based on the text of the internal procedure used to enable cdc (usefully made accessible here), it might be that one or more tables in the cdc schema contain the information - I'd suggest cdc.change_tables as a starting point.

In sys.tables, there are two columns that will tell you whether the server thinks the table is replicated or enabled for cdc (regardless of the database status for those features). Do the ff:
select name, is_tracked_by_cdc, is_replicated
from sys.tables
where is_tracked_by_cdc = 1
or is_replicated = 1
If either is true, you will have to enable the database feature in question (e.g. CDC), disable the feature for any tables that have it, then re-disable the feature at the database level.

Related

Monitor when Database is created and receive an email

I created a trigger at the level of the server to control when a db is created.
I have this script that was working fine on SQL 2014, now we moved to SQL 2017, the script is working but I receive lot of emails
CREATE TRIGGER [ddl_trig_database]
ON ALL SERVER
FOR ALTER_DATABASE
AS
DECLARE #results NVARCHAR(max)
DECLARE #subjectText NVARCHAR(max)
DECLARE #databaseName NVARCHAR(255)
SET #subjectText = 'NEW DATABASE Created on ' + ##SERVERNAME + ' by ' + SUSER_SNAME()
SET #results = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/TSQLCommand/CommandText)[1]','nvarchar(max)'))
SET #databaseName = (SELECT EVENTDATA().value('(/EVENT_INSTANCE/DatabaseName)[1]', 'VARCHAR(255)'))
EXEC msdb.dbo.sp_send_dbmail
#profile_name = 'EmailProfile',
#recipients = 'test#domain.com',
#body = #results,
#subject = #subjectText,
#exclude_query_output = 1 --Suppress 'Mail Queued' message
GO
I receive for example in different emails each of these lines:
ALTER DATABASE [testNewDB] SET DELAYED_DURABILITY = DISABLED
ALTER DATABASE [testNewDB] SET RECOVERY FULL
ALTER DATABASE [testNewDB] SET READ_WRITE
ALTER DATABASE [testNewDB] SET READ_COMMITTED_SNAPSHOT OFF
There are more so I believe the trigger is sending the info for each configuration parameter of the new db created, any idea how to receive only the info of the new DB created without all the rest?
You can replace ALTER_DATABASE with CREATE_DATABASE, but this will not catch a restore event because a restore does not generate a DLL event.
CREATE TRIGGER [ddl_trig_database]
ON ALL SERVER
FOR CREATE_DATABASE
AS
The following article covers a solution that will work around the missing DDL event:
DDL triggers enable us to audit DDL changes but there are a few
missing events, design decisions and installation complications. This
post explains and provides a full solution that includes auditing for
database restores (there is no DDL event for this) and an incremental
self install, which keeps the whole server audit configured for DDL
auditing.
https://www.sqlservercentral.com/forums/topic/sql-2008-ddl-auditing-a-full-self-installingupdating-solution-for-whole-server
The solution in the article for RESTORE events involves a job that runs to check for new databases:
SQL 2008 Audit RESTORE DATABASE
SQL Agent job which runs (in less than 1 second) every 1 minute to
copy new restore database auditing information from
msdb.dbo.restorehistory to dbadata.dbo.ServerAudit. If it finds that a
database restore has happened but has not been audited it
automatically runs the “Setup DDL Audit” job because there is a
possibility that the restored database is not configured for DDL
auditing as expected.

snapshot isolation error using sp_setapprole on a read-only Availability Group replica

I am investigating SQL Server Always On Availability Groups and ran into a problem when setting an application role on the read-only replica database. What really irritates me is the behavior, and I don't know how to interpret the error message.
All I do is call
DECLARE #cookie varbinary(8000);
EXEC sys.sp_setapprole
#rolename = 'TestRole', -- sysname
#password = 'password', -- sysname
#fCreateCookie = 1, -- bit
#cookie = #cookie OUTPUT; -- varbinary(8000)
EXEC sys.sp_unsetapprole #cookie = #cookie; -- varbinary(8000)
which works fine for the first attempt. On the second and all following tries, I receive the following error:
Msg 3961, Level 16, State 1, Procedure sp_setapprole, Line 44 [Batch
Start Line 25]
Snapshot isolation transaction failed in database
'AGTest' because the object accessed by the statement has been
modified by a DDL statement in another concurrent transaction since
the start of this transaction. It is disallowed because the metadata
is not versioned. A concurrent update to metadata can lead to
inconsistency if mixed with snapshot isolation.
When I execute the same statement on the primary database, I can set the approle on the replica again - once.
I tested different isolation level settings (although I wouldn't be willing to change it for the later productive database), which didn't work. I currently have no further approach to the problem, and google has almost no info for me.
Just to sum this up (for those who may run into similar problems): It was a SQL Server bug, which was fixed by Microsoft after I filed a support request (SP2 CU4). Unfortunately the fix seems to be available for SQL Server 2016 only, 2017 didn't inherit it - I hope it will be part of 2019, else I will have to create a new support case.
https://support.microsoft.com/en-us/help/4469908/error-3961-when-you-use-application-roles-read-only-secondary-replicas

Cannot drop the table <TableName> because it is being used for replication

I am not able to modify the structure of a table in a database.
The database is used for replication.
I am getting This error
As the error says the table is used for replication, meaning it's an article in a replication publisher. To be able to modify the table you should remove it from replication, then update the schema, afterwards add it again in the replication. After adding it again you will have to reinitialize the subscriptions to pick up the modified table schema.
I was having this error on my replication
Cannot drop the table 'dbo.repl_application_camp_choice' because it is
being used for replication. (Source: MSSQLServer, Error number: 3724)
the first thing I tried - wrongly - is to manually drop the table in the subscriber db.
But the same error was there.
the next thing I tried is this:
USE [ORCASTG]
GO
EXEC sp_msunmarkreplinfo 'dbo.repl_application_camp_choice'
--Msg 3724, Level 16, State 3, Line 5
--Cannot drop the table 'dbo.repl_application_camp_choice' because it is being used for replication.
but it did not work
then I tried this one:
USE [ORCASTG]
GO
DECLARE #subscriptionDB AS sysname
SET #subscriptionDB = N'ORCASTG'
USE master
EXEC sp_removedbreplication #subscriptionDB
GO
USE [ORCASTG]
GO
DROP TABLE IF EXISTS [dbo].[repl_application_camp_choice]
GO
and this did the trick
and after running the script above:
I also looked here and here and here.

How to set change tracking on a Visual Studio database project (SSDT)

I have a SQL Server 2005 DB project and am looking to deploy the Schema over an existing DB that is on a later version of SQL Server. The issue I have is that Change Tracking is enabled on the DB I wish to deploy to and so the first thing SSDT wants to do is disable CT. This poses a problem as I get the error below:
(43,1): SQL72014: .Net SqlClient Data Provider: Msg 22115, Level 16,
State 1, Line 5 Change tracking is enabled for one or more tables in
database 'Test'. Disable change tracking on each table before
disabling it for the database. Use the sys.change_tracking_tables
catalog view to obtain a list of tables for which change tracking is
enabled. (39,0): SQL72045: Script execution error. The executed
script:
IF EXISTS (SELECT 1
FROM [master].[dbo].[sysdatabases]
WHERE [name] = N'$(DatabaseName)')
BEGIN
ALTER DATABASE [$(DatabaseName)]
SET CHANGE_TRACKING = OFF
WITH ROLLBACK IMMEDIATE;
END
In an effort to get around this I have created a PreDeployment script that executes the below:
/* Run pre-deployment scripts to resolve issues */
IF(SELECT SUBSTRING(##VERSION, 29,4)) = '11.0'
BEGIN
PRINT 'Enabling Change Tracking';
DECLARE #dbname VARCHAR(250)
SELECT #dbname = DB_NAME()
EXEC('
IF NOT EXISTS(SELECT * FROM [master].[dbo].[sysdatabases] WHERE name = ''' + #dbname + ''')
ALTER DATABASE ['+ #dbname +
']SET CHANGE_TRACKING = ON
(CHANGE_RETENTION = 5 DAYS, AUTO_CLEANUP = ON);
');
EXEC('
IF NOT EXISTS(SELECT * FROM sys.change_tracking_tables ctt
INNER JOIN sys.tables t ON t.object_id = ctt.object_id
INNER JOIN sys.schemas s ON s.schema_id = t.schema_id
WHERE t.name = ''TableName'')
BEGIN
ALTER TABLE [dbo].[TableName] ENABLE CHANGE_TRACKING;
END;');
So based on the DB Version Change Tracking is set to enabled on the DB and relevant Tables assuming it is not already enabled.I got this idea from a previous post: # ifdef type conditional compilation in T-SQL sql server 2008 2005
Unfortunately this is still not working as SSDT is trying to disable Change Tracking before the PreDeployment script is executed.
Make sure change tracking is enabled in your database project.
Open your database project's properties > Project Settings > Database Settings... > Operational tab > check the "Change tracking" option
As Keith said if you want it in enable it. If you do want to disable it then just run your script before doing the compare so you have a pre-pre-deploy script like:
https://the.agilesql.club/Blog/Ed-Elliott/Pre-Compare-and-Pre-Deploy-Scripts-In-SSDT
If you are disabling it then it is a one off thing so pretty simple.
Other options are to write your own deployment contributor and raising a bug via connect.
Deployment Contributor:
https://the.agilesql.club/blog/Ed-Elliott/2015/09/23/Inside-A-SSDT-Deployment-Contributor
https://github.com/DacFxDeploymentContributors/Contributors
Ed

CDC is enabled, but cdc.dbo<table-name>_CT table is not being populated

I have enabled CDC using the following steps:
exec sys.sp_cdc_enable_db;
exec sys.sp_cdc_enable_table
#source_schema = N'dbo',
#source_name = N'table_name',
#role_name = N'CDC_Access',
#supports_net_changes = 1;
I can see that a CT table has been created in the System Tables; SQL Server Agent is on, and I can see the cdc.db_name_capture job has been created and is running.
However, even though the table_name table is being populated, I never see anything in the CT table. I have other tables that have CDC enabled for them in the same database which are being updated, and CDC is capturing data for them and storing it in the CT table created for that specific table.
Why would this one table not be capturing data even though other tables are?
I read online that perhaps it has something to do with the transaction log becoming too large, but I still have plenty of drive space left (~2TB free).
What can I do to debug this issue?
Thank you so much, in advance! :)
Edit 1
Here is the output of exec sys.sp_cdc_help_change_data_capture. subscription_events is the table that I am having troubles with.
Edit 2
Here is the output of exec sys.sp_cdc_help_jobs;.
Edit 3
Here is the output of select * from sys.dm_cdc_log_scan_sessions;.
Here is the output of select * from sys.dm_cdc_errors;
Edit 4
Running select serverproperty('productversion') provides the following version number: 11.0.3401.0.
Do the following:
Stop the capture job;
Run EXEC sp_repldone #xactid = NULL, #xact_segno = NULL, #numtrans = 0, #time = 0, #reset = 1; EXEC sp_replflush;
Close this query window in which you executed these commands;
Start the capture job;
Check the sys.dm_cdc_errors table for new rows and check if the changes starting to be visible.

Resources