SQL Server Wrapper stored procedure to create publication for transactional replication

hfyxw5xn  于 2023-05-28  发布在  其他
关注(0)|答案(3)|浏览(105)

I have created a wrapper stored procedure to create publication for transactional replication for SQL Server 2008 Standard Edition SP3. But when I execute the procedure I get the following error. The column "file_exists" is not user defined. This error doesn't make any sense to me. This works on Dev environment but same code doesn't work on test environment. Dev and Test are identical as far as I can tell. I also tried to explicitly set options, made them 5496 (SELECT @@OPTIONS). Any help greatly appreciated.

-- error

Msg 50000, Level 16, State 1, Procedure CreatePublicationForDB, Line 161
Invalid column name 'file_exists'.

-- Begin Script

CREATE DATABASE TestPublication

GO
USE TestPublication

CREATE TABLE Orders(
    OrderID INT PRIMARY KEY,
    CustomerID INT,
    ProductID INT,
    UpdatedAt DATETIME,
    UpdatedBy DATETIME
)
GO
CREATE TABLE Products(
ProductID INT PRIMARY KEY,
ProductName VARCHAR(100)
)
GO
CREATE VIEW V_Order
AS
SELECT o.OrderID,o.CustomerID, p.ProductName
FROM Orders o 
JOIN Products p
    ON o.ProductID = p.ProductID

GO
CREATE SCHEMA repl
GO
CREATE TABLE repl.ReplicationTables
(
    DBName sys.sysname NOT NULL DEFAULT('TestPublication'),
    SchemaOwner sys.sysname NOT NULL DEFAULT('dbo'),
    TableName sys.sysname NOT NULL
) 
GO
INSERT INTO repl.ReplicationTables (tablename)
VALUES('Orders'),('Products'),('V_Order')
GO
USE TestPublication
GO
CREATE PROCEDURE CreatePublicationForDB( @databaseName sysname, @publicationName sysname = @databaseName,   @allow_initialize_from_backup NVARCHAR(5) = 'true')
AS
BEGIN

