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

#2490 SQL script variables


Former-commit-id: 0cf95675
上级 cd24d43a
......@@ -1026,6 +1026,9 @@ public class CoreMessages extends NLS {
// SQLExecute
public static String pref_page_sql_editor_label_sql_timeout_tip;
public static String pref_page_sql_editor_enable_parameters_in_ddl;
public static String pref_page_sql_editor_enable_parameters_in_ddl_tip;
public static String pref_page_sql_editor_enable_variables;
public static String pref_page_sql_editor_enable_variables_tip;
// SQLFormat
public static String pref_page_sql_format_group_auto_close;
public static String pref_page_sql_format_label_single_quotes;
......
......@@ -991,6 +991,10 @@ pref_page_sql_editor_link_text_editor = Text Editor Settings
#SQLExecute
pref_page_sql_editor_label_sql_timeout_tip = Query execute timeout (in seconds). 0 means no timeout
pref_page_sql_editor_enable_parameters_in_ddl = Enable parameters in DDL
pref_page_sql_editor_enable_parameters_in_ddl_tip = Usually DDL (like CREATE PROCEDURE) don't use input query parameters but may contain complex logic/scripting.\nThis may conflict with parameters prefix.\nSo it makes sense to disable parameters parsing for DDL queries.
pref_page_sql_editor_enable_variables = Enable variables
pref_page_sql_editor_enable_variables_tip = Enable variables in SQL scripts.\nVariable is a special mark ${VAR_NAME} which will be replaced with user input before query execution
#SQLFormat
pref_page_sql_format_group_auto_close = Auto close
pref_page_sql_format_label_single_quotes = Single quotes
......
......@@ -1497,6 +1497,7 @@ public class SQLEditor extends SQLEditorBase implements
case ModelPreferences.SQL_PARAMETERS_ENABLED:
case ModelPreferences.SQL_ANONYMOUS_PARAMETERS_MARK:
case ModelPreferences.SQL_ANONYMOUS_PARAMETERS_ENABLED:
case ModelPreferences.SQL_VARIABLES_ENABLED:
case ModelPreferences.SQL_NAMED_PARAMETERS_PREFIX:
reloadSyntaxRules();
break;
......
......@@ -59,6 +59,7 @@ import org.jkiss.dbeaver.ui.IErrorVisualizer;
import org.jkiss.dbeaver.ui.TextUtils;
import org.jkiss.dbeaver.ui.editors.sql.syntax.SQLPartitionScanner;
import org.jkiss.dbeaver.ui.editors.sql.syntax.SQLRuleManager;
import org.jkiss.dbeaver.ui.editors.sql.syntax.rules.SQLVariableRule;
import org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLControlToken;
import org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLToken;
import org.jkiss.dbeaver.ui.editors.sql.templates.SQLTemplatesPage;
......@@ -72,6 +73,8 @@ import org.jkiss.utils.Pair;
import java.util.ArrayList;
import java.util.List;
import java.util.ResourceBundle;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* SQL Executor
......@@ -1009,6 +1012,47 @@ public abstract class SQLEditorBase extends BaseTextEditor implements IErrorVisu
}
}
}
if (syntaxManager.isVariablesEnabled()) {
try {
// Find variables in strings, comments, etc
// Use regex
String query = document.get(queryOffset, queryLength);
Matcher matcher = SQLVariableRule.VARIABLE_PATTERN.matcher(query);
int position = 0;
while (matcher.find(position)) {
{
int start = matcher.start();
int orderPos = 0;
SQLQueryParameter param = null;
if (parameters != null) {
for (SQLQueryParameter p : parameters) {
if (p.getTokenOffset() == start) {
param = p;
break;
} else if (p.getTokenOffset() < start) {
orderPos++;
}
}
}
if (param == null) {
param = new SQLQueryParameter(orderPos, matcher.group(0), start, matcher.end() - matcher.start());
if (parameters == null) {
parameters = new ArrayList<>();
}
parameters.add(param.getOrdinalPosition(), param);
}
}
position = matcher.end();
}
} catch (BadLocationException e) {
log.warn("Error parsing variables", e);
}
}
return parameters;
}
......
......@@ -36,10 +36,7 @@ import org.jkiss.dbeaver.model.sql.SQLSyntaxManager;
import org.jkiss.dbeaver.registry.sql.SQLCommandHandlerDescriptor;
import org.jkiss.dbeaver.registry.sql.SQLCommandsRegistry;
import org.jkiss.dbeaver.ui.editors.EditorUtils;
import org.jkiss.dbeaver.ui.editors.sql.syntax.rules.LineCommentRule;
import org.jkiss.dbeaver.ui.editors.sql.syntax.rules.SQLDelimiterRule;
import org.jkiss.dbeaver.ui.editors.sql.syntax.rules.SQLDelimiterSetRule;
import org.jkiss.dbeaver.ui.editors.sql.syntax.rules.SQLParameterRule;
import org.jkiss.dbeaver.ui.editors.sql.syntax.rules.*;
import org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.*;
import org.jkiss.dbeaver.ui.editors.text.TextWhiteSpaceDetector;
import org.jkiss.utils.ArrayUtils;
......@@ -158,6 +155,8 @@ public class SQLRuleManager extends RuleBasedScanner {
new TextAttribute(getColor(SQLConstants.CONFIG_COLOR_DELIMITER, SWT.COLOR_RED), null, SWT.NORMAL));
final SQLParameterToken parameterToken = new SQLParameterToken(
new TextAttribute(getColor(SQLConstants.CONFIG_COLOR_PARAMETER, SWT.COLOR_DARK_BLUE), null, SWT.BOLD));
final SQLVariableToken variableToken = new SQLVariableToken(
new TextAttribute(getColor(SQLConstants.CONFIG_COLOR_PARAMETER, SWT.COLOR_DARK_BLUE), null, SWT.BOLD));
final IToken otherToken = new Token(
new TextAttribute(getColor(SQLConstants.CONFIG_COLOR_TEXT), null, SWT.NORMAL));
final SQLBlockHeaderToken blockHeaderToken = new SQLBlockHeaderToken(
......@@ -200,6 +199,12 @@ public class SQLRuleManager extends RuleBasedScanner {
rules.add(new EndOfLineRule(commandPrefix + controlCommand.getId(), controlToken)); //$NON-NLS-1$
}
}
{
if (!minimalRules && syntaxManager.isVariablesEnabled()) {
// Variable rule
rules.add(new SQLVariableRule(parameterToken));
}
}
{
// Add rules for delimited identifiers and string literals.
......@@ -214,7 +219,6 @@ public class SQLRuleManager extends RuleBasedScanner {
} else if (quoteStrings[i][1].equals(SQLConstants.STR_QUOTE_DOUBLE) && quoteStrings[i][0].equals(quoteStrings[i][1])) {
hasDoubleQuoteRule = true;
}
}
}
if (!hasSingleQuoteRule) {
......
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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.editors.sql.syntax.rules;
import org.eclipse.jface.text.rules.ICharacterScanner;
import org.eclipse.jface.text.rules.IRule;
import org.eclipse.jface.text.rules.IToken;
import org.eclipse.jface.text.rules.Token;
import java.util.regex.Pattern;
/**
* SQL variable rule.
* ${varName}
*/
public class SQLVariableRule implements IRule {
public static final Pattern VARIABLE_PATTERN = Pattern.compile("\\$\\{[^\\s]+\\}");
private final IToken parameterToken;
public SQLVariableRule(IToken parameterToken) {
this.parameterToken = parameterToken;
}
@Override
public IToken evaluate(ICharacterScanner scanner)
{
int c = scanner.read();
if (c == '$') {
c = scanner.read();
if (c == '{') {
int varLength = 0;
for (;;) {
c = scanner.read();
if (c == '}' || Character.isWhitespace(c) || c == ICharacterScanner.EOF) {
break;
}
varLength++;
}
if (varLength > 0 && c == '}') {
return parameterToken;
}
scanner.unread();
for (int i = varLength - 1; i >= 0; i--) {
scanner.unread();
}
}
scanner.unread();
}
scanner.unread();
return Token.UNDEFINED;
}
}
......@@ -36,6 +36,7 @@ public class SQLToken extends Token {
public static final int T_DELIMITER = 1007;
public static final int T_SET_DELIMITER = 1008;
public static final int T_PARAMETER = 1009;
public static final int T_VARIABLE = 1010;
private final int type;
......
/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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.editors.sql.syntax.tokens;
/**
* SQLVariableToken
*/
public class SQLVariableToken extends SQLToken {
public SQLVariableToken(Object data)
{
super(T_VARIABLE, data);
}
}
......@@ -61,6 +61,7 @@ public class PrefPageSQLExecute extends TargetPrefPage
private Text anonymousParameterMarkText;
private Text namedParameterPrefixText;
private Button enableParametersInDDL;
private Button enableVariables;
public PrefPageSQLExecute()
{
......@@ -90,6 +91,8 @@ public class PrefPageSQLExecute extends TargetPrefPage
store.contains(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_ENABLED) ||
store.contains(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_MARK) ||
store.contains(ModelPreferences.SQL_NAMED_PARAMETERS_PREFIX) ||
store.contains(ModelPreferences.SQL_VARIABLES_ENABLED) ||
store.contains(SQLPreferenceConstants.RESET_CURSOR_ON_EXECUTE) ||
store.contains(SQLPreferenceConstants.MAXIMIZE_EDITOR_ON_SCRIPT_EXECUTE) ||
store.contains(SQLPreferenceConstants.BEEP_ON_QUERY_END) ||
......@@ -173,7 +176,8 @@ public class PrefPageSQLExecute extends TargetPrefPage
anonymousParameterMarkText.setTextLimit(1);
namedParameterPrefixText = UIUtils.createLabelText(paramsGroup, CoreMessages.pref_page_sql_editor_text_named_parameter_prefix, "", SWT.BORDER, new GridData(32, SWT.DEFAULT));
namedParameterPrefixText.setTextLimit(1);
enableParametersInDDL = UIUtils.createCheckbox(paramsGroup, CoreMessages.pref_page_sql_editor_enable_parameters_in_ddl, null, false, 2);
enableParametersInDDL = UIUtils.createCheckbox(paramsGroup, CoreMessages.pref_page_sql_editor_enable_parameters_in_ddl, CoreMessages.pref_page_sql_editor_enable_parameters_in_ddl_tip, false, 2);
enableVariables = UIUtils.createCheckbox(paramsGroup, CoreMessages.pref_page_sql_editor_enable_variables, CoreMessages.pref_page_sql_editor_enable_variables_tip, false, 2);
}
// Delimiters
......@@ -215,6 +219,7 @@ public class PrefPageSQLExecute extends TargetPrefPage
anonymousParameterMarkText.setText(store.getString(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_MARK));
namedParameterPrefixText.setText(store.getString(ModelPreferences.SQL_NAMED_PARAMETERS_PREFIX));
enableParametersInDDL.setSelection(store.getBoolean(ModelPreferences.SQL_PARAMETERS_IN_DDL_ENABLED));
enableVariables.setSelection(store.getBoolean(ModelPreferences.SQL_VARIABLES_ENABLED));
} catch (Exception e) {
log.warn(e);
}
......@@ -246,6 +251,7 @@ public class PrefPageSQLExecute extends TargetPrefPage
store.setValue(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_MARK, anonymousParameterMarkText.getText());
store.setValue(ModelPreferences.SQL_NAMED_PARAMETERS_PREFIX, namedParameterPrefixText.getText());
store.setValue(ModelPreferences.SQL_PARAMETERS_IN_DDL_ENABLED, enableParametersInDDL.getSelection());
store.setValue(ModelPreferences.SQL_VARIABLES_ENABLED, enableVariables.getSelection());
} catch (Exception e) {
log.warn(e);
}
......@@ -275,6 +281,7 @@ public class PrefPageSQLExecute extends TargetPrefPage
store.setToDefault(ModelPreferences.SQL_PARAMETERS_IN_DDL_ENABLED);
store.setToDefault(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_ENABLED);
store.setToDefault(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_MARK);
store.setToDefault(ModelPreferences.SQL_VARIABLES_ENABLED);
store.setToDefault(ModelPreferences.SQL_NAMED_PARAMETERS_PREFIX);
store.setToDefault(SQLPreferenceConstants.BEEP_ON_QUERY_END);
......
......@@ -80,6 +80,7 @@ public final class ModelPreferences
public static final String SQL_ANONYMOUS_PARAMETERS_MARK = "sql.parameter.mark"; //$NON-NLS-1$
public static final String SQL_NAMED_PARAMETERS_PREFIX = "sql.parameter.prefix"; //$NON-NLS-1$
public static final String SQL_CONTROL_COMMAND_PREFIX = "sql.command.prefix"; //$NON-NLS-1$
public static final String SQL_VARIABLES_ENABLED = "sql.variables.enabled"; //$NON-NLS-1$
public final static String SQL_FORMAT_FORMATTER = "sql.format.formatter";
public final static String SQL_FORMAT_KEYWORD_CASE = "sql.format.keywordCase";
......@@ -161,6 +162,7 @@ public final class ModelPreferences
PrefUtils.setDefaultPreferenceValue(store, SQL_ANONYMOUS_PARAMETERS_MARK, String.valueOf(SQLConstants.DEFAULT_PARAMETER_MARK));
PrefUtils.setDefaultPreferenceValue(store, SQL_NAMED_PARAMETERS_PREFIX, String.valueOf(SQLConstants.DEFAULT_PARAMETER_PREFIX));
PrefUtils.setDefaultPreferenceValue(store, SQL_CONTROL_COMMAND_PREFIX, String.valueOf(SQLConstants.DEFAULT_CONTROL_COMMAND_PREFIX));
PrefUtils.setDefaultPreferenceValue(store, SQL_VARIABLES_ENABLED, false);
PrefUtils.setDefaultPreferenceValue(store, SQL_FORMAT_FORMATTER, SQLFormatterTokenized.FORMATTER_ID);
PrefUtils.setDefaultPreferenceValue(store, SQL_FORMAT_KEYWORD_CASE, "");
......
......@@ -16,6 +16,8 @@
*/
package org.jkiss.dbeaver.model.sql;
import org.jkiss.dbeaver.utils.GeneralUtils;
/**
* SQL statement parameter info
*/
......@@ -82,7 +84,9 @@ public class SQLQueryParameter {
}
public String getTitle() {
if (name.startsWith(":")) {
if (GeneralUtils.isVariablePattern(name)) {
return GeneralUtils.stripVariablePattern(name);
} else if (name.startsWith(":")) {
return name.substring(1);
} else {
return name;
......
......@@ -48,6 +48,7 @@ public class SQLSyntaxManager {
private char anonymousParameterMark;
private char namedParameterPrefix;
private String controlCommandPrefix;
private boolean variablesEnabled;
@NotNull
private String catalogSeparator = String.valueOf(SQLConstants.STRUCT_SEPARATOR);
@NotNull
......@@ -121,6 +122,10 @@ public class SQLSyntaxManager {
return controlCommandPrefix;
}
public boolean isVariablesEnabled() {
return variablesEnabled;
}
public void init(@NotNull DBPDataSource dataSource) {
init(SQLUtils.getDialectFromObject(dataSource), dataSource.getContainer().getPreferenceStore());
}
......@@ -150,6 +155,7 @@ public class SQLSyntaxManager {
this.parametersEnabled = preferenceStore.getBoolean(ModelPreferences.SQL_PARAMETERS_ENABLED);
this.anonymousParametersEnabled = preferenceStore.getBoolean(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_ENABLED);
this.variablesEnabled = preferenceStore.getBoolean(ModelPreferences.SQL_VARIABLES_ENABLED);
String markString = preferenceStore.getString(ModelPreferences.SQL_ANONYMOUS_PARAMETERS_MARK);
if (CommonUtils.isEmpty(markString)) {
this.anonymousParameterMark = SQLConstants.DEFAULT_PARAMETER_MARK;
......
......@@ -397,6 +397,19 @@ public class GeneralUtils {
return "${" + name + "}";
}
@NotNull
public static boolean isVariablePattern(String pattern) {
return pattern.startsWith("${") && pattern.endsWith("}");
}
@NotNull
public static String stripVariablePattern(String pattern) {
if (isVariablePattern(pattern)) {
return pattern.substring(2, pattern.length() - 1);
}
return pattern;
}
@NotNull
public static String generateVariablesLegend(@NotNull String[][] vars) {
StringBuilder text = new StringBuilder();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册