diff options
author | Alexandre Fayolle <alexandre.fayolle@logilab.fr> | 2010-01-20 09:19:20 +0100 |
---|---|---|
committer | Alexandre Fayolle <alexandre.fayolle@logilab.fr> | 2010-01-20 09:19:20 +0100 |
commit | ed82e1854ffa05655a24bdb1637e7115df8a1c8c (patch) | |
tree | dc5f8409796b0daa81637acfb4e984235d3e4d4d | |
parent | 0fa7d0581ce27b6a07d3c87492cb5b509c1b907e (diff) | |
download | logilab-common-ed82e1854ffa05655a24bdb1637e7115df8a1c8c.tar.gz |
enable support for backup and restore operations in SQL Server (ticket 19687)
-rw-r--r-- | adbh.py | 60 | ||||
-rw-r--r-- | db.py | 14 |
2 files changed, 74 insertions, 0 deletions
@@ -16,6 +16,8 @@ Helpers are provided for postgresql, mysql and sqlite. """ __docformat__ = "restructuredtext en" +import os +import sys class BadQuery(Exception): pass class UnsupportedFunction(BadQuery): pass @@ -175,6 +177,7 @@ class _GenericAdvFuncHelper: """return a list of commands to restore a backup of the given database""" raise NotImplementedError('not supported by this DBMS') + # helpers to standardize SQL according to the database def sql_current_date(self): @@ -595,6 +598,59 @@ class _SqlServer2005FuncHelper(_GenericAdvFuncHelper): return StringIO.StringIO(value) + def backup_command(self, dbname, dbhost, dbuser, backupfile, + keepownership=True): + """return a command to backup the given database""" + return [sys.executable, os.path.normpath(__file__), + "_SqlServer2005FuncHelper._do_backup", dbhost, dbname, backupfile] + + def restore_commands(self, dbname, dbhost, dbuser, backupfile, + encoding='utf-8', keepownership=True, drop=True): + """return a list of commands to restore a backup of the given database""" + return [[sys.executable, os.path.normpath(__file__), + "_SqlServer2005FuncHelper._do_restore", dbhost, dbname, backupfile], + ] + + @staticmethod + def _do_backup(): + import time + from logilab.common.db import get_connection + dbhost = sys.argv[2] + dbname = sys.argv[3] + filename = sys.argv[4] + cnx = get_connection(driver='sqlserver2005', host=dbhost, database=dbname, extra_args='autocommit;trusted_connection') + cursor = cnx.cursor() + cursor.execute("BACKUP DATABASE ? TO DISK= ? ", (dbname, filename,)) + prev_size = -1 + err_count = 0 + same_size_count = 0 + while err_count < 10 and same_size_count < 10: + time.sleep(1) + try: + size = os.path.getsize(filename) + except OSError, exc: + err_count +=1 + print exc + if size > prev_size: + same_size_count = 0 + prev_size = size + else: + same_size_count += 1 + cnx.close() + sys.exit(0) + + @staticmethod + def _do_restore(): + """return the SQL statement to restore a backup of the given database""" + from logilab.common.db import get_connection + dbhost = sys.argv[2] + dbname = sys.argv[3] + filename = sys.argv[4] + cnx = get_connection(driver='sqlserver2005', host=dbhost, database='master', extra_args='autocommit;trusted_connection') + cursor = cnx.cursor() + cursor.execute("RESTORE DATABASE ? FROM DISK= ? WITH REPLACE", (dbname, filename,)) + sys.exit(0) + ADV_FUNC_HELPER_DIRECTORY = {'postgres': _PGAdvFuncHelper(), 'sqlite': _SqliteAdvFuncHelper(), 'mysql': _MyAdvFuncHelper(), @@ -616,3 +672,7 @@ def auto_register_function(funcdef): """register the function `funcdef` on supported backends""" for driver in funcdef.supported_backends: register_function(driver, funcdef) + +if __name__ == "__main__": # used to backup sql server db + func_call = sys.argv[1] + eval(func_call+'()') @@ -604,6 +604,7 @@ class _MySqlDBAdapter(DBAPIAdapter): class _BaseSqlServerAdapter(DBAPIAdapter): driver = 'Override in subclass' _use_trusted_connection = False + _use_autocommit = False _fetch_lock = threading.Lock() @classmethod @@ -613,11 +614,22 @@ class _BaseSqlServerAdapter(DBAPIAdapter): Authentication (i.e. passwordless auth) """ klass._use_trusted_connection = use_trusted + + @classmethod + def use_autocommit(klass, use_autocommit=False): + """ + pass True to this class method to enable autocommit (required + for backup and restore) + """ + klass._use_autocommit = use_autocommit + @classmethod def _process_extra_args(klass, arguments): arguments = arguments.lower().split(';') if 'trusted_connection' in arguments: klass.use_trusted_connection(True) + if 'autocommit' in arguments: + klass.use_autocommit(True) def connect(self, host='', database='', user='', password='', port=None, extra_args=None): """Handles pyodbc connection format @@ -750,6 +762,8 @@ class _PyodbcAdapter(_BaseSqlServerAdapter): variables['Trusted_Connection'] = 'yes' del variables['user'] del variables['password'] + if self._use_autocommit: + variables['autocommit'] = True return self._native_module.connect(**variables) class _PyodbcSqlServer2000Adapter(_PyodbcAdapter): |