SandyFlat.Net

DB Cloning

Database Cloning
 

A development database is one of the most valuable tools that a Maximo admin can have. It provides a platform for testing version upgrades, patches and customizations without interrupting or endangering the production platform.

For a development database to be valid test environment, it should be kept reasonably up-to-date with the state of the production database. If the development database is on the same server as the production database, it's pretty straight forward to restore a production backup copy to the development container.

But when the development database is on another server, it's a little trickier. This page outlines a technique to copy a production Maximo database to a development server with source logins and passwords intact.

Jump to section: Prerequisites    Backup from Source    Restore to Destination    Automation

Prequisites (back to top)

On the source database server, these two stored procedures are used to export a file that will be used to setup logins with passwords on the destination server. To install, open Query Analyzer, paste in the first stored procedure's text and execute. Repeat for the second one. This only needs to be done once.

sp_hexadecimal.sql
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'sp_hexadecimal' AND type = 'P')
   DROP PROCEDURE sp_hexadecimal
   GO
CREATE PROCEDURE sp_hexadecimal
   @binvalue varbinary(256),
   @hexvalue varchar(256) OUTPUT
AS
DECLARE @charvalue varchar(255)
DECLARE @i int
DECLARE @length int
DECLARE @hexstring char(16)
SELECT @charvalue = '0x'
SELECT @i = 1
SELECT @length = DATALENGTH (@binvalue)
SELECT @hexstring = '0123456789ABCDEF'
WHILE (@i <= @length)
   BEGIN
      DECLARE @tempint int
      DECLARE @firstint int
      DECLARE @secondint int
      SELECT @tempint = CONVERT(int, SUBSTRING(@binvalue,@i,1))
      SELECT @firstint = FLOOR(@tempint/16)
      SELECT @secondint = @tempint - (@firstint*16)
      SELECT @charvalue = @charvalue +
         SUBSTRING(@hexstring, @firstint+1, 1) +
         SUBSTRING(@hexstring, @secondint+1, 1)
      SELECT @i = @i + 1
   END
SELECT @hexvalue = @charvalue
GO
Download SP_HEXADECIMAL.ZIP (1 kb)
Background info at: Microsoft Knowledgebase Article 246133

sp_help_revlogin_maximo.sql
IF EXISTS (SELECT name FROM sysobjects WHERE name = 'sp_help_revlogin_maximo' AND type = 'P')
   DROP PROCEDURE sp_help_revlogin_maximo
   GO
CREATE PROCEDURE sp_help_revlogin_maximo @login_name sysname = NULL AS
DECLARE @name sysname
DECLARE @xstatus int
DECLARE @binpwd varbinary (255)
DECLARE @txtpwd sysname
DECLARE @tmpstr varchar (255)
IF (@login_name IS NULL)
   DECLARE login_curs CURSOR FOR
      SELECT name, xstatus, password FROM master..sysxlogins
      WHERE srvid IS NULL AND name <> 'sa'
      AND name NOT IN ('MAXIMO','DEFLT','REPL_PUBLISHER', 'REPL_SUBSCRIBER','SYSADM','SYSSQL')
      AND name NOT LIKE '%\%'
ELSE
   DECLARE login_curs CURSOR FOR
      SELECT name, xstatus, password FROM master..sysxlogins
      WHERE srvid IS NULL AND name = @login_name
      AND name NOT IN ('MAXIMO','DEFLT','REPL_PUBLISHER','REPL_SUBSCRIBER','SYSADM','SYSSQL')
      AND name NOT LIKE '%\%'OPEN login_curs
FETCH NEXT FROM login_curs INTO @name, @xstatus, @binpwd
IF (@@fetch_status = -1)
   BEGIN
      PRINT 'No login(s) found.'
      CLOSE login_curs
      DEALLOCATE login_curs
      RETURN -1
   END