BEGIN TRY
SET ANSI_WARNINGS ON
SET ANSI_PADDING ON
SET ANSI_NULLS ON
SET ARITHABORT ON
SET QUOTED_IDENTIFIER ON
SET ANSI_NULL_DFLT_ON ON
SET CONCAT_NULL_YIELDS_NULL ON 
        DECLARE @sp_replicationdboption varchar(MAX) = ' USE '+@databaseName +';',
                @sp_addpulication VARCHAR(MAX) = ' USE '+@databaseName +';', 
                @sp_addpublication_snapshot VARCHAR(MAX) = ' USE '+@databaseName +';', 
                @sp_addarticle VARCHAR(MAX) = ' USE '+@databaseName +';',
                @sp_startpublication_snapshot VARCHAR(MAX) = ' USE '+@databaseName +';'

        DECLARE @allow_anonymous NVARCHAR(5) = CASE WHEN @allow_initialize_from_backup = 'false' OR @allow_initialize_from_backup IS NULL THEN 'true' ELSE 'false' END

        DECLARE @immediate_sync NVARCHAR(5) = @allow_anonymous, @publisher sysname = @@SERVERNAME
        -- set up database publication
        SET @sp_replicationdboption += '
        exec sp_replicationdboption @dbname = N'''+@databaseName+ ''', 
                                @optname = N''publish'', 
                                @value = N''true'''
        -- Publication
        SET @sp_addpulication += '
        exec sp_addpublication @publication = N'''+@publicationName+ ''', 
                            @description = N''Transactional publication of database '+@databaseName+' from Publisher '+@publisher+''', 
                            @sync_method = N''concurrent'', 
                            @retention = 0, 
                            @allow_push = N''true'', 
                            @allow_pull = N''true'', 
                            @allow_anonymous = N'''+@allow_anonymous+ ''' , 
                            @enabled_for_internet = N''false'', 
                            @snapshot_in_defaultfolder = N''true'', 
                            @compress_snapshot = N''false'', 
                            @ftp_port = 21, 
                            @ftp_login = N''anonymous'', 
                            @allow_subscription_copy = N''false'', 
                            @add_to_active_directory = N''false'', 
                            @repl_freq = N''continuous'', 
                            @status = N''active'', 
                            @independent_agent = N''true'', 
                            @immediate_sync =  N'''+@immediate_sync+ ''' , 
                            @allow_sync_tran = N''false'', 
                            @autogen_sync_procs = N''false'', 
                            @allow_queued_tran = N''false'', 
                            @allow_dts = N''false'', 
                            @replicate_ddl = 1, 
                            @allow_initialize_from_backup =  N'''+COALESCE(@allow_initialize_from_backup, 'false')+ ''' , 
                            @enabled_for_p2p = N''false'', 
                            @enabled_for_het_sub = N''false'''

        IF @allow_initialize_from_backup = 'false'
        BEGIN
            -- publication snapshot
            SET @sp_addpublication_snapshot +='
            exec sp_addpublication_snapshot @publication = N'''+@publicationName+ ''', 
                                        @frequency_type = 1, 
                                        @frequency_interval = 0, 
                                        @frequency_relative_interval = 0, 
                                        @frequency_recurrence_factor = 0, 
                                        @frequency_subday = 0, 
                                        @frequency_subday_interval = 0, 
                                        @active_start_time_of_day = 0, 
                                        @active_end_time_of_day = 235959, 
                                        @active_start_date = 0, 
                                        @active_end_date = 0, 
                                        @job_login = null, 
                                        @job_password = null, 
                                        @publisher_security_mode = 1'

            SET @sp_startpublication_snapshot+=' exec sys.sp_startpublication_snapshot @publication = N'''+@publicationName+ ''''
        END
        -- Articles
        IF OBJECT_ID('tempdb..#t') IS NULL
            BEGIN
                PRINT 'creating temp table t'
                CREATE TABLE #t (NAME sysname,objectid INT, sch_owner sysname  NULL, article sysname NOT NULL, isIndexed BIT NULL, IsSchemaBound BIT NULL, TYPE CHAR(2) NULL)
            END
        INSERT INTO #t(NAME,objectid, sch_owner,isIndexed,IsSchemaBound, TYPE,article)
        EXEC('
        USE '+@databaseName + '
        SELECT f.Name, f.object_id,f.sch, f.IsIndexed,f.IsSchemaBound, f.type,CASE WHEN ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) > 1 THEN f.name + CAST((ROW_NUMBER() OVER (PARTITION BY f.name ORDER BY f.sch) - 1) AS VARCHAR(2)) ELSE f.name END AS Article
        FROM(
        SELECT t.Name, t.object_id,t.sch, IsIndexed,IsSchemaBound, type
        FROM 
            (SELECT DBName, SchemaOwner, TableName
            FROM TestPublication.repl.ReplicationTables
            GROUP BY DBName, SchemaOwner, TableName )rt JOIN
        (SELECT o.Name, o.object_id,s.name AS sch,  objectproperty(o.object_id, ''IsIndexed'') AS IsIndexed,objectproperty(o.object_id, ''IsSchemaBound'') AS IsSchemaBound, o.type
        FROM
        sys.objects o
        JOIN sys.schemas s ON o.schema_id = s.schema_id
        WHERE o.type IN (''U'',''V'')
            AND ObjectProperty(o.object_id, ''IsMSShipped'') = 0
            AND (ObjectProperty(o.object_id, ''TableHasPrimaryKey'') = 1 OR ObjectProperty(o.object_id, ''TableHasPrimaryKey'') IS NULL)
        ) t ON rt.tablename = t.name AND rt.SchemaOwner = t.sch
        WHERE rt.DBName = '''+@databaseName + '''
        ) f'
        )
        SELECT @sp_addarticle += 
                'exec sp_addarticle 
                @publication = N''' +@databaseName +
                ''', @article = N''' +t.article+
                ''', @source_owner = N''' +t.sch_owner +
                ''', @source_object = N''' + t.NAME +
                ''', @type = N''' +
                CASE WHEN t.type = 'U' THEN 'logbased'
                     WHEN t.type = 'V' AND (IsIndexed = 1 OR IsSchemaBound = 1 )THEN 'indexed view schema only'
                     WHEN t.type = 'V' AND IsIndexed = 0 THEN 'view schema only' END

                    +''', @description = null,@creation_script = null,@pre_creation_cmd = N''drop'', 
                @schema_option = '+
                    CASE WHEN t.type = 'U' THEN '0x000000000803509F'
                     WHEN t.type = 'V' THEN '0x0000000008000001' END+
                ',@destination_table = N'''+t.Name+
                ''',@destination_owner = N'''+t.sch_owner+''''+
                CASE WHEN t.TYPE = 'U' THEN
                        ', @identityrangemanagementoption = N''manual'',@vertical_partition = N''false'',
                @ins_cmd = N''CALL sp_MSins_'+t.sch_owner+''+t.Name+
                ''', @del_cmd = N''CALL sp_MSdel_'+t.sch_owner+''+t.Name+''',
                @upd_cmd = N''SCALL sp_MSupd_'+t.sch_owner+''+t.Name+''''
                        ELSE ''
                    END
                    +';'

        FROM #t t

        PRINT 'Now running sp_replicationdboption'
        PRINT @sp_replicationdboption
        EXEC(@sp_replicationdboption)

        PRINT 'Now running sp_addpulication'
        PRINT @sp_addpulication
        EXEC(@sp_addpulication)

        IF @allow_initialize_from_backup = 'false'
        BEGIN
            PRINT 'Now running sp_addpulication_snapshot and starting snapshot'
            PRINT @sp_addpublication_snapshot
            EXEC(@sp_addpublication_snapshot)
            EXEC(@sp_startpublication_snapshot)
        END

        PRINT 'Now running sp_addarticles'
        PRINT @sp_addarticle
        EXEC(@sp_addarticle)

    -- exec sp_droppublication @publication = N'Products'   
    END TRY

    BEGIN CATCH
        IF @@trancount > 0
            ROLLBACK

            DECLARE @ERROR_SEVERITY INT, @ERROR_STATE INT, @ERROR_MESSAGE NVARCHAR(4000)
            SELECT @ERROR_SEVERITY = ERROR_SEVERITY(), @ERROR_STATE = ERROR_STATE(), @ERROR_MESSAGE = ERROR_MESSAGE()
            RAISERROR(@ERROR_MESSAGE, @ERROR_SEVERITY, @ERROR_STATE)
    END CATCH

END
GO

and finally execute

EXEC CreatePublicationForDB 'TestPublication'

-- drop replication in case you want to run the above again.

exec TestPublication.dbo.sp_droppublication @publication = 'TestPublication'
exec TestPublication.dbo.sp_replicationdboption @dbname = 'TestPublication', @optname = 'publish', @value = 'false'

-- cleanup database

DROP DATABASE TestPublication
xghobddn

xghobddn1#

Sorry, old post I know, but I ran into a very similar situation and got around it. I haven't found a workable solution anywhere else. I'm including my experience to help others.

Summary of my situation is that I have an msbuild process running a series of scripts from a manifest file (text file with a series of script names) within a transaction. The scripts that were intended to create and configure agent jobs always died with the same error. (invalid column name "file_exists")

Procs used in my failing script(s):

msdb.dbo.sp_add_category
msdb.dbo.sp_add_job
msdb.dbo.sp_add_jobstep
msdb.dbo.sp_update_job
msdb.dbo.sp_add_jobschedule
msdb.dbo.sp_add_jobserver

Commenting out the call to msdb.dbo.sp_add_jobstep allowed the script to complete.

I do have SQL command variables in the form @database_name=N'$(DatabaseName)' in the script as well. This led to some misdirected efforts to try to use escape macros as mentioned in the "Important" note under [ @command= ] 'command' on the documentation for sp_add_jobstep.

https://msdn.microsoft.com/en-us/library/ms187358.aspx

If I run the build up to, but not including, the job creation script and start over, it succeeds.

What I found, after much trial and error, was that, even though the procs are qualified as being in [MSDB], unless I actually included a USE statement, the process fails. By beginning the script with "USE [MSDB] GO" and then switching back to my build target (i.e. USE [MyBuildDB] GO), I no longer get the error.

My agent jobs create as expected, and several scripts within the build run without error.

bf1o4zei

bf1o4zei2#

It's hard to say what the problem is without seeing all of the code and having the schema. I'd recommend not creating a wrapper to create publication(s). The create publication scripts can be saved and executed on demand when needed - eliminating the need for a wrapper.

t0ybt7op

t0ybt7op3#

I have procedure which create many SQL agent jobs. And sometimes i have problem with next ERROR with calling msdb.dbo.sp_add_jobstep - Return ERROR: Invalid column name 'file_exists' After using "Begin try" i got procedure of error msdb.dbo.sp_verify_subsystems And this procedure has next code:

CREATE TABLE #t (file_exists int, is_directory int, parent_directory_exists int)
INSERT #t EXEC xp_fileexist @DTExec
SELECT TOP 1 @DTExecExists=file_exists from #t
DROP TABLE #t

I suggest that in parallel session some procedure use the same name #t with another column names.

In procedure msdb.dbo.sp_verify_subsystems i changed temp table name from #t to some unique #tsp_verify_subsystems

it's helped me.

P.S. Don't use temp table name such #t

相关问题