提交 7ba6961a 编写于 作者: S serge-rider

CB-1385 SQL translator POC. CLI model enhancements.

上级 7fb0b58d
......@@ -23,6 +23,7 @@ Export-Package: org.jkiss.dbeaver.model.sql,
org.jkiss.dbeaver.model.sql.parser.tokens,
org.jkiss.dbeaver.model.sql.registry,
org.jkiss.dbeaver.model.sql.task,
org.jkiss.dbeaver.model.sql.translate,
org.jkiss.dbeaver.model.text,
org.jkiss.dbeaver.model.text.parser,
org.jkiss.dbeaver.model.text.parser.rules
......
......@@ -16,6 +16,8 @@
*/
package org.jkiss.dbeaver.model.sql.format;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.sql.SQLSyntaxManager;
import org.jkiss.dbeaver.model.sql.registry.SQLFormatterConfigurationRegistry;
......@@ -25,10 +27,13 @@ import org.jkiss.dbeaver.model.sql.registry.SQLFormatterConfigurationRegistry;
*/
public class SQLFormatUtils {
public static String formatSQL(DBPDataSource dataSource, String query)
{
public static String formatSQL(DBPDataSource dataSource, String query) {
SQLSyntaxManager syntaxManager = new SQLSyntaxManager();
syntaxManager.init(dataSource.getSQLDialect(), dataSource.getContainer().getPreferenceStore());
return formatSQL(dataSource, syntaxManager, query);
}
public static String formatSQL(@Nullable DBPDataSource dataSource, @NotNull SQLSyntaxManager syntaxManager, String query) {
SQLFormatterConfiguration configuration = new SQLFormatterConfiguration(dataSource, syntaxManager);
SQLFormatter formatter = SQLFormatterConfigurationRegistry.getInstance().createFormatter(configuration);
if (formatter == null) {
......
......@@ -107,7 +107,7 @@ public class SQLFormatterConfiguration {
}
public boolean isFunction(String name) {
return syntaxManager.getDialect().getFunctions(dataSource).contains(name.toUpperCase(Locale.ENGLISH));
return syntaxManager.getDialect().getFunctions().contains(name.toUpperCase(Locale.ENGLISH));
}
public Object getProperty(String name) {
......
......@@ -43,6 +43,9 @@ public class SQLParserContext {
private final IDocument document;
private TPRuleBasedScanner scanner;
@Nullable
private DBPPreferenceStore preferenceStore;
public SQLParserContext(@Nullable DBPDataSource dataSource, @NotNull SQLSyntaxManager syntaxManager, @NotNull SQLRuleManager ruleManager, @NotNull IDocument document) {
this.dataSource = dataSource;
this.syntaxManager = syntaxManager;
......@@ -83,12 +86,19 @@ public class SQLParserContext {
}
public DBPPreferenceStore getPreferenceStore() {
if (preferenceStore != null) {
return preferenceStore;
}
DBPDataSource dataSource = getDataSource();
return dataSource == null ?
DBWorkbench.getPlatform().getPreferenceStore() :
dataSource.getContainer().getPreferenceStore();
}
public void setPreferenceStore(@Nullable DBPPreferenceStore preferenceStore) {
this.preferenceStore = preferenceStore;
}
void startScriptEvaluation() {
getScanner().startEval();
}
......
......@@ -18,6 +18,7 @@ package org.jkiss.dbeaver.model.sql.parser;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.DBPDataSourceContainer;
import org.jkiss.dbeaver.model.DBPKeywordType;
......@@ -49,6 +50,8 @@ import java.util.List;
*/
public class SQLRuleManager {
private static final Log log = Log.getLog(SQLRuleManager.class);
@NotNull
private TPRule[] allRules = new TPRule[0];
@NotNull
......@@ -127,11 +130,15 @@ public class SQLRuleManager {
if (!minimalRules) {
final SQLControlToken controlToken = new SQLControlToken();
String commandPrefix = syntaxManager.getControlCommandPrefix();
try {
String commandPrefix = syntaxManager.getControlCommandPrefix();
// Control rules
for (SQLCommandHandlerDescriptor controlCommand : SQLCommandsRegistry.getInstance().getCommandHandlers()) {
rules.add(new SQLCommandRule(commandPrefix, controlCommand, controlToken)); //$NON-NLS-1$
// Control rules
for (SQLCommandHandlerDescriptor controlCommand : SQLCommandsRegistry.getInstance().getCommandHandlers()) {
rules.add(new SQLCommandRule(commandPrefix, controlCommand, controlToken)); //$NON-NLS-1$
}
} catch (Exception e) {
log.error(e);
}
}
{
......@@ -223,7 +230,7 @@ public class SQLRuleManager {
for (String type : dialect.getDataTypes(dataSource)) {
wordRule.addWord(type, typeToken);
}
for (String function : dialect.getFunctions(dataSource)) {
for (String function : dialect.getFunctions()) {
wordRule.addFunction(function);
}
}
......
......@@ -23,7 +23,7 @@ import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.ModelPreferences;
import org.jkiss.dbeaver.model.DBPDataSource;
import org.jkiss.dbeaver.model.impl.preferences.SimplePreferenceStore;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.sql.*;
import org.jkiss.dbeaver.model.sql.parser.tokens.SQLControlToken;
import org.jkiss.dbeaver.model.sql.parser.tokens.SQLTokenType;
......@@ -35,7 +35,6 @@ import org.jkiss.dbeaver.model.text.parser.TPTokenDefault;
import org.jkiss.utils.ArrayUtils;
import org.jkiss.utils.CommonUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
......@@ -747,20 +746,16 @@ public class SQLScriptParser
return SQLScriptParser.extractScriptQueries(parserContext, 0, sqlScriptContent.length(), true, false, true);
}
public static List<SQLScriptElement> parseScript(SQLDialect dialect, String sqlScriptContent) {
public static List<SQLScriptElement> parseScript(SQLDialect dialect, DBPPreferenceStore preferenceStore, String sqlScriptContent) {
SQLSyntaxManager syntaxManager = new SQLSyntaxManager();
syntaxManager.init(dialect, new SimplePreferenceStore() {
@Override
public void save() throws IOException {
// Noop
}
});
syntaxManager.init(dialect, preferenceStore);
SQLRuleManager ruleManager = new SQLRuleManager(syntaxManager);
ruleManager.loadRules();
Document sqlDocument = new Document(sqlScriptContent);
SQLParserContext parserContext = new SQLParserContext(null, syntaxManager, ruleManager, sqlDocument);
parserContext.setPreferenceStore(preferenceStore);
return SQLScriptParser.extractScriptQueries(parserContext, 0, sqlScriptContent.length(), true, false, true);
}
......
......@@ -17,15 +17,23 @@
package org.jkiss.dbeaver.model.sql.translate;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.create.table.ColumnDefinition;
import net.sf.jsqlparser.statement.create.table.CreateTable;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.DBException;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.sql.SQLDialect;
import org.jkiss.dbeaver.model.sql.SQLQuery;
import org.jkiss.dbeaver.model.sql.SQLScriptElement;
import org.jkiss.dbeaver.model.sql.format.SQLFormatUtils;
import org.jkiss.dbeaver.model.sql.parser.SQLScriptParser;
import org.jkiss.utils.CommonUtils;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
/**
* SQL translator
......@@ -35,30 +43,108 @@ public final class SQLQueryTranslator {
public static String translateScript(
@NotNull SQLDialect sourceDialect,
@NotNull SQLDialect targetDialect,
@NotNull DBPPreferenceStore preferenceStore,
@NotNull String script) throws DBException
{
List<SQLScriptElement> sqlScriptElements = SQLScriptParser.parseScript(sourceDialect, script);
SQLTranslateContext context = new SQLTranslateContext(sourceDialect, targetDialect, preferenceStore);
List<SQLScriptElement> sqlScriptElements = SQLScriptParser.parseScript(sourceDialect, preferenceStore, script);
List<SQLScriptElement> result = new ArrayList<>();
for (SQLScriptElement element : sqlScriptElements) {
result.addAll(
translateCommand(sourceDialect, targetDialect, element));
translateCommand(context, element));
}
String scriptDelimiter = targetDialect.getScriptDelimiters()[0];
StringBuilder sql = new StringBuilder();
for (SQLScriptElement element : result) {
sql.append(element.getText());
sql.append(scriptDelimiter);
sql.append(scriptDelimiter).append("\n");
}
return sql.toString();
}
public static List<? extends SQLScriptElement> translateCommand(
@NotNull SQLDialect sourceDialect,
@NotNull SQLDialect targetDialect,
@NotNull SQLTranslateContext context,
@NotNull SQLScriptElement element) throws DBException {
if (element instanceof SQLQuery) {
return translateQuery(context, (SQLQuery)element);
}
return Collections.singletonList(element);
}
private static List<? extends SQLScriptElement> translateQuery(
@NotNull SQLTranslateContext context,
@NotNull SQLQuery query) throws DBException
{
Statement statement = query.getStatement();
if (statement != null) {
return translateStatement(context, query, statement);
}
return Collections.singletonList(query);
}
private static List<? extends SQLScriptElement> translateStatement(
@NotNull SQLTranslateContext context,
@NotNull SQLQuery query,
@NotNull Statement statement) throws DBException
{
// FIXME: currently it is a dummy translator to PostgreSQL dialect
List<SQLScriptElement> extraQueries = null;
if (statement instanceof CreateTable) {
boolean defChanged = false;
CreateTable createTable = (CreateTable)statement;
for (ColumnDefinition cd : createTable.getColumnDefinitions()) {
String newDataType = null;
switch (cd.getColDataType().getDataType().toUpperCase(Locale.ENGLISH)) {
case "CLOB":
newDataType = "varchar";
break;
}
if (newDataType != null) {
cd.getColDataType().setDataType(newDataType);
defChanged = true;
}
if (!CommonUtils.isEmpty(cd.getColumnSpecs())) {
for (String cSpec : new ArrayList<>(cd.getColumnSpecs())) {
switch (cSpec.toUpperCase(Locale.ENGLISH)) {
case "AUTO_INCREMENT":
String sequenceName = CommonUtils.escapeIdentifier(createTable.getTable().getName()) +
"_" + CommonUtils.escapeIdentifier(cd.getColumnName());
cd.getColumnSpecs().remove(cSpec);
cd.getColumnSpecs().add("DEFAULT");
cd.getColumnSpecs().add("NEXTVAL('" + sequenceName + "')");
defChanged = true;
String createSeqQuery = "CREATE SEQUENCE " + sequenceName;
if (extraQueries == null) {
extraQueries = new ArrayList<>();
}
extraQueries.add(new SQLQuery(null, createSeqQuery));
break;
}
}
}
}
if (defChanged) {
String newQueryText = SQLFormatUtils.formatSQL(null, context.getSyntaxManager(), createTable.toString());
query.setText(newQueryText);
if (extraQueries == null) {
extraQueries = new ArrayList<>();
}
extraQueries.add(query);
}
}
if (extraQueries == null) {
return Collections.singletonList(query);
}
return extraQueries;
}
}
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2021 DBeaver Corp and others
*
* 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.model.sql.translate;
import org.jkiss.code.NotNull;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.sql.SQLDialect;
import org.jkiss.dbeaver.model.sql.SQLSyntaxManager;
/**
* SQL translator
*/
public final class SQLTranslateContext {
@NotNull
private final SQLDialect sourceDialect;
@NotNull
private final SQLDialect targetDialect;
@NotNull
private final DBPPreferenceStore preferenceStore;
@NotNull
private final SQLSyntaxManager syntaxManager;
public SQLTranslateContext(
@NotNull SQLDialect sourceDialect,
@NotNull SQLDialect targetDialect,
@NotNull DBPPreferenceStore preferenceStore)
{
this.sourceDialect = sourceDialect;
this.targetDialect = targetDialect;
this.preferenceStore = preferenceStore;
syntaxManager = new SQLSyntaxManager();
syntaxManager.init(targetDialect, preferenceStore);
}
@NotNull
public SQLDialect getSourceDialect() {
return sourceDialect;
}
@NotNull
public SQLDialect getTargetDialect() {
return targetDialect;
}
@NotNull
public DBPPreferenceStore getPreferenceStore() {
return preferenceStore;
}
@NotNull
public SQLSyntaxManager getSyntaxManager() {
return syntaxManager;
}
}
......@@ -152,6 +152,10 @@ public final class ModelPreferences
return preferences;
}
public static void setPreferences(DBPPreferenceStore preferences) {
ModelPreferences.preferences = preferences;
}
public static void setMainBundle(Bundle mainBundle) {
ModelPreferences.mainBundle = mainBundle;
ModelPreferences.preferences = new BundlePreferenceStore(mainBundle);
......
......@@ -222,7 +222,7 @@ public abstract class SimplePreferenceStore extends AbstractPreferenceStore {
public String getString(String name)
{
String value = properties.get(name);
if (value == null) {
if (value == null && parentStore != null) {
if (parentStore.isDefault(name)) {
value = defaultProperties.get(name);
}
......@@ -237,7 +237,7 @@ public abstract class SimplePreferenceStore extends AbstractPreferenceStore {
public String getDefaultString(String name)
{
String value = defaultProperties.get(name);
if (value == null) {
if (value == null && parentStore != null) {
if (parentStore.isDefault(name)) {
return parentStore.getDefaultString(name);
} else {
......@@ -250,7 +250,7 @@ public abstract class SimplePreferenceStore extends AbstractPreferenceStore {
@Override
public boolean isDefault(String name)
{
return (!properties.containsKey(name) && (defaultProperties.containsKey(name) || parentStore.isDefault(name)));
return (!properties.containsKey(name) && (defaultProperties.containsKey(name) || (parentStore != null && parentStore.isDefault(name))));
}
public boolean isSet(String name)
......@@ -266,7 +266,7 @@ public abstract class SimplePreferenceStore extends AbstractPreferenceStore {
public String[] preferenceNames()
{
return properties.keySet().toArray(new String[properties.size()]);
return properties.keySet().toArray(new String[0]);
}
@Override
......
......@@ -26,7 +26,10 @@ import org.jkiss.dbeaver.model.impl.data.formatters.BinaryFormatterHexNative;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.model.sql.*;
import org.jkiss.dbeaver.model.sql.parser.SQLSemanticProcessor;
import org.jkiss.dbeaver.model.struct.*;
import org.jkiss.dbeaver.model.struct.DBSDataType;
import org.jkiss.dbeaver.model.struct.DBSObject;
import org.jkiss.dbeaver.model.struct.DBSTypedObject;
import org.jkiss.dbeaver.model.struct.DBSTypedObjectEx;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedure;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedureParameter;
import org.jkiss.dbeaver.model.struct.rdb.DBSProcedureParameterKind;
......@@ -168,7 +171,7 @@ public abstract class AbstractSQLDialect implements SQLDialect {
@NotNull
@Override
public Set<String> getFunctions(@Nullable DBPDataSource dataSource) {
public Set<String> getFunctions() {
return functions;
}
......
......@@ -115,7 +115,7 @@ public interface SQLDialect {
@NotNull
Set<String> getReservedWords();
@NotNull
Set<String> getFunctions(@Nullable DBPDataSource dataSource);
Set<String> getFunctions();
@NotNull
Set<String> getDataTypes(@Nullable DBPDataSource dataSource);
@Nullable
......
......@@ -150,7 +150,7 @@ public class SQLSyntaxManager {
}
}
String extraDelimiters = preferenceStore.getString(ModelPreferences.SCRIPT_STATEMENT_DELIMITER);
String extraDelimiters = CommonUtils.toString(preferenceStore.getString(ModelPreferences.SCRIPT_STATEMENT_DELIMITER), SQLConstants.DEFAULT_STATEMENT_DELIMITER);
StringTokenizer st = new StringTokenizer(extraDelimiters, " \t,");
while (st.hasMoreTokens()) {
String delim = st.nextToken();
......
......@@ -17,6 +17,7 @@
package org.jkiss.dbeaver.utils;
import org.eclipse.core.internal.runtime.AdapterManager;
import org.eclipse.core.runtime.*;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
......@@ -726,10 +727,14 @@ public class GeneralUtils {
public static Object queryAdapterManager(Object sourceObject, String adapterId, boolean allowActivation) {
Object result;
AdapterManager adapterManager = AdapterManager.getDefault();
if (adapterManager == null) {
return null;
}
if (allowActivation) {
result = Platform.getAdapterManager().loadAdapter(sourceObject, adapterId);
result = adapterManager.loadAdapter(sourceObject, adapterId);
} else {
result = Platform.getAdapterManager().getAdapter(sourceObject, adapterId);
result = adapterManager.getAdapter(sourceObject, adapterId);
}
return result;
}
......
......@@ -426,4 +426,13 @@
<initializer class="org.jkiss.dbeaver.ui.app.standalone.DBeaverApplicationPreferenceInitializer"/>
</extension>
<extension point="org.jkiss.dbeaver.commandLine">
<parameter name="translateSQL"
longName="translate-sql-script"
description="Translates sql script from one dialect to another."
exitAfterExecute="true"
hasArg="true"
handler="org.jkiss.dbeaver.ui.app.standalone.cli.SQLTranslatorHandler"/>
</extension>
</plugin>
......@@ -16,8 +16,10 @@
*/
package org.jkiss.dbeaver.ui.app.standalone;
import org.apache.commons.cli.CommandLine;
public interface CommandLineParameterHandler {
void handleParameter(String name, String value);
void handleParameter(CommandLine commandLine, String name, String value);
}
......@@ -20,7 +20,6 @@ import org.apache.commons.cli.*;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.IExtensionRegistry;
import org.eclipse.core.runtime.Platform;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.ui.actions.datasource.ConnectionCommands;
......@@ -281,11 +280,13 @@ public class DBeaverCommandLine
if (param.hasArg) {
for (String optValue : commandLine.getOptionValues(param.name)) {
param.handler.handleParameter(
commandLine,
param.name,
optValue);
}
} else {
param.handler.handleParameter(
commandLine,
param.name,
null);
}
......
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2021 DBeaver Corp and others
*
* 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.ui.app.standalone.cli;
import org.apache.commons.cli.CommandLine;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.model.impl.preferences.SimplePreferenceStore;
import org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect;
import org.jkiss.dbeaver.model.preferences.DBPPreferenceStore;
import org.jkiss.dbeaver.model.sql.SQLDialect;
import org.jkiss.dbeaver.model.sql.SQLModelPreferences;
import org.jkiss.dbeaver.model.sql.translate.SQLQueryTranslator;
import org.jkiss.dbeaver.ui.app.standalone.CommandLineParameterHandler;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.IOUtils;
import java.io.FileReader;
import java.io.IOException;
public class SQLTranslatorHandler implements CommandLineParameterHandler {
private static final Log log = Log.getLog(SQLTranslatorHandler.class);
@Override
public void handleParameter(CommandLine commandLine, String name, String value) {
String[] args = value.split(",");
if (args.length != 2) {
throw new IllegalStateException("Input parameter format: dialect,<input-file-path>");
}
String dialect = args[0];
String inputFile = args[1];
if (CommonUtils.isEmpty(inputFile)) {
throw new IllegalStateException("Input file not specified");
}
DBPPreferenceStore preferenceStore = new SimplePreferenceStore() {
@Override
public void save() throws IOException {
}
};
preferenceStore.setValue(SQLModelPreferences.SQL_FORMAT_FORMATTER, "default");
String script;
try (FileReader fr = new FileReader(inputFile)) {
script = IOUtils.readToString(fr);
} catch (IOException e) {
throw new RuntimeException("Error opening input file " + inputFile, e);
}
SQLDialect srcDialect = new BasicSQLDialect() {
};
SQLDialect targetDialect = new BasicSQLDialect() {
};
String result = null;
try {
result = SQLQueryTranslator.translateScript(srcDialect, targetDialect, preferenceStore, script);
} catch (Exception e) {
throw new RuntimeException("Error translating file " + inputFile, e);
}
System.out.println(result);
}
}
\ No newline at end of file
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册