Anthony Tuininga avatar Anthony Tuininga committed b7b88df

Last changes made at Computronix.

Comments (0)

Files changed (18)

 """Backs up an Oracle database."""
 
+import cx_LoggingOptions
 import cx_OptionParser
 import os
 import sys
 
 import BackupFile
+import Exceptions
 import Manager
 import Options
 
         help = "specifies the amount of compression to do; "
                "this is a number from 1 to 9 with 1 being the least "
                "compression and 9 being the most compression")
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sid", required = True,
         help = "the SID of the database to backup")
 parser.AddArgument("fileName", required = True,
         help = "the name of the file to create")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 if options.compressLevel < 1 or options.compressLevel > 9:
-    raise "Compression level must be between 1 and 9 inclusive"
+    raise Exceptions.InvalidCompressionLevel()
 
 # perform the work
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceFromEnvironment(options.sysPassword,
+database = manager.DatabaseFromEnvironment(options.sysPassword,
         options.tnsentry)
-if instance is not None:
-    wasAvailable = manager.IsInstanceAvailable(instance)
+if database is not None:
+    wasAvailable = manager.IsDatabaseAvailable(database)
     if not wasAvailable:
         if options.noStart:
-            raise "Instance %s not started." % instance.sid
-        manager.StartInstance(instance)
-    instance.GetDatabaseInfo()
-    manager.StopInstance(instance, options.shutdownMode)
-    manager.WriteDirsConfig(instance.sid, instance.GetDirectories())
+            raise Exceptions.DatabaseNotStarted(sid = database.sid)
+        manager.StartDatabase(database)
+    info = database.info
+    manager.StopDatabase(database, options.shutdownMode)
     backupFile = BackupFile.BackupFile(options.fileName, "w",
             options.compressLevel)
-    backupFile.Backup(instance)
+    backupFile.Backup(database)
     if wasAvailable:
-        manager.StartInstance(instance)
+        manager.StartDatabase(database)
 else:
-    instance = manager.InstanceBySid(options.sid)
-    manager.ExecuteForInstance(instance)
+    database = manager.DatabaseBySid(options.sid)
+    manager.ExecuteForDatabase(database)
 
 import bz2
 import cPickle
 import cStringIO
+import cx_Logging
 import os
 import sys
 import time
 
+import Database
+import DatabaseInfo
 import Utils
 
 PICKLE_PROTOCOL = 2
 FILE_FRAG_SIZE = 1024 * 1024
 
-class BackupFile:
+class BackupFile(object):
     """Manages backup files which are pickled representations of the Oracle
        data files and all files found in directories that the database
        references."""
         self.__allFiles = {}
 
     def __BackupFile(self, fileName):
-        """Back up the file to the backup file."""
         fileName = Utils.NormalizePath(fileName)
         if fileName in self.__allFiles:
             return
         self.__allFiles[fileName] = None
-        print fileName, "...",
-        sys.stdout.flush()
+        cx_Logging.Trace("Backing up %s...", fileName)
         statResult = os.stat(fileName)
         times = (statResult.st_atime, statResult.st_mtime)
         cPickle.dump((fileName, times), self.__file, PICKLE_PROTOCOL)
                 break
             cPickle.dump(data, self.__file, PICKLE_PROTOCOL)
         cPickle.dump(None, self.__file, PICKLE_PROTOCOL)
-        print "[OK]"
 
     def __BackupDir(self, dirName):
-        """Back up the directory to the file, if necessary."""
         dirName = Utils.NormalizePath(dirName)
         if dirName in self.__allDirs:
             return
     def __FormatTime(self, xTime):
         return time.strftime("%Y/%m/%d %H:%M:%S", time.localtime(xTime))
 
-    def __RestoreFile(self, dirMapping, name, times):
-        """Restore the file."""
-        newName = Utils.NormalizePath(name)
-        if dirMapping is not None:
-            newName = Utils.MappedName(name, dirMapping)
-        print newName, "...",
-        sys.stdout.flush()
-        dir = os.path.dirname(newName)
+    def __RestoreFile(self, mapping, name, times):
+        if mapping is not None:
+            name = mapping.MappedFileName(name)
+        cx_Logging.Trace("Restoring %s...", name)
+        dir = os.path.dirname(name)
         if not os.path.exists(dir):
             os.makedirs(dir)
-        outFile = file(newName, "wb", 0)
+        outFile = file(name, "wb", 0)
         while True:
             data = cPickle.load(self.__file)
             if data is None:
                 break
             outFile.write(data)
         outFile.close()
-        os.utime(newName, times)
-        print "[OK]"
+        os.utime(name, times)
 
-    def Backup(self, instance):
-        """Back up the instance to the file."""
-        cPickle.dump(instance, self.__file, PICKLE_PROTOCOL)
-        print "Backing up files..."
-        for dirName in instance.GetDirectories(includeDataFiles = False):
+    def Backup(self, database):
+        cPickle.dump(database.info, self.__file, PICKLE_PROTOCOL)
+        cx_Logging.Info("Backing up files...")
+        self.__BackupDir(database.adminDir)
+        for dirName in database.info.GetDirectories(includeDataFiles = False):
             self.__BackupDir(dirName)
-        for fileName in instance.GetDataFiles(includeTempFiles = False):
+        for fileName in (database.storedParameterFileName,
+                database.passwordFileName):
+            if os.path.exists(fileName):
+                self.__BackupFile(fileName)
+        for fileName in database.info.GetDataFiles(includeTempFiles = False):
             self.__BackupFile(fileName)
         cPickle.dump(None, self.__file, PICKLE_PROTOCOL)
         self.__file.close()
 
     def Directory(self, details):
-        """Lists the files contained in the backup."""
         if details:
             print "      Size        Update Time  File"
             print "----------", "-------------------", "-" * 48
         print "*" * 79
         self.__file.close()
 
-    def GetInstance(self):
-        """Return the instance from the file."""
-        return cPickle.load(self.__file)
+    def GetDatabase(self, adminDir):
+        rawInfo = cPickle.load(self.__file)
+        if isinstance(rawInfo, DatabaseInfo.DatabaseInfo):
+            info = rawInfo
+        else:
+            info = DatabaseInfo.DatabaseInfo()
+            info.PopulateFromOldStyleBackup(rawInfo)
+        database = Database.Database(info.sid, info.oracleHome, adminDir,
+                info.startMode)
+        database.info = info
+        return database
 
-    def Restore(self, dirMapping = None):
-        """Restore the instance from the file."""
-        print "Restoring files..."
+    def Restore(self, mapping = None):
+        cx_Logging.Info("Restoring files...")
         while True:
             value = cPickle.load(self.__file)
             if value is None:
                 break
-            self.__RestoreFile(dirMapping, *value)
+            self.__RestoreFile(mapping, *value)
         self.__file.close()
 
 """Starts up an Oracle database."""
 
+import cx_Logging
+import cx_LoggingOptions
 import cx_OptionParser
 import cx_ShellUtils
 import os
 import sys
 
+import Database
+import Exceptions
 import Manager
 import Options
 import Utils
 parser.AddOption(Options.REPLACE_EXISTING)
 parser.AddOption(Options.NO_START)
 parser.AddOption(Options.SHUTDOWN_MODE)
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("origSid", required = True,
         help = "the SID of the database to clone")
 parser.AddArgument("newSid", required = True,
         help = "the SID of the database to create")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
-# make sure the target instance does not exist
+# make sure the target database does not exist
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceBySid(options.newSid, ignoreIfMissing = True)
-if instance is not None and not options.replaceExisting:
-    raise "Instance %s already exists." % options.newSid
+database = manager.DatabaseBySid(options.newSid, ignoreIfMissing = True)
+if database is not None and not options.replaceExisting:
+    raise Exceptions.DatabaseAlreadyExists(sid = options.newSid)
 
 # perform the work
-instance = manager.InstanceFromEnvironment(options.sysPassword,
+database = manager.DatabaseFromEnvironment(options.sysPassword,
         options.tnsentry)
-if instance is None:
-    instance = manager.InstanceBySid(options.origSid)
-    manager.ExecuteForInstance(instance)
+if database is None:
+    database = manager.DatabaseBySid(options.origSid)
+    manager.ExecuteForDatabase(database)
 else:
     if options.replaceExisting:
-        existingInstance = manager.InstanceBySid(options.newSid,
+        existingDatabase = manager.DatabaseBySid(options.newSid,
                 ignoreIfMissing = True)
-        if existingInstance is not None:
-            manager.RemoveInstance(existingInstance)
-    wasAvailable = manager.IsInstanceAvailable(instance)
+        if existingDatabase is not None:
+            manager.RemoveDatabase(existingDatabase)
+    wasAvailable = manager.IsDatabaseAvailable(database)
     if not wasAvailable:
         if options.noStart:
-            raise "Instance %s not started." % instance.sid
-        manager.StartInstance(instance)
-    instance.GetDatabaseInfo()
-    dirMapping = Utils.GetDirMapping(instance.GetDirectories(),
-            options.origSid, options.newSid, options.prompts)
-    newInstance = instance.Clone(options.newSid, options.sysPassword,
-            dirMapping)
-    manager.StopInstance(instance, options.shutdownMode)
-    for name in instance.GetDataFiles(includeTempFiles = False):
-        newName = Utils.MappedName(name, dirMapping)
-        print "Copying", name, "to", newName, "...",
-        sys.stdout.flush()
+            raise Exceptions.DatabaseNotStarted(sid = database.sid)
+        manager.StartDatabase(database)
+    info = database.info
+    newDatabase = Database.Database(options.newSid,
+            database.oracleHome, manager.adminDir, database.startMode,
+            database.sysPassword)
+    mapping = Utils.Mapping(newDatabase, database, options.prompts)
+    newDatabase.Clone(database, mapping)
+    manager.StopDatabase(database, options.shutdownMode)
+    for name in database.info.GetDataFiles(includeTempFiles = False):
+        newName = mapping.MappedFileName(name)
+        cx_Logging.Trace("Copying %s to %s...", name, newName)
         dirName = os.path.dirname(newName)
         if not os.path.exists(dirName):
             os.makedirs(dirName)
         cx_ShellUtils.Copy(name, newName, includeTimes = True)
-        print "[ok]"
-    manager.CreateInstanceFromClone(newInstance)
+    for name in (database.storedParameterFileName, database.passwordFileName):
+        if os.path.exists(name):
+            newName = mapping.MappedFileName(name)
+            cx_ShellUtils.Copy(name, newName, includeTimes = True)
+    manager.CreateDatabaseFromClone(newDatabase)
     if wasAvailable:
-        manager.StartInstance(instance)
+        manager.StartDatabase(database)
 
 """Creates an Oracle database."""
 
 import cx_ClassLibrary
+import cx_LoggingOptions
 import cx_OptionParser
 import socket
 
+import Exceptions
 import Options
 import Manager
 
         help = "the sys password for the new database; if omitted the "
                "name of the machine is used")
 parser.AddOption(Options.TNSENTRY)
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sid", required = True,
         help = "the SID to use for the database to create")
-parser.AllowVarArgs("parms",
+parser.AddArgument("substitutions", keywords = True,
         help = 'this is a set of "name=value" pairs that override the '
                'substitutions specified in the config file.')
 options = parser.Parse()
-parms = cx_ClassLibrary.CaselessDict()
-for parm in options.parms:
-    parts = parm.split("=")
-    if len(parts) != 2:
-        raise "Expecting parmeters of style \"name=value\"."
-    name, value = parts
-    parms[name] = value
+cx_LoggingOptions.ProcessOptions(options)
 
 # perform the work
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceBySid(options.sid, ignoreIfMissing = True)
-if instance is not None:
-    raise "Instance %s already exists." % options.sid
-manager.CreateInstance(options.sid, options.sysPassword, options.tnsentry,
-        options.startMode, options.databaseType, parms)
+database = manager.DatabaseFromTypeName(options.sid, options.databaseType,
+        options.sysPassword, options.tnsentry, options.startMode)
+databaseFromEnv = manager.DatabaseFromEnvironment(options.sysPassword,
+        options.tnsentry)
+if databaseFromEnv is None:
+    manager.ExecuteForDatabase(database)
+else:
+    existingDatabase = manager.DatabaseBySid(options.sid,
+            ignoreIfMissing = True)
+    if existingDatabase is not None:
+        raise Exceptions.DatabaseAlreadyExists(sid = options.sid)
+    manager.CreateDatabase(database, options.substitutions)
 
+"""Define classes for handling Oracle databases."""
+
+import cx_Logging
+import imp
+import os
+import socket
+import sys
+
+import Exceptions
+import DatabaseInfo
+import Utils
+
+if sys.platform == "win32":
+    import cx_Win32Pipe
+    popen = cx_Win32Pipe.popen
+    CONFIG_DIR = "Database"
+else:
+    popen = os.popen
+    CONFIG_DIR = "dbs"
+
+
+class ActualParameterFileNameDescriptor(object):
+
+    def __get__(self, database, databaseType):
+        return os.path.join(database.adminDir, "pfile", "init.ora")
+
+
+class ConfigFileNameDescriptor(object):
+
+    def __init__(self, baseName):
+        self.baseName = baseName
+
+    def __get__(self, database, databaseType):
+        fileName = "%s.cfg" % self.baseName
+        return os.path.join(database.adminDir, "config", fileName)
+
+
+class ConnectionDescriptor(object):
+
+    def __get__(self, database, databaseType):
+        database.SetEnvironment()
+        driver = database.driver
+        return driver.Connection(database.connectString, mode = driver.SYSDBA)
+
+
+class ConnectStringDescriptor(object):
+
+    def __get__(self, database, databaseType):
+        if database.sysPassword is None:
+            return "/"
+        connectString = "sys/%s" % database.sysPassword
+        if database.tnsentry is not None:
+            connectString = "%s@%s" % (connectString, database.tnsentry)
+        return connectString
+
+
+class DriverDescriptor(object):
+    if sys.platform == "win32":
+        filesToCheck = [
+                ("10g", "oraclient10.dll"),
+                ("9i", "oraclient9.dll"),
+                ("8i", "oraclient8.dll")
+        ]
+    else:
+        filesToCheck = [
+                ("10g", "libclient10.a"),
+                ("9i", "libclient9.a"),
+                ("8i", "libclient8.a")
+        ]
+
+    def __get__(self, database, databaseType):
+        for version, fileName in self.filesToCheck:
+            if sys.platform == "win32":
+                fileName = os.path.join(database.binDir, fileName)
+            else:
+                fileName = os.path.join(database.libDir, fileName)
+            if os.path.exists(fileName):
+                suffix, mode, moduleType = imp.get_suffixes()[0]
+                dirName = os.path.dirname(sys.executable)
+                fileName = os.path.join(dirName,
+                        "cx_Oracle_%s%s" % (version, suffix))
+                try:
+                    database.driver = imp.load_dynamic("cx_Oracle", fileName)
+                except ImportError:
+                    raise Exceptions.MissingOracleDriver(version = version)
+                return database.driver
+        raise Exceptions.MissingOracleInstallation()
+
+
+class InfoDescriptor(object):
+
+    def __get__(self, database, databaseType):
+        info = DatabaseInfo.DatabaseInfo()
+        info.PopulateFromDatabase(database)
+        database.info = info
+        return info
+
+
+class OracleConfigFileNameDescriptor(object):
+
+    def __init__(self, prefix):
+        self.prefix = prefix
+
+    def __get__(self, database, databaseType):
+        fileName = "%s%s.ora" % (self.prefix, database.sid)
+        return os.path.join(database.oracleHome, CONFIG_DIR, fileName)
+
+
+class PasswordFileNameDescriptor(object):
+
+    def __get__(self, database, databaseType):
+        if sys.platform == "win32":
+            fileName = "%s%s.ora" % (self.prefix, database.sid)
+        else:
+            fileName = "orapw%s" % database.sid
+        return os.path.join(database.oracleHome, CONFIG_DIR, fileName)
+
+
+class Database(object):
+    parameterFileName = OracleConfigFileNameDescriptor("init")
+    storedParameterFileName = OracleConfigFileNameDescriptor("spfile")
+    passwordFileName = PasswordFileNameDescriptor()
+    actualParameterFileName = ActualParameterFileNameDescriptor()
+    diskConfigFileName = ConfigFileNameDescriptor("disk")
+    envConfigFileName = ConfigFileNameDescriptor("env")
+    connectString = ConnectStringDescriptor()
+    connection = ConnectionDescriptor()
+    driver = DriverDescriptor()
+    info = InfoDescriptor()
+
+    def __init__(self, sid, oracleHome, adminDir, startMode = "Manual",
+            sysPassword = None, tnsentry = None, databaseType = None):
+        self.sid = sid
+        self.oracleHome = oracleHome
+        self.adminDir = os.path.join(adminDir, sid)
+        self.startMode = startMode
+        self.sysPassword = sysPassword
+        self.tnsentry = tnsentry
+        self.databaseType = databaseType
+        self.binDir = os.path.join(oracleHome, "bin")
+        self.libDir = os.path.join(oracleHome, "lib")
+        path = os.path.join(oracleHome, "lib64")
+        if os.path.exists(path):
+            self.libDir = path
+        if sys.platform == "win32":
+            self.serviceName = "OracleService%s" % sid
+        if tnsentry is not None and sysPassword is None:
+            self.sysPassword = socket.gethostname().split(".")[0]
+
+    def __repr__(self):
+        return "<%s %s (%s)>" % \
+                (self.__class__.__name__, self.sid, self.oracleHome)
+
+    def __CreateDirectory(self, dirName):
+        if not os.path.isdir(dirName):
+            os.makedirs(dirName)
+
+    def __CreateFile(self, fileName):
+        self.__CreateDirectory(os.path.dirname(fileName))
+        return file(fileName, "w")
+
+    def __PrependPathEnvVar(self, varName, value):
+        origValue = os.environ.get(varName)
+        if origValue is not None:
+            if not origValue.startswith(value + os.pathsep):
+                value = value + os.pathsep + origValue
+        os.environ[varName] = value
+
+    def Clone(self, database, mapping):
+        self.info = database.info.Clone(self.sid, mapping)
+
+    def GetDirectories(self, includeDataFiles = True):
+        dirs = self.info.GetDirectories(includeDataFiles)
+        if self.adminDir not in dirs:
+            dirs.insert(0, self.adminDir)
+        return dirs
+
+    def IsAvailable(self):
+        try:
+            cursor = self.connection.cursor()
+            return True
+        except self.driver.DatabaseError, errorInfo:
+            errorInfo, = errorInfo.args
+            if errorInfo.code == 1034:    # Oracle not started up
+                return False
+            elif errorInfo.code in (1089, 1090):  # shutdown in progress
+                return True
+            raise
+
+    def LinkParameterFile(self):
+        parameterFileName = self.parameterFileName
+        actualParameterFileName = self.actualParameterFileName
+        dirName = os.path.dirname(actualParameterFileName)
+        if sys.platform == "win32":
+            syntax = "FILE='%s'" % actualParameterFileName
+            file(parameterFileName, "w").write(syntax)
+        else:
+            if os.path.exists(parameterFileName):
+                os.remove(parameterFileName)
+            os.symlink(actualParameterFileName, parameterFileName)
+
+    def RemoveControlFiles(self):
+        controlFiles = self.info.parameters["control_files"]
+        for name in controlFiles.split(","):
+            name = name.strip()
+            if os.path.exists(name):
+                os.remove(name)
+
+    def RunInSqlplus(self, sql):
+        self.SetEnvironment()
+        cx_Logging.Debug("SQL\n%s", sql)
+        command = "%s -s /nolog" % os.path.join(self.binDir, "sqlplus")
+        pipe = popen(command, "w")
+        print >> pipe, "whenever sqlerror exit failure"
+        print >> pipe, "connect", self.connectString, "as sysdba"
+        print >> pipe, sql
+        print >> pipe, "exit"
+        if pipe.close() is not None:
+            raise Exceptions.CommandFailed(command = command)
+
+    def SetEnvironment(self):
+        cx_Logging.Debug("setting environment for %s", self)
+        os.environ["ORACLE_SID"] = self.sid
+        os.environ["ORACLE_HOME"] = self.oracleHome
+        self.__PrependPathEnvVar("PATH", self.binDir)
+        if sys.platform != "win32":
+            self.__PrependPathEnvVar("LD_LIBRARY_PATH", self.libDir)
+
+    def WriteActualParameterFile(self, parameters):
+        outFile = self.__CreateFile(self.actualParameterFileName)
+        outFile.write(parameters)
+
+    def WriteCreateSql(self, sql):
+        fileName = os.path.join(self.adminDir, "create", "create.sql")
+        outFile = self.__CreateFile(fileName)
+        outFile.write(sql)
+
+    def WriteDiskConfigFile(self, entries = None):
+        if entries is not None:
+            for entry in entries:
+                self.__CreateDirectory(entry)
+        else:
+            entries = self.GetDirectories(includeDataFiles = False)
+            entries.extend(self.info.GetDataFiles())
+        entries.sort()
+        outFile = self.__CreateFile(self.diskConfigFileName)
+        for entry in entries:
+            print >> outFile, entry
+
+    def WriteEnvironmentConfigFile(self):
+        outFile = self.__CreateFile(self.envConfigFileName)
+        print >> outFile, "[Environment]"
+        print >> outFile, "OracleHome=%s" % self.oracleHome
+        print >> outFile, "StartMode=%s" % self.startMode
+
+"""Define classes for storing information about a database."""
+
+import os
+
+import Exceptions
+import Utils
+
+class DatabaseInfo(object):
+    dirParameters = [
+            "background_dump_dest",
+            "core_dump_dest",
+            "user_dump_dest"
+    ]
+    fileParameters = [
+            "control_files"
+    ]
+    removeParameters = [
+            "ifile",
+            "instance_name",
+            "service_names"
+    ]
+    sizeParameters = [
+            "db_cache_size",
+            "java_pool_size",
+            "large_pool_size",
+            "pga_aggregate_target",
+            "shared_pool_size"
+    ]
+
+    def __repr__(self):
+        return "<%s %s (%s)>" % \
+                (self.__class__.__name__, self.sid, self.oracleHome)
+
+    def __GetControlFileInfo(self, cursor):
+        cursor.execute("""
+                select
+                  type,
+                  records_total
+                from v$controlfile_record_section""")
+        values = dict(cursor)
+        try:
+            self.maxLogFiles = int(values["REDO LOG"])
+            self.maxLogHistory = int(values["LOG HISTORY"])
+            self.maxDataFiles = int(values["DATAFILE"])
+            self.maxInstances = int(values["REDO THREAD"])
+        except KeyError, name:
+            raise Exceptions.MissingControlFileRecordSection(name = name)
+        cursor.execute("select dimlm from x$kccdi")
+        self.maxLogMembers = int(cursor.fetchone()[0])
+        cursor.execute("select name, log_mode from v$database")
+        self.databaseName, self.archiveLogMode = cursor.fetchone()
+        cursor.execute("""
+                select value
+                from nls_database_parameters
+                where parameter = 'NLS_CHARACTERSET'""")
+        self.characterSet, = cursor.fetchone()
+
+    def __GetDataFiles(self, cursor):
+        cursor.execute("""
+                select file_name
+                from dba_data_files
+                order by file_name""")
+        self.dataFiles = [DataFileInfo(*r) for r in cursor]
+        cursor.execute("""
+                select
+                  file_name,
+                  bytes,
+                  tablespace_name,
+                  autoextensible,
+                  increment_by,
+                  maxbytes
+                from dba_temp_files""")
+        self.tempFiles = [TempFileInfo(*r) for r in cursor]
+
+    def __GetLogFiles(self, cursor):
+        self.logFileGroups = []
+        cursor.execute("select group#, bytes from v$log order by group#")
+        for groupNumber, bytes in cursor.fetchall():
+            cursor.execute("select member from v$logfile where group# = :gn",
+                    gn = groupNumber)
+            members = [n for n, in cursor]
+            group = LogFileGroupInfo(groupNumber, bytes, members)
+            self.logFileGroups.append(group)
+
+    def __GetParameters(self, cursor):
+        cursor.execute("""
+                select
+                  name,
+                  value
+                from v$parameter
+                where isdefault = 'FALSE'""")
+        self.parameters = dict(cursor)
+
+    def ExportControlFile(self, createStoredParameterFile = False):
+        syntax = []
+        if createStoredParameterFile:
+            syntax.append("CREATE SPFILE FROM PFILE;")
+            syntax.append("")
+        syntax.append("STARTUP NOMOUNT")
+        syntax.append("")
+        syntax.append('CREATE CONTROLFILE SET DATABASE "%s" RESETLOGS' % \
+                self.databaseName)
+        syntax.append("    MAXLOGFILES %r" % self.maxLogFiles)
+        syntax.append("    MAXLOGMEMBERS %r" % self.maxLogMembers)
+        syntax.append("    MAXDATAFILES %r" % self.maxDataFiles)
+        syntax.append("    MAXINSTANCES %r" % self.maxInstances)
+        syntax.append("    MAXLOGHISTORY %r" % self.maxLogHistory)
+        syntax.append("LOGFILE")
+        groups = ",\n    ".join([g.GetSyntax() for g in self.logFileGroups])
+        syntax.append("    %s" % groups)
+        syntax.append("DATAFILE")
+        fileNames = ["    '%s'" % f.name for f in self.dataFiles]
+        syntax.append(",\n".join(fileNames))
+        syntax.append(self.archiveLogMode)
+        syntax.append("CHARACTER SET %s;" % self.characterSet)
+        syntax.append("")
+        syntax.append("ALTER DATABASE OPEN RESETLOGS;")
+        syntax.append("")
+        for tempFile in self.tempFiles:
+            syntax.append(tempFile.GetSyntax())
+        return "".join([s + "\n" for s in syntax])
+
+    def Clone(self, sid, mapping):
+        info = DatabaseInfo()
+        info.sid = sid
+        info.databaseName = sid
+        info.oracleHome = self.oracleHome
+        info.startMode = self.startMode
+        info.maxLogFiles = self.maxLogFiles
+        info.maxLogHistory = self.maxLogHistory
+        info.maxDataFiles = self.maxDataFiles
+        info.maxInstances = self.maxInstances
+        info.maxLogMembers = self.maxLogMembers
+        info.archiveLogMode = self.archiveLogMode
+        info.characterSet = self.characterSet
+        info.logFileGroups = [g.Clone(mapping) for g in self.logFileGroups]
+        info.dataFiles = [d.Clone(mapping) for d in self.dataFiles]
+        info.tempFiles = [t.Clone(mapping) for t in self.tempFiles]
+        info.parameters = self.parameters.copy()
+        for name in self.fileParameters:
+            value = info.parameters.get(name)
+            if value is None:
+                continue
+            files = [mapping.MappedFileName(n.strip()) \
+                    for n in value.split(",")]
+            info.parameters[name] = ", ".join(files)
+        for name in self.dirParameters:
+            value = self.parameters.get(name)
+            if value is not None:
+                info.parameters[name] = mapping.MappedDir(value)
+        info.parameters["db_name"] = info.databaseName
+        for name in self.removeParameters:
+            if name in info.parameters:
+                del info.parameters[name]
+        return info
+
+    def ExportParameterFile(self):
+        syntax = []
+        names = self.parameters.keys()
+        names.sort()
+        for name in names:
+            value = self.parameters[name]
+            if name in self.sizeParameters:
+                try:
+                    longValue = long(value)
+                except ValueError:
+                    pass
+                else:
+                    value = FormattedSize(longValue)
+            syntax.append("%s=%s" % (name, value))
+        return "".join([s + "\n" for s in syntax])
+
+    def ExportRestoreScript(self):
+        if not self.tempFiles:
+            return "STARTUP"
+        syntax = []
+        syntax.append("STARTUP MOUNT")
+        for tempFile in self.tempFiles:
+            syntax.append("ALTER DATABASE TEMPFILE '%s' DROP;" % tempFile.name)
+        syntax.append("ALTER DATABASE OPEN;")
+        for tempFile in self.tempFiles:
+            syntax.append(tempFile.GetSyntax())
+        return "".join([s + "\n" for s in syntax])
+
+    def GetDataFiles(self, includeTempFiles = True):
+        logFiles = [m for g in self.logFileGroups for m in g.members]
+        files = [d.name for d in self.dataFiles] + logFiles
+        if includeTempFiles:
+            files.extend([t.name for t in self.tempFiles])
+        return files
+
+    def GetDirectories(self, includeDataFiles = True):
+        if includeDataFiles:
+            files = self.GetDataFiles()
+        else:
+            files = []
+        for name in self.fileParameters:
+            value = self.parameters.get(name)
+            if value is not None:
+                files.extend([Utils.NormalizePath(n.strip()) \
+                        for n in value.split(",")])
+        dirs = {}
+        for name in files:
+            name = Utils.NormalizePath(name)
+            dirs[os.path.dirname(name)] = None
+        for name in self.dirParameters:
+            value = self.parameters.get(name)
+            if value is not None:
+                value = Utils.NormalizePath(value)
+                dirs[value] = None
+        for name, value in self.parameters.iteritems():
+            if name.startswith("log_archive_dest"):
+                parts = value.split("=")
+                if len(parts) > 1:
+                    if parts[0].lower() != "location":
+                        continue
+                    del parts[0]
+                value = Utils.NormalizePath(parts[0])
+                dirs[value] = None
+        return dirs.keys()
+
+    def PopulateFromDatabase(self, database):
+        self.sid = database.sid
+        self.oracleHome = database.oracleHome
+        self.startMode = database.startMode
+        cursor = database.connection.cursor()
+        self.__GetControlFileInfo(cursor)
+        self.__GetLogFiles(cursor)
+        self.__GetDataFiles(cursor)
+        self.__GetParameters(cursor)
+
+    def PopulateFromOldStyleBackup(self, info):
+        self.sid = info.sid
+        self.oracleHome = info.oracleHome
+        self.startMode = info.startMode
+        self.maxLogFiles = info.maxLogFiles
+        self.maxLogHistory = info.maxLogHistory
+        self.maxDataFiles = info.maxDataFiles
+        self.maxInstances = info.maxInstances
+        self.maxLogMembers = info.maxLogMembers
+        self.databaseName = info.databaseName
+        self.archiveLogMode = info.logMode
+        self.characterSet = info.characterSet
+        self.logFileGroups = [LogFileGroupInfo(n, *i) \
+                for n, i in info.logFileGroups.iteritems()]
+        self.dataFiles = [DataFileInfo(n) for n in info.dataFiles]
+        self.tempFiles = [TempFileInfo(*i) for i in info.tempFiles]
+        self.parameters = info.parameters
+
+
+class DataFileInfo(object):
+
+    def __init__(self, name):
+        self.name = name
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__, self.name)
+
+    def Clone(self, mapping):
+        return DataFileInfo(mapping.MappedFileName(self.name))
+
+
+class LogFileGroupInfo(object):
+
+    def __init__(self, groupNumber, size, members):
+        self.groupNumber = groupNumber
+        self.size = FormattedSize(size)
+        self.members = members
+        self.members.sort()
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__, self.members)
+
+    def Clone(self, mapping):
+        return LogFileGroupInfo(self.groupNumber, self.size,
+                [mapping.MappedFileName(n) for n in self.members])
+
+    def GetSyntax(self):
+        members = ",".join(["'%s'" % m for m in self.members])
+        return "GROUP %s (%s) size %s" % \
+                (self.groupNumber, members, self.size)
+
+
+class TempFileInfo(object):
+
+    def __init__(self, name, size, tablespaceName, autoExtensible = "NO",
+            incrementBy = 0, maxBytes = 0):
+        self.name = name
+        self.size = FormattedSize(size)
+        self.tablespaceName = tablespaceName
+        self.autoExtensible = autoExtensible
+        self.incrementBy = incrementBy
+        self.maxBytes = FormattedSize(maxBytes)
+
+    def __repr__(self):
+        return "<%s %s>" % (self.__class__.__name__, self.name)
+
+    def Clone(self, mapping):
+        return TempFileInfo(mapping.MappedFileName(self.name), self.size,
+                self.tablespaceName, self.autoExtensible, self.incrementBy,
+                self.maxBytes)
+
+    def GetSyntax(self):
+        syntax = []
+        syntax.append("ALTER TABLESPACE %s ADD TEMPFILE '%s'" % \
+                (self.tablespaceName, self.name))
+        syntax.append("    SIZE %s REUSE" % self.size)
+        if self.autoExtensible == "YES":
+            syntax.append("    AUTOEXTEND ON NEXT %s MAXSIZE %s" % \
+                    (self.incrementBy, self.maxBytes))
+        return "%s;" % "\n".join(syntax)
+
+
+def FormattedSize(size):
+    """Return the size formatted for use in a SQL statement. Note that a
+       negative size is assumed to be unlimited and that if the value is
+       already a string it is assumed to be formatted already."""
+    if isinstance(size, str):
+        return size
+    if size < 0:
+        return "unlimited"
+    kilobytes, remainder = divmod(size, 1024)
+    if not remainder:
+        megabytes, remainder = divmod(kilobytes, 1024)
+        if not remainder:
+            return "%ldm" % megabytes
+        else:
+            return "%ldk" % kilobytes
+    return str(size)
+
+"""Defines exceptions used by the build tools."""
+
+import cx_Exceptions
+
+class CommandFailed(cx_Exceptions.BaseException):
+    message = "Command %(command)s failed."
+
+
+class DatabaseAlreadyExists(cx_Exceptions.BaseException):
+    message = "Database %(sid)s already exists."
+
+
+class DatabaseNotStarted(cx_Exceptions.BaseException):
+    message = "Database %(sid)s not started."
+
+
+class InvalidCompressionLevel(cx_Exceptions.BaseException):
+    message = "Compression level must be between 1 and 9 inclusive."
+
+
+class MissingControlFileRecordSection(cx_Exceptions.BaseException):
+    message = "Missing control file record section %(name)s."
+
+
+class MissingDatabaseType(cx_Exceptions.BaseException):
+    message = "No section defined for database type %(typeName)s."
+
+
+class MissingDefaultDatabaseType(cx_Exceptions.BaseException):
+    message = "No section defined for default database type."
+
+
+class MissingOracleDriver(cx_Exceptions.BaseException):
+    message = "Missing cx_Oracle driver for %(version)s installation."
+
+
+class MissingOracleInstallation(cx_Exceptions.BaseException):
+    message = "Cannot locate Oracle 8i, 9i or 10g installation."
+

