未验证 提交 fa213e7f 编写于 作者: S Serge Rider 提交者: GitHub

Merge pull request #10223 from dbeaver/sql-parser-blocks#5467

#5467 Fix for parsing inner blocks
......@@ -63,6 +63,11 @@ class OracleSQLDialect extends JDBCSQLDialect {
"DECLARE",
};
public static final String[] ORACLE_INNER_BLOCK_PREFIXES = new String[]{
"AS",
"IS",
};
public static final String[] OTHER_TYPES_FUNCTIONS = {
//functions without parentheses #8710
"CURRENT_DATE",
......@@ -350,6 +355,12 @@ class OracleSQLDialect extends JDBCSQLDialect {
return ORACLE_BLOCK_HEADERS;
}
@Nullable
@Override
public String[] getInnerBlockPrefixes() {
return ORACLE_INNER_BLOCK_PREFIXES;
}
@NotNull
@Override
public String[] getExecuteKeywords() {
......
......@@ -779,12 +779,6 @@ public class PostgreDialect extends JDBCSQLDialect implements TPRuleProvider {
return BLOCK_BOUND_KEYWORDS;
}
@Nullable
@Override
public String[] getBlockHeaderStrings() {
return new String[] { "DECLARE" };
}
@NotNull
@Override
public String getTypeCastClause(DBSAttributeBase attribute, String expression) {
......
......@@ -129,10 +129,7 @@ public class SQLScriptParser
}
if (tokenType == SQLTokenType.T_BLOCK_HEADER) {
if (curBlock == null) {
// Check for double block header, e.g. DO, DECLARE
curBlock = new ScriptBlockInfo(curBlock, true);
}
curBlock = new ScriptBlockInfo(curBlock, true);
hasBlocks = true;
} else if (tokenType == SQLTokenType.T_BLOCK_TOGGLE) {
String togglePattern;
......@@ -142,39 +139,28 @@ public class SQLScriptParser
log.warn(e);
togglePattern = "";
}
// Second toggle pattern must be the same as first one.
// Toggles can be nested (PostgreSQL) and we need to count only outer
if (curBlock != null && curBlock.parent == null && togglePattern.equals(curBlock.togglePattern)) {
if (curBlock != null && togglePattern.equals(curBlock.togglePattern)) {
curBlock = curBlock.parent;
} else if (curBlock == null) {
curBlock = new ScriptBlockInfo(curBlock, togglePattern);
} else {
log.debug("Block toggle token inside another block. Can't process it");
curBlock = new ScriptBlockInfo(curBlock, togglePattern);
hasBlocks = true;
}
hasBlocks = true;
} else if (tokenType == SQLTokenType.T_BLOCK_BEGIN) {
if (curBlock == null || !curBlock.isHeader) {
curBlock = new ScriptBlockInfo(curBlock, false);
} else {
curBlock.isHeader = false;
// Drop header block if it is followed by a regular block and
// that block is not preceded by the prefix e.g 'AS', because in many dialects
// there's no direct header block terminators
// like 'BEGIN ... END' but 'DECLARE ... BEGIN ... END'
if (curBlock != null && curBlock.isHeader) {
if (prevNotEmptyTokenType != SQLTokenType.T_KEYWORD || !ArrayUtils.contains(dialect.getInnerBlockPrefixes(), lastKeyword)) {
curBlock = curBlock.parent;
}
}
curBlock = new ScriptBlockInfo(curBlock, false);
hasBlocks = true;
} else if (tokenType == SQLTokenType.T_BLOCK_END) {
// Sometimes query contains END clause without BEGIN. E.g. CASE, IF, etc.
// This END doesn't mean block
if (curBlock != null) {
if (!CommonUtils.isEmpty(curBlock.togglePattern)) {
// Block end inside of block toggle (#7460).
// Actually it is a result of some wrong SQL parse (e.g. we didn't recognize block begin correctly).
// However block toggle has higher priority. At the moment it is PostgreSQL specific.
try {
log.debug("Block end '" + document.get(tokenOffset, tokenLength) + "' inside of named block toggle '" + curBlock.togglePattern + "'. Ignore.");
} catch (Throwable e) {
log.debug(e);
}
} else {
curBlock = curBlock.parent;
}
curBlock = curBlock.parent;
}
} else if (isDelimiter && curBlock != null) {
// Delimiter in some brackets or inside block. Ignore it.
......@@ -285,6 +271,9 @@ public class SQLScriptParser
if (tokenType == SQLTokenType.T_DELIMITER) {
queryEndPos += tokenLength;
}
if (curBlock != null) {
log.warn("Found leftover blocks in script after parsing");
}
// make script line
return new SQLQuery(
context.getDataSource(),
......
......@@ -292,6 +292,12 @@ public abstract class AbstractSQLDialect implements SQLDialect {
return null;
}
@Nullable
@Override
public String[] getInnerBlockPrefixes() {
return null;
}
@Override
public boolean validIdentifierStart(char c) {
return Character.isLetter(c);
......
......@@ -206,6 +206,14 @@ public interface SQLDialect {
@Nullable
String[] getBlockHeaderStrings();
/**
* Inner block prefixes strings.
* Determines if the block is a child of the header block.
* @return inner block prefixes or null (if not supported)
*/
@Nullable
String[] getInnerBlockPrefixes();
/**
* Retrieves whether a catalog appears at the start of a fully qualified
* table name. If not, the catalog appears at the end.
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册