#if SQLSERVER
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace Sdaleo.Systems.SQLServer
{  

    /// <summary>
    /// Specific actions for SQL Server Databases
    /// </summary>
    public class SQLServerDatabase
    {
        #region Database List

        /// <summary>
        /// Returns a array of any found Databases on the specified SQL Server intance
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="DatabaseList">list of Databases if any found, or null if not</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabasesListAll(IConnectDb credential, out string[] DatabaseList)
        {
            DatabaseList = null;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;
                      
            // Execute the Query
            string sql = "SELECT [name] FROM sys.databases";
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.FillDataTable(sql);
            if (retVal.IsValid)
            {
                List<string> DataBaseNames = new List<String>();
                foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
                         DataBaseNames.Add(row["name"].ToString());
                DatabaseList = DataBaseNames.ToArray();
            }
            return retVal;
        }

        /// <summary>
        /// Returns a array of any found Databases that are NOT SQL Default Databases (like master, model, etc);
        /// </summary>
        /// <param name="credential">SQL Server Credentials</param>
        /// <param name="DatabaseList">list of Databases if any found, or null if not</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabasesListNonDefault(IConnectDb credential, out string[] DatabaseList)
        {
            DatabaseList = null;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            // Look for all Databases that are Non-Default
            string[] DatabaseListAll = null;
            DBError retVal = DatabasesListAll(credential, out DatabaseListAll);
            if(!retVal.ErrorOccured && DatabaseListAll != null)
            {
                List<String> DatabaseListNonDefault = new List<String>();
                foreach (string DatabaseName in DatabaseListAll)
                {
                    if(!SQLServerUtilities.IsDefaultDatabaseName(DatabaseName))
                        DatabaseListNonDefault.Add(DatabaseName);
                }
                DatabaseList = DatabaseListNonDefault.ToArray();
            }
            return retVal;
        }

        #endregion

        #region Alter Database

        /// <summary>
        /// Use this to Raise the specified Database to it's highest Compatibility Level as allowed
        /// on the specified SQLServer (2005/2008/etc.)
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>        
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseRaiseCompatibility(IConnectDb credential)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;
             
            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");            

            // How to change compatibility level has changed in sql server 2008 (so we'll try to
            // use the newer way of doing it if we can.
            string sql = string.Empty;
            SQLServerVersion ServerVersion;
            DBError dberror = SQLServerGeneral.GetSQLServerVersion(credential, out ServerVersion);
            if (dberror.ErrorOccured)
                return dberror;

            switch (ServerVersion)
            {
                case SQLServerVersion.SQL_SERVER_2008:
                    sql = String.Format("ALTER DATABASE [{0}] SET COMPATIBILITY_LEVEL = {1}", credential.DBMS.Database, (int)ServerVersion);
                    break;

                default:
                    sql = String.Format("EXEC sp_dbcmptlevel [{0}], {1}", credential.DBMS.Database, (int)ServerVersion);
                    break;
            }

            // Execute the Query and return result
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        /// <summary>
        /// Allows the caller to set the Database into Single User Mode. This is * microsoft recommended *
        /// for certain type of operations on the Database to make sure nobody else can use the DB.
        /// Note: If Database is in Use * This will timeout
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>       
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseSetToSingleUserMode(IConnectDb credential)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // Execute the Query and return result
            string sql = String.Format("ALTER DATABASE [{0}] SET SINGLE_USER", credential.DBMS.Database);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        /// <summary>
        /// Allows the caller to set the Database into Multi User Mode. This should be called
        /// if the caller called DatabaseSetToSingleUserMode() previously
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseSetToMultiUserMode(IConnectDb credential)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");            

            // Execute the Query and return result
            string sql = String.Format("ALTER DATABASE [{0}] SET MULTI_USER", credential.DBMS.Database);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        /// <summary>
        /// Calls DBCC SHRINKDATABASE and DBCC UPDATEUSAGE on the passed in Database
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseShrink(IConnectDb credential)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // Execute the Query and return result
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            string sql = String.Format("DBCC SHRINKDATABASE ([{0}])", credential.DBMS.Database);
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            if (!retVal.ErrorOccured)
            {
                sql = String.Format("DBCC UPDATEUSAGE ([{0}])", credential.DBMS.Database);
                retVal = db.ExecuteNonQuery(sql);
            }
            return retVal;
        }

        /// <summary>
        /// Iterates all tables on the database and enables/disables all trigers for each table
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="bEnable">true to enable, false to disable</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError EnableDisableAllTriggers(IConnectDb credential, bool bEnable)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // Get All Table Names from the Database
            string[] TableNames = null;
            DBError dberror = SQLServerTable.Tables(credential, out TableNames);
            if (dberror.ErrorOccured)
                return dberror;

            // Execute the Query and return result
            DB db = DB.Create(credential);
            DBRetVal retVal = new DBRetVal(); 
            foreach (string TableName in TableNames)
            {                                                
                // Execute the Query for each Table
                string sql = String.Format("ALTER TABLE [{0}] {1} TRIGGER ALL", TableName, (bEnable ? "ENABLE" : "DISABLE"));
                retVal = db.ExecuteNonQuery(sql);
                if (retVal.ErrorOccured)
                    break;
            }
            return retVal;           
        }

        #endregion

        #region Databae Create / Exists

        /// <summary>
        /// Checks to see if we can query the specified server for the Database (Existence check)
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="bExists">Returns true if the Database Exists, false otherwise</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseExists(IConnectDb credential, out bool bExists)
        {
            bExists = false;
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // Execute the Query and return result
            string sql = String.Format("EXEC sp_helpdb @dbname = [{0}]", credential.DBMS.Database);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            bExists = !retVal.ErrorOccured;
            return retVal;
        }

        /// <summary>
        /// Create a new Database with the specified DatabaseName in the specified DataPath, if specified, or DefaultPath otherwise
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="DataPath">Data Path to Create Database in (not required)</param>
        /// <param name="TryAttachDBOnError">true to allow Attach Database when error occurs, false otherwise</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseCreate(IConnectDb credential, string DataPath, bool TryAttachDBOnError)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // if DataPath is empty, get default datapath for SQL ServerInstance
            if (String.IsNullOrEmpty(DataPath))
                SQLServerGeneral.SQLServerDefaultPath(credential.DBMS.WithoutDatabase(), out DataPath);

            // Fill in Database FileName and Path Details
            string sql = String.Format("CREATE DATABASE [{0}] ", credential.DBMS.Database);
            if (!String.IsNullOrEmpty(DataPath))
                sql += String.Format(@"ON (NAME = [{0}_dat], FILENAME = '{1}\{0}.dat') LOG ON (NAME = [{0}_log], FILENAME = '{1}\{0}_log.ldf')", credential.DBMS.Database, DataPath);

            // Execute the Command
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);

            // Upon DB Creation error, see if we could possibly attach the DB
            bool bErrorOccuredThatCouldMaybeBeResolvedByAttaching = false;
            if (retVal.ErrorOccured && !DBMS.GetAllErrorNumbers(DBSystem.SQL_SERVER, retVal).Contains(ErrorConst.ERROR_DB_ALREADY_EXISTS) && (
                 DBMS.GetAllErrorNumbers(DBSystem.SQL_SERVER, retVal).Contains(ErrorConst.ERROR_DB_SOME_FILE_NAMES_COULD_NOT_BE_CREATED) ||
                 DBMS.GetAllErrorNumbers(DBSystem.SQL_SERVER, retVal).Contains(ErrorConst.ERROR_DB_CAN_NOT_CREATE_FILE_BECAUSE_IT_ALREADY_EXISTS) ||
                 DBMS.GetAllErrorNumbers(DBSystem.SQL_SERVER, retVal).Contains(ErrorConst.ERROR_DB_THERE_ALREADY_IS_AN_OBJECT_IN_THE_DB_WITH_THIS_NAME)))
            {
                bErrorOccuredThatCouldMaybeBeResolvedByAttaching = true;
            }

            // Upon Error, and if we are allowed to attach && datapath is valid, try to attach
            if (retVal.ErrorOccured && TryAttachDBOnError && bErrorOccuredThatCouldMaybeBeResolvedByAttaching && !String.IsNullOrEmpty(DataPath))
            {
                String[] strFileNames = new String[] 
                    { 
                        string.Format(@"{1}\{0}.dat", credential.DBMS.Database, DataPath),
                        string.Format(@"{1}\{0}_log.ldf", credential.DBMS.Database, DataPath)
                    };
                DBError retValError = DatabaseAttach(credential, strFileNames);
                return retValError;
            }

            return retVal;
        }

        #endregion

        #region Database Attach / Dettach

        /// <summary>
        /// Attaches a Database to an SQL Server Instance
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>       
        /// <param name="strFileNames">Pass in the filenames when attaching Database (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseAttach(IConnectDb credential, string[] strFileNames)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            if ((strFileNames == null || strFileNames.Length == 0))
                return DBError.Create("Invalid FileNames Passed In");

            // Generate the SQL Query
            string sql = String.Format("EXEC sp_attach_db @dbname = [{0}]", credential.DBMS.Database);            
            for (int i = 0; i < strFileNames.Length; ++i)
                 sql = sql + String.Format(", @filename{0:d1} = '{1}'", (i + 1), strFileNames[i]);

            // Execute the Query
            DB db = DB.Create(credential.DBMS.WithoutDatabase());            
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            
            // If Error Occured try renaming dat files to mdf * legacy code *
            bool bRetryAttachingErrorOccured = false;
            if (retVal.ErrorOccured &&
                (DBMS.GetAllErrorNumbers(DBSystem.SQL_SERVER, retVal).Contains(ErrorConst.ERROR_DB_THERE_ALREADY_IS_AN_OBJECT_IN_THE_DB_WITH_THIS_NAME) ||
                 DBMS.GetAllErrorNumbers(DBSystem.SQL_SERVER, retVal).Contains(ErrorConst.ERROR_DB_DEVICE_ACTIVATION_FAILED)))
            {
                bRetryAttachingErrorOccured = true;
            }

            // Retry on Attach if failure occured & 
            // filenames contain .dat files & we have an attach specific error * LEGACY CODE Usuage *
            if (retVal.ErrorOccured && bRetryAttachingErrorOccured)
            {
                bool bRetry = false;
                List<string> retryArr = new List<string>();
                foreach (string strFileName in strFileNames)
                {
                    if (strFileName.Contains(".dat"))
                    {
                        strFileName.Replace(".dat", ".mdf");
                        bRetry = true;
                    }
                    retryArr.Add(strFileName);
                }

                // Only do an actually retry if .dat files were replaced
                if (bRetry)
                    return DatabaseAttach(credential, retryArr.ToArray());
            }
            return retVal;
        }

        /// <summary>
        /// Dettaches a Database from an SQL Server Instance
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>        
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseDettach(IConnectDb credential)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            // Execute the Query and return result
            string sql = String.Format("sp_detach_db @dbname = [{0}]", credential.DBMS.Database);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            return retVal;
        }

        #endregion

        #region Database Copy

        /// <summary>
        /// Copies a specified Database on the specified SQLServer into a new specified Database
        /// </summary>
        /// <param name="credential">SQL Server Credentials with Database Info</param>
        /// <param name="DatabaseNameDest">Name of Database To be copied To (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseCopy(IConnectDb credential, string DatabaseNameDest)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credential, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credential.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            dbError = Validation.IsValidDatabaseName(DatabaseNameDest);
            if (dbError.ErrorOccured)
                return dbError;
                

            string strDefaultPath;
            DBError dberror = SQLServerGeneral.SQLServerDefaultPath(credential, out strDefaultPath);
            if (dberror.ErrorOccured)
                return dberror;
           
            // First Step - Backup the source database to a custom Backup file
            string sql = String.Format(@"BACKUP DATABASE [{0}] TO DISK = '{1}\{0}.DB Backup' WITH INIT, NAME = '{0} Backup', PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', INIT , FORMAT", credential.DBMS.Database, strDefaultPath);
            DB db = DB.Create(credential.DBMS.WithoutDatabase());
            DBRetVal retVal = db.ExecuteNonQuery(sql);
            if (retVal.ErrorOccured)
                return retVal;

            // Second Step - Retrieve the dat & log Logical Names for the newly backed-up Database
            string strDataLogical = string.Empty;
            string strLogLogical = string.Empty;
            sql = String.Format(@"RESTORE FILELISTONLY FROM DISK = '{0}\{1}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33'", strDefaultPath, credential.DBMS.Database);
            retVal = db.FillDataTable(sql);            
            if (!retVal.IsValid)
                 return retVal;
            foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
            {
                switch (row["Type"].ToString())
                {
                    case "D":
                        strDataLogical = row["LogicalName"].ToString();
                        break;

                    case "L":
                        strLogLogical = row["LogicalName"].ToString();
                        break;
                }
            }
            if (String.IsNullOrEmpty(strDataLogical) || String.IsNullOrEmpty(strLogLogical))
                return DBError.Create("DataLogical or LogLogical could not be found");

            // Third Step - Restore Backup file to the new Database name
            sql = String.Format(@"RESTORE DATABASE [{0}] FROM DISK = '{1}\{2}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', MOVE '{3}' TO '{1}\{0}.dat', MOVE '{4}' TO '{1}\{0}_log.ldf', RECOVERY, REPLACE", DatabaseNameDest, strDefaultPath, credential.DBMS.Database, strDataLogical, strLogLogical);
            retVal = db.ExecuteNonQuery(sql);           
            if (retVal.ErrorOccured)
            {
                // try again
                retVal = db.ExecuteNonQuery(sql);
                if (!retVal.IsValid)
                    return retVal;
            }

            // Fourth Step - Try to Delete the Backup file (No Need to have a potentially massive data file just sitting there
            // ~SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the 
            //  security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. 
            //  For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online
            // sql = String.Format("exec master.dbo.xp_cmdshell 'del /Q /F \"{0}\\{1}.DB Backup\"'", strDefaultPath, DatabaseNameSrc);
            // db.ExecuteNonQuery(sql);

            // Legacy Usuage, we are leaving the Backup File behind (*leaking the file* so to speak)
            return retVal;
        }

        /// <summary>
        /// Copies a specified Database on the specified SQLServer into a new specified Database onto a different specified Instance * Must be on Same Server *
        /// </summary>
        /// <param name="credentialSrc">SQL Server Credentials with Database Info to be copied from (required)</param>
        /// <param name="credentialDest">SQL Server Credentials with Database Info to be copied to (required)</param>
        /// <returns>DBError Object with ErrorOccured, if error Occured</returns>
        public static DBError DatabaseCopySepInst(IConnectDb credentialSrc, IConnectDb credentialDst)
        {
            DBError dbError = ValidationConsts.IsCredentialValid(credentialSrc, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credentialSrc.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");

            dbError = ValidationConsts.IsCredentialValid(credentialDst, DBSystem.SQL_SERVER);
            if (dbError.ErrorOccured)
                return dbError;

            if (!credentialDst.DBMS.IsDatabaseSetAndNonSystem)
                return DBError.Create("Invalid Database Passed In via Credential");
            
            if (String.Compare(credentialSrc.DBMS.Server, credentialDst.DBMS.Server, true) != 0)
                return DBError.Create("Must be on the Same Server");

            if (String.Compare(credentialSrc.DBMS.Instance, credentialDst.DBMS.Instance, true) == 0)
                return DBError.Create("Can not be the same Instance");            

            // Get Src Default Path *of the DB*
            string strDefaultPathSrc;
            DBError dberror = SQLServerGeneral.SQLServerDefaultPath(credentialSrc, out strDefaultPathSrc);
            if (dberror.ErrorOccured)
                return dberror;

            // Get Dest Default Path *of the Server*
            string strDefaultPathDest;
            dberror = SQLServerGeneral.SQLServerDefaultPath(credentialDst, out strDefaultPathDest);
            if (dberror.ErrorOccured)
                return dberror;            

            // Make sure that both Paths aren't the same *Two instances should never have the same path!*
            if (strDefaultPathSrc.ToUpper() == strDefaultPathDest.ToUpper())
                return DBError.Create(String.Format("The File Path of the Source Database {0} and the Destination Database {1} on Server {1} are identical.", credentialSrc.DBMS.Database, credentialDst.DBMS.Database, credentialDst.DBMS.Server));

            // Create Src N' Dest Connections * No Limit on the Command timeout *
            //                                  Could be very large database that we are trying to copy            
            DB dbSrc = DB.Create(credentialSrc.DBMS.WithoutDatabase().Timeouts.WithCommandTimeout(0));
            DB dbDst = DB.Create(credentialDst.DBMS.WithoutDatabase().Timeouts.WithCommandTimeout(0));

            // First Step - Backup the source database to a custom DB Backup file to the DESTINATION path
            string sql = String.Format(@"BACKUP DATABASE [{0}] TO DISK = '{1}\{0}.DB Backup' WITH INIT, NAME = '{0} Backup', PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', INIT , FORMAT", credentialSrc.DBMS.Database, strDefaultPathSrc);
            DBRetVal retVal = dbSrc.ExecuteNonQuery(sql);
            if (retVal.ErrorOccured)
                return retVal;

            // Second Step - Retrieve the dat & log Logical Names for the newly backed-up Database File
            string strDataLogical = string.Empty;
            string strLogLogical = string.Empty;
            sql = String.Format(@"RESTORE FILELISTONLY FROM DISK = '{0}\{1}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33'", strDefaultPathSrc, credentialSrc.DBMS.Database);
            retVal = dbSrc.FillDataTable(sql);
            if (!retVal.IsValid)
                 return retVal;            
            foreach (DataRow row in retVal.GetDataTableRetVal().Rows)
            {
                switch (row["Type"].ToString())
                {
                    case "D":
                        strDataLogical = row["LogicalName"].ToString();
                        break;

                    case "L":
                        strLogLogical = row["LogicalName"].ToString();
                        break;
                }
            }
            if (String.IsNullOrEmpty(strDataLogical) || String.IsNullOrEmpty(strLogLogical))
                return DBError.Create(String.Format("The retrieval of Logical Names for Database '{0}' failed for Server Instance '{1}' in Path '{2}'.", credentialSrc.DBMS.Database, credentialSrc.DataSource, strDefaultPathDest));

            // Third Step - Restore Backup file to the new Database name onto the new (Dest) instance
            sql = String.Format(@"RESTORE DATABASE [{0}] FROM DISK = '{1}\{2}.DB Backup' WITH FILE = 1, PASSWORD = 'dbCopy Backup', MEDIAPASSWORD = 'XaseY 1-33', MOVE '{3}' TO '{5}\{0}.dat', MOVE '{4}' TO '{5}\{0}_log.ldf', RECOVERY, REPLACE", credentialDst.DBMS.Database, strDefaultPathSrc, credentialSrc.DBMS.Database, strDataLogical, strLogLogical, strDefaultPathDest);
            retVal = dbDst.ExecuteNonQuery(sql);
            if (!retVal.ErrorOccured)
            {
                // try again
                retVal = dbDst.ExecuteNonQuery(sql);
                if (!retVal.IsValid)
                    return retVal;
            }

            // Fourth Step - Try to Delete the Backup file (No Need to have a potentially massive data file just sitting there
            // ~SQL Server blocked access to procedure 'sys.xp_cmdshell' of component 'xp_cmdshell' because this component is turned off as part of the 
            //  security configuration for this server. A system administrator can enable the use of 'xp_cmdshell' by using sp_configure. 
            //  For more information about enabling 'xp_cmdshell', see "Surface Area Configuration" in SQL Server Books Online
            // sql = String.Format("exec master.dbo.xp_cmdshell 'del /Q /F \"{0}\\{1}.DB Backup\"'", strDefaultPath, DatabaseNameSrc);
            // db.RunSQLCommandTextExecuteNonQuery(sql);

            // Legacy Usuage, we are leaving the Backup File behind (*leaking the file* so to speak)
            return retVal;
        }

        #endregion
    }
}
#endif