/* * DBeaver - Universal Database Manager * Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org) * Copyright (C) 2011-2012 Eugene Fradkin (eugene.fradkin@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jkiss.dbeaver.ext.mysql.tools; import org.eclipse.jface.viewers.IStructuredSelection; import org.eclipse.jface.wizard.IWizardPage; import org.eclipse.osgi.util.NLS; import org.eclipse.swt.SWT; import org.eclipse.ui.IExportWizard; import org.eclipse.ui.IWorkbench; import org.jkiss.code.NotNull; import org.jkiss.dbeaver.core.DBeaverCore; import org.jkiss.dbeaver.ext.mysql.MySQLConstants; import org.jkiss.dbeaver.ext.mysql.MySQLDataSourceProvider; import org.jkiss.dbeaver.ext.mysql.MySQLMessages; import org.jkiss.dbeaver.ext.mysql.MySQLServerHome; import org.jkiss.dbeaver.ext.mysql.model.MySQLTableBase; import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore; import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor; import org.jkiss.dbeaver.model.struct.DBSObject; import org.jkiss.dbeaver.ui.UIUtils; import org.jkiss.dbeaver.ui.dialogs.DialogUtils; import org.jkiss.dbeaver.ui.dialogs.tools.AbstractImportExportWizard; import org.jkiss.dbeaver.utils.GeneralUtils; import org.jkiss.dbeaver.utils.RuntimeUtils; import org.jkiss.utils.CommonUtils; import java.io.*; import java.text.NumberFormat; import java.util.ArrayList; import java.util.Collection; import java.util.Iterator; import java.util.List; import java.util.regex.Matcher; import java.util.regex.Pattern; class MySQLExportWizard extends AbstractImportExportWizard<MySQLDatabaseExportInfo> implements IExportWizard { public enum DumpMethod { ONLINE, LOCK_ALL_TABLES, NORMAL } DumpMethod method; boolean noCreateStatements; boolean addDropStatements = true; boolean disableKeys = true; boolean extendedInserts = true; boolean dumpEvents; boolean comments; boolean removeDefiner; boolean binariesInHex; boolean showViews; private String extraCommandArgs; public List<MySQLDatabaseExportInfo> objects = new ArrayList<>(); private MySQLExportWizardPageObjects objectsPage; private MySQLExportWizardPageSettings settingsPage; public MySQLExportWizard(Collection<DBSObject> objects) { super(objects, MySQLMessages.tools_db_export_wizard_task_name); this.method = DumpMethod.NORMAL; this.outputFolder = new File(DialogUtils.getCurDialogFolder()); //$NON-NLS-1$ //$NON-NLS-2$ final DBPPreferenceStore store = DBeaverCore.getGlobalPreferenceStore(); this.outputFilePattern = store.getString("MySQL.export.outputFilePattern"); if (CommonUtils.isEmpty(this.outputFilePattern)) { this.outputFilePattern = "dump-${database}-${timestamp}.sql"; } noCreateStatements = CommonUtils.getBoolean(store.getString("MySQL.export.noCreateStatements"), false); addDropStatements = CommonUtils.getBoolean(store.getString("MySQL.export.addDropStatements"), true); disableKeys = CommonUtils.getBoolean(store.getString("MySQL.export.disableKeys"), true); extendedInserts = CommonUtils.getBoolean(store.getString("MySQL.export.extendedInserts"), true); dumpEvents = CommonUtils.getBoolean(store.getString("MySQL.export.dumpEvents"), false); comments = CommonUtils.getBoolean(store.getString("MySQL.export.comments"), false); removeDefiner = CommonUtils.getBoolean(store.getString("MySQL.export.removeDefiner"), false); binariesInHex = CommonUtils.getBoolean(store.getString("MySQL.export.binariesInHex"), false); showViews = CommonUtils.getBoolean(store.getString("MySQL.export.showViews"), false); extraCommandArgs = store.getString("MySQL.export.extraArgs"); } @Override public void init(IWorkbench workbench, IStructuredSelection selection) { super.init(workbench, selection); objectsPage = new MySQLExportWizardPageObjects(this); settingsPage = new MySQLExportWizardPageSettings(this); } @Override public void addPages() { addPage(objectsPage); addPage(settingsPage); super.addPages(); } @Override public IWizardPage getNextPage(IWizardPage page) { if (page == settingsPage) { return null; } return super.getNextPage(page); } @Override public IWizardPage getPreviousPage(IWizardPage page) { if (page == logPage) { return settingsPage; } return super.getPreviousPage(page); } @Override public void onSuccess() { UIUtils.showMessageBox( getShell(), MySQLMessages.tools_db_export_wizard_title, CommonUtils.truncateString(NLS.bind(MySQLMessages.tools_db_export_wizard_message_export_completed, getObjectsName()), 255), SWT.ICON_INFORMATION); UIUtils.launchProgram(outputFolder.getAbsolutePath()); } public String getExtraCommandArgs() { return extraCommandArgs; } public void setExtraCommandArgs(String extraCommandArgs) { this.extraCommandArgs = extraCommandArgs; } @Override public void fillProcessParameters(List<String> cmd, MySQLDatabaseExportInfo arg) throws IOException { File dumpBinary = RuntimeUtils.getHomeBinary(getClientHome(), MySQLConstants.BIN_FOLDER, "mysqldump"); //$NON-NLS-1$ String dumpPath = dumpBinary.getAbsolutePath(); cmd.add(dumpPath); switch (method) { case LOCK_ALL_TABLES: cmd.add("--lock-all-tables"); //$NON-NLS-1$ break; case ONLINE: cmd.add("--single-transaction"); //$NON-NLS-1$ break; } if (noCreateStatements) { cmd.add("--no-create-info"); //$NON-NLS-1$ } else { if (CommonUtils.isEmpty(arg.getTables())) { cmd.add("--routines"); //$NON-NLS-1$ } } if (addDropStatements) cmd.add("--add-drop-table"); //$NON-NLS-1$ if (disableKeys) cmd.add("--disable-keys"); //$NON-NLS-1$ if (extendedInserts) { cmd.add("--extended-insert"); //$NON-NLS-1$ } else { cmd.add("--skip-extended-insert"); //$NON-NLS-1$ } if (binariesInHex) { cmd.add("--hex-blob"); //$NON-NLS-1$ } if (dumpEvents) cmd.add("--events"); //$NON-NLS-1$ if (comments) cmd.add("--comments"); //$NON-NLS-1$ if (!CommonUtils.isEmptyTrimmed(extraCommandArgs)) { cmd.add(extraCommandArgs); } } @Override protected void setupProcessParameters(ProcessBuilder process) { if (!CommonUtils.isEmpty(getToolUserPassword())) { process.environment().put(MySQLConstants.ENV_VARIABLE_MYSQL_PWD, getToolUserPassword()); } } @Override public boolean performFinish() { objectsPage.saveState(); final DBPPreferenceStore store = DBeaverCore.getGlobalPreferenceStore(); store.setValue("MySQL.export.outputFilePattern", this.outputFilePattern); store.setValue("MySQL.export.noCreateStatements", noCreateStatements); store.setValue("MySQL.export.addDropStatements", addDropStatements); store.setValue("MySQL.export.disableKeys", disableKeys); store.setValue("MySQL.export.extendedInserts", extendedInserts); store.setValue("MySQL.export.dumpEvents", dumpEvents); store.setValue("MySQL.export.comments", comments); store.setValue("MySQL.export.removeDefiner", removeDefiner); store.setValue("MySQL.export.binariesInHex", binariesInHex); store.setValue("MySQL.export.showViews", showViews); store.setValue("MySQL.export.extraArgs", extraCommandArgs); return super.performFinish(); } @Override public MySQLServerHome findServerHome(String clientHomeId) { return MySQLDataSourceProvider.getServerHome(clientHomeId); } @Override public Collection<MySQLDatabaseExportInfo> getRunInfo() { return objects; } @Override protected List<String> getCommandLine(MySQLDatabaseExportInfo arg) throws IOException { List<String> cmd = MySQLToolScript.getMySQLToolCommandLine(this, arg); if (objects.isEmpty()) { // no dump } else if (!CommonUtils.isEmpty(arg.getTables())) { cmd.add(arg.getDatabase().getName()); for (MySQLTableBase table : arg.getTables()) { cmd.add(table.getName()); } } else { cmd.add(arg.getDatabase().getName()); } return cmd; } @Override public boolean isVerbose() { return true; } @Override protected void startProcessHandler(DBRProgressMonitor monitor, final MySQLDatabaseExportInfo arg, ProcessBuilder processBuilder, Process process) { super.startProcessHandler(monitor, arg, processBuilder, process); String outFileName = GeneralUtils.replaceVariables(outputFilePattern, new GeneralUtils.IVariableResolver() { @Override public String get(String name) { switch (name) { case VARIABLE_DATABASE: return arg.getDatabase().getName(); case VARIABLE_HOST: return arg.getDatabase().getDataSource().getContainer().getConnectionConfiguration().getHostName(); case VARIABLE_TABLE: final Iterator<MySQLTableBase> iterator = arg.getTables() == null ? null : arg.getTables().iterator(); if (iterator != null && iterator.hasNext()) { return iterator.next().getName(); } else { return "null"; } case VARIABLE_TIMESTAMP: return RuntimeUtils.getCurrentTimeStamp(); default: System.getProperty(name); } return null; } }); File outFile = new File(outputFolder, outFileName); boolean isFiltering = removeDefiner; Thread job = isFiltering ? new DumpFilterJob(monitor, process.getInputStream(), outFile) : new DumpCopierJob(monitor, MySQLMessages.tools_db_export_wizard_monitor_export_db, process.getInputStream(), outFile); job.start(); } private static Pattern DEFINER_PATTER = Pattern.compile("DEFINER\\s*=\\s*`[^*]*`@`[0-9a-z\\-_\\.%]*`", Pattern.CASE_INSENSITIVE); class DumpFilterJob extends DumpJob { protected DumpFilterJob(DBRProgressMonitor monitor, InputStream stream, File outFile) { super(MySQLMessages.tools_db_export_wizard_job_dump_log_reader, monitor, stream, outFile); } @Override public void runDump() throws IOException { monitor.beginTask(MySQLMessages.tools_db_export_wizard_monitor_export_db, 100); long prevStatusUpdateTime = 0; try { NumberFormat numberFormat = NumberFormat.getInstance(); LineNumberReader reader = new LineNumberReader(new InputStreamReader(input, GeneralUtils.DEFAULT_ENCODING)); try (OutputStream output = new FileOutputStream(outFile)) { BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(output, GeneralUtils.DEFAULT_ENCODING)); for (;;) { String line = reader.readLine(); if (line == null) { break; } final Matcher matcher = DEFINER_PATTER.matcher(line); if (matcher.find()) { line = matcher.replaceFirst(""); } long currentTime = System.currentTimeMillis(); if (currentTime - prevStatusUpdateTime > 300) { monitor.subTask("Saved " + numberFormat.format(reader.getLineNumber()) + " lines"); prevStatusUpdateTime = currentTime; } line = filterLine(line); writer.write(line); writer.newLine(); } writer.flush(); } } finally { monitor.done(); } } @NotNull private String filterLine(@NotNull String line) { return line; } } }