ExportControlFile.py

 """Export the control file for the database in the same format as the output
 from the command "alter database backup controlfile to trace;\""""
 
+import cx_LoggingOptions
 import cx_OptionParser
+import sys
 
+import Exceptions
 import Manager
 import Options
 
 parser.AddOption(Options.CONFIG_FILE_NAME)
 parser.AddOption(Options.SYS_PASSWORD)
 parser.AddOption(Options.TNSENTRY)
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sid", required = True,
         help = "the SID of the database to export the control file for")
-parser.AddArgument("fileName", required = True,
+parser.AddArgument("fileName",
         help = "the name of the file in which to place the output")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
 # create the manager
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceFromEnvironment(options.sysPassword,
+database = manager.DatabaseFromEnvironment(options.sysPassword,
         options.tnsentry)
-if instance is not None:
-    if manager.IsInstanceAvailable(instance):
-        instance.GetDatabaseInfo()
-        syntax = instance.ExportControlFile()
-        file(options.fileName, "w").write(syntax)
+if database is not None:
+    if manager.IsDatabaseAvailable(database):
+        if options.fileName is not None:
+            outFile = file(options.fileName, "w")
+        else:
+            outFile = sys.stdout
+        outFile.write(database.info.ExportControlFile())
     else:
-        raise "Instance %s not started." % options.sid
+        raise Exceptions.DatabaseNotStarted(sid = options.sid)
 else:
-    instance = manager.InstanceBySid(options.sid)
-    manager.ExecuteForInstance(instance)
+    database = manager.DatabaseBySid(options.sid)
+    manager.ExecuteForDatabase(database)
 
-"""Define classes for handling Oracle instances."""
-
-import glob
-import imp
-import os
-import socket
-import sys
-
-import Utils
-
-if sys.platform == "win32":
-    import cx_Win32Pipe
-    popen = cx_Win32Pipe.popen
-else:
-    popen = os.popen
-
-SIZE_PARAMETERS = [
-        "db_cache_size",
-        "java_pool_size",
-        "large_pool_size",
-        "pga_aggregate_target",
-        "shared_pool_size"
-]
-
-DIR_PARAMETERS = [
-        "background_dump_dest",
-        "core_dump_dest",
-        "user_dump_dest"
-]
-
-FILE_PARAMETERS = [
-        "control_files"
-]
-
-REMOVE_PARAMETERS = [
-        "ifile",
-        "instance_name",
-        "service_names"
-]
-
-DRIVER = None
+"""Module retained solely for restoring old backup files."""
 
 class Instance:
-    """Contains information about the instance."""
-    archiveLogMode = "NOARCHIVELOG"
+    pass
 
-    def __init__(self, sid, oracleHome, sysPassword, tnsentry, startMode,
-            adminDir):
-        self.sid = sid
-        self.oracleHome = oracleHome
-        self.sysPassword = sysPassword
-        self.tnsentry = tnsentry
-        self.startMode = startMode
-        self.adminDir = adminDir
-        self.binDir = os.path.join(oracleHome, "bin")
-        self.libDir = os.path.join(oracleHome, "lib")
-        path = os.path.join(oracleHome, "lib64")
-        if os.path.exists(path):
-            self.libDir = path
-        if sys.platform == "win32":
-            self.serviceName = "OracleService%s" % sid
-        if tnsentry is not None and sysPassword is None:
-            self.sysPassword = socket.gethostname().split(".")[0]
-
-    def __GetControlFileInfo(self, cursor):
-        """Get the information required for creating the control file."""
-        cursor.execute("""
-                select
-                  type,
-                  records_total
-                from v$controlfile_record_section""")
-        values = dict(cursor)
-        try:
-            self.maxLogFiles = int(values["REDO LOG"])
-            self.maxLogHistory = int(values["LOG HISTORY"])
-            self.maxDataFiles = int(values["DATAFILE"])
-            self.maxInstances = int(values["REDO THREAD"])
-        except KeyError, name:
-            raise "v$controlfile_record_section missing key %s" % name
-        cursor.execute("select dimlm from x$kccdi")
-        self.maxLogMembers = int(cursor.fetchone()[0])
-        cursor.execute("select name, log_mode from v$database")
-        self.databaseName, self.logMode = cursor.fetchone()
-        cursor.execute("""
-                select value
-                from nls_database_parameters
-                where parameter = 'NLS_CHARACTERSET'""")
-        self.characterSet, = cursor.fetchone()
-
-    def __GetDataFiles(self, cursor):
-        cursor.execute("select name from v$datafile order by file#")
-        self.dataFiles = [n for n, in cursor]
-        cursor.execute("""
-                select
-                  tf.name,
-                  tf.bytes,
-                  ts.name
-                from
-                  v$tablespace ts,
-                  v$tempfile tf
-                where ts.ts# = tf.ts#
-                order by tf.ts#, tf.name""")
-        self.tempFiles = [(fn, Utils.SizeForOutput(s), tn) \
-                for fn, s, tn in cursor]
-
-    def __GetLogFiles(self, cursor):
-        """Get the information about the log files in the database."""
-        self.logFileGroups = {}
-        cursor.execute("select group#, bytes from v$log")
-        for groupNumber, bytes in cursor.fetchall():
-            cursor.execute("select member from v$logfile where group# = :gn",
-                    gn = groupNumber)
-            members = [n for n, in cursor]
-            self.logFileGroups[groupNumber] = \
-                    (Utils.SizeForOutput(bytes), members)
-
-    def __GetParameters(self, cursor):
-        """Get the non default parameters from the database."""
-        cursor.execute("""
-                select
-                  name,
-                  value
-                from v$parameter
-                where isdefault = 'FALSE'""")
-        self.parameters = dict(cursor)
-        cursor.execute("select log_mode from v$database")
-        self.archiveLogMode, = cursor.fetchone()
-
-    def __PopulateDriver(self):
-        """Populate the driver attribute."""
-        global DRIVER
-        if DRIVER is not None:
-            return
-        if sys.platform == "win32":
-            ora8Name = os.path.join(self.binDir, "oraclient8.dll")
-            ora9Name = os.path.join(self.binDir, "oraclient9.dll")
-            ora10Name = os.path.join(self.binDir, "oraclient10.dll")
-        else:
-            ora8Name = os.path.join(self.libDir, "libclient8.a")
-            ora9Name = os.path.join(self.libDir, "libclient9.a")
-            ora10Name = os.path.join(self.libDir, "libclient10.a")
-        if os.path.exists(ora8Name):
-            version = "8i"
-        elif os.path.exists(ora9Name):
-            version = "9i"
-        elif os.path.exists(ora10Name):
-            version = "10g"
-        else:
-            raise "Cannot locate Oracle 8i, 9i or 10g installation."
-        dirName = os.path.dirname(sys.executable)
-        files = glob.glob(os.path.join(dirName, "cx_Oracle_%s.*" % version))
-        if len(files) == 0:
-            raise "Cannot locate cx_Oracle driver for Oracle %s installation."
-        DRIVER = imp.load_dynamic("cx_Oracle", files[0])
-
-    def __PrepareToConnect(self):
-        """Prepare to connect as sys as sysdba."""
-        self.SetEnvironment()
-        username = password = tnsentry = ""
-        if self.sysPassword is not None:
-            username = "sys"
-            password = self.sysPassword
-            if self.tnsentry is not None:
-                tnsentry = self.tnsentry
-        return username, password, tnsentry
-
-    def __PrependPathEnvVar(self, varName, value):
-        """Prepend the value to the environment variable."""
-        origValue = os.environ.get(varName)
-        if origValue is not None:
-            if not origValue.startswith(value + os.pathsep):
-                value = value + os.pathsep + origValue
-        os.environ[varName] = value
-
-    def Clone(self, sid, sysPassword, dirMapping):
-        """Return a clone of this instance, with all directories changed as
-           necessary according to the directory mapping."""
-        oracleHome = Utils.MappedDir(self.oracleHome, dirMapping)
-        instance = Instance(sid, oracleHome, sysPassword, None,
-                self.startMode, Utils.MappedDir(self.adminDir, dirMapping))
-        instance.databaseName = sid
-        instance.logMode = self.logMode
-        instance.maxLogFiles = self.maxLogFiles
-        instance.maxLogHistory = self.maxLogHistory
-        instance.maxDataFiles = self.maxDataFiles
-        instance.maxInstances = self.maxInstances
-        instance.maxLogMembers = self.maxLogMembers
-        instance.characterSet = self.characterSet
-        instance.dataFiles = []
-        for name in self.dataFiles:
-            instance.dataFiles.append(Utils.MappedName(name, dirMapping))
-        instance.tempFiles = []
-        for name, size, tablespaceName in self.tempFiles:
-            name = Utils.MappedName(name, dirMapping)
-            instance.tempFiles.append((name, size, tablespaceName))
-        instance.logFileGroups = {}
-        for num, info in self.logFileGroups.iteritems():
-            newMembers = []
-            size, members = info
-            for name in members:
-                name = Utils.MappedName(name, dirMapping)
-                newMembers.append(name)
-            instance.logFileGroups[num] = (size, newMembers)
-        instance.parameters = self.parameters.copy()
-        for name in FILE_PARAMETERS:
-            value = self.parameters.get(name)
-            if value is not None:
-                files = []
-                for fileName in value.split(","):
-                    fileName = Utils.MappedName(fileName.strip(), dirMapping)
-                    files.append(fileName)
-                instance.parameters[name] = ", ".join(files)
-        for name in DIR_PARAMETERS:
-            value = self.parameters.get(name)
-            if value is not None:
-                instance.parameters[name] = Utils.MappedDir(value, dirMapping)
-        instance.parameters["db_name"] = instance.databaseName
-        for name in REMOVE_PARAMETERS:
-            if name in instance.parameters:
-                del instance.parameters[name]
-        return instance
-
-    def ConnectAsSys(self):
-        """Connect directly and return a connection object to use."""
-        username, password, tnsentry = self.__PrepareToConnect()
-        return DRIVER.connect(username, password, tnsentry, DRIVER.SYSDBA)
-
-    def ExportControlFile(self):
-        """Return a string suitable for recreating the control file."""
-        syntax = []
-        syntax.append("STARTUP NOMOUNT")
-        syntax.append("")
-        syntax.append('CREATE CONTROLFILE SET DATABASE "%s" RESETLOGS' % \
-                self.databaseName)
-        syntax.append("    MAXLOGFILES %r" % self.maxLogFiles)
-        syntax.append("    MAXLOGMEMBERS %r" % self.maxLogMembers)
-        syntax.append("    MAXDATAFILES %r" % self.maxDataFiles)
-        syntax.append("    MAXINSTANCES %r" % self.maxInstances)
-        syntax.append("    MAXLOGHISTORY %r" % self.maxLogHistory)
-        syntax.append("LOGFILE")
-        groups = self.logFileGroups.keys()
-        groups.sort()
-        groupStrs = []
-        for groupNumber in groups:
-            size, members = self.logFileGroups[groupNumber]
-            members.sort()
-            membersStr = ",".join(["'%s'" % m for m in members])
-            strRep = "    GROUP %d (%s) size %s" % \
-                    (groupNumber, membersStr, size)
-            groupStrs.append(strRep)
-        syntax.append(",\n".join(groupStrs))
-        syntax.append("DATAFILE")
-        syntax.append(",\n".join(["    '%s'" % s for s in self.dataFiles]))
-        syntax.append(self.archiveLogMode)
-        syntax.append("CHARACTER SET %s;" % self.characterSet)
-        syntax.append("")
-        syntax.append("ALTER DATABASE OPEN RESETLOGS;")
-        syntax.append("")
-        for name, size, tablespaceName in self.tempFiles:
-            syntax.append("ALTER TABLESPACE %s ADD TEMPFILE '%s'" % \
-                    (tablespaceName, name))
-            syntax.append("    SIZE %s REUSE;" % size)
-        return "".join([s + "\n" for s in syntax])
-
-    def ExportRestoreScript(self):
-        """Return a string suitable for restoring the database."""
-        if not self.tempFiles:
-            return "startup"
-        syntax = []
-        syntax.append("STARTUP MOUNT")
-        for name, size, tablespaceName in self.tempFiles:
-            syntax.append("ALTER DATABASE TEMPFILE '%s' DROP;" % name)
-        syntax.append("ALTER DATABASE OPEN;")
-        for name, size, tablespaceName in self.tempFiles:
-            syntax.append("ALTER TABLESPACE %s ADD TEMPFILE '%s'" % \
-                    (tablespaceName, name))
-            syntax.append("    SIZE %s REUSE;" % size)
-        return "".join([s + "\n" for s in syntax])
-
-    def ExportParameterFile(self):
-        """Return a string suitable for creating the parameter file."""
-        syntax = []
-        names = self.parameters.keys()
-        names.sort()
-        for name in names:
-            value = self.parameters[name]
-            if name in SIZE_PARAMETERS:
-                try:
-                    longValue = long(value)
-                except ValueError:
-                    pass
-                else:
-                    value = Utils.SizeForOutput(longValue)
-            syntax.append("%s=%s" % (name, value))
-        return "".join([s + "\n" for s in syntax])
-
-    def GetDatabaseInfo(self):
-        """Retrieve the database information into instance variables."""
-        self.__PopulateDriver()
-        connection = self.ConnectAsSys()
-        cursor = connection.cursor()
-        self.__GetControlFileInfo(cursor)
-        self.__GetLogFiles(cursor)
-        self.__GetDataFiles(cursor)
-        self.__GetParameters(cursor)
-
-    def GetDataFiles(self, includeTempFiles = True):
-        """Return a list of the data files, temporary files and log files
-           associated with the database."""
-        logFiles = [m for s, ml  in self.logFileGroups.values() for m in ml]
-        files = self.dataFiles + logFiles
-        if includeTempFiles:
-            files += [n for n, s, tn in self.tempFiles]
-        return files
-
-    def GetDirectories(self, includeDataFiles = True):
-        """Return a list of all directories used by the database."""
-        if includeDataFiles:
-            files = self.GetDataFiles()
-        else:
-            files = []
-        for name in FILE_PARAMETERS:
-            value = self.parameters.get(name)
-            if value is not None:
-                files += [Utils.NormalizePath(n.strip()) \
-                        for n in value.split(",")]
-        dirs = {}
-        # this is placed in an exception handler to allow for restoration of
-        # old backup files; it can be removed once all old backup files have
-        # been eliminated
-        try:
-            dirs[self.adminDir] = None
-        except AttributeError:
-            pass
-        for name in files:
-            name = Utils.NormalizePath(name)
-            dirs[os.path.dirname(name)] = None
-        for name in DIR_PARAMETERS:
-            value = self.parameters.get(name)
-            if value is not None:
-                value = Utils.NormalizePath(value)
-                dirs[value] = None
-        for name, value in self.parameters.iteritems():
-            if name.startswith("log_archive_dest"):
-                parts = value.split("=")
-                if len(parts) > 1:
-                    if parts[0].lower() != "location":
-                        continue
-                    del parts[0]
-                value = Utils.NormalizePath(parts[0])
-                dirs[value] = None
-        return dirs.keys()
-
-    def IsAvailable(self):
-        """Return a boolean indicating if the instance is available."""
-        self.__PopulateDriver()
-        try:
-            self.ConnectAsSys()
-            return True
-        except DRIVER.DatabaseError, errorInfo:
-            errorInfo, = errorInfo.args
-            if errorInfo.code == 1034:    # Oracle not started up
-                return False
-            elif errorInfo.code in (1089, 1090):  # shutdown in progress
-                return True
-            raise
-
-    def RunInSqlplus(self, sql):
-        """Run the command(s) in SQL*Plus."""
-        username, password, tnsentry = self.__PrepareToConnect()
-        command = "%s -s /nolog" % os.path.join(self.binDir, "sqlplus")
-        connectString = "%s/%s" % (username, password)
-        if tnsentry:
-            connectString = "%s@%s" % (connectString, tnsentry)
-        pipe = popen(command, "w")
-        print >> pipe, "whenever sqlerror exit failure"
-        print >> pipe, "connect", connectString, "as sysdba"
-        print >> pipe, sql
-        print >> pipe, "exit"
-        if pipe.close() is not None:
-            raise "Command %s failed." % command
-
-    def SetEnvironment(self):
-        """Set the environment variables in the operating system."""
-        os.environ["ORACLE_SID"] = self.sid
-        os.environ["ORACLE_HOME"] = self.oracleHome
-        self.__PrependPathEnvVar("PATH", self.binDir)
-        if sys.platform != "win32":
-            self.__PrependPathEnvVar("LD_LIBRARY_PATH", self.libDir)
-
+README.txt
+LICENSE.txt
+HISTORY.txt
+BackupDB.py
+BackupFile.py
+CloneDB.py
+CreateDB.py
+Database.py
+DatabaseInfo.py
+Exceptions.py
+ExportControlFile.py
+Instance.py
+Manager.py
+Options.py
+RemoveDB.py
+RestoreDB.py
+ShowMemoryDB.py
+StartDB.py
+StopDB.py
+Utils.py
+templates
 
 import cx_ClassLibrary
 import cx_IniFile
+import cx_Logging
 import cx_Utils
 import cx_ShellUtils
 import os
 if sys.platform == "win32":
     import cx_Win32Service
 
-import Instance
+import Database
+import Exceptions
 
 GENERAL_SECTION = "general"
 ENV_NAME = "CX_ORACLEDBATOOLS_ENV_SET"
 
-class DatabaseType:
-    """Class for handling types of databases."""
+class DatabaseType(object):
 
     def __init__(self, iniFile, section, baseDir):
+
         # First set the required attributes on myself
         requiredKeys = ["oracleHome", "templateInitOra", "templateDirs",
                 "templateCreate"]
                 self.substitutions[key.name] = key.value
 
 
-class Manager:
-    """Class for managing Oracle dataases."""
+class Manager(object):
 
     def __init__(self, fileName):
         iniFile = cx_IniFile.IniFile()
                         DatabaseType(iniFile, section, self.baseDir)
         defaultDatabaseType = iniFile.GetValue(GENERAL_SECTION, "DefaultType")
         if defaultDatabaseType not in self.databaseTypes:
-            raise "No section defined for default database type."
+            raise Exceptions.MissingDefaultDatabaseType()
         self.defaultDatabaseType = self.databaseTypes[defaultDatabaseType]
         self.serviceManager = None
         if sys.platform == "win32":
             self.serviceManager = cx_Win32Service.ServiceManager()
 
-    def __AdminDir(self, sid):
-        """Return the directory containing admin for the sid."""
-        return os.path.join(self.adminDir, sid)
-
-    def __ConfigDir(self, sid):
-        return os.path.join(self.__AdminDir(sid), "config")
-
-    def __CreateDirectory(self, *dirComponents):
-        """Create the directory and return the full directory name."""
-        dirName = os.path.join(*dirComponents)
-        if dirName and not os.path.isdir(dirName):
-            os.makedirs(dirName)
-        return dirName
-
-    def __CreateInstance(self, instance, parameters, createSql, dirs):
-        """Create the given instance."""
-        fileName, linkFileName = self.__LinkParameterFile(instance.sid,
-                instance.oracleHome)
+    def __CreateDatabase(self, database, parameters, createSql, dirs):
         if parameters is not None:
-            file(fileName, "w").write(parameters)
-        self.__CreateDirectory(self.__ConfigDir(instance.sid))
-        self.WriteDirsConfig(instance.sid, dirs)
-        for dirName in dirs:
-            self.__CreateDirectory(dirName)
-        outFile = file(self.__EnvironmentConfig(instance.sid), "w")
-        print >> outFile, "[Environment]"
-        print >> outFile, "OracleHome=%s" % instance.oracleHome
-        print >> outFile, "StartMode=%s" % instance.startMode
-        outFile.close()
+            database.WriteActualParameterFile(parameters)
+        database.LinkParameterFile()
+        database.WriteDiskConfigFile(dirs)
+        database.WriteEnvironmentConfigFile()
         if self.serviceManager is not None:
-            oraDim = os.path.join(instance.binDir, "oradim")
+            oraDim = os.path.join(database.binDir, "oradim")
             command = "%s -NEW -SID %s -INTPWD %s -STARTMODE MANUAL -PFILE %s"
             cx_Utils.ExecuteOSCommands(command % \
-                    (oraDim, instance.sid, instance.sysPassword, linkFileName))
+                    (oraDim, database.sid, database.sysPassword, linkFileName))
         if createSql is not None:
-            dirName = self.__CreateDirectory(self.__AdminDir(instance.sid),
-                    "create")
-            fileName = os.path.join(dirName, "create.sql")
-            file(fileName, "w").write(createSql)
-            instance.RunInSqlplus(createSql)
-            self.StopInstance(instance)
+            database.WriteCreateSql(createSql)
+            database.RunInSqlplus(createSql)
+            self.StopDatabase(database)
         else:
-            script = instance.ExportRestoreScript()
-            instance.RunInSqlplus(script)
-
-    def __DirsConfig(self, sid):
-        """Return the name of the file where directories are configured."""
-        return os.path.join(self.__ConfigDir(sid), "dirs.cfg")
+            script = database.info.ExportRestoreScript()
+            database.RunInSqlplus(script)
 
     def __EnvironmentConfig(self, sid):
-        """Return the name of the file where the environment is configured."""
-        return os.path.join(self.__ConfigDir(sid), "env.cfg")
-
-    def __LinkFileName(self, sid, oracleHome):
-        """Return the name of the link file for the parameters."""
-        baseLinkFileName = "init%s.ora" % sid
-        if sys.platform == "win32":
-            return os.path.join(oracleHome, "database", baseLinkFileName)
-        else:
-            return os.path.join(oracleHome, "dbs", baseLinkFileName)
-
-    def __LinkParameterFile(self, sid, oracleHome):
-        """Link the parameter file to the location where Oracle expects it.
-           Return the actual file name and the linked file name."""
-        dirName = self.__CreateDirectory(self.__AdminDir(sid), "pfile")
-        fileName = os.path.join(dirName, "init.ora")
-        linkFileName = self.__LinkFileName(sid, oracleHome)
-        if sys.platform == "win32":
-            file(linkFileName, "w").write("IFILE='%s'" % fileName)
-        else:
-            if os.path.exists(linkFileName):
-                os.remove(linkFileName)
-            os.symlink(fileName, linkFileName)
-        return fileName, linkFileName
+        return os.path.join(self.adminDir, sid, "config", "env.cfg")
 
     def AllSids(self):
-        """Return a list of all the SIDs of configured databases."""
         sids = []
         for name in os.listdir(self.adminDir):
             fileName = self.__EnvironmentConfig(name)
                 sids.append(name)
         return sids
 
-    def CreateInstanceFromBackup(self, instance):
-        """Create a new instance from backup."""
-        self.__CreateInstance(instance, None, None, instance.GetDirectories())
+    def CreateDatabaseFromBackup(self, database):
+        self.__CreateDatabase(database, None, None, database.GetDirectories())
 
-    def CreateInstanceFromClone(self, instance):
-        """Create a new instance given a cloned instance."""
-        self.__CreateInstance(instance, instance.ExportParameterFile(),
-                instance.ExportControlFile(), instance.GetDirectories())
+    def CreateDatabaseFromClone(self, database):
+        createStoredParameterFile = \
+                os.path.exists(database.storedParameterFileName)
+        createSql = database.info.ExportControlFile(createStoredParameterFile)
+        self.__CreateDatabase(database, database.info.ExportParameterFile(),
+                createSql, database.GetDirectories())
 
-    def CreateInstance(self, sid, sysPassword, tnsentry, startMode, typeName,
-            substitutions=None):
-        """Create a new instance from a template."""
+    def CreateDatabase(self, database, substitutions):
+        args = cx_ClassLibrary.CaselessDict(SID = database.sid,
+                BASE_DIR = self.baseDir,
+                ADMIN_DIR = database.adminDir,
+                ORACLE_HOME = database.oracleHome,
+                SYS_PW = database.sysPassword)
+        for key in substitutions:
+            if key not in args:
+                args[key] = substitutions[key]
+        for key in database.databaseType.substitutions:
+            if key not in args:
+                args[key] = database.databaseType.substitutions[key]
+        parameters = file(database.databaseType.templateInitOra).read() % args
+        createSql = file(database.databaseType.templateCreate).read() % args
+        rawDirs = file(database.databaseType.templateDirs).read() % args
+        dirs = [s.strip() for s in rawDirs.splitlines() if s.strip()]
+        self.__CreateDatabase(database, parameters, createSql, dirs)
+
+    def DatabaseBySid(self, sid, ignoreIfMissing = False):
+        fileName = self.__EnvironmentConfig(sid)
+        if not ignoreIfMissing or os.path.exists(fileName):
+            cx_Logging.Info("Reading environment from %s", fileName)
+            iniFile = cx_IniFile.IniFile()
+            iniFile.Read(fileName)
+            oracleHome = iniFile.GetValue("Environment", "OracleHome")
+            startMode = iniFile.GetValue("Environment", "StartMode")
+            return Database.Database(sid, oracleHome, self.adminDir, startMode)
+
+    def DatabaseFromTypeName(self, sid, typeName, sysPassword, tnsentry,
+            startMode):
         if typeName is None:
             databaseType = self.defaultDatabaseType
         else:
             if typeName not in self.databaseTypes:
-                raise "No section defined for class %s." % typeName
+                raise Exceptions.MissingDatabaseType(typeName = typeName)
             databaseType = self.databaseTypes[typeName]
-        adminDir = self.__AdminDir(sid)
-        args = databaseType.substitutions + {
-                "SID" : sid,
-                "BASE_DIR" : self.baseDir,
-                "ADMIN_DIR" : adminDir,
-                "ORACLE_HOME" : databaseType.oracleHome,
-                "SYS_PW" : sysPassword
-        }
-        if substitutions:
-            args += substitutions
-        parameters = file(databaseType.templateInitOra).read() % args
-        createSql = file(databaseType.templateCreate).read() % args
-        rawDirs = file(databaseType.templateDirs).read() % args
-        dirs = [s for s in rawDirs.splitlines() if s]
-        for dirName in dirs:
-            self.__CreateDirectory(dirName)
-        instance = Instance.Instance(sid, databaseType.oracleHome, sysPassword,
-                tnsentry, startMode, self.__AdminDir(sid))
-        self.__CreateInstance(instance, parameters, createSql, dirs)
+        return Database.Database(sid, databaseType.oracleHome, self.adminDir,
+                startMode, sysPassword, tnsentry, databaseType)
 
-    def ExecuteForInstance(self, instance):
-        """Execute the program specifically for the instance."""
-        instance.SetEnvironment()
-        os.environ[ENV_NAME] = "Y"
-        os.environ["START_MODE"] = instance.startMode
-        returnCode = os.spawnv(os.P_WAIT, sys.executable,
-                [sys.executable] + sys.argv[1:])
-        if returnCode != 0:
-            sys.exit(1)
-
-    def InstanceBySid(self, sid, ignoreIfMissing = False):
-        """Return an instance given the SID."""
-        fileName = self.__EnvironmentConfig(sid)
-        if not ignoreIfMissing or os.path.exists(fileName):
-            print "Reading environment from", fileName
-            iniFile = cx_IniFile.IniFile()
-            iniFile.Read(fileName)
-            oracleHome = iniFile.GetValue("Environment", "OracleHome")
-            startMode = iniFile.GetValue("Environment", "StartMode")
-            return Instance.Instance(sid, oracleHome, None, None, startMode,
-                    self.__AdminDir(sid))
-
-    def InstanceFromEnvironment(self, sysPassword, tnsentry):
-        """Return an instance from the environment or None if not set."""
+    def DatabaseFromEnvironment(self, sysPassword, tnsentry):
         if ENV_NAME in os.environ:
             sid = os.environ["ORACLE_SID"]
             oracleHome = os.environ["ORACLE_HOME"]
             startMode = os.environ["START_MODE"]
-            return Instance.Instance(sid, oracleHome, sysPassword, tnsentry,
-                    startMode, self.__AdminDir(sid))
+            return Database.Database(sid, oracleHome, self.adminDir, startMode,
+                    sysPassword, tnsentry)
 
-    def IsInstanceAvailable(self, instance):
-        """Return True if the instance is available for connecting."""
+    def ExecuteForDatabase(self, database):
+        database.SetEnvironment()
+        os.environ[ENV_NAME] = "Y"
+        os.environ["START_MODE"] = database.startMode
+        if sys.platform == "win32":
+            executable = '"%s"' % sys.executable
+        else:
+            executable = sys.executable
+        returnCode = os.spawnv(os.P_WAIT, sys.executable,
+                [executable] + sys.argv[1:])
+        if returnCode != 0:
+            sys.exit(1)
+
+    def IsDatabaseAvailable(self, database):
         if self.serviceManager is not None:
-            state = self.serviceManager.State(instance.serviceName)
+            state = self.serviceManager.State(database.serviceName)
             if state == cx_Win32Service.SERVICE_STOPPED:
                 return False
-        return instance.IsAvailable()
+        return database.IsAvailable()
 
-    def RemoveInstance(self, instance):
-        """Remove the database."""
-        print "Removing instance...."
-        fileName = self.__DirsConfig(instance.sid)
-        dirs = [s.strip() for s in file(fileName)]
-        self.StopInstance(instance, "abort")
+    def RemoveDatabase(self, database):
+        cx_Logging.Trace("Removing database...")
+        self.StopDatabase(database, "abort")
         if self.serviceManager is not None:
-            oraDim = os.path.join(instance.binDir, "oradim")
-            command = "%s -DELETE -SID %s" % (oraDim, instance.sid)
+            oraDim = os.path.join(database.binDir, "oradim")
+            command = "%s -DELETE -SID %s" % (oraDim, database.sid)
             cx_Utils.ExecuteOSCommands(command)
-        linkFileName = self.__LinkFileName(instance.sid, instance.oracleHome)
-        if os.path.exists(linkFileName):
-            os.remove(linkFileName)
-        pwdFileName = os.path.join(os.path.dirname(linkFileName),
-            "pwd%s.ora" % instance.sid)
-        if os.path.exists(pwdFileName):
-            os.remove(pwdFileName)
-        adminDir = self.__AdminDir(instance.sid)
-        if adminDir not in dirs:
-            dirs.append(adminDir)
-        for dir in dirs:
-            print "Removing directory", dir + "...",
-            sys.stdout.flush()
-            if os.path.exists(dir):
-                cx_ShellUtils.RemoveTree(dir)
-            print "[ok]"
-        print "Instance", instance.sid, "removed."
+        entries = [s.strip() for s in file(database.diskConfigFileName)]
+        entries.append(database.adminDir)
+        entries.append(database.parameterFileName)
+        entries.append(database.storedParameterFileName)
+        entries.append(database.passwordFileName)
+        dirsToCheck = {}
+        for entry in entries:
+            if not os.path.exists(entry):
+                continue
+            if os.path.isdir(entry):
+                cx_Logging.Trace("Removing directory %s...", entry)
+            else:
+                cx_Logging.Trace("Removing file %s...", entry)
+                dirsToCheck[os.path.dirname(entry)] = None
+            cx_ShellUtils.Remove(entry)
+        for dir in dirsToCheck:
+            if not os.listdir(dir):
+                cx_Logging.Trace("Removing directory %s...", dir)
+                os.rmdir(dir)
+        cx_Logging.Trace("Database %s removed.", database.sid)
 
-    def StartInstance(self, instance):
-        """Start up the database."""
+    def StartDatabase(self, database):
         if self.serviceManager is not None:
-            state = self.serviceManager.State(instance.serviceName)
+            state = self.serviceManager.State(database.serviceName)
             if state == cx_Win32Service.SERVICE_STOPPED:
-                self.serviceManager.Start(instance.serviceName)
+                self.serviceManager.Start(database.serviceName)
             else:
-                print "Service", instance.serviceName, "already started."
-        if instance.IsAvailable():
-            print "Instance", instance.sid, "already started."
+                cx_Logging.Trace("Service %s already started.",
+                        database.serviceName)
+        if database.IsAvailable():
+            cx_Logging.Trace("Database %s already started.", database.sid)
         else:
-            print "Starting instance %s..." % instance.sid
-            instance.RunInSqlplus("startup")
-            print "Instance", instance.sid, "started."
+            cx_Logging.Trace("Starting database %s...", database.sid)
+            database.RunInSqlplus("startup")
+            cx_Logging.Trace("Database %s started.", database.sid)
 
-    def StopInstance(self, instance, mode = ""):
-        """Stop the database."""
+    def StopDatabase(self, database, mode = ""):
         if self.serviceManager is not None:
-            state = self.serviceManager.State(instance.serviceName)
+            state = self.serviceManager.State(database.serviceName)
             if state == cx_Win32Service.SERVICE_STOPPED:
-                print "Service", instance.serviceName, "already stopped."
+                cx_Logging.Trace("Service %s already stopped.",
+                        database.serviceName)
                 return
-        if instance.IsAvailable():
-            print "Stopping instance %s..." % instance.sid
-            instance.RunInSqlplus("shutdown %s" % mode)
-            print "Instance", instance.sid, "stopped."
+        aborting = (mode.lower() == "abort")
+        if database.IsAvailable():
+            if not aborting:
+                database.WriteDiskConfigFile()
+            cx_Logging.Trace("Stopping database %s...", database.sid)
+            database.RunInSqlplus("shutdown %s" % mode)
+            cx_Logging.Trace("Database %s stopped.", database.sid)
         else:
-            print "Instance", instance.sid, "already stopped."
+            cx_Logging.Trace("Database %s already stopped.", database.sid)
         if self.serviceManager is not None:
-            self.serviceManager.Stop(instance.serviceName)
+            self.serviceManager.Stop(database.serviceName)
 
-    def WriteDirsConfig(self, sid, dirs):
-        """Write the directory configuration to disk so that RemoveDB has valid
-           information to use."""
-        dirs.sort()
-        outFile = file(self.__DirsConfig(sid), "w")
-        for dirName in dirs:
-            print >> outFile, dirName
-
 """Remove an Oracle database from the machine."""
 
+import cx_Logging
+import cx_LoggingOptions
 import cx_OptionParser
 
 import Manager
 parser.AddOption(Options.TNSENTRY)
 parser.AddOption("--ignore-if-missing", default = False, action = "store_true",
         help = "do not raise an error if the database is missing")
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sids", required = True,
         help = "the SID(s) of the database(s) to remove, separated by commas")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
 # perform the work
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceFromEnvironment(options.sysPassword,
+database = manager.DatabaseFromEnvironment(options.sysPassword,
         options.tnsentry)
-if instance is not None:
-    manager.RemoveInstance(instance)
+if database is not None:
+    manager.RemoveDatabase(database)
 else:
     for sid in options.sids.split(","):
-        instance = manager.InstanceBySid(sid, options.ignoreIfMissing)
-        if instance:
-            manager.ExecuteForInstance(instance)
+        database = manager.DatabaseBySid(sid, options.ignoreIfMissing)
+        if database is not None:
+            manager.ExecuteForDatabase(database)
         else:
-            print "Instance", sid, "already removed."
+            cx_Logging.Warning("Database %s does not exist.", sid)
 
 """Restores an Oracle database."""
 
+import cx_LoggingOptions
 import cx_OptionParser
 import cx_ReadLine
 import os
 
 import BackupFile
+import Database
+import Exceptions
 import Manager
 import Options
 import Utils
 parser.AddOption("--list", action = "store_true",
         help = "print the list of all files contained in the backup file "
                "and stop")
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("fileName", required = True,
         help = "the name of the file containing the backup")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
-# retrieve the instance from the backup file
+# retrieve the database from the backup file
+manager = Manager.Manager(options.configFileName)
 backupFile = BackupFile.BackupFile(options.fileName)
-instance = backupFile.GetInstance()
+database = backupFile.GetDatabase(manager.adminDir)
 
 # perform the work
 if options.info or options.list:
     print "*" * 79
-    print "Backup of Database %s" % instance.sid
-    print "ORACLE_HOME=%s" % instance.oracleHome
+    print "Backup of Database %s" % database.sid
+    print "ORACLE_HOME=%s" % database.oracleHome
     print "*" * 79
     backupFile.Directory(options.list)
 else:
-    manager = Manager.Manager(options.configFileName)
-    instanceFromEnv = manager.InstanceFromEnvironment(options.sysPassword,
+    databaseFromEnv = manager.DatabaseFromEnvironment(options.sysPassword,
             options.tnsentry)
-    if instanceFromEnv:
+    if databaseFromEnv:
         if options.replaceExisting:
-            sid = options.asSid or instanceFromEnv.sid
-            existingInstance = manager.InstanceBySid(sid,
+            sid = options.asSid or databaseFromEnv.sid
+            existingDatabase = manager.DatabaseBySid(sid,
                     ignoreIfMissing = True)
-            if existingInstance is not None:
-                manager.RemoveInstance(existingInstance)
+            if existingDatabase is not None:
+                manager.RemoveDatabase(existingDatabase)
         if options.asSid:
-            dirMapping = Utils.GetDirMapping(instance.GetDirectories(),
-                    instance.sid, options.asSid, options.prompts)
-            origValue = Utils.NormalizePath(instance.oracleHome)
-            dirMapping[origValue] = instanceFromEnv.oracleHome
-            newInstance = instance.Clone(options.asSid, instance.sysPassword,
-                    dirMapping)
-            backupFile.Restore(dirMapping)
-            controlFiles = newInstance.parameters["control_files"]
-            for name in controlFiles.split(","):
-                name = name.strip()
-                if os.path.exists(name):
-                    os.remove(name)
-            manager.CreateInstanceFromClone(newInstance)
-            manager.StartInstance(newInstance)
+            newDatabase = Database.Database(options.asSid,
+                    databaseFromEnv.oracleHome, manager.adminDir,
+                    database.startMode, database.sysPassword)
+            mapping = Utils.Mapping(newDatabase, database, options.prompts)
+            newDatabase.Clone(database, mapping)
+            backupFile.Restore(mapping)
+            newDatabase.RemoveControlFiles()
+            manager.CreateDatabaseFromClone(newDatabase)
+            manager.StartDatabase(newDatabase)
         else:
             backupFile.Restore()
-            manager.CreateInstanceFromBackup(instance)
+            manager.CreateDatabaseFromBackup(database)
     else:
-        sid = options.asSid or instance.sid
-        existingInstance = manager.InstanceBySid(sid, ignoreIfMissing = True)
-        if existingInstance is not None:
+        sid = options.asSid or database.sid
+        existingDatabase = manager.DatabaseBySid(sid, ignoreIfMissing = True)
+        if existingDatabase is not None:
             if not options.replaceExisting:
-                raise "Instance %s already exists." % sid
+                raise Exceptions.DatabaseAlreadyExists(sid = sid)
         if options.asSid and options.prompts:
-            origValue = Utils.NormalizePath(instance.oracleHome)
-            instance.oracleHome = cx_ReadLine.ReadLine("Map %s to" % origValue,
+            origValue = Utils.NormalizePath(database.oracleHome)
+            database.oracleHome = cx_ReadLine.ReadLine("Map %s to" % origValue,
                     origValue)
-        manager.ExecuteForInstance(instance)
+        manager.ExecuteForDatabase(database)
 
 """Shows the memory used by the database."""
 
+import cx_LoggingOptions
 import cx_OptionParser
 import os
 
 # parse command line
 parser = cx_OptionParser.OptionParser("ShowMemoryDB")
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sid", required = True,
         help = "the SID of the database for which memory usage will be shown")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
 # define method that returns a list of pids
 def GetPids(mask):
 """Starts up an Oracle database."""
 
+import cx_Logging
+import cx_LoggingOptions
 import cx_OptionParser
 
 import Manager
         help = "start all configured databases")
 parser.AddOption("--all-auto", action = "store_true",
         help = "start all configured databases set to automatic start")
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sids",
         help = "the SID(s) of the database(s) to start, separated by commas")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
 # perform the work
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceFromEnvironment(options.sysPassword,
+database = manager.DatabaseFromEnvironment(options.sysPassword,
         options.tnsentry)
-if instance is not None:
+if database is not None:
     if options.restart:
-        manager.StopInstance(instance, options.shutdownMode)
-    manager.StartInstance(instance)
+        manager.StopDatabase(database, options.shutdownMode)
+    manager.StartDatabase(database)
 else:
     if options.all or options.allAuto:
         for sid in manager.AllSids():
-            instance = manager.InstanceBySid(sid)
-            if instance.startMode.lower() == "auto" or options.all:
-                manager.ExecuteForInstance(instance)
+            database = manager.DatabaseBySid(sid)
+            if database.startMode.lower() == "auto" or options.all:
+                manager.ExecuteForDatabase(database)
     elif options.sids:
         for sid in options.sids.split(","):
-            instance = manager.InstanceBySid(sid)
-            manager.ExecuteForInstance(instance)
+            database = manager.DatabaseBySid(sid)
+            manager.ExecuteForDatabase(database)
     else:
-        print "Nothing to do."
+        cx_Logging.Warning("Nothing to do.")
 
 """Stop an Oracle database."""
 
+import cx_Logging
+import cx_LoggingOptions
 import cx_OptionParser
 
 import Manager
 parser.AddOption(Options.SHUTDOWN_MODE)
 parser.AddOption("--all", action = "store_true",
         help = "stop all configured databases")
+cx_LoggingOptions.AddOptions(parser)
 parser.AddArgument("sids",
         help = "the SID(s) of the database(s) to stop, separated by commas")
 options = parser.Parse()
+cx_LoggingOptions.ProcessOptions(options)
 
 # perform the work
 manager = Manager.Manager(options.configFileName)
-instance = manager.InstanceFromEnvironment(options.sysPassword,
+database = manager.DatabaseFromEnvironment(options.sysPassword,
         options.tnsentry)
-if instance is not None:
-    manager.StopInstance(instance, options.shutdownMode)
+if database is not None:
+    manager.StopDatabase(database, options.shutdownMode)
 else:
     if options.all:
         sids = manager.AllSids()
         sids = options.sids.split(",")
     else:
         sids = []
-        print "Nothing to do."
+        cx_Logging.Warning("Nothing to do.")
     for sid in sids:
-        instance = manager.InstanceBySid(sid)
-        manager.ExecuteForInstance(instance)
+        database = manager.DatabaseBySid(sid)
+        manager.ExecuteForDatabase(database)
 
 import os
 import sys
 
-def GetDirMapping(dirs, origValue, newValue, prompts):
-    """Return a mapping of directories from original values to new values."""
-    dirMapping = {}
-    origValue = NormalizePath(origValue)
-    temp = [(len(n), n) for n in dirs]
-    temp.sort()
-    dirs = [n for s, n in temp]
-    for dir in dirs:
-        dir = NormalizePath(dir)
-        defaultDir = MappedDir(dir, dirMapping)
-        if defaultDir == dir:
-            defaultDir = dir.replace(origValue, newValue)
-        if prompts:
-            newDir = cx_ReadLine.ReadLine("Map %s to" % dir, defaultDir)
-        else:
-            newDir = defaultDir
-        dirMapping[dir] = newDir
-    return dirMapping
 
+class Mapping(object):
 
-def MappedDir(name, dirMapping):
-    """Return the name modified by the directory mapping, if applicable."""
-    rightPart = ""
-    name = leftPart = NormalizePath(name)
-    while True:
-        if leftPart in dirMapping:
-            leftPart = dirMapping[leftPart]
-            return NormalizePath(os.path.join(leftPart, rightPart))
-        leftPart, remainder = os.path.split(leftPart)
-        if not remainder:
-            break
-        rightPart = NormalizePath(os.path.join(remainder, rightPart))
-    return name
+    def __init__(self, database, origDatabase, prompts):
+        self.dirMapping = {}
+        dir = NormalizePath(origDatabase.adminDir)
+        self.dirMapping[dir] = database.adminDir
+        if database.oracleHome != origDatabase.oracleHome:
+            dir = NormalizePath(origDatabase.oracleHome)
+            self.dirMapping[dir] = database.oracleHome
+        self.fileMapping = {}
+        self.fileMapping[origDatabase.storedParameterFileName] = \
+                database.storedParameterFileName
+        self.fileMapping[origDatabase.passwordFileName] = \
+                database.passwordFileName
+        self.__PopulateDirMapping(database, origDatabase, prompts)
 
+    def __PopulateDirMapping(self, database, origDatabase, prompts):
+        """Populate the directory mapping by taking all of the directories
+           from the original database and creating a mapping for each one."""
+        origSid = NormalizePath(origDatabase.sid)
+        temp = [(len(n), n) for n in origDatabase.GetDirectories()]
+        temp.sort()
+        dirs = [n for s, n in temp]
+        for dir in dirs:
+            dir = NormalizePath(dir)
+            if dir in self.dirMapping:
+                continue
+            defaultDir = self.MappedDir(dir)
+            if defaultDir == dir:
+                defaultDir = dir.replace(origSid, database.sid)
+            if prompts:
+                newDir = cx_ReadLine.ReadLine("Map %s to" % dir, defaultDir)
+            else:
+                newDir = defaultDir
+            self.dirMapping[dir] = newDir
 
-def MappedName(name, dirMapping):
-    """Return the name modified by the directory mapping, if applicable."""
-    dir, name = os.path.split(name)
-    dir = MappedDir(dir, dirMapping)
-    return NormalizePath(os.path.join(dir, name))
+    def MappedDir(self, name):
+        """Return the directory to use given the original directory."""
+        rightPart = ""
+        name = leftPart = NormalizePath(name)
+        while True:
+            if leftPart in self.dirMapping:
+                leftPart = self.dirMapping[leftPart]
+                return NormalizePath(os.path.join(leftPart, rightPart))
+            leftPart, remainder = os.path.split(leftPart)
+            if not remainder:
+                break
+            rightPart = NormalizePath(os.path.join(remainder, rightPart))
+        return name
+
+    def MappedFileName(self, name):
+        """Return the file name to use given the original file name."""
+        if name in self.fileMapping:
+            return self.fileMapping[name]
+        dir, name = os.path.split(name)
+        dir = self.MappedDir(dir)
+        return NormalizePath(os.path.join(dir, name))
 
 
 def NormalizePath(name):
     name = os.path.normcase(os.path.normpath(name))
     return name
 
-
-def SizeForOutput(size):
-    """Return the size suitable for output in a SQL statement. Note that a
-       negative size is assumed to be unlimited."""
-    if size < 0:
-        return "unlimited"
-    kilobytes, remainder = divmod(size, 1024)
-    if not remainder:
-        megabytes, remainder = divmod(kilobytes, 1024)
-        if not remainder:
-            return "%ldm" % megabytes
-        else:
-            return "%ldk" % kilobytes
-    else:
-        return str(size)
-

templates/Oracle10g/init.ora

 os_authent_prefix = ""
 pga_aggregate_target = 30M
 query_rewrite_enabled = false
-shared_pool_size = 50M
+shared_pool_size = 100M
 sort_area_retained_size = 1048576
 sort_area_size = 1048576
 star_transformation_enabled = false
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.