SET @tmpstr = '/* sp_help_revlogin_maximo script '
PRINT @tmpstr
SET @tmpstr = '** Generated ' + CONVERT (varchar, GETDATE()) + ' on ' + @@SERVERNAME + ' */'
PRINT @tmpstr
PRINT ''
PRINT 'DECLARE @pwd sysname'
WHILE (@@fetch_status <> -1)
   BEGIN
      IF (@@fetch_status <> -2)
         BEGIN
            PRINT ''
            SET @tmpstr = '-- Login: ' + @name
            PRINT @tmpstr
            IF (@xstatus & 4) = 4
               BEGIN -- NT authenticated account/group
                  IF (@xstatus & 1) = 1
                     BEGIN -- NT login is denied access
                        SET @tmpstr = 'EXEC master..sp_denylogin ''' + @name + ''''
                        PRINT @tmpstr
                     END
                  ELSE
                     BEGIN -- NT login has access
                        SET @tmpstr = 'EXEC master..sp_grantlogin ''' + @name + ''''
                        PRINT @tmpstr
                     END
               END
            ELSE
               BEGIN -- SQL Server authentication
                  IF (@binpwd IS NOT NULL)
                     BEGIN -- Non-null password
                        EXEC sp_hexadecimal @binpwd, @txtpwd OUT
                        IF (@xstatus & 2048) = 2048
                        SET @tmpstr = 'SET @pwd = CONVERT(varchar, ' + @txtpwd + ')'
                        ELSE
                           SET @tmpstr = 'SET @pwd = ' + @txtpwd
                           PRINT @tmpstr
                           SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name + ''', @pwd, @encryptopt = '
                     END
                  ELSE
                     BEGIN -- Null password
                        SET @tmpstr = 'EXEC master..sp_addlogin ''' + @name + ''', NULL, @encryptopt = '
                     END
                  IF (@xstatus & 2048) = 2048 -- login upgraded from 6.5
                     SET @tmpstr = @tmpstr + '''skip_encryption_old'''
                  ELSE
                     SET @tmpstr = @tmpstr + '''skip_encryption'''
                     PRINT @tmpstr
               END
         END
         FETCH NEXT FROM login_curs INTO @name, @xstatus, @binpwd
   END
CLOSE login_curs
DEALLOCATE login_curs
RETURN 0
GO
Download SP_HELP_REVLOGON_MAXIMO.ZIP (2 kb)
Background info at: Microsoft Knowledgebase Article 246133

Backup from Source (back to top)

Once the above stored procedures are installed on the source production database server, you're ready to run the 'source' section that will build a login file and create a database backup file.

On the source machine, open Query Analyzer and run:
              EXEC sp_help_revlogin_maximo

Click into the result pane and save the output as BUILD_LOGINS.SQL. This file will be used on the destination machine to create logins with passwords.
Clear the Query Analyzer window and run the following script, after setting your local backup path and database name:

backup_database.sql
USE master
BACKUP DATABASE maximodb TO DISK = 'i:\backups\maximodb.bak' WITH INIT
GO
Download BACKUP_DATABASE.ZIP (1 kb)

When the backup completes, copy the database backup file, MAXIMODB.BAK, and the BUILD_LOGINS.SQL script to the destination database server.

Restore to Destination (back to top)

On the destination database server, substitute your database name and database device paths and run this script to setup the development database container:

setup_destination.sql
/* Drop old database */
USE master
DROP DATABASE maximodb

/* Generate list of present logins to drop and drop them */
EXEC xp_execresultset 'select ''EXEC sp_droplogin ''+loginname FROM syslogins WHERE loginname NOT IN (''sa'') AND loginname NOT LIKE ''%\%'' ORDER BY loginname','master'

/* When debugging, be sure that logins: DEFLT, MAXIMO, SYSADM, SYSSQL, report and updater got dropped, above */
/* Setup standard Maximo required logins */

USE master
EXEC sp_addlogin MAXIMO, MAXIMO
EXEC sp_addlogin SYSADM, SYSADM
EXEC sp_addlogin SYSSQL, SYSSQL
EXEC sp_addlogin DEFLT, DEFLT

/* Create new database container */
USE master
CREATE DATABASE maximodb
ON
( NAME = maximodbdata,
   FILENAME = 'e:\data\maximodbdata.mdf')
LOG ON
( NAME = maximodblog,
   FILENAME = 'f:\logs\maximodblog.ldf')

/* Set up new database per PSDI specs - case sensitive! */
USE maximodb
EXEC sp_changedbowner MAXIMO
EXEC sp_addalias SYSADM,dbo
EXEC sp_adduser SYSSQL,SYSSQL
EXEC sp_adduser DEFLT,DEFLT
EXEC sp_adduser guest
GRANT CREATE TABLE, CREATE VIEW, CREATE PROCEDURE TO SYSSQL
GO

/* Check the work so far */
EXEC sp_helplogins
EXEC sp_helpuser
Download SETUP_DESTINATION.ZIP (1 kb)

Clear the Query Analyzer window and run the BUILD_LOGINS.SQL script to create the logins and passwords as the appeared on the source server. Use only the BUILD_LOGINS.SQL script that was generated on your source server as this file is unique to your installation. It's not available for download here and you shouldn't cut-and-paste the below sample:

SAMPLE build_logins.sql
/* sp_help_revlogin_maximo */
DECLARE @pwd sysname

-- Login: ADAM
SET @pwd = CONVERT (varchar, 0x2131235F2727395F5557564A5E523824)
EXEC master..sp_addlogin 'ADAM', @pwd, @encryptopt = 'skip_encryption_old'

-- Login: BAKER
SET @pwd = 0x0100E52A50350D874CD4B396EAD77259C983E397923E6A09B39 -> 80D874CD4B396EAD77259C983E397923E6A09B398
EXEC master..sp_addlogin 'BAKER', @pwd, @encryptopt = 'skip_encryption'

-- Login: CHARLIE
SET @pwd = 0x01008D0BFE1BCE05AF4F257CE412E2B188D663C20CD54577454 -> 3CE05AF4F257CE412E2B188D663C20CD545774543
EXEC master..sp_addlogin 'CHARLIE', @pwd, @encryptopt = 'skip_encryption'

-- Login: DELTA
SET @pwd = CONVERT (varchar, 0x2131214A212C482F58505E2C5D35252A)
EXEC master..sp_addlogin 'DELTA', @pwd, @encryptopt = 'skip_encryption_old'

When the BUILD_LOGINS.SQL script completes, substitute your database name and database device paths and run the following to restore the database backup made earlier:

restore_database.sql
/* Restore the *.BAK backup to the database */
USE master
RESTORE DATABASE maximodb
   FROM DISK = 'i:\backups\maximodb.bak'
   WITH MOVE 'maximodbdata' TO 'e:\data\maximodbdata.mdf',
   MOVE 'maximodblog' TO 'f:\logs\maximodblog.ldf',
   REPLACE
GO
Download RESTORE_DATABASE.ZIP (1 kb)

When the database restore completes, substitute your database name and run the following script to resynchronize the logins and userid:

resync_logins.sql
/* Resync users to logins */
USE maximodb
EXEC sp_helpuser -- should show many NULL LoginNames
                 -- as the SIDs are out of sync


/* The following resync section reconciles the Logins and Users */
DECLARE @username nvarchar(255)
DECLARE orphanuser_cur cursor FOR
   SELECT username = name
   FROM sysusers
   WHERE issqluser = 1 AND (sid IS NOT NULL AND sid <> 0x0) AND suser_sname(sid) IS NULL
   ORDER BY name

OPEN orphanuser_cur
FETCH NEXT FROM orphanuser_cur INTO @username
WHILE (@@fetch_status = 0)
   BEGIN
      PRINT @username + ' user name being resynced'
      EXEC sp_change_users_login 'Update_one', @username, @username
      FETCH NEXT FROM orphanuser_cur INTO @username
   END

CLOSE orphanuser_cur
DEALLOCATE orphanuser_cur
GO
/* End of resync section */

/* Check results */
EXEC sp_helpuser -- now nearly all of the NULL LoginNames
                 -- have been matched up
                 -- with the usernames, except DBO and
                 -- GUEST. Then there's that
                 -- NULL alias at the bottom to fix


/* Fix the NULL alias */
USE master
EXEC sp_droplogin SYSADM
USE maximodb
EXEC sp_dropalias 'SYSADM'
USE master
EXEC sp_addlogin SYSADM, SYSADM
USE maximodb
EXEC sp_addalias SYSADM, dbo

/* Check results again */
USE maximodb
EXEC sp_helpuser -- That fixed the alias but there
                 -- are still two NULL logins

                 -- one on DBO and one on GUEST

EXEC sp_changedbowner MAXIMO -- This will set user DBO to
                             -- login Maximo, the remaining
                             -- NULL on guest is OK


/* Patch miscellaneous items */
USE maximodb
GRANT SELECT ON matusetrans TO public
GO

/* Final review */
EXEC sp_helpuser
EXEC sp_helplogins

/* Then take a look to see if the data is there */
SELECT COUNT(wonum) FROM workorder

/* Finished */
Download RESYNC_LOGINS.ZIP (1 kb)

At this point, you should have a copy of your production database in a development environment with logins and passwords intact. This method was originally used with SQL Server V6.5, and should work with V6.5, V7.0 and 2000. With the release of SQL Server 2000, DTS has become a viable alternative to the above method.

Automation (back to top)

If you'd like to automate the running of the scripts, you can use command files on the source and destination machines. On the source machine, you might use:

source.cmd
@ECHO OFF
CLS
REM Run this on the source database server
ECHO Preparing to backup database backup and logins.
->Press CTRL C now to abort, or
PAUSE

REM Build a source list of logins and passwords
ECHO Backing up logins and passwords...
ECHO Backing up database...
osql /U sa /P sa_passsord /S source_server -d master /q "EXIT(sp_help_revlogin_maximo)" /w 999 /o i:\backups\build_logins.sql

REM Make backup file
osql /U sa /P sa_password /S source_server -d master /i backup_database.sql
ECHO Finished
PAUSE
Download SOURCE.ZIP(1 kb)

On the destination machine, you might use:

destination.cmd
@ECHO OFF
REM Run this on the destination server only after
REM SOURCE.CMD has been run

REM and the database .BAK backup file and BUILD_LOGINS.SQL
REM file are available

ECHO Preparing to restore database backup and logins.
ECHO Press CTRL C now to abort, or
PAUSE

REM Setup destination server
ECHO Performing setup...
osql /U sa /P sa_password /S destination_server -d master /i setup_destination.sql /o setup_destination.log

REM Build logins
ECHO Building logins...
osql /U sa /P sa_password /S destination_server -d master /i i:\backups\build_logins.sql /o build_logins.log

REM Restore .BAK file from source server to destination server

ECHO Restoring database backup...
osql /U sa /P sa_password /S destination_server -d master /i restore_database.sql /o restore_database.log

REM Resync logins with users and perform misc cleanups
ECHO Resyncing logins...
osql /U sa /P sa_password /S destination_server -d master /i resync_logins.sql /o resync_logins.log

ECHO Finished
PAUSE
Download DESTINATION.ZIP(1 kb)

Of course, if you do use OSQL's /P option to specify a password, you must make sure that the command files are secure. A more secure method, at the cost of automation, would be to omit the /P options, causing each OSQL line to prompt for the password.

Each of the steps in the DESTINATION.CMD will write to a log file.

Although I have just checked the above on a Maximo V4.1.1, Patch Level 05 installation, running on SQL Server 2000 SP3, I strongly advise that you verify the scripts and tailor them to suit your installation. The 'source' scripts won't change the source system, but the 'destination' scripts definitely will change the system that they're run on.

Disclaimer: as with all of the tips and scripts, be sure that you understand what they do before trying them. I make no guarantees - use the scripts at your own risk!