Search in sources :

Example 1 with SQLToken

use of org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLToken in project dbeaver by dbeaver.

the class SQLEditorBase method parseParameters.

protected List<SQLQueryParameter> parseParameters(IDocument document, int queryOffset, int queryLength) {
    final SQLDialect sqlDialect = getSQLDialect();
    boolean supportParamsInDDL = getActivePreferenceStore().getBoolean(ModelPreferences.SQL_PARAMETERS_IN_DDL_ENABLED);
    boolean execQuery = false;
    List<SQLQueryParameter> parameters = null;
    ruleManager.setRange(document, queryOffset, queryLength);
    boolean firstKeyword = true;
    for (; ; ) {
        IToken token = ruleManager.nextToken();
        final int tokenOffset = ruleManager.getTokenOffset();
        final int tokenLength = ruleManager.getTokenLength();
        if (token.isEOF() || tokenOffset > queryOffset + queryLength) {
            break;
        }
        // Handle only parameters which are not in SQL blocks
        int tokenType = SQLToken.T_UNKNOWN;
        if (token instanceof SQLToken) {
            tokenType = ((SQLToken) token).getType();
        }
        if (token.isWhitespace() || tokenType == SQLToken.T_COMMENT) {
            continue;
        }
        if (!supportParamsInDDL) {
            if (firstKeyword) {
                // Detect query type
                try {
                    String tokenText = document.get(tokenOffset, tokenLength);
                    if (ArrayUtils.containsIgnoreCase(sqlDialect.getDDLKeywords(), tokenText)) {
                        // DDL doesn't support parameters
                        return null;
                    }
                    execQuery = ArrayUtils.containsIgnoreCase(sqlDialect.getExecuteKeywords(), tokenText);
                } catch (BadLocationException e) {
                    log.warn(e);
                }
                firstKeyword = false;
            }
        }
        if (tokenType == SQLToken.T_PARAMETER && tokenLength > 0) {
            try {
                String paramName = document.get(tokenOffset, tokenLength);
                if (execQuery && paramName.equals("?")) {
                    // Skip ? parameters for stored procedures (they have special meaning? [DB2])
                    continue;
                }
                if (parameters == null) {
                    parameters = new ArrayList<>();
                }
                SQLQueryParameter parameter = new SQLQueryParameter(parameters.size(), paramName, tokenOffset - queryOffset, tokenLength);
                SQLQueryParameter previous = null;
                if (parameter.isNamed()) {
                    for (int i = parameters.size(); i > 0; i--) {
                        if (parameters.get(i - 1).getName().equals(paramName)) {
                            previous = parameters.get(i - 1);
                            break;
                        }
                    }
                }
                parameter.setPrevious(previous);
                parameters.add(parameter);
            } catch (BadLocationException e) {
                log.warn("Can't extract query parameter", e);
            }
        }
    }
    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;
}
Also used : IToken(org.eclipse.jface.text.rules.IToken) SQLToken(org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLToken) Matcher(java.util.regex.Matcher) BasicSQLDialect(org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect) ArrayList(java.util.ArrayList)

Example 2 with SQLToken

use of org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLToken in project dbeaver by dbeaver.

the class SQLEditorBase method parseQuery.

