def connect(connection, password): '''Establishes a connection to the server and stores the connection object in the connections pool. It first looks for a connection with the given connection parameters in the connections pool to reuse existent connections. If such connection is found it queries the server to ensure that the connection is alive and reestablishes it if is dead. If no suitable connection is found in the connections pool, a new one is created and stored in the pool. Parameters: =========== connection: an object of the class db_mgmt_Connection storing the parameters for the connection. password: a string with the password to use for the connection. ''' con = None host_identifier = connection.hostIdentifier try: con = get_connection(connection) try: if not con.cursor().execute('SELECT 1'): raise Exception("connection error") except Exception as exc: grt.send_info("Connection to %s apparently lost, reconnecting..." % connection.hostIdentifier) raise NotConnectedError("Connection error") except NotConnectedError as exc: grt.send_info("Connecting to %s..." % host_identifier) import pyodbc try: con = db_driver.connect(connection, password) # Sybase metadata query SPs use things that don't work inside transactions, so enable autocommit con.autocommit = True # Adds data type conversion functions for pyodbc # if connection.driver.driverLibraryName == 'pyodbc': # cursor = con.cursor() # version = con.execute("SELECT CAST(SERVERPROPERTY('ProductVersion') AS VARCHAR)").fetchone()[0] # majorVersion = int(version.split('.', 1)[0]) # if majorVersion >= 9: # con.add_output_converter(-150, lambda value: value if value is None else value.decode('utf-16')) # con.add_output_converter(0, lambda value: value if value is None else value.decode('utf-16')) # else: # con.add_output_converter(-150, lambda value: value if value is None else str(value)) # con.add_output_converter(0, lambda value: value if value is None else str(value)) except pyodbc.Error as odbc_err: # 28000 is from native SQL Server driver... 42000 seems to be from FreeTDS # FIXME: This should be tuned for Sybase if len(odbc_err.args) == 2 and odbc_err.args[0] in ('28000', '42000') and "(18456)" in odbc_err.args[1]: raise grt.DBLoginError(odbc_err.args[1]) if not con: grt.send_error('Connection failed', str(exc)) raise _connections[connection.__id__] = {"connection" : con } _connections[connection.__id__]["version"] = getServerVersion(connection) version = execute_query(connection, "SELECT @@version").fetchone()[0] grt.send_info("Connected to %s, %s", (host_identifier, version)) return 1
total_size = os.stat(path).st_size processed = 0 self.report_progress("Importing %s..." % os.path.basename(path), 0, total_size) stdout_q, thr = start_reading_from(p1.stdout) input_file = open(path, "r") while p1 and p1.poll() == None: try: if stdout_q: text = stdout_q.get_nowait() if text: log_info("Task stdout: %s\n" % text) if 'Access denied for user' in text: raise grt.DBLoginError(text) elif "Can't open named pipe to host" in text and sys.platform.lower( ) == "win32": text = "%s\n%s" % ( text, "Please check if the server started with the --enabled-named-pipe parameter. The parameter can also be set in the config file." ) self.report_output(text.strip()) elif text is None: stdout_q = None except Empty: pass line = input_file.readline() if not line: break
class MySQLScriptImporter(object): """Import a SQL script using the MySQL command line tool""" def __init__(self, connection_params): self._extra_params = [] self._password = "" self._tool_path = get_path_to_mysql() self._tunnel = ConnectionTunnel(connection_params) conn = connection_params.parameterValues params = [] if connection_params.driver.name == "MysqlNativeSocket": params.append("--protocol=" + ("pipe" if sys.platform == "win32" else "socket")) if conn["socket"]: params.append("--socket=" + conn["socket"]) else: params.append("--protocol=tcp") if self._tunnel.port or conn["port"]: params.append("--port=" + str(self._tunnel.port or conn["port"])) if (self._tunnel.port and ["localhost"] or [conn["hostName"]])[0]: params.append("--host=" + (self._tunnel.port and ["localhost"] or [conn["hostName"]])[0]) if conn.get("useSSL", 0): if conn.get("sslCert", ""): params.append("--ssl-cert=%s" % conn["sslCert"]) if conn.get("sslCA", ""): params.append("--ssl-ca=%s" % conn["sslCA"]) if conn.get("sslKey", ""): params.append("--ssl-key=%s" % conn["sslKey"]) if conn.get("sslCipher", ""): params.append("--ssl-cipher=%s" % conn["sslCipher"]) if conn.get("OPT_ENABLE_CLEARTEXT_PLUGIN", ""): params.append("--enable-cleartext-plugin") params += ["--user="******"userName"]] self._connection_params = params def set_extra_params(self, param_list): self._extra_params = param_list def set_password(self, password): self._password = password def report_progress(self, message, current, total): pass def report_output(self, text): print text def import_script(self, path, default_schema=None, default_charset="utf8"): if not self._tool_path: raise RuntimeError( "mysql command line client not found. Please fix its path in Preferences -> Administration" ) is_windows = platform.system() == 'Windows' if is_windows: params = ['"%s"' % self._tool_path] pwdfile = tempfile.NamedTemporaryFile(delete=False, suffix=".cnf") pwdfilename = pwdfile.name tmpdir = None else: params = [self._tool_path] # use a pipe to feed the password to the client tmpdir = tempfile.mkdtemp() pwdfilename = os.path.join(tmpdir, 'extraparams.cnf') os.mkfifo(pwdfilename) params.append('--defaults-extra-file=' + pwdfilename) if default_charset: params.append("--default-character-set=%s" % default_charset) params += self._connection_params params += self._extra_params if default_schema: params.append(default_schema) cmdstr = " ".join(params) workdir = os.path.dirname(path) log_info("Feeding data from %s to %s (cwd=%s)\n" % (path, cmdstr, workdir)) p1 = None try: self.report_progress("Preparing...", None, None) if not is_windows: try: p1 = subprocess.Popen(params, cwd=workdir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT) except OSError, exc: log_error("Error executing command %s\n%s\n" % (" ".join(params), exc)) raise RuntimeError("Error executing %s:\n%s" % (" ".join(params), str(exc))) # in !Windows feed password to client after it's started (otherwise the fifo would block on open for writing) pwdfile = open(pwdfilename, 'w') pwdfile.write('[client]\npassword='******'\n') pwdfile.close() if is_windows: try: info = subprocess.STARTUPINFO() info.dwFlags |= _subprocess.STARTF_USESHOWWINDOW info.wShowWindow = _subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. fse = sys.getfilesystemencoding() cmd = cmdstr.encode(fse) if isinstance(cmdstr, unicode) else cmdstr log_debug("Executing command: %s\n" % cmdstr) p1 = subprocess.Popen(cmd, cwd=workdir, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=info, shell=cmdstr[0] != '"') except OSError, exc: log_error("Error executing command %s\n%s\n" % (cmdstr, exc)) import traceback traceback.print_exc() raise RuntimeError("Error executing %s:\n%s" % (cmdstr, str(exc))) # do the import total_size = os.stat(path).st_size processed = 0 self.report_progress("Importing %s..." % os.path.basename(path), 0, total_size) stdout_q, thr = start_reading_from(p1.stdout) input_file = open(path, "r") while p1 and p1.poll() == None: try: if stdout_q: text = stdout_q.get_nowait() if text: log_info("Task stdout: %s\n" % text) if 'Access denied for user' in text: raise grt.DBLoginError(text) elif "Can't open named pipe to host" in text and sys.platform.lower( ) == "win32": text = "%s\n%s" % ( text, "Please check if the server started with the --enabled-named-pipe parameter. The parameter can also be set in the config file." ) self.report_output(text.strip()) elif text is None: stdout_q = None except Empty: pass line = input_file.readline() if not line: break processed += len(line) try: p1.stdin.write(line) except IOError, e: log_error( "Exception writing to stdin from cmdline client: %s\n" % e) if e.errno == 32: # broken pipe log_error("Broken pipe from child process\n") break elif e.errno == 22: # invalid argument (happens in Windows, when child process just dies) log_error("Broken pipe from child process\n") break raise e self.report_progress(None, processed, total_size)
def import_script(self, path, default_schema=None, default_charset="utf8"): if not self._tool_path: raise RuntimeError( "mysql command line client not found. Please fix its path in Preferences -> Administration" ) is_windows = platform.system() == 'Windows' if is_windows: params = ['"%s"' % self._tool_path] pwdfile = tempfile.NamedTemporaryFile(delete=False, suffix=".cnf") pwdfilename = pwdfile.name tmpdir = None else: params = [to_unicode(self._tool_path)] # use a pipe to feed the password to the client tmpdir = tempfile.mkdtemp() pwdfilename = os.path.join(tmpdir, 'extraparams.cnf') os.mkfifo(pwdfilename) params.append('--defaults-extra-file=' + pwdfilename) if default_charset: params.append("--default-character-set=%s" % default_charset) params += self._connection_params params += self._extra_params if default_schema: params.append(default_schema) cmdstr = " ".join(params) workdir = os.path.dirname(path) log_info("Feeding data from %s to %s (cwd=%s)\n" % (path, cmdstr, workdir)) p1 = None try: self.report_progress("Preparing...", None, None) if not is_windows: try: p1 = subprocess.Popen(params, cwd=workdir, stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.STDOUT, encoding='utf8') except OSError as exc: log_error("Error executing command %s\n%s\n" % (" ".join(params), exc)) raise RuntimeError("Error executing %s:\n%s" % (" ".join(params), str(exc))) # in !Windows feed password to client after it's started (otherwise the fifo would block on open for writing) with open(pwdfilename, 'w') as pwdfile: pwdfile.write('[client]\npassword='******'' pwdfile.write(self._password.replace("\\", "\\\\")) pwdfile.write('\n') if is_windows: try: info = subprocess.STARTUPINFO() info.dwFlags |= subprocess.STARTF_USESHOWWINDOW info.wShowWindow = subprocess.SW_HIDE # Command line can contain object names in case of export and filename in case of import # Object names must be in utf-8 but filename must be encoded in the filesystem encoding, # which probably isn't utf-8 in windows. log_debug("Executing command: %s\n" % cmdstr) p1 = subprocess.Popen(cmdstr, cwd=workdir, stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.STDOUT, startupinfo=info, shell=cmdstr[0] != '"', encoding='utf8') except OSError as exc: log_error("Error executing command %s\n%s\n" % (cmdstr, str(exc))) import traceback traceback.print_exc() raise RuntimeError("Error executing %s:\n%s" % (cmdstr, str(exc))) # do the import total_size = os.stat(path).st_size processed = 0 self.report_progress("Importing %s..." % os.path.basename(path), 0, total_size) stdout_q, thr = start_reading_from(p1.stdout) with open(path, "r") as input_file: while p1 and p1.poll() == None: try: if stdout_q: text = stdout_q.get_nowait() if text: log_info("Task stdout: %s\n" % text) if 'Access denied for user' in text: raise grt.DBLoginError(text) elif "Can't open named pipe to host" in text and sys.platform.lower( ) == "win32": text = "%s\n%s" % ( text, "Please check if the server started with the --enabled-named-pipe parameter. The parameter can also be set in the config file." ) self.report_output(text.strip()) elif text is None: stdout_q = None except Empty: pass line = input_file.readline() if not line: break processed += len(line) try: p1.stdin.write(line) except IOError as e: log_error( "Exception writing to stdin from cmdline client: %s\n" % e) if e.errno == 32: # broken pipe log_error("Broken pipe from child process\n") break elif e.errno == 22: # invalid argument (happens in Windows, when child process just dies) log_error("Broken pipe from child process\n") break raise e self.report_progress(None, processed, total_size) # close the writer end of the client's pipe, so it can exit p1.stdin.close() self.report_progress("Finished executing script", processed, total_size) # flush queue from reader if stdout_q: while True: text = stdout_q.get() if text is None: break log_info("Task stdout: %s\n" % text) if 'Access denied for user' in text: raise grt.DBLoginError(text) elif "Can't open named pipe to host" in text and sys.platform.lower( ) == "win32": text = "%s\n%s" % ( text, "Please check if the server started with the --enabled-named-pipe parameter. The parameter can also be set in the config file." ) self.report_output(text.strip()) # let reader thread die thr.join() p1.wait() exitcode = p1.returncode log_info("mysql tool exited with code %s\n" % exitcode) if exitcode != 0: self.report_progress( "Operation failed with exitcode " + str(exitcode), None, None) else: self.report_progress("Operation completed successfully", None, None) return exitcode finally: if pwdfilename: os.remove(pwdfilename) if tmpdir: os.rmdir(tmpdir)