提交 0ff5a53b 编写于 作者: S Serge Rider 提交者: GitHub

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

#5467 Fix for parsing inner blocks

Former-commit-id: fa213e7f
...@@ -63,6 +63,11 @@ class OracleSQLDialect extends JDBCSQLDialect { ...@@ -63,6 +63,11 @@ class OracleSQLDialect extends JDBCSQLDialect {
"DECLARE", "DECLARE",
}; };
public static final String[] ORACLE_INNER_BLOCK_PREFIXES = new String[]{
"AS",
"IS",
};
public static final String[] OTHER_TYPES_FUNCTIONS = { public static final String[] OTHER_TYPES_FUNCTIONS = {
//functions without parentheses #8710 //functions without parentheses #8710
"CURRENT_DATE", "CURRENT_DATE",
...@@ -350,6 +355,12 @@ class OracleSQLDialect extends JDBCSQLDialect { ...@@ -350,6 +355,12 @@ class OracleSQLDialect extends JDBCSQLDialect {
return ORACLE_BLOCK_HEADERS; return ORACLE_BLOCK_HEADERS;
} }
@Nullable
@Override
public String[] getInnerBlockPrefixes() {
return ORACLE_INNER_BLOCK_PREFIXES;
}
@NotNull @NotNull
@Override @Override
public String[] getExecuteKeywords() { public String[] getExecuteKeywords() {
......
...@@ -779,12 +779,6 @@ public class PostgreDialect extends JDBCSQLDialect implements TPRuleProvider { ...@@ -779,12 +779,6 @@ public class PostgreDialect extends JDBCSQLDialect implements TPRuleProvider {
return BLOCK_BOUND_KEYWORDS; return BLOCK_BOUND_KEYWORDS;
} }
@Nullable
@Override
public String[] getBlockHeaderStrings() {
return new String[] { "DECLARE" };
}
@NotNull @NotNull
@Override @Override
public String getTypeCastClause(DBSAttributeBase attribute, String expression) { public String getTypeCastClause(DBSAttributeBase attribute, String expression) {
......
...@@ -129,10 +129,7 @@ public class SQLScriptParser ...@@ -129,10 +129,7 @@ public class SQLScriptParser
} }
if (tokenType == SQLTokenType.T_BLOCK_HEADER) { if (tokenType == SQLTokenType.T_BLOCK_HEADER) {
if (curBlock == null) { curBlock = new ScriptBlockInfo(curBlock, true);
// Check for double block header, e.g. DO, DECLARE
curBlock = new ScriptBlockInfo(curBlock, true);
}
hasBlocks = true; hasBlocks = true;
} else if (tokenType == SQLTokenType.T_BLOCK_TOGGLE) { } else if (tokenType == SQLTokenType.T_BLOCK_TOGGLE) {
String togglePattern; String togglePattern;
...@@ -142,39 +139,28 @@ public class SQLScriptParser ...@@ -142,39 +139,28 @@ public class SQLScriptParser
log.warn(e); log.warn(e);
togglePattern = ""; 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 && togglePattern.equals(curBlock.togglePattern)) {
if (curBlock != null && curBlock.parent == null && togglePattern.equals(curBlock.togglePattern)) {
curBlock = curBlock.parent; curBlock = curBlock.parent;
} else if (curBlock == null) {
curBlock = new ScriptBlockInfo(curBlock, togglePattern);
} else { } 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) { } else if (tokenType == SQLTokenType.T_BLOCK_BEGIN) {
if (curBlock == null || !curBlock.isHeader) { // Drop header block if it is followed by a regular block and
curBlock = new ScriptBlockInfo(curBlock, false); // that block is not preceded by the prefix e.g 'AS', because in many dialects
} else { // there's no direct header block terminators
curBlock.isHeader = false; // 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; hasBlocks = true;
} else if (tokenType == SQLTokenType.T_BLOCK_END) { } 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 (curBlock != null) {
if (!CommonUtils.isEmpty(curBlock.togglePattern)) { curBlock = curBlock.parent;
// 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;
}
} }
} else if (isDelimiter && curBlock != null) { } else if (isDelimiter && curBlock != null) {
// Delimiter in some brackets or inside block. Ignore it. // Delimiter in some brackets or inside block. Ignore it.
...@@ -285,6 +271,9 @@ public class SQLScriptParser ...@@ -285,6 +271,9 @@ public class SQLScriptParser
if (tokenType == SQLTokenType.T_DELIMITER) { if (tokenType == SQLTokenType.T_DELIMITER) {
queryEndPos += tokenLength; queryEndPos += tokenLength;
} }
if (curBlock != null) {
log.warn("Found leftover blocks in script after parsing");
}
// make script line // make script line
return new SQLQuery( return new SQLQuery(
context.getDataSource(), context.getDataSource(),
......
...@@ -292,6 +292,12 @@ public abstract class AbstractSQLDialect implements SQLDialect { ...@@ -292,6 +292,12 @@ public abstract class AbstractSQLDialect implements SQLDialect {
return null; return null;
} }
@Nullable
@Override
public String[] getInnerBlockPrefixes() {
return null;
}
@Override @Override
public boolean validIdentifierStart(char c) { public boolean validIdentifierStart(char c) {
return Character.isLetter(c); return Character.isLetter(c);
......
...@@ -206,6 +206,14 @@ public interface SQLDialect { ...@@ -206,6 +206,14 @@ public interface SQLDialect {
@Nullable @Nullable
String[] getBlockHeaderStrings(); 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 * Retrieves whether a catalog appears at the start of a fully qualified
* table name. If not, the catalog appears at the end. * 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.
先完成此消息的编辑!
想要评论请 注册