protected SQLScriptElement parseQuery(final IDocument document, final int startPos, final int endPos, final int currentPos, final boolean scriptMode, final boolean keepDelimiters) {
    if (endPos - startPos <= 0) {
        return null;
    }
    SQLDialect dialect = getSQLDialect();
    // Parse range
    boolean useBlankLines = !scriptMode && syntaxManager.isBlankLineDelimiter();
    ruleManager.setRange(document, startPos, endPos - startPos);
    int statementStart = startPos;
    int bracketDepth = 0;
    boolean hasBlocks = false;
    boolean hasValuableTokens = false;
    boolean hasBlockHeader = false;
    String blockTogglePattern = null;
    int lastTokenLineFeeds = 0;
    int prevNotEmptyTokenType = SQLToken.T_UNKNOWN;
    for (; ; ) {
        IToken token = ruleManager.nextToken();
        int tokenOffset = ruleManager.getTokenOffset();
        int tokenLength = ruleManager.getTokenLength();
        int tokenType = token instanceof SQLToken ? ((SQLToken) token).getType() : SQLToken.T_UNKNOWN;
        if (tokenOffset < startPos) {
            // This may happen with EOF tokens (bug in jface?)
            return null;
        }
        boolean isDelimiter = tokenType == SQLToken.T_DELIMITER;
        boolean isControl = false;
        String delimiterText = null;
        try {
            if (isDelimiter) {
                // Save delimiter text
                try {
                    delimiterText = document.get(tokenOffset, tokenLength);
                } catch (BadLocationException e) {
                    log.debug(e);
                }
            } else if (useBlankLines && token.isWhitespace() && tokenLength >= 1) {
                // Check for blank line delimiter
                if (lastTokenLineFeeds + countLineFeeds(document, tokenOffset, tokenLength) >= 2) {
                    isDelimiter = true;
                }
            }
            lastTokenLineFeeds = 0;
            if (tokenLength == 1) {
                // Check for bracket block begin/end
                try {
                    char aChar = document.getChar(tokenOffset);
                    if (aChar == '(' || aChar == '{' || aChar == '[') {
                        bracketDepth++;
                    } else if (aChar == ')' || aChar == '}' || aChar == ']') {
                        bracketDepth--;
                    }
                } catch (BadLocationException e) {
                    log.warn(e);
                }
            }
            if (tokenType == SQLToken.T_BLOCK_BEGIN && prevNotEmptyTokenType == SQLToken.T_BLOCK_END) {
                // This is a tricky thing.
                // In some dialects block end looks like END CASE, END LOOP. It is parsed as
                // Block end followed by block begin (as CASE and LOOP are block begin tokens)
                // So let's ignore block begin if previos token was block end and there were no delimtiers.
                tokenType = SQLToken.T_UNKNOWN;
            }
            if (tokenType == SQLToken.T_BLOCK_HEADER) {
                bracketDepth++;
                hasBlocks = true;
                hasBlockHeader = true;
            } else if (tokenType == SQLToken.T_BLOCK_TOGGLE) {
                String togglePattern;
                try {
                    togglePattern = document.get(tokenOffset, tokenLength);
                } catch (BadLocationException e) {
                    log.warn(e);
                    togglePattern = "";
                }
                // Toggles can be nested (PostgreSQL) and we need to count only outer
                if (bracketDepth == 1 && togglePattern.equals(blockTogglePattern)) {
                    bracketDepth--;
                    blockTogglePattern = null;
                } else if (bracketDepth == 0 && blockTogglePattern == null) {
                    bracketDepth++;
                    blockTogglePattern = togglePattern;
                } else {
                    log.debug("Block toggle token inside another block. Can't process it");
                }
                hasBlocks = true;
            } else if (tokenType == SQLToken.T_BLOCK_BEGIN) {
                if (!hasBlockHeader) {
                    bracketDepth++;
                }
                hasBlocks = true;
                hasBlockHeader = false;
            } else if (bracketDepth > 0 && tokenType == SQLToken.T_BLOCK_END) {
                // This END doesn't mean block
                if (hasBlocks) {
                    bracketDepth--;
                }
                hasBlockHeader = false;
            } else if (isDelimiter && bracketDepth > 0) {
                // Delimiter in some brackets - ignore it
                continue;
            } else if (tokenType == SQLToken.T_SET_DELIMITER || tokenType == SQLToken.T_CONTROL) {
                isDelimiter = true;
                isControl = true;
            } else if (tokenType == SQLToken.T_COMMENT) {
                lastTokenLineFeeds = tokenLength < 2 ? 0 : countLineFeeds(document, tokenOffset + tokenLength - 2, 2);
            }
            boolean cursorInsideToken = currentPos >= tokenOffset && currentPos < tokenOffset + tokenLength;
            if (isControl && (scriptMode || cursorInsideToken) && !hasValuableTokens) {
                // Control query
                try {
                    String controlText = document.get(tokenOffset, tokenLength);
                    String commandId = null;
                    if (token instanceof SQLControlToken) {
                        commandId = ((SQLControlToken) token).getCommandId();
                    }
                    return new SQLControlCommand(getDataSource(), syntaxManager, controlText.trim(), commandId, tokenOffset, tokenLength, tokenType == SQLToken.T_SET_DELIMITER);
                } catch (BadLocationException e) {
                    // $NON-NLS-1$
                    log.warn("Can't extract control statement", e);
                    return null;
                }
            }
            if (hasValuableTokens && (token.isEOF() || (isDelimiter && tokenOffset >= currentPos) || tokenOffset > endPos)) {
                if (tokenOffset > endPos) {
                    tokenOffset = endPos;
                }
                if (tokenOffset >= document.getLength()) {
                    // Sometimes (e.g. when comment finishing script text)
                    // last token offset is beyond document range
                    tokenOffset = document.getLength();
                }
                assert (tokenOffset >= currentPos);
                try {
                    // remove leading spaces
                    while (statementStart < tokenOffset && Character.isWhitespace(document.getChar(statementStart))) {
                        statementStart++;
                    }
                    /*
                        while (statementStart < tokenOffset && Character.isWhitespace(document.getChar(tokenOffset - 1))) {
                            tokenOffset--;
                            tokenLength++;
                        }
*/
                    if (tokenOffset == statementStart) {
                        // Empty statement
                        if (token.isEOF()) {
                            return null;
                        }
                        statementStart = tokenOffset + tokenLength;
                        continue;
                    }
                    String queryText = document.get(statementStart, tokenOffset - statementStart);
                    queryText = SQLUtils.fixLineFeeds(queryText);
                    if (isDelimiter && (keepDelimiters || (hasBlocks ? dialect.isDelimiterAfterBlock() : dialect.isDelimiterAfterQuery()))) {
                        if (delimiterText != null && delimiterText.equals(SQLConstants.DEFAULT_STATEMENT_DELIMITER)) {
                            // Add delimiter in the end of query. Do this only for semicolon delimiters
                            // Quite dirty workaround needed for SQL server
                            queryText += delimiterText;
                        }
                    }
                    int queryEndPos = tokenOffset;
                    if (tokenType == SQLToken.T_DELIMITER) {
                        queryEndPos += tokenLength;
                    }
                    // make script line
                    return new SQLQuery(getDataSource(), queryText, statementStart, queryEndPos - statementStart);
                } catch (BadLocationException ex) {
                    // $NON-NLS-1$
                    log.warn("Can't extract query", ex);
                    return null;
                }
            }
            if (isDelimiter) {
                statementStart = tokenOffset + tokenLength;
            }
            if (token.isEOF()) {
                return null;
            }
            if (!hasValuableTokens && !token.isWhitespace() && !isControl) {
                if (tokenType == SQLToken.T_COMMENT) {
                    hasValuableTokens = dialect.supportsCommentQuery();
                } else {
                    hasValuableTokens = true;
                }
            }
        } finally {
            if (!token.isWhitespace() && !token.isEOF()) {
                prevNotEmptyTokenType = tokenType;
            }
        }
    }
}
Also used : IToken(org.eclipse.jface.text.rules.IToken) SQLToken(org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLToken) BasicSQLDialect(org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect) SQLControlToken(org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLControlToken)

Aggregations

IToken (org.eclipse.jface.text.rules.IToken)2 BasicSQLDialect (org.jkiss.dbeaver.model.impl.sql.BasicSQLDialect)2 SQLToken (org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLToken)2 ArrayList (java.util.ArrayList)1 Matcher (java.util.regex.Matcher)1 SQLControlToken (org.jkiss.dbeaver.ui.editors.sql.syntax.tokens.SQLControlToken)1