Merge pull request #246 from wenshao/master

improve Oracle SQL Parser
This commit is contained in:
温高铁
2012-12-27 21:01:54 -08:00
16 changed files with 380 additions and 21 deletions
@@ -95,7 +95,7 @@ public class SQLUtils {
public static String toOracleString(SQLObject sqlObject) {
StringBuilder out = new StringBuilder();
sqlObject.accept(new OracleOutputVisitor(out));
sqlObject.accept(new OracleOutputVisitor(out, false));
String sql = out.toString();
return sql;
@@ -1431,7 +1431,7 @@ public class MySqlStatementParser extends SQLStatementParser {
}
}
if (identifierEquals("TO")) {
if (lexer.token() == Token.TO) {
lexer.nextToken();
if (identifierEquals("SAVEPOINT")) {
@@ -2329,7 +2329,7 @@ public class MySqlStatementParser extends SQLStatementParser {
for (;;) {
MySqlRenameTableStatement.Item item = new MySqlRenameTableStatement.Item();
item.setName(this.exprParser.name());
acceptIdentifier("TO");
accept(Token.TO);
item.setTo(this.exprParser.name());
stmt.getItems().add(item);
@@ -0,0 +1,114 @@
/*
* Copyright 1999-2011 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.druid.sql.dialect.oracle.ast.stmt;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLName;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleASTVisitor;
public class OracleCreateDatabaseDbLinkStatement extends OracleStatementImpl {
private static final long serialVersionUID = 1L;
private boolean shared;
private boolean _public;
private SQLName name;
private SQLName user;
private String password;
private SQLExpr using;
private SQLExpr authenticatedUser;
private String authenticatedPassword;
public boolean isShared() {
return shared;
}
public void setShared(boolean shared) {
this.shared = shared;
}
public boolean isPublic() {
return _public;
}
public void setPublic(boolean value) {
this._public = value;
}
public SQLName getName() {
return name;
}
public void setName(SQLName name) {
this.name = name;
}
public SQLName getUser() {
return user;
}
public void setUser(SQLName user) {
this.user = user;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public SQLExpr getUsing() {
return using;
}
public void setUsing(SQLExpr using) {
this.using = using;
}
public SQLExpr getAuthenticatedUser() {
return authenticatedUser;
}
public void setAuthenticatedUser(SQLExpr authenticatedUser) {
this.authenticatedUser = authenticatedUser;
}
public String getAuthenticatedPassword() {
return authenticatedPassword;
}
public void setAuthenticatedPassword(String authenticatedPassword) {
this.authenticatedPassword = authenticatedPassword;
}
@Override
public void accept0(OracleASTVisitor visitor) {
if (visitor.visit(this)) {
acceptChild(visitor, name);
acceptChild(visitor, user);
acceptChild(visitor, using);
acceptChild(visitor, authenticatedUser);
}
visitor.endVisit(this);
}
}
@@ -380,7 +380,7 @@ public class OracleExprParser extends SQLExprParser {
accept(Token.RPAREN);
}
acceptIdentifier("TO");
accept(Token.TO);
if (identifierEquals("SECOND")) {
lexer.nextToken();
interval.setToType(OracleIntervalType.SECOND);
@@ -405,7 +405,7 @@ public class OracleExprParser extends SQLExprParser {
char markChar = lexer.current();
int markBp = lexer.bp();
lexer.nextToken();
if (lexer.token() == Token.LOCAL) {
if (identifierEquals("LOCAL")) {
lexer.nextToken();
expr = new OracleDatetimeExpr(expr, new SQLIdentifierExpr("LOCAL"));
} else {
@@ -706,7 +706,7 @@ public class OracleExprParser extends SQLExprParser {
accept(Token.RPAREN);
}
if (identifierEquals("TO")) {
if (lexer.token() == Token.TO) {
lexer.nextToken();
if (identifierEquals("SECOND")) {
lexer.nextToken();
@@ -56,7 +56,6 @@ public class OracleLexer extends Lexer {
map.put("IF", Token.IF);
map.put("LIMIT", Token.LIMIT);
map.put("LOCAL", Token.LOCAL);
map.put("LOOP", Token.LOOP);
map.put("MATCHED", Token.MATCHED);
map.put("MERGE", Token.MERGE);
@@ -81,6 +80,8 @@ public class OracleLexer extends Lexer {
map.put("WAIT", Token.WAIT);
map.put("WITH", Token.WITH);
map.put("IDENTIFIED", Token.IDENTIFIED);
DEFAULT_ORACLE_KEYWORDS = new Keywords(map);
}
@@ -211,7 +211,7 @@ public class OracleSelectParser extends SQLSelectParser {
exprParser.exprList(cycleClause.getAliases());
accept(Token.SET);
cycleClause.setMark(exprParser.expr());
acceptIdentifier("TO");
accept(Token.TO);
cycleClause.setValue(exprParser.expr());
accept(Token.DEFAULT);
cycleClause.setDefaultValue(exprParser.expr());
@@ -33,6 +33,7 @@ import com.alibaba.druid.sql.ast.statement.SQLColumnDefinition;
import com.alibaba.druid.sql.ast.statement.SQLConstaint;
import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLInsertInto;
import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
@@ -65,6 +66,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterTriggerStatement
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterViewStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleBlockStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCommitStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateDatabaseDbLinkStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateIndexStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateSequenceStatement;
@@ -110,7 +112,7 @@ public class OracleStatementParser extends SQLStatementParser {
public OracleExprParser getExprParser() {
return (OracleExprParser) exprParser;
}
public void parseHints(List<SQLHint> hints) {
this.getExprParser().parseHints(hints);
}
@@ -279,6 +281,13 @@ public class OracleStatementParser extends SQLStatementParser {
statementList.add(stmt);
continue;
}
if (identifierEquals("ROLLBACK")) {
SQLRollbackStatement stmt = parseRollback();
statementList.add(stmt);
continue;
}
if (lexer.token() == Token.IDENTIFIER) {
if (identifierEquals("EXPLAIN")) {
@@ -384,7 +393,7 @@ public class OracleStatementParser extends SQLStatementParser {
OracleSavePointStatement stmt = new OracleSavePointStatement();
if (identifierEquals("TO")) {
if (lexer.token() == Token.TO) {
lexer.nextToken();
stmt.setTo(this.exprParser.name());
}
@@ -622,7 +631,7 @@ public class OracleStatementParser extends SQLStatementParser {
if (identifierEquals("RENAME")) {
lexer.nextToken();
acceptIdentifier("TO");
accept(Token.TO);
stmt.setRenameTo(this.exprParser.name());
}
@@ -897,7 +906,7 @@ public class OracleStatementParser extends SQLStatementParser {
private OracleAlterTableItem parseAlterTableRename() {
acceptIdentifier("RENAME");
if (identifierEquals("TO")) {
if (lexer.token() == Token.TO) {
lexer.nextToken();
OracleAlterTableRenameTo item = new OracleAlterTableRenameTo();
item.setTo(this.exprParser.name());
@@ -1222,7 +1231,7 @@ public class OracleStatementParser extends SQLStatementParser {
return stmt;
}
accept(Token.INSERT);
List<SQLHint> hints = new ArrayList<SQLHint>();
@@ -1458,6 +1467,59 @@ public class OracleStatementParser extends SQLStatementParser {
return deleteStatement;
}
public SQLStatement parseCreateDbLink() {
accept(Token.CREATE);
OracleCreateDatabaseDbLinkStatement dbLink = new OracleCreateDatabaseDbLinkStatement();
if (identifierEquals("SHARED")) {
dbLink.setShared(true);
lexer.nextToken();
}
if (identifierEquals("PUBLIC")) {
dbLink.setPublic(true);
lexer.nextToken();
}
accept(Token.DATABASE);
acceptIdentifier("LINK");
dbLink.setName(this.exprParser.name());
if (lexer.token() == Token.CONNECT) {
lexer.nextToken();
accept(Token.TO);
dbLink.setUser(this.exprParser.name());
if (lexer.token() == Token.IDENTIFIED) {
lexer.nextToken();
accept(Token.BY);
dbLink.setPassword(lexer.stringVal());
accept(Token.IDENTIFIER);
}
}
if (identifierEquals("AUTHENTICATED")) {
lexer.nextToken();
accept(Token.BY);
dbLink.setAuthenticatedUser(this.exprParser.name());
accept(Token.IDENTIFIED);
accept(Token.BY);
dbLink.setPassword(lexer.stringVal());
accept(Token.IDENTIFIER);
}
if (lexer.token() == Token.USING) {
lexer.nextToken();
dbLink.setUsing(this.exprParser.expr());
}
return dbLink;
}
public OracleCreateIndexStatement parseCreateIndex(boolean acceptCreate) {
if (acceptCreate) {
accept(Token.CREATE);
@@ -70,6 +70,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterViewStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleBlockStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCommitStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateDatabaseDbLinkStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateIndexStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateSequenceStatement;
@@ -601,4 +602,8 @@ public interface OracleASTVisitor extends SQLASTVisitor {
boolean visit(OracleCreateProcedureStatement x);
void endVisit(OracleCreateProcedureStatement x);
boolean visit(OracleCreateDatabaseDbLinkStatement x);
void endVisit(OracleCreateDatabaseDbLinkStatement x);
}
@@ -78,6 +78,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterViewStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleBlockStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCommitStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateDatabaseDbLinkStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateIndexStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateSequenceStatement;
@@ -1371,4 +1372,14 @@ public class OracleASTVisitorAdapter extends SQLASTVisitorAdapter implements Ora
}
@Override
public boolean visit(OracleCreateDatabaseDbLinkStatement x) {
return true;
}
@Override
public void endVisit(OracleCreateDatabaseDbLinkStatement x) {
}
}
@@ -107,6 +107,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterViewStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleBlockStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCommitStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateDatabaseDbLinkStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateIndexStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateSequenceStatement;
@@ -3032,4 +3033,51 @@ public class OracleOutputVisitor extends SQLASTOutputVisitor implements OracleAS
public void endVisit(OracleCreateProcedureStatement x) {
}
@Override
public boolean visit(OracleCreateDatabaseDbLinkStatement x) {
print("CREATE ");
if (x.isShared()) {
print("SHARE ");
}
if (x.isPublic()) {
print("PUBLIC ");
}
print("DATABASE LINK ");
x.getName().accept(this);
if (x.getUser() != null) {
print(" CONNECT TO ");
x.getUser().accept(this);
if (x.getPassword() != null) {
print(" IDENTIFIED BY ");
print(x.getPassword());
}
}
if (x.getAuthenticatedUser() != null) {
print(" AUTHENTICATED BY ");
x.getAuthenticatedUser().accept(this);
if (x.getAuthenticatedPassword() != null) {
print(" IDENTIFIED BY ");
print(x.getAuthenticatedPassword());
}
}
if (x.getUsing() != null) {
print(" USING ");
x.getUsing().accept(this);
}
return false;
}
@Override
public void endVisit(OracleCreateDatabaseDbLinkStatement x) {
}
}
@@ -99,6 +99,7 @@ import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleAlterViewStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleBlockStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCommitStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleConstraintState;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateDatabaseDbLinkStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateIndexStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateProcedureStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleCreateSequenceStatement;
@@ -161,17 +162,17 @@ import com.alibaba.druid.util.JdbcUtils;
public class OracleSchemaStatVisitor extends SchemaStatVisitor implements OracleASTVisitor {
public OracleSchemaStatVisitor(){
this (new ArrayList<Object>());
this(new ArrayList<Object>());
}
public OracleSchemaStatVisitor(List<Object> parameters) {
super (parameters);
public OracleSchemaStatVisitor(List<Object> parameters){
super(parameters);
this.variants.put("DUAL", null);
this.variants.put("NOTFOUND", null);
this.variants.put("TRUE", null);
this.variants.put("FALSE", null);
}
@Override
public String getDbType() {
return JdbcUtils.ORACLE;
@@ -1800,4 +1801,15 @@ public class OracleSchemaStatVisitor extends SchemaStatVisitor implements Oracle
public void endVisit(OracleCreateProcedureStatement x) {
}
@Override
public boolean visit(OracleCreateDatabaseDbLinkStatement x) {
return false;
}
@Override
public void endVisit(OracleCreateDatabaseDbLinkStatement x) {
}
}
@@ -113,6 +113,7 @@ public class Keywords {
map.put("XOR", Token.XOR);
map.put("OVER", Token.OVER);
map.put("TO", Token.TO);
DEFAULT_KEYWORDS = new Keywords(map);
}
@@ -234,7 +234,7 @@ public class SQLStatementParser extends SQLParser {
SQLRollbackStatement stmt = new SQLRollbackStatement();
if (identifierEquals("TO")) {
if (lexer.token() == Token.TO) {
lexer.nextToken();
if (identifierEquals("SAVEPOINT")) {
@@ -439,7 +439,7 @@ public class SQLStatementParser extends SQLParser {
exprParser.exprList(stmt.getParameters());
accept(Token.RPAREN);
}
if (brace) {
accept(Token.RBRACE);
}
@@ -496,12 +496,26 @@ public class SQLStatementParser extends SQLParser {
// lexer.reset(mark_bp, mark_ch, Token.CREATE);
throw new ParserException("TODO " + lexer.token() + " " + lexer.stringVal());
} else if (token == Token.DATABASE) {
lexer.nextToken();
if (identifierEquals("LINK")) {
lexer.reset(markBp, markChar, Token.CREATE);
return parseCreateDbLink();
}
lexer.reset(markBp, markChar, Token.CREATE);
return parseCreateDatabase();
} else if (identifierEquals("PUBLIC") || identifierEquals("SHARE")) {
lexer.reset(markBp, markChar, Token.CREATE);
return parseCreateDbLink();
}
throw new ParserException("TODO " + lexer.token());
}
public SQLStatement parseCreateDbLink() {
throw new ParserException("TODO " + lexer.token());
}
public SQLStatement parseCreateDatabase() {
if (lexer.token() == Token.CREATE) {
lexer.nextToken();
@@ -70,6 +70,7 @@ public enum Token {
COLUMN("COLUMN"),
USE("USE"),
DATABASE("DATABASE"),
TO("TO"),
AND("AND"),
OR("OR"),
@@ -154,7 +155,6 @@ public enum Token {
ADVISE("ADVISE"),
SESSION("SESSION"),
PROCEDURE("PROCEDURE"),
LOCAL("LOCAL"),
SYSDATE("SYSDATE"),
DECLARE("DECLARE"),
EXCEPTION("EXCEPTION"),
@@ -49,6 +49,7 @@ import com.alibaba.druid.sql.ast.statement.SQLDropTableStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLRollbackStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectItem;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
@@ -982,4 +983,9 @@ public class SchemaStatVisitor extends SQLASTVisitorAdapter {
public void endVisit(SQLAlterTableAddColumn x) {
}
@Override
public boolean visit(SQLRollbackStatement x) {
return false;
}
}
@@ -0,0 +1,85 @@
/*
* Copyright 1999-2011 Alibaba Group Holding Ltd.
*
* 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 com.alibaba.druid.bvt.sql.oracle;
import java.util.List;
import org.junit.Assert;
import com.alibaba.druid.sql.OracleTest;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.dialect.oracle.parser.OracleStatementParser;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleSchemaStatVisitor;
import com.alibaba.druid.util.JdbcConstants;
public class OracleCreateDbLinkTest extends OracleTest {
public void test_0() throws Exception {
String sql = //
"CREATE PUBLIC DATABASE LINK remote USING 'remote'; ";
OracleStatementParser parser = new OracleStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement statement = statementList.get(0);
print(statementList);
Assert.assertEquals("CREATE PUBLIC DATABASE LINK remote USING 'remote'",
SQLUtils.toSQLString(statement, JdbcConstants.ORACLE));
OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor();
statement.accept(visitor);
Assert.assertEquals(0, visitor.getTables().size());
}
public void test_1() throws Exception {
String sql = //
"CREATE DATABASE LINK local CONNECT TO hr IDENTIFIED BY hr USING 'local';";
OracleStatementParser parser = new OracleStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement statement = statementList.get(0);
print(statementList);
Assert.assertEquals("CREATE DATABASE LINK local CONNECT TO hr IDENTIFIED BY hr USING 'local'",
SQLUtils.toSQLString(statement, JdbcConstants.ORACLE));
OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor();
statement.accept(visitor);
Assert.assertEquals(0, visitor.getTables().size());
}
public void test_2() throws Exception {
String sql = //
"CREATE DATABASE LINK remote.us.oracle.com CONNECT TO CURRENT_USER USING 'remote';";
OracleStatementParser parser = new OracleStatementParser(sql);
List<SQLStatement> statementList = parser.parseStatementList();
SQLStatement statement = statementList.get(0);
print(statementList);
Assert.assertEquals("CREATE DATABASE LINK remote.us.oracle.com CONNECT TO CURRENT_USER USING 'remote'",
SQLUtils.toSQLString(statement, JdbcConstants.ORACLE));
OracleSchemaStatVisitor visitor = new OracleSchemaStatVisitor();
statement.accept(visitor);
Assert.assertEquals(0, visitor.getTables().size());
}
}