chore(project): 添加项目配置文件和忽略规则

- 添加 Babel 配置文件支持 ES6+ 语法转换
- 添加 ESLint 忽略规则和配置文件
- 添加 Git 忽略规则文件
- 添加 Travis CI 配置文件
- 添加 1.4.2 版本变更日志文件
- 添加 Helm 图表辅助模板文件
- 添加 Helm 忽略规则文件
This commit is contained in:
2026-03-27 17:36:48 +08:00
commit c2453d6434
1703 changed files with 277582 additions and 0 deletions

35
sqlparser/pom.xml Normal file
View File

@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2019 Seata.io Group.
~
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.seata</groupId>
<artifactId>seata-parent</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>seata-sqlparser</artifactId>
<packaging>pom</packaging>
<name>seata-sqlparser ${project.version}</name>
<modules>
<module>seata-sqlparser-core</module>
<module>seata-sqlparser-antlr</module>
<module>seata-sqlparser-druid</module>
</modules>
</project>

View File

@@ -0,0 +1,51 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2019 Seata.io Group.
~
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.seata</groupId>
<artifactId>seata-sqlparser</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>seata-sqlparser-antlr</artifactId>
<name>seata-sqlparser-antlr ${project.version}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>seata-sqlparser-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.antlr</groupId>
<artifactId>antlr4</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,62 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import io.seata.sqlparser.SqlParserType;
import java.lang.reflect.Constructor;
import java.util.List;
/**
* @author zhihou
*/
@LoadLevel(name = SqlParserType.SQL_PARSER_TYPE_ANTLR)
public class AntlrDelegatingSQLRecognizerFactory implements SQLRecognizerFactory {
private volatile SQLRecognizerFactory recognizerFactoryImpl;
public AntlrDelegatingSQLRecognizerFactory() {
setClassLoader();
}
/**
* Only for unit test
*
*/
void setClassLoader() {
try {
Class<?> recognizerFactoryImplClass = ClassLoader.getSystemClassLoader().loadClass("io.seata.sqlparser.antlr.mysql.AntlrMySQLRecognizerFactory");
Constructor<?> implConstructor = recognizerFactoryImplClass.getDeclaredConstructor();
implConstructor.setAccessible(true);
try {
recognizerFactoryImpl = (SQLRecognizerFactory) implConstructor.newInstance();
} finally {
implConstructor.setAccessible(false);
}
} catch (Exception e) {
throw new SQLParsingException(e);
}
}
@Override
public List<SQLRecognizer> create(String sql, String dbType) {
return recognizerFactoryImpl.create(sql, dbType);
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.sqlparser.SQLRecognizer;
/**
* The interface SQLOperateRecognizerHolder
*
* @author zhihou
*/
public interface SQLOperateRecognizerHolder {
/**
* Get delete recognizer
*
* @param sql the sql
* @return the delete recognizer
*/
SQLRecognizer getDeleteRecognizer(String sql);
/**
* Get insert recognizer
*
* @param sql the sql
* @return the insert recognizer
*/
SQLRecognizer getInsertRecognizer(String sql);
/**
* Get update recognizer
*
* @param sql the sql
* @return the update recognizer
*/
SQLRecognizer getUpdateRecognizer(String sql);
/**
* Get SelectForUpdate recognizer
*
* @param sql the sql
* @return the SelectForUpdate recognizer
*/
SQLRecognizer getSelectForUpdateRecognizer(String sql);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.common.loader.EnhancedServiceLoader;
import io.seata.common.util.CollectionUtils;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* The SQLOperateRecognizerHolderFactory
*
* @author: zhi hou
*/
public class SQLOperateRecognizerHolderFactory {
private static final Map<String, SQLOperateRecognizerHolder> RECOGNIZER_HOLDER_MAP = new ConcurrentHashMap<>();
/**
* get SQLOperateRecognizer by db type
*
* @param dbType the db type
* @return the SQLOperateRecognizer
*/
public static SQLOperateRecognizerHolder getSQLRecognizerHolder(String dbType) {
return CollectionUtils.computeIfAbsent(RECOGNIZER_HOLDER_MAP, dbType, key -> EnhancedServiceLoader.load(SQLOperateRecognizerHolder.class, dbType, SQLOperateRecognizerHolderFactory.class.getClassLoader()));
}
}

View File

@@ -0,0 +1,82 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLDeleteRecognizer;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.antlr.mysql.listener.DeleteSpecificationSqlListener;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayList;
import java.util.List;
/**
* AntlrMySQLDeleteRecognizer
*
* @author zhihou
*/
public class AntlrMySQLDeleteRecognizer implements SQLDeleteRecognizer {
private MySqlContext sqlContext;
public AntlrMySQLDeleteRecognizer(String sql) {
MySqlLexer mySqlLexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream commonTokenStream = new CommonTokenStream(mySqlLexer);
MySqlParser parser2 = new MySqlParser(commonTokenStream);
MySqlParser.RootContext root = parser2.root();
ParseTreeWalker walker2 = new ParseTreeWalker();
sqlContext = new MySqlContext();
sqlContext.setOriginalSQL(sql);
walker2.walk(new DeleteSpecificationSqlListener(sqlContext), root);
}
@Override
public String getWhereCondition(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
return sqlContext.getWhereCondition();
}
@Override
public String getWhereCondition() {
return sqlContext.getWhereCondition();
}
@Override
public SQLType getSQLType() {
return SQLType.DELETE;
}
@Override
public String getTableAlias() {
return sqlContext.tableAlias;
}
@Override
public String getTableName() {
return sqlContext.tableName;
}
@Override
public String getOriginalSQL() {
return sqlContext.getOriginalSQL();
}
}

View File

@@ -0,0 +1,98 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import io.seata.sqlparser.SQLInsertRecognizer;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import io.seata.sqlparser.antlr.mysql.visit.InsertStatementSqlVisitor;
import org.antlr.v4.runtime.CommonTokenStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
/**
* AntlrMySQLInsertRecognizer
*
* @author zhihou
*/
public class AntlrMySQLInsertRecognizer implements SQLInsertRecognizer {
private MySqlContext sqlContext;
public AntlrMySQLInsertRecognizer(String sql) {
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
sqlContext = new MySqlContext();
sqlContext.setOriginalSQL(sql);
InsertStatementSqlVisitor visitor = new InsertStatementSqlVisitor(sqlContext);
visitor.visit(rootContext);
}
@Override
public SQLType getSQLType() {
return SQLType.INSERT;
}
@Override
public String getTableAlias() {
return sqlContext.tableAlias;
}
@Override
public String getTableName() {
return sqlContext.tableName;
}
@Override
public String getOriginalSQL() {
return sqlContext.getOriginalSQL();
}
@Override
public boolean insertColumnsIsEmpty() {
List<MySqlContext.SQL> insertColumnNames = sqlContext.getInsertColumnNames();
if (insertColumnNames.isEmpty()) {
return true;
}
return false;
}
@Override
public List<String> getInsertColumns() {
List<MySqlContext.SQL> insertColumnNames = sqlContext.getInsertColumnNames();
if (insertColumnNames.isEmpty()) {
return new ArrayList<>();
}
return insertColumnNames.stream().map(insertColumns -> insertColumns.getColumnName()).collect(Collectors.toList());
}
@Override
public List<List<Object>> getInsertRows(Collection<Integer> primaryKeyIndex) {
return null;
}
}

View File

@@ -0,0 +1,81 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import io.seata.sqlparser.antlr.SQLOperateRecognizerHolder;
import io.seata.sqlparser.antlr.SQLOperateRecognizerHolderFactory;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
import org.antlr.v4.runtime.CommonTokenStream;
import java.util.ArrayList;
import java.util.List;
/**
* AntlrMySQLRecognizerFactory
*
* @author zhihou
*/
class AntlrMySQLRecognizerFactory implements SQLRecognizerFactory {
@Override
public List<SQLRecognizer> create(String sqlData, String dbType) {
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sqlData));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.SqlStatementsContext sqlStatementsContext = parser.sqlStatements();
List<MySqlParser.SqlStatementContext> sqlStatementContexts = sqlStatementsContext.sqlStatement();
List<SQLRecognizer> recognizers = null;
SQLRecognizer recognizer = null;
for (MySqlParser.SqlStatementContext sql : sqlStatementContexts) {
StatementSqlVisitor visitor = new StatementSqlVisitor();
String originalSQL = visitor.visit(sql).toString();
SQLOperateRecognizerHolder recognizerHolder =
SQLOperateRecognizerHolderFactory.getSQLRecognizerHolder(dbType.toLowerCase());
if (sql.dmlStatement().updateStatement() != null) {
recognizer = recognizerHolder.getUpdateRecognizer(originalSQL);
} else if (sql.dmlStatement().insertStatement() != null) {
recognizer = recognizerHolder.getInsertRecognizer(originalSQL);
} else if (sql.dmlStatement().deleteStatement() != null) {
recognizer = recognizerHolder.getDeleteRecognizer(originalSQL);
} else if (sql.dmlStatement().selectStatement() != null) {
recognizer = recognizerHolder.getSelectForUpdateRecognizer(originalSQL);
}
if (recognizer != null) {
if (recognizers == null) {
recognizers = new ArrayList<>();
}
recognizers.add(recognizer);
}
}
return recognizers;
}
}

View File

@@ -0,0 +1,80 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLSelectRecognizer;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.antlr.mysql.listener.SelectSpecificationSqlListener;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayList;
import java.util.List;
/**
* AntlrMySQLSelectRecognizer
*
* @author zhihou
*/
public class AntlrMySQLSelectRecognizer implements SQLSelectRecognizer {
private MySqlContext sqlContext;
public AntlrMySQLSelectRecognizer(String sql) {
MySqlLexer mySqlLexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream commonTokenStream = new CommonTokenStream(mySqlLexer);
MySqlParser parser = new MySqlParser(commonTokenStream);
MySqlParser.RootContext root = parser.root();
ParseTreeWalker walker = new ParseTreeWalker();
sqlContext = new MySqlContext();
sqlContext.setOriginalSQL(sql);
walker.walk(new SelectSpecificationSqlListener(sqlContext), root);
}
@Override
public String getWhereCondition(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
return sqlContext.getWhereCondition();
}
@Override
public String getWhereCondition() {
return sqlContext.getWhereCondition();
}
@Override
public SQLType getSQLType() {
return SQLType.SELECT;
}
@Override
public String getTableAlias() {
return sqlContext.tableAlias;
}
@Override
public String getTableName() {
return sqlContext.tableName;
}
@Override
public String getOriginalSQL() {
return sqlContext.getOriginalSQL();
}
}

View File

@@ -0,0 +1,104 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.SQLUpdateRecognizer;
import io.seata.sqlparser.antlr.mysql.listener.UpdateSpecificationSqlListener;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
/**
* AntlrMySQLUpdateRecognizer
*
* @author zhihou
*/
public class AntlrMySQLUpdateRecognizer implements SQLUpdateRecognizer {
private MySqlContext sqlContext;
public AntlrMySQLUpdateRecognizer(String sql) {
MySqlLexer mySqlLexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream commonTokenStream = new CommonTokenStream(mySqlLexer);
MySqlParser parser2 = new MySqlParser(commonTokenStream);
MySqlParser.RootContext root = parser2.root();
ParseTreeWalker walker2 = new ParseTreeWalker();
sqlContext = new MySqlContext();
sqlContext.setOriginalSQL(sql);
walker2.walk(new UpdateSpecificationSqlListener(sqlContext), root);
}
@Override
public List<String> getUpdateColumns() {
List<MySqlContext.SQL> updateFoColumnNames = sqlContext.getUpdateFoColumnNames();
List<String> sqlList = new ArrayList<>();
for (MySqlContext.SQL sql : updateFoColumnNames) {
sqlList.add(sql.getUpdateColumn());
}
return sqlList;
}
@Override
public List<Object> getUpdateValues() {
List<MySqlContext.SQL> updateForValues = sqlContext.getUpdateForValues();
if (updateForValues.isEmpty()) {
return new ArrayList<>();
}
return updateForValues.stream().map(updateValues -> updateValues.getUpdateValue()).collect(Collectors.toList());
}
@Override
public String getWhereCondition(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
return sqlContext.getWhereCondition();
}
@Override
public String getWhereCondition() {
return sqlContext.getWhereCondition();
}
@Override
public SQLType getSQLType() {
return SQLType.UPDATE;
}
@Override
public String getTableAlias() {
return sqlContext.tableAlias;
}
@Override
public String getTableName() {
return sqlContext.tableName;
}
@Override
public String getOriginalSQL() {
return sqlContext.getOriginalSQL();
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.antlr.SQLOperateRecognizerHolder;
import io.seata.sqlparser.util.JdbcConstants;
/**
* The class MySqlOperateRecognizerHolder
*
* @author zhihou
*/
@LoadLevel(name = JdbcConstants.MYSQL)
public class MySQLOperateRecognizerHolder implements SQLOperateRecognizerHolder {
@Override
public SQLRecognizer getDeleteRecognizer(String sql) {
return new AntlrMySQLDeleteRecognizer(sql);
}
@Override
public SQLRecognizer getInsertRecognizer(String sql) {
return new AntlrMySQLInsertRecognizer(sql);
}
@Override
public SQLRecognizer getUpdateRecognizer(String sql) {
return new AntlrMySQLUpdateRecognizer(sql);
}
@Override
public SQLRecognizer getSelectForUpdateRecognizer(String sql) {
return new AntlrMySQLSelectRecognizer(sql);
}
}

View File

@@ -0,0 +1,391 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql;
import java.util.ArrayList;
import java.util.List;
/**
* MySqlContext
*
* @author zhihou
*/
public class MySqlContext {
/**
* Table Name
*/
public String tableName;
/**
* Table Alias
*/
public String tableAlias;
/**
* Number of inserts
*/
public Integer insertRows;
/**
* Where condition
*/
private String whereCondition;
/**
* Query column name collection
*/
public List<SQL> queryColumnNames = new ArrayList<>();
/**
* Conditional query column name collection
*/
public List<SQL> queryWhereColumnNames = new ArrayList<>();
/**
* Conditional query column name corresponding value collection
*/
public List<SQL> queryWhereValColumnNames = new ArrayList<>();
/**
* Query column name collection
*/
public List<SQL> insertColumnNames = new ArrayList<>();
/**
* Insert the value set corresponding to the column name
*/
public List<List<String>> insertForValColumnNames = new ArrayList<>();
/**
* Delete condition column name set
*/
public List<SQL> deleteForWhereColumnNames = new ArrayList<>();
/**
* Conditional delete column name object value collection
*/
public List<SQL> deleteForWhereValColumnNames = new ArrayList<>();
/**
* Conditional update condition column name object collection
*/
public List<SQL> updateForWhereColumnNames = new ArrayList<>();
/**
* Conditional update column name object value collection
*/
public List<SQL> updateForWhereValColumnNames = new ArrayList<>();
/**
* Update column name object value collection
*/
public List<SQL> updateFoColumnNames = new ArrayList<>();
/**
* Update object value collection
*/
public List<SQL> updateForValues = new ArrayList<>();
/**
* sql object information collection
*/
public List<SQL> sqlInfos = new ArrayList<>();
/**
* originalSQL
*/
private String originalSQL;
public void addSqlInfo(SQL sql) {
sqlInfos.add(sql);
}
public void addForInsertColumnName(String columnName) {
SQL sql = new SQL();
sql.setInsertColumnName(columnName);
insertColumnNames.add(sql);
}
public void addForInsertValColumnName(List<String> columnName) {
insertForValColumnNames.add(columnName);
}
public void addQueryColumnNames(String columnName) {
SQL sql = new SQL();
sql.setColumnName(columnName);
queryColumnNames.add(sql);
}
public void addQueryWhereColumnNames(String columnName) {
SQL sql = new SQL();
sql.setQueryWhereColumnName(columnName);
queryWhereColumnNames.add(sql);
}
public void addQueryWhereValColumnNames(String columnName) {
SQL sql = new SQL();
sql.setQueryWhereValColumnName(columnName);
queryWhereValColumnNames.add(sql);
}
public void addDeleteWhereColumnNames(String columnName) {
SQL sql = new SQL();
sql.setDeleteWhereColumnName(columnName);
deleteForWhereColumnNames.add(sql);
}
public void addDeleteWhereValColumnNames(String columnName) {
SQL sql = new SQL();
sql.setDeleteWhereValColumnName(columnName);
deleteForWhereValColumnNames.add(sql);
}
public void addUpdateWhereValColumnNames(String columnName) {
SQL sql = new SQL();
sql.setUpdateWhereValColumnName(columnName);
updateForWhereValColumnNames.add(sql);
}
public void addUpdateWhereColumnNames(String columnName) {
SQL sql = new SQL();
sql.setUpdateWhereColumnName(columnName);
updateForWhereColumnNames.add(sql);
}
public void addUpdateColumnNames(String columnName) {
SQL sql = new SQL();
sql.setUpdateColumn(columnName);
updateFoColumnNames.add(sql);
}
public void addUpdateValues(String columnName) {
SQL sql = new SQL();
sql.setUpdateValue(columnName);
updateForValues.add(sql);
}
public static class SQL {
private String columnName;
private String tableName;
private String queryWhereValColumnName;
private String queryWhereColumnName;
private String insertColumnName;
private String deleteWhereValColumnName;
private String deleteWhereColumnName;
private String updateWhereValColumnName;
private String updateWhereColumnName;
private String updateColumn;
private String updateValue;
private Integer sqlType;
private String sql;
public String getColumnName() {
return columnName;
}
public void setColumnName(String columnName) {
this.columnName = columnName;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public String getQueryWhereValColumnName() {
return queryWhereValColumnName;
}
public void setQueryWhereValColumnName(String queryWhereValColumnName) {
this.queryWhereValColumnName = queryWhereValColumnName;
}
public String getQueryWhereColumnName() {
return queryWhereColumnName;
}
public void setQueryWhereColumnName(String queryWhereColumnName) {
this.queryWhereColumnName = queryWhereColumnName;
}
public String getInsertColumnName() {
return insertColumnName;
}
public void setInsertColumnName(String insertColumnName) {
this.insertColumnName = insertColumnName;
}
public String getDeleteWhereValColumnName() {
return deleteWhereValColumnName;
}
public void setDeleteWhereValColumnName(String deleteWhereValColumnName) {
this.deleteWhereValColumnName = deleteWhereValColumnName;
}
public String getDeleteWhereColumnName() {
return deleteWhereColumnName;
}
public void setDeleteWhereColumnName(String deleteWhereColumnName) {
this.deleteWhereColumnName = deleteWhereColumnName;
}
public String getUpdateWhereValColumnName() {
return updateWhereValColumnName;
}
public void setUpdateWhereValColumnName(String updateWhereValColumnName) {
this.updateWhereValColumnName = updateWhereValColumnName;
}
public String getUpdateWhereColumnName() {
return updateWhereColumnName;
}
public void setUpdateWhereColumnName(String updateWhereColumnName) {
this.updateWhereColumnName = updateWhereColumnName;
}
public String getUpdateColumn() {
return updateColumn;
}
public void setUpdateColumn(String updateColumn) {
this.updateColumn = updateColumn;
}
public String getUpdateValue() {
return updateValue;
}
public void setUpdateValue(String updateValue) {
this.updateValue = updateValue;
}
public Integer getSqlType() {
return sqlType;
}
public void setSqlType(Integer sqlType) {
this.sqlType = sqlType;
}
public String getSql() {
return sql;
}
public void setSql(String sql) {
this.sql = sql;
}
}
public List<SQL> getQueryColumnNames() {
return queryColumnNames;
}
public List<SQL> getQueryWhereColumnNames() {
return queryWhereColumnNames;
}
public List<SQL> getQueryWhereValColumnNames() {
return queryWhereValColumnNames;
}
public List<SQL> getInsertColumnNames() {
return insertColumnNames;
}
public List<List<String>> getInsertForValColumnNames() {
return insertForValColumnNames;
}
public List<SQL> getDeleteForWhereColumnNames() {
return deleteForWhereColumnNames;
}
public List<SQL> getDeleteForWhereValColumnNames() {
return deleteForWhereValColumnNames;
}
public List<SQL> getUpdateForWhereColumnNames() {
return updateForWhereColumnNames;
}
public List<SQL> getUpdateForWhereValColumnNames() {
return updateForWhereValColumnNames;
}
public List<SQL> getUpdateFoColumnNames() {
return updateFoColumnNames;
}
public List<SQL> getUpdateForValues() {
return updateForValues;
}
public String getTableName() {
return tableName;
}
public void setTableName(String tableName) {
this.tableName = tableName;
}
public Integer getInsertRows() {
return insertRows;
}
public void setInsertRows(Integer insertRows) {
this.insertRows = insertRows;
}
public String getWhereCondition() {
return whereCondition;
}
public void setWhereCondition(String whereCondition) {
this.whereCondition = whereCondition;
}
public List<SQL> getSqlInfos() {
return sqlInfos;
}
public String getOriginalSQL() {
return originalSQL;
}
public void setOriginalSQL(String originalSQL) {
this.originalSQL = originalSQL;
}
public void setTableAlias(String tableAlias) {
this.tableAlias = tableAlias;
}
public String getTableAlias() {
return tableAlias;
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.listener;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParserBaseListener;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
/**
* @author houzhi
*/
public class DeleteSpecificationSqlListener extends MySqlParserBaseListener {
private MySqlContext sqlQueryContext;
public DeleteSpecificationSqlListener(MySqlContext sqlQueryContext) {
this.sqlQueryContext = sqlQueryContext;
}
@Override
public void enterAtomTableItem(MySqlParser.AtomTableItemContext ctx) {
MySqlParser.TableNameContext tableNameContext = ctx.tableName();
sqlQueryContext.setTableName(tableNameContext.getText());
MySqlParser.UidContext uid = ctx.uid();
sqlQueryContext.setTableAlias(uid.getText());
super.enterAtomTableItem(ctx);
}
@Override
public void enterConstantExpressionAtom(MySqlParser.ConstantExpressionAtomContext ctx) {
sqlQueryContext.addDeleteWhereValColumnNames(ctx.getText());
super.enterConstantExpressionAtom(ctx);
}
@Override
public void enterFullColumnNameExpressionAtom(MySqlParser.FullColumnNameExpressionAtomContext ctx) {
sqlQueryContext.addDeleteWhereColumnNames(ctx.getText());
super.enterFullColumnNameExpressionAtom(ctx);
}
@Override
public void enterSingleDeleteStatement(MySqlParser.SingleDeleteStatementContext ctx) {
MySqlParser.TableNameContext tableNameContext = ctx.tableName();
sqlQueryContext.setTableName(tableNameContext.getText());
MySqlParser.ExpressionContext expression = ctx.expression();
StatementSqlVisitor statementSqlVisitor = new StatementSqlVisitor();
String text = statementSqlVisitor.visit(expression).toString();
sqlQueryContext.setWhereCondition(text);
super.enterSingleDeleteStatement(ctx);
}
@Override
public void enterMultipleDeleteStatement(MySqlParser.MultipleDeleteStatementContext ctx) {
MySqlParser.ExpressionContext expression = ctx.expression();
StatementSqlVisitor statementSqlVisitor = new StatementSqlVisitor();
String text = statementSqlVisitor.visit(expression).toString();
sqlQueryContext.setWhereCondition(text);
super.enterMultipleDeleteStatement(ctx);
}
@Override
public void enterInPredicate(MySqlParser.InPredicateContext ctx) {
StatementSqlVisitor statementSqlVisitor = new StatementSqlVisitor();
String text = statementSqlVisitor.visit(ctx).toString();
sqlQueryContext.setWhereCondition(text);
super.enterInPredicate(ctx);
}
}

View File

@@ -0,0 +1,89 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.listener;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParserBaseListener;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
import java.util.List;
/**
* @author houzhi
*/
public class SelectSpecificationSqlListener extends MySqlParserBaseListener {
private MySqlContext sqlQueryContext;
public SelectSpecificationSqlListener(MySqlContext sqlQueryContext) {
this.sqlQueryContext = sqlQueryContext;
}
@Override
public void enterTableName(MySqlParser.TableNameContext ctx) {
sqlQueryContext.setTableName(ctx.getText());
super.enterTableName(ctx);
}
@Override
public void enterAtomTableItem(MySqlParser.AtomTableItemContext ctx) {
MySqlParser.UidContext uid = ctx.uid();
if (uid != null) {
String text = uid.getText();
if (!text.isEmpty()) {
sqlQueryContext.setTableAlias(text);
}
}
super.enterAtomTableItem(ctx);
}
@Override
public void enterFromClause(MySqlParser.FromClauseContext ctx) {
MySqlParser.ExpressionContext whereExpr = ctx.whereExpr;
StatementSqlVisitor statementSqlVisitor = new StatementSqlVisitor();
String text = statementSqlVisitor.visit(whereExpr).toString();
sqlQueryContext.setWhereCondition(text);
super.enterFromClause(ctx);
}
@Override
public void enterFullColumnNameExpressionAtom(MySqlParser.FullColumnNameExpressionAtomContext ctx) {
sqlQueryContext.addQueryWhereColumnNames(ctx.getText());
super.enterFullColumnNameExpressionAtom(ctx);
}
@Override
public void enterConstantExpressionAtom(MySqlParser.ConstantExpressionAtomContext ctx) {
sqlQueryContext.addQueryWhereValColumnNames(ctx.getText());
super.enterConstantExpressionAtom(ctx);
}
@Override
public void enterSelectElements(MySqlParser.SelectElementsContext ctx) {
List<MySqlParser.SelectElementContext> selectElementContexts = ctx.selectElement();
for (MySqlParser.SelectElementContext selectElementContext : selectElementContexts) {
sqlQueryContext.addQueryColumnNames(selectElementContext.getText());
}
super.enterSelectElements(ctx);
}
}

View File

@@ -0,0 +1,87 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.listener;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParserBaseListener;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
/**
* @author houzhi
*/
public class UpdateSpecificationSqlListener extends MySqlParserBaseListener {
private MySqlContext sqlQueryContext;
public UpdateSpecificationSqlListener(MySqlContext sqlQueryContext) {
this.sqlQueryContext = sqlQueryContext;
}
@Override
public void enterTableName(MySqlParser.TableNameContext ctx) {
sqlQueryContext.setTableName(ctx.getText());
super.enterTableName(ctx);
}
@Override
public void enterConstantExpressionAtomForUpdate(MySqlParser.ConstantExpressionAtomForUpdateContext ctx) {
sqlQueryContext.addUpdateWhereValColumnNames(ctx.getText());
super.enterConstantExpressionAtomForUpdate(ctx);
}
@Override
public void enterFullColumnNameExpressionAtomForUpdate(MySqlParser.FullColumnNameExpressionAtomForUpdateContext ctx) {
sqlQueryContext.addUpdateWhereColumnNames(ctx.getText());
super.enterFullColumnNameExpressionAtomForUpdate(ctx);
}
@Override
public void enterSingleUpdateStatement(MySqlParser.SingleUpdateStatementContext ctx) {
MySqlParser.ExpressionForUpdateContext expressionForUpdateContext = ctx.expressionForUpdate();
StatementSqlVisitor statementSqlVisitor = new StatementSqlVisitor();
String text = statementSqlVisitor.visit(expressionForUpdateContext).toString();
sqlQueryContext.setWhereCondition(text);
MySqlParser.UidContext uid = ctx.uid();
if (uid != null) {
String alias = uid.getText();
if (!text.isEmpty()) {
sqlQueryContext.setTableAlias(alias);
}
}
super.enterSingleUpdateStatement(ctx);
}
@Override
public void enterUpdatedElement(MySqlParser.UpdatedElementContext ctx) {
MySqlParser.ExpressionContext expression = ctx.expression();
sqlQueryContext.addUpdateValues(expression.getText());
MySqlParser.FullColumnNameContext fullColumnNameContext = ctx.fullColumnName();
sqlQueryContext.addUpdateColumnNames(fullColumnNameContext.getText());
super.enterUpdatedElement(ctx);
}
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,41 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.stream;
import org.antlr.v4.runtime.ANTLRInputStream;
import org.antlr.v4.runtime.IntStream;
/**
* ANTLRNoCaseStringStream
*
* @author zhihou
*/
public class ANTLRNoCaseStringStream extends ANTLRInputStream {
public ANTLRNoCaseStringStream(String input) {
super(input);
}
@Override
public int LA(int i) {
int la = super.LA(i);
if (la == 0 || la == IntStream.EOF) {
return la;
} else {
return Character.toUpperCase(la);
}
}
}

View File

@@ -0,0 +1,74 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.visit;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParserBaseVisitor;
import java.util.Arrays;
import java.util.List;
/**
* InsertSpecificationSqlVisitor
*
* @author zhihou
*/
public class InsertSpecificationSqlVisitor extends MySqlParserBaseVisitor<MySqlContext> {
private MySqlContext mySqlContext;
public InsertSpecificationSqlVisitor(MySqlContext mySqlContext) {
this.mySqlContext = mySqlContext;
}
@Override
public MySqlContext visitInsertStatement(MySqlParser.InsertStatementContext ctx) {
MySqlParser.TableNameContext tableNameContext = ctx.tableName();
mySqlContext.setTableName(tableNameContext.getText());
MySqlParser.UidListContext columns = ctx.columns;
List<String> strings = Arrays.asList(columns.getText().split(","));
for (String insertColumnName : strings) {
mySqlContext.addForInsertColumnName(insertColumnName);
}
MySqlParser.InsertStatementValueContext insertStatementValueContext = ctx.insertStatementValue();
List<MySqlParser.ExpressionsWithDefaultsContext> expressionsWithDefaultsContexts = insertStatementValueContext.expressionsWithDefaults();
for (MySqlParser.ExpressionsWithDefaultsContext expressions : expressionsWithDefaultsContexts) {
String text = expressions.getText();
String str = null;
if (text.contains("'")) {
str = text.replace("'", "");
} else if (text.contains("\"")) {
str = text.replace("\"", "");
} else {
str = text;
}
if (!str.isEmpty() && !str.contains("'") && !str.contains("\"")) {
mySqlContext.addForInsertValColumnName(Arrays.asList(str.split(",")));
}
}
mySqlContext.setInsertRows(expressionsWithDefaultsContexts.size());
return this.mySqlContext;
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.visit;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParserBaseVisitor;
/**
* InsertStatementSqlVisitor
*
* @author zhihou
*/
public class InsertStatementSqlVisitor extends MySqlParserBaseVisitor<MySqlContext> {
private MySqlContext mySqlContext;
public InsertStatementSqlVisitor(MySqlContext mySqlContext) {
this.mySqlContext = mySqlContext;
}
@Override
public MySqlContext visitInsertStatement(MySqlParser.InsertStatementContext ctx) {
return new InsertSpecificationSqlVisitor(this.mySqlContext).visitInsertStatement(ctx);
}
}

View File

@@ -0,0 +1,68 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr.mysql.visit;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParserBaseVisitor;
import org.antlr.v4.runtime.tree.TerminalNode;
/**
* StatementSqlVisitor
*
* @author zhihou
*/
public class StatementSqlVisitor extends MySqlParserBaseVisitor<StringBuilder> {
private StringBuilder sb = new StringBuilder();
@Override
public StringBuilder visitTerminal(TerminalNode node) {
String text = node.getText();
if (text != null && !"".equals(text.trim())) {
if (shouldAddSpace(text.trim())) {
sb.append(" ");
}
sb.append(text);
}
return sb;
}
private boolean shouldAddSpace(String text) {
if (sb.length() == 0) {
return false;
}
char lastChar = sb.charAt(sb.length() - 1);
switch (lastChar) {
case '.':
case ',':
case '(':
return false;
default:
break;
}
switch (text.charAt(0)) {
case '.':
case ',':
case ')':
return false;
default:
break;
}
return true;
}
}

View File

@@ -0,0 +1 @@
io.seata.sqlparser.antlr.AntlrDelegatingSQLRecognizerFactory

View File

@@ -0,0 +1 @@
io.seata.sqlparser.antlr.mysql.MySQLOperateRecognizerHolder

View File

@@ -0,0 +1,42 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.common.loader.EnhancedServiceLoader;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import io.seata.sqlparser.SqlParserType;
import io.seata.sqlparser.util.JdbcConstants;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* @author zhihou
*/
public class AntlrIsolationTest {
String TEST_SQL = "SELECT name,phone FROM t1 WHERE id = 1 and username = '11' and age = 'a' or hz = '1' or aa = 1 FOR UPDATE";
@Test
public void testAntlrIsolation() {
AntlrDelegatingSQLRecognizerFactory recognizerFactory = (AntlrDelegatingSQLRecognizerFactory) EnhancedServiceLoader.load(SQLRecognizerFactory.class, SqlParserType.SQL_PARSER_TYPE_ANTLR);
List<SQLRecognizer> sqlRecognizer = recognizerFactory.create(TEST_SQL, JdbcConstants.MYSQL);
Assertions.assertNotNull(sqlRecognizer);
}
}

View File

@@ -0,0 +1,175 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.listener.DeleteSpecificationSqlListener;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author houzhi
* @date 2020-7-10
* @description
*/
public class MySQLDeleteRecognizerTest {
/**
* base statementSql visitor test
*/
private String baseStatementSqlVisitor(String sql) {
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.SqlStatementContext sqlStatementContext = parser.sqlStatement();
StatementSqlVisitor sqlToStringVisitor = new StatementSqlVisitor();
return sqlToStringVisitor.visit(sqlStatementContext).toString();
}
/**
* Delete recognizer test 0.
*/
@Test
public void deleteRecognizerTest_0() {
String sql = "DELETE t FROM t1 as t WHERE t.id = 'id1'";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new DeleteSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("t.id = 'id1'", mySqlContext.getWhereCondition());
Assertions.assertEquals("t", mySqlContext.getTableAlias());
}
/**
* Delete recognizer test 1.
*/
@Test
public void deleteRecognizerTest_1() {
String sql = "DELETE FROM t1 WHERE id = 'id1'";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new DeleteSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("'id1'",
mySqlContext.getDeleteForWhereValColumnNames().get(0).getDeleteWhereValColumnName());
Assertions.assertEquals("id = 'id1'", mySqlContext.getWhereCondition());
}
/**
* Delete recognizer test 1.
*/
@Test
public void deleteRecognizerTest_2() {
String sql = "DELETE FROM t1 WHERE id = ?";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new DeleteSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("?",
mySqlContext.getDeleteForWhereValColumnNames().get(0).getDeleteWhereValColumnName());
Assertions.assertEquals("id = ?", mySqlContext.getWhereCondition());
}
/**
* Delete recognizer test 2.
*/
@Test
public void deleteRecognizerTest_3() {
String sql = "DELETE FROM t1 WHERE id IN (1, 2)";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new DeleteSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("2", mySqlContext.getDeleteForWhereValColumnNames().get(1).getDeleteWhereValColumnName());
Assertions.assertEquals("id IN (1,2)", mySqlContext.getWhereCondition());
}
/**
* Delete recognizer test 3.
*/
@Test
public void deleteRecognizerTest_4() {
String sql = "DELETE FROM t1 WHERE id between 1 AND 'id'";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new DeleteSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("'id'", mySqlContext.getDeleteForWhereValColumnNames().get(1).getDeleteWhereValColumnName());
Assertions.assertEquals("id between 1 AND 'id'", mySqlContext.getWhereCondition());
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import io.seata.sqlparser.antlr.mysql.visit.InsertStatementSqlVisitor;
import org.antlr.v4.runtime.CommonTokenStream;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.Arrays;
import java.util.Collections;
import java.util.stream.Collectors;
/**
* @author houzhi
* @date 2020-7-10
* @description
*/
public class MySQLInsertRecognizerTest {
/**
* Insert recognizer test 0.
*/
@Test
public void insertRecognizerTest_0() {
String sql = "INSERT INTO t1 (id) VALUES (1)";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext visitorSqlContext = new MySqlContext();
InsertStatementSqlVisitor visitor = new InsertStatementSqlVisitor(visitorSqlContext);
visitor.visit(rootContext);
Assertions.assertEquals("t1", visitorSqlContext.tableName);
Assertions.assertEquals(Collections.singletonList("id"), Arrays.asList(visitorSqlContext.getInsertColumnNames().get(0).getInsertColumnName()));
Assertions.assertEquals(1, visitorSqlContext.insertRows);
Assertions.assertEquals(Arrays.asList("1"), visitorSqlContext.getInsertForValColumnNames().get(0));
}
/**
* Insert recognizer test 1.
*/
@Test
public void insertRecognizerTest_1() {
String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 12)";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext visitorSqlContext = new MySqlContext();
InsertStatementSqlVisitor visitor = new InsertStatementSqlVisitor(visitorSqlContext);
visitor.visit(rootContext);
Assertions.assertEquals("t1", visitorSqlContext.tableName);
Assertions.assertEquals(Arrays.asList("name1", "name2"), visitorSqlContext.getInsertColumnNames().stream().map(insert -> {
return insert.getInsertColumnName();
}).collect(Collectors.toList()));
Assertions.assertEquals(1, visitorSqlContext.insertRows);
Assertions.assertEquals(Arrays.asList("name1", "12"), visitorSqlContext.getInsertForValColumnNames().get(0));
}
/**
* Insert recognizer test 3.
*/
@Test
public void insertRecognizerTest_3() {
String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2'), ('name3', 'name4'), ('name5', 'name6')";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext visitorSqlContext = new MySqlContext();
InsertStatementSqlVisitor visitor = new InsertStatementSqlVisitor(visitorSqlContext);
visitor.visit(rootContext);
Assertions.assertEquals("t1", visitorSqlContext.tableName);
Assertions.assertEquals("name2", visitorSqlContext.getInsertColumnNames().get(1).getInsertColumnName());
Integer insertRows = visitorSqlContext.insertRows;
Assertions.assertEquals(3, insertRows);
Assertions.assertEquals(Arrays.asList("name1", "name2"), visitorSqlContext.getInsertForValColumnNames().get(0));
Assertions.assertEquals(Arrays.asList("name3", "name4"), visitorSqlContext.getInsertForValColumnNames().get(1));
Assertions.assertEquals(Arrays.asList("name5", "name6"), visitorSqlContext.getInsertForValColumnNames().get(2));
}
}

View File

@@ -0,0 +1,218 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.listener.SelectSpecificationSqlListener;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author houzhi
* @date 2020-7-9
* @description
*/
public class MySQLSelectForUpdateRecognizerForListenerTest {
/**
* base statementSql visitor test
*/
private String baseStatementSqlVisitor(String sql) {
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.SqlStatementContext sqlStatementContext = parser.sqlStatement();
StatementSqlVisitor sqlToStringVisitor = new StatementSqlVisitor();
return sqlToStringVisitor.visit(sqlStatementContext).toString();
}
/**
* Select for update recognizer test 0.
*/
@Test
public void selectForUpdateRecognizerTest_0() {
String sql = "SELECT a FROM t1 b WHERE b.id = d FOR UPDATE";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext listenerSqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new SelectSpecificationSqlListener(listenerSqlContext), rootContext);
Assertions.assertEquals("t1", listenerSqlContext.getTableName());
Assertions.assertEquals("b.id = d", listenerSqlContext.getWhereCondition());
Assertions.assertEquals("b", listenerSqlContext.getTableAlias());
}
/**
* Select for update recognizer test 1.
*/
@Test
public void selectForUpdateRecognizerTest_1() {
String sql = "SELECT name,age,phone FROM t1 WHERE id = 'id1' FOR UPDATE";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext listenerSqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new SelectSpecificationSqlListener(listenerSqlContext), rootContext);
Assertions.assertEquals("t1", listenerSqlContext.getTableName());
Assertions.assertEquals("phone", listenerSqlContext.getQueryColumnNames().get(2).getColumnName());
Assertions.assertEquals("id = 'id1'", listenerSqlContext.getWhereCondition());
}
/**
* Select for update recognizer test 1.
*/
@Test
public void selectForUpdateRecognizerTest_2() {
String sql = "SELECT name,age,phone FROM t2 WHERE id = 'id'FOR UPDATE";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new SelectSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t2", mySqlContext.getTableName());
Assertions.assertEquals("phone", mySqlContext.getQueryColumnNames().get(2).getColumnName());
Assertions.assertEquals("id = 'id'", mySqlContext.getWhereCondition());
Assertions.assertEquals("id", mySqlContext.getQueryWhereColumnNames().get(0).getQueryWhereColumnName());
Assertions.assertEquals("'id'", mySqlContext.getQueryWhereValColumnNames().get(0).getQueryWhereValColumnName());
}
/**
* Select for update recognizer test 1.
*/
@Test
public void selectForUpdateRecognizerTest_3() {
String sql = "SELECT name,phone FROM t1 WHERE id = 1 and username = '11' and age = 'a' or hz = '1' or aa = 1 FOR UPDATE";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new SelectSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("name", mySqlContext.getQueryColumnNames().get(0).getColumnName());
Assertions.assertEquals("username", mySqlContext.getQueryWhereColumnNames().get(1).getQueryWhereColumnName());
Assertions.assertEquals("'a'", mySqlContext.getQueryWhereValColumnNames().get(2).getQueryWhereValColumnName());
Assertions.assertEquals("id = 1 and username = '11' and age = 'a' or hz = '1' or aa = 1", mySqlContext.getWhereCondition());
}
/**
* Select for update recognizer test 4.
*/
@Test
public void selectForUpdateRecognizerTest_4() {
String sql = "SELECT name1, name2 FROM t1 WHERE id IN (100,101) FOR UPDATE";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new SelectSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("name1", mySqlContext.getQueryColumnNames().get(0).getColumnName());
Assertions.assertEquals("id", mySqlContext.getQueryWhereColumnNames().get(0).getQueryWhereColumnName());
Assertions.assertEquals("101", mySqlContext.getQueryWhereValColumnNames().get(1).getQueryWhereValColumnName());
Assertions.assertEquals("id IN (100,101)", mySqlContext.getWhereCondition());
}
/**
* Select for update recognizer test 5.
*/
@Test
public void selectForUpdateRecognizerTest_5() {
String sql = "SELECT name1, name2 FROM t1 WHERE name = 1 and id between 2 and 3 or img = '11' FOR UPDATE";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new SelectSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("name1", mySqlContext.getQueryColumnNames().get(0).getColumnName());
Assertions.assertEquals("id", mySqlContext.getQueryWhereColumnNames().get(1).getQueryWhereColumnName());
Assertions.assertEquals("3", mySqlContext.getQueryWhereValColumnNames().get(2).getQueryWhereValColumnName());
Assertions.assertEquals("name = 1 and id between 2 and 3 or img = '11'", mySqlContext.getWhereCondition());
}
}

View File

@@ -0,0 +1,190 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.antlr;
import io.seata.sqlparser.antlr.mysql.MySqlContext;
import io.seata.sqlparser.antlr.mysql.listener.UpdateSpecificationSqlListener;
import io.seata.sqlparser.antlr.mysql.parser.MySqlLexer;
import io.seata.sqlparser.antlr.mysql.parser.MySqlParser;
import io.seata.sqlparser.antlr.mysql.stream.ANTLRNoCaseStringStream;
import io.seata.sqlparser.antlr.mysql.visit.StatementSqlVisitor;
import org.antlr.v4.runtime.CommonTokenStream;
import org.antlr.v4.runtime.tree.ParseTreeWalker;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* The type My sql update recognizer test.
*/
public class MySQLUpdateRecognizerTest {
/**
* base statementSql visitor test
*/
private String baseStatementSqlVisitor(String sql) {
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.SqlStatementContext sqlStatementContext = parser.sqlStatement();
StatementSqlVisitor sqlToStringVisitor = new StatementSqlVisitor();
return sqlToStringVisitor.visit(sqlStatementContext).toString();
}
/**
* Update recognizer test 0.
*/
@Test
public void updateRecognizerTest_0() {
String sql = "UPDATE t1 a SET a.name = 'name1' WHERE a.id = 'id1'";
String visitorText = baseStatementSqlVisitor(sql);
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(visitorText));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new UpdateSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals(1, mySqlContext.getUpdateForValues().size());
Assertions.assertEquals("a.id", mySqlContext.getUpdateForWhereColumnNames().get(0).getUpdateWhereColumnName());
Assertions.assertEquals("a.name", mySqlContext.getUpdateFoColumnNames().get(0).getUpdateColumn());
Assertions.assertEquals("a.id = 'id1'", mySqlContext.getWhereCondition());
Assertions.assertEquals("a", mySqlContext.getTableAlias());
}
/**
* Update recognizer test 1.
*/
@Test
public void updateRecognizerTest_1() {
String sql = "UPDATE t1 SET name1 = name1, name2 = name2 WHERE id = 'id1'";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new UpdateSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("name1", mySqlContext.getUpdateFoColumnNames().get(0).getUpdateColumn());
Assertions.assertEquals("name1", mySqlContext.getUpdateForValues().get(0).getUpdateValue());
Assertions.assertEquals("name2", mySqlContext.getUpdateFoColumnNames().get(1).getUpdateColumn());
Assertions.assertEquals("name2", mySqlContext.getUpdateForValues().get(1).getUpdateValue());
Assertions.assertEquals("id = 'id1'", mySqlContext.getWhereCondition());
}
/**
* Update recognizer test 2.
*/
@Test
public void updateRecognizerTest_2() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = ?";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new UpdateSpecificationSqlListener(mySqlContext), rootContext);
List<MySqlContext.SQL> updateForWhereValColumnNames = mySqlContext.getUpdateForWhereValColumnNames();
System.out.println(updateForWhereValColumnNames);
Assertions.assertEquals("?", mySqlContext.getUpdateForWhereValColumnNames().get(0).getUpdateWhereValColumnName());
Assertions.assertEquals("name1", mySqlContext.getUpdateFoColumnNames().get(0).getUpdateColumn());
Assertions.assertEquals("name2", mySqlContext.getUpdateFoColumnNames().get(1).getUpdateColumn());
Assertions.assertEquals("id = ?", mySqlContext.getWhereCondition());
}
/**
* Update recognizer test 3.
*/
@Test
public void updateRecognizerTest_3() {
String sql = "UPDATE t1 as t SET t.name1 = 'name1', t.name2 = 'name2' WHERE id in (1, 2)";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new UpdateSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("1", mySqlContext.getUpdateForWhereValColumnNames().get(0).getUpdateWhereValColumnName());
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("t.name1", mySqlContext.getUpdateFoColumnNames().get(0).getUpdateColumn());
Assertions.assertEquals("'name1'", mySqlContext.getUpdateForValues().get(0).getUpdateValue());
Assertions.assertEquals("t.name2", mySqlContext.getUpdateFoColumnNames().get(1).getUpdateColumn());
Assertions.assertEquals("id in (1,2)", mySqlContext.getWhereCondition());
Assertions.assertEquals("t", mySqlContext.getTableAlias());
}
/**
* Update recognizer test 5.
*/
@Test
public void updateRecognizerTest_5() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id between 1 and 2";
MySqlLexer lexer = new MySqlLexer(new ANTLRNoCaseStringStream(sql));
CommonTokenStream tokenStream = new CommonTokenStream(lexer);
MySqlParser parser = new MySqlParser(tokenStream);
MySqlParser.RootContext rootContext = parser.root();
MySqlContext mySqlContext = new MySqlContext();
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new UpdateSpecificationSqlListener(mySqlContext), rootContext);
Assertions.assertEquals("t1", mySqlContext.getTableName());
Assertions.assertEquals("name1", mySqlContext.getUpdateFoColumnNames().get(0).getUpdateColumn());
Assertions.assertEquals("'name1'", mySqlContext.getUpdateForValues().get(0).getUpdateValue());
Assertions.assertEquals("name2", mySqlContext.getUpdateFoColumnNames().get(1).getUpdateColumn());
Assertions.assertEquals("2", mySqlContext.getUpdateForWhereValColumnNames().get(1).getUpdateWhereValColumnName());
Assertions.assertEquals("id between 1 and 2", mySqlContext.getWhereCondition());
}
}

View File

@@ -0,0 +1,34 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2019 Seata.io Group.
~
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.seata</groupId>
<artifactId>seata-sqlparser</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>seata-sqlparser-core</artifactId>
<name>seata-sqlparser-core ${project.version}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>seata-common</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>

View File

@@ -0,0 +1,34 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
import java.util.ArrayList;
import java.util.Map;
/**
* The interface Parameters holder.
*
* @author sharajava
*/
public interface ParametersHolder {
/**
* Get parameters array list [ ].
*
* @return the array list [ ]
*/
Map<Integer,ArrayList<Object>> getParameters();
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
/**
* The interface Sql delete recognizer.
*
* @author sharajava
*/
public interface SQLDeleteRecognizer extends WhereRecognizer {
}

View File

@@ -0,0 +1,48 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
import java.util.Collection;
import java.util.List;
/**
* The interface Sql insert recognizer.
*
* @author sharajava
*/
public interface SQLInsertRecognizer extends SQLRecognizer {
/**
* insert columns is empty.
* @return true: empty. false: not empty.
*/
boolean insertColumnsIsEmpty();
/**
* Gets insert columns.
*
* @return the insert columns
*/
List<String> getInsertColumns();
/**
* Gets insert rows.
*
* @param primaryKeyIndex insert sql primary key index.
* @return the insert rows
*/
List<List<Object>> getInsertRows(Collection<Integer> primaryKeyIndex);
}

View File

@@ -0,0 +1,51 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
/**
* The type Sql parsing exception.
*
* @author sharajava
*/
public class SQLParsingException extends RuntimeException {
/**
* Instantiates a new Sql parsing exception.
*
* @param message the message
*/
public SQLParsingException(String message) {
super(message);
}
/**
* Instantiates a new Sql parsing exception.
*
* @param message the message
* @param cause the cause
*/
public SQLParsingException(String message, Throwable cause) {
super(message, cause);
}
/**
* Instantiates a new Sql parsing exception.
*
* @param cause the cause
*/
public SQLParsingException(Throwable cause) {
super(cause);
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
/**
* The interface Sql recognizer.
*
* @author sharajava
*/
public interface SQLRecognizer {
/**
* Type of the SQL. INSERT/UPDATE/DELETE ...
*
* @return sql type
*/
SQLType getSQLType();
/**
* TableRecords source related in the SQL, including alias if any.
* SELECT id, name FROM user u WHERE ...
* Alias should be 'u' for this SQL.
*
* @return table source.
*/
String getTableAlias();
/**
* TableRecords name related in the SQL.
* SELECT id, name FROM user u WHERE ...
* TableRecords name should be 'user' for this SQL, without alias 'u'.
*
* @return table name.
* @see #getTableAlias() #getTableAlias()#getTableAlias()
*/
String getTableName();
/**
* Return the original SQL input by the upper application.
*
* @return The original SQL.
*/
String getOriginalSQL();
}

View File

@@ -0,0 +1,25 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
import java.util.List;
/**
* @author ggndnn
*/
public interface SQLRecognizerFactory {
List<SQLRecognizer> create(String sql, String dbType);
}

View File

@@ -0,0 +1,24 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
/**
* The interface Sql select recognizer.
*
* @author sharajava
*/
public interface SQLSelectRecognizer extends WhereRecognizer {
}

View File

@@ -0,0 +1,245 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
/**
* The enum Sql type.
*
* @author sharajava
*/
public enum SQLType {
/**
* Select sql type.
*/
SELECT(0),
/**
* Insert sql type.
*/
INSERT(1),
/**
* Update sql type.
*/
UPDATE(2),
/**
* Delete sql type.
*/
DELETE(3),
/**
* Select for update sql type.
*/
SELECT_FOR_UPDATE(4),
/**
* Replace sql type.
*/
REPLACE(5),
/**
* Truncate sql type.
*/
TRUNCATE(6),
/**
* Create sql type.
*/
CREATE(7),
/**
* Drop sql type.
*/
DROP(8),
/**
* Load sql type.
*/
LOAD(9),
/**
* Merge sql type.
*/
MERGE(10),
/**
* Show sql type.
*/
SHOW(11),
/**
* Alter sql type.
*/
ALTER(12),
/**
* Rename sql type.
*/
RENAME(13),
/**
* Dump sql type.
*/
DUMP(14),
/**
* Debug sql type.
*/
DEBUG(15),
/**
* Explain sql type.
*/
EXPLAIN(16),
/**
* Stored procedure
*/
PROCEDURE(17),
/**
* Desc sql type.
*/
DESC(18),
/**
* Select last insert id
*/
SELECT_LAST_INSERT_ID(19),
/**
* Select without table sql type.
*/
SELECT_WITHOUT_TABLE(20),
/**
* Create sequence sql type.
*/
CREATE_SEQUENCE(21),
/**
* Show sequences sql type.
*/
SHOW_SEQUENCES(22),
/**
* Get sequence sql type.
*/
GET_SEQUENCE(23),
/**
* Alter sequence sql type.
*/
ALTER_SEQUENCE(24),
/**
* Drop sequence sql type.
*/
DROP_SEQUENCE(25),
/**
* Tddl show sql type.
*/
TDDL_SHOW(26),
/**
* Set sql type.
*/
SET(27),
/**
* Reload sql type.
*/
RELOAD(28),
/**
* Select union sql type.
*/
SELECT_UNION(29),
/**
* Create table sql type.
*/
CREATE_TABLE(30),
/**
* Drop table sql type.
*/
DROP_TABLE(31),
/**
* Alter table sql type.
*/
ALTER_TABLE(32),
/**
* Save point sql type.
*/
SAVE_POINT(33),
/**
* Select from update sql type.
*/
SELECT_FROM_UPDATE(34),
/**
* multi delete/update
*/
MULTI_DELETE(35),
/**
* Multi update sql type.
*/
MULTI_UPDATE(36),
/**
* Create index sql type.
*/
CREATE_INDEX(37),
/**
* Drop index sql type.
*/
DROP_INDEX(38),
/**
* Kill sql type.
*/
KILL(39),
/**
* Release dblock sql type.
*/
RELEASE_DBLOCK(40),
/**
* Lock tables sql type.
*/
LOCK_TABLES(41),
/**
* Unlock tables sql type.
*/
UNLOCK_TABLES(42),
/**
* Check table sql type.
*/
CHECK_TABLE(43),
/**
* Select found rows.
*/
SELECT_FOUND_ROWS(44),
/**
* Insert ignore sql type.
*/
INSERT_IGNORE(101),
/**
* Insert on duplicate update sql type.
*/
INSERT_ON_DUPLICATE_UPDATE(102);
private int i;
private SQLType(int i) {
this.i = i;
}
/**
* Value int.
*
* @return the int
*/
public int value() {
return this.i;
}
/**
* Value of sql type.
*
* @param i the
* @return the sql type
*/
public static SQLType valueOf(int i) {
for (SQLType t : values()) {
if (t.value() == i) {
return t;
}
}
throw new IllegalArgumentException("Invalid SQLType:" + i);
}
}

View File

@@ -0,0 +1,40 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
import java.util.List;
/**
* The interface Sql update recognizer.
*
* @author sharajava
*/
public interface SQLUpdateRecognizer extends WhereRecognizer {
/**
* Gets update columns.
*
* @return the update columns
*/
List<String> getUpdateColumns();
/**
* Gets update values.
*
* @return the update values
*/
List<Object> getUpdateValues();
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
/**
* @author ggndnn
*/
public interface SqlParserType {
/**
* The constant SQL_PARSER_TYPE_DRUID.
*/
String SQL_PARSER_TYPE_DRUID = "druid";
/**
* The constant SQL_PARSER_TYPE_ANTLR.
*/
String SQL_PARSER_TYPE_ANTLR = "antlr";
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser;
import java.util.ArrayList;
import java.util.List;
/**
* The interface Where recognizer.
*
* @author sharajava
*/
public interface WhereRecognizer extends SQLRecognizer {
/**
* Gets where condition.
*
* @param parametersHolder the parameters holder
* @param paramAppenderList the param appender list
* @return the where condition
*/
String getWhereCondition(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList);
/**
* Gets where condition.
*
* @return the where condition
*/
String getWhereCondition();
/**
* Return the limit SQL
*
* @param parametersHolder the parameters holder
* @param paramAppenderList the param appender list
* @return The limit SQL.
*/
default String getLimit(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
return null;
}
/**
* Return the order by SQL
*
* @return The order by SQL.
*/
default String getOrderBy() {
return null;
}
}

View File

@@ -0,0 +1,36 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
import java.sql.SQLException;
import java.util.List;
/**
* The default expr able.
*
* @author jsbxyyx
*/
public interface Defaultable {
/**
* get primary key values by default keyword.
*
* @return pk values by default
* @throws SQLException the sql exception
*/
List<Object> getPkValuesByDefault() throws SQLException;
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
/**
* The not placeholder expression.
* @author jsbxyyx
*/
public class NotPlaceholderExpr {
private static NotPlaceholderExpr instance = new NotPlaceholderExpr();
/**
* Get NotPlaceholder.
*
* @return the NotPlaceholder
*/
public static NotPlaceholderExpr get() {
return instance;
}
private NotPlaceholderExpr() {
}
@Override
public String toString() {
return "NOT_PLACEHOLDER";
}
}

View File

@@ -0,0 +1,42 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
/**
* The type Null.
*
* @author sharajava
*/
public class Null {
private static Null instance = new Null();
/**
* Get null.
*
* @return the null
*/
public static Null get() {
return instance;
}
private Null() {
}
@Override
public String toString() {
return "NULL";
}
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
/**
* The sequence able.
*
* @author jsbxyyx
*/
public interface Sequenceable {
/**
* get sequence sql.
*
* @param expr the expr
* @return sequence sql
*/
String getSequenceSql(SqlSequenceExpr expr);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
/**
* sql default expression
* @author jsbxyyx
*/
public class SqlDefaultExpr {
private static SqlDefaultExpr instance = new SqlDefaultExpr();
/**
* Get SqlDefaultExpr.
*
* @return the SqlDefaultExpr
*/
public static SqlDefaultExpr get() {
return instance;
}
private SqlDefaultExpr() {
}
@Override
public String toString() {
return "DEFAULT";
}
}

View File

@@ -0,0 +1,44 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
/**
* TODO
* sql method invoke expression
* @author jsbxyyx
*/
public class SqlMethodExpr {
private static SqlMethodExpr instance = new SqlMethodExpr();
/**
* Get SqlMethodExpr.
*
* @return the SqlMethodExpr
*/
public static SqlMethodExpr get() {
return instance;
}
private SqlMethodExpr() {
}
@Override
public String toString() {
return "SQL_METHOD";
}
}

View File

@@ -0,0 +1,50 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.struct;
/**
* TODO
* sql sequence expression
* @author jsbxyyx
*/
public class SqlSequenceExpr {
private String sequence;
private String function;
public SqlSequenceExpr() {}
public SqlSequenceExpr(String sequence, String function) {
this.sequence = sequence;
this.function = function;
}
public String getSequence() {
return sequence;
}
public void setSequence(String sequence) {
this.sequence = sequence;
}
public String getFunction() {
return function;
}
public void setFunction(String function) {
this.function = function;
}
}

View File

@@ -0,0 +1,23 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.util;
/**
* @author ggndnn
*/
public interface DbTypeParser {
String parseFromJdbcUrl(String jdbcUrl);
}

View File

@@ -0,0 +1,33 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.util;
/**
* @author ggndnn
*/
public interface JdbcConstants {
String ORACLE = "oracle";
String MYSQL = "mysql";
String DB2 = "db2";
String H2 = "h2";
String MARIADB = "mariadb";
String POSTGRESQL = "postgresql";
}

View File

@@ -0,0 +1,68 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
~ Copyright 1999-2019 Seata.io Group.
~
~ 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.
-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<groupId>io.seata</groupId>
<artifactId>seata-sqlparser</artifactId>
<version>${revision}</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>seata-sqlparser-druid</artifactId>
<name>seata-sqlparser-druid ${project.version}</name>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>seata-sqlparser-core</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.0.2</version>
<executions>
<execution>
<id>copy-druid</id>
<phase>compile</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<includeGroupIds>com.alibaba</includeGroupIds>
<includeArtifactIds>druid</includeArtifactIds>
<stripVersion>true</stripVersion>
<outputDirectory>
${project.build.outputDirectory}/lib/sqlparser
</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>

View File

@@ -0,0 +1,77 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLBetweenExpr;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLExistsExpr;
import com.alibaba.druid.sql.ast.expr.SQLInListExpr;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import io.seata.sqlparser.SQLRecognizer;
/**
* The type Base recognizer.
*
* @author sharajava
*/
public abstract class BaseRecognizer implements SQLRecognizer {
/**
* The type V marker.
*/
public static class VMarker {
@Override
public String toString() {
return "?";
}
}
/**
* The Original sql.
*/
protected String originalSQL;
/**
* Instantiates a new Base recognizer.
*
* @param originalSQL the original sql
*/
public BaseRecognizer(String originalSQL) {
this.originalSQL = originalSQL;
}
public void executeVisit(SQLExpr where, SQLASTVisitor visitor) {
if (where instanceof SQLBinaryOpExpr) {
visitor.visit((SQLBinaryOpExpr) where);
} else if (where instanceof SQLInListExpr) {
visitor.visit((SQLInListExpr) where);
} else if (where instanceof SQLBetweenExpr) {
visitor.visit((SQLBetweenExpr) where);
} else if (where instanceof SQLExistsExpr) {
visitor.visit((SQLExistsExpr) where);
} else {
throw new IllegalArgumentException("unexpected WHERE expr: " + where.getClass().getSimpleName());
}
}
@Override
public String getOriginalSQL() {
return originalSQL;
}
}

View File

@@ -0,0 +1,102 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.URL;
import java.security.CodeSource;
/**
* @author ggndnn
*/
class DefaultDruidLoader implements DruidLoader {
/**
* Default druid location in classpath
*/
private final static String DRUID_LOCATION = "lib/sqlparser/druid.jar";
private final static DefaultDruidLoader DRUID_LOADER = new DefaultDruidLoader(DRUID_LOCATION);
private final URL druidUrl;
/**
* @param druidLocation druid location in classpath
*/
private DefaultDruidLoader(String druidLocation) {
if (druidLocation == null) {
druidLocation = DRUID_LOCATION;
}
URL url = DefaultDruidLoader.class.getClassLoader().getResource(druidLocation);
if (url != null) {
try {
// extract druid.jar to temp file
// TODO use URLStreamHandler to handle nested jar loading in the future
File tempFile = File.createTempFile("seata", "sqlparser");
try (InputStream input = url.openStream(); OutputStream output = new FileOutputStream(tempFile)) {
byte[] buf = new byte[1024];
while (true) {
int readCnt = input.read(buf);
if (readCnt < 0) {
break;
}
output.write(buf, 0, readCnt);
}
output.flush();
}
tempFile.deleteOnExit();
druidUrl = tempFile.toURI().toURL();
} catch (Exception e) {
throw new RuntimeException(e);
}
} else {
// try to find druid in class code source if it's not in classpath which should usually happen in unit test
Class<?> clazz = null;
try {
clazz = DefaultDruidLoader.class.getClassLoader().loadClass("com.alibaba.druid.util.StringUtils");
} catch (ClassNotFoundException ignore) {
}
if (clazz != null) {
CodeSource cs = clazz.getProtectionDomain().getCodeSource();
if (cs == null) {
throw new IllegalStateException("Can not find druid code source");
}
druidUrl = cs.getLocation();
} else {
druidUrl = null;
}
}
}
/**
* Get default druid loader
*
* @return default druid loader
*/
static DruidLoader get() {
return DRUID_LOADER;
}
@Override
public URL getEmbeddedDruidLocation() {
if (druidUrl == null) {
throw new IllegalStateException("Can not find embedded druid");
}
return druidUrl;
}
}

View File

@@ -0,0 +1,29 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.util.JdbcUtils;
import io.seata.sqlparser.util.DbTypeParser;
/**
* @author ggndnn
*/
class DruidDbTypeParserImpl implements DbTypeParser {
@Override
public String parseFromJdbcUrl(String jdbcUrl) {
return JdbcUtils.getDbType(jdbcUrl, null);
}
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SqlParserType;
import io.seata.sqlparser.util.DbTypeParser;
import java.lang.reflect.Constructor;
/**
* @author ggndnn
*/
@LoadLevel(name = SqlParserType.SQL_PARSER_TYPE_DRUID)
public class DruidDelegatingDbTypeParser implements DbTypeParser {
private DbTypeParser dbTypeParserImpl;
public DruidDelegatingDbTypeParser() {
setClassLoader(DruidIsolationClassLoader.get());
}
/**
* Only for unit test
*
* @param classLoader classLoader
*/
void setClassLoader(ClassLoader classLoader) {
try {
Class<?> druidDbTypeParserImplClass = classLoader.loadClass("io.seata.sqlparser.druid.DruidDbTypeParserImpl");
Constructor<?> implConstructor = druidDbTypeParserImplClass.getDeclaredConstructor();
implConstructor.setAccessible(true);
try {
dbTypeParserImpl = (DbTypeParser) implConstructor.newInstance();
} finally {
implConstructor.setAccessible(false);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Override
public String parseFromJdbcUrl(String jdbcUrl) {
return dbTypeParserImpl.parseFromJdbcUrl(jdbcUrl);
}
}

View File

@@ -0,0 +1,62 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import io.seata.sqlparser.SqlParserType;
import java.lang.reflect.Constructor;
import java.util.List;
/**
* @author ggndnn
*/
@LoadLevel(name = SqlParserType.SQL_PARSER_TYPE_DRUID)
public class DruidDelegatingSQLRecognizerFactory implements SQLRecognizerFactory {
private volatile SQLRecognizerFactory recognizerFactoryImpl;
public DruidDelegatingSQLRecognizerFactory() {
setClassLoader(DruidIsolationClassLoader.get());
}
/**
* Only for unit test
*
* @param classLoader classLoader
*/
void setClassLoader(ClassLoader classLoader) {
try {
Class<?> recognizerFactoryImplClass = classLoader.loadClass("io.seata.sqlparser.druid.DruidSQLRecognizerFactoryImpl");
Constructor<?> implConstructor = recognizerFactoryImplClass.getDeclaredConstructor();
implConstructor.setAccessible(true);
try {
recognizerFactoryImpl = (SQLRecognizerFactory) implConstructor.newInstance();
} finally {
implConstructor.setAccessible(false);
}
} catch (Exception e) {
throw new SQLParsingException(e);
}
}
@Override
public List<SQLRecognizer> create(String sql, String dbType) {
return recognizerFactoryImpl.create(sql, dbType);
}
}

View File

@@ -0,0 +1,83 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.net.URL;
import java.net.URLClassLoader;
import java.security.CodeSource;
import java.util.ArrayList;
import java.util.List;
/**
* Used for druid isolation.
*
* @author ggndnn
*/
class DruidIsolationClassLoader extends URLClassLoader {
private final static String[] DRUID_CLASS_PREFIX = new String[]{"com.alibaba.druid.", "io.seata.sqlparser.druid."};
private final static DruidIsolationClassLoader INSTANCE = new DruidIsolationClassLoader(DefaultDruidLoader.get());
DruidIsolationClassLoader(DruidLoader druidLoader) {
super(getDruidUrls(druidLoader), DruidIsolationClassLoader.class.getClassLoader());
}
@Override
protected Class<?> loadClass(String name, boolean resolve) throws ClassNotFoundException {
for (String prefix : DRUID_CLASS_PREFIX) {
if (name.startsWith(prefix)) {
return loadInternalClass(name, resolve);
}
}
return super.loadClass(name, resolve);
}
private Class<?> loadInternalClass(String name, boolean resolve) throws ClassNotFoundException {
Class<?> c;
synchronized (getClassLoadingLock(name)) {
c = findLoadedClass(name);
if (c == null) {
c = findClass(name);
}
}
if (c == null) {
throw new ClassNotFoundException(name);
}
if (resolve) {
resolveClass(c);
}
return c;
}
private static URL[] getDruidUrls(DruidLoader druidLoader) {
List<URL> urls = new ArrayList<>();
urls.add(findClassLocation(DruidIsolationClassLoader.class));
urls.add(druidLoader.getEmbeddedDruidLocation());
return urls.toArray(new URL[0]);
}
private static URL findClassLocation(Class<?> clazz) {
CodeSource cs = clazz.getProtectionDomain().getCodeSource();
if (cs == null) {
throw new IllegalStateException("Not a normal druid startup environment");
}
return cs.getLocation();
}
static DruidIsolationClassLoader get() {
return INSTANCE;
}
}

View File

@@ -0,0 +1,30 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.net.URL;
/**
* ggndnn
*/
interface DruidLoader {
/**
* Gets embedded druid.jar
*
* @return embedded druid.jar url
*/
URL getEmbeddedDruidLocation();
}

View File

@@ -0,0 +1,71 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import io.seata.common.util.CollectionUtils;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import java.util.ArrayList;
import java.util.List;
/**
* DruidSQLRecognizerFactoryImpl
*
* @author sharajava
* @author ggndnn
*/
class DruidSQLRecognizerFactoryImpl implements SQLRecognizerFactory {
@Override
public List<SQLRecognizer> create(String sql, String dbType) {
List<SQLStatement> asts = SQLUtils.parseStatements(sql, dbType);
if (CollectionUtils.isEmpty(asts)) {
throw new UnsupportedOperationException("Unsupported SQL: " + sql);
}
if (asts.size() > 1 && !(asts.stream().allMatch(statement -> statement instanceof SQLUpdateStatement)
|| asts.stream().allMatch(statement -> statement instanceof SQLDeleteStatement))) {
throw new UnsupportedOperationException("ONLY SUPPORT SAME TYPE (UPDATE OR DELETE) MULTI SQL -" + sql);
}
List<SQLRecognizer> recognizers = null;
SQLRecognizer recognizer = null;
for (SQLStatement ast : asts) {
SQLOperateRecognizerHolder recognizerHolder =
SQLOperateRecognizerHolderFactory.getSQLRecognizerHolder(dbType.toLowerCase());
if (ast instanceof SQLInsertStatement) {
recognizer = recognizerHolder.getInsertRecognizer(sql, ast);
} else if (ast instanceof SQLUpdateStatement) {
recognizer = recognizerHolder.getUpdateRecognizer(sql, ast);
} else if (ast instanceof SQLDeleteStatement) {
recognizer = recognizerHolder.getDeleteRecognizer(sql, ast);
} else if (ast instanceof SQLSelectStatement) {
recognizer = recognizerHolder.getSelectForUpdateRecognizer(sql, ast);
}
if (recognizer != null) {
if (recognizers == null) {
recognizers = new ArrayList<>();
}
recognizers.add(recognizer);
}
}
return recognizers;
}
}

View File

@@ -0,0 +1,64 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.sql.ast.SQLStatement;
import io.seata.sqlparser.SQLRecognizer;
/**
* The interface SQLOperateRecognizerHolder
*
* @author: Zhibei Hao
*/
public interface SQLOperateRecognizerHolder {
/**
* Get delete recognizer
*
* @param sql the sql
* @param ast the ast
* @return the delete recognizer
*/
SQLRecognizer getDeleteRecognizer(String sql, SQLStatement ast);
/**
* Get insert recognizer
*
* @param sql the sql
* @param ast the ast
* @return the insert recognizer
*/
SQLRecognizer getInsertRecognizer(String sql, SQLStatement ast);
/**
* Get update recognizer
*
* @param sql the sql
* @param ast the ast
* @return the update recognizer
*/
SQLRecognizer getUpdateRecognizer(String sql, SQLStatement ast);
/**
* Get SelectForUpdate recognizer
*
* @param sql the sql
* @param ast the ast
* @return the SelectForUpdate recognizer
*/
SQLRecognizer getSelectForUpdateRecognizer(String sql, SQLStatement ast);
}

View File

@@ -0,0 +1,43 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import io.seata.common.loader.EnhancedServiceLoader;
import io.seata.common.util.CollectionUtils;
/**
* The SQLOperateRecognizerHolderFactory
*
* @author: Zhibei Hao
*/
public class SQLOperateRecognizerHolderFactory {
private static final Map<String, SQLOperateRecognizerHolder> RECOGNIZER_HOLDER_MAP = new ConcurrentHashMap<>();
/**
* get SQLOperateRecognizer by db type
*
* @param dbType the db type
* @return the SQLOperateRecognizer
*/
public static SQLOperateRecognizerHolder getSQLRecognizerHolder(String dbType) {
return CollectionUtils.computeIfAbsent(RECOGNIZER_HOLDER_MAP, dbType,
key -> EnhancedServiceLoader.load(SQLOperateRecognizerHolder.class, dbType, SQLOperateRecognizerHolderFactory.class.getClassLoader()));
}
}

View File

@@ -0,0 +1,165 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.mysql;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLLimit;
import com.alibaba.druid.sql.ast.SQLOrderBy;
import com.alibaba.druid.sql.ast.SQLOrderingSpecification;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLIntegerExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLSelectOrderByItem;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import io.seata.common.util.StringUtils;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.druid.BaseRecognizer;
import io.seata.sqlparser.struct.Null;
/**
* @author will
*/
public abstract class BaseMySQLRecognizer extends BaseRecognizer {
/**
* Instantiates a new mysql base recognizer
*
* @param originalSql the original sql
*/
public BaseMySQLRecognizer(String originalSql) {
super(originalSql);
}
public MySqlOutputVisitor createOutputVisitor(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList,
final StringBuilder sb) {
return new MySqlOutputVisitor(sb) {
@Override
public boolean visit(SQLVariantRefExpr x) {
if ("?".equals(x.getName())) {
ArrayList<Object> oneParamValues = parametersHolder.getParameters().get(x.getIndex() + 1);
if (paramAppenderList.isEmpty()) {
oneParamValues.forEach(t -> paramAppenderList.add(new ArrayList<>()));
}
for (int i = 0; i < oneParamValues.size(); i++) {
Object o = oneParamValues.get(i);
paramAppenderList.get(i).add(o instanceof Null ? null : o);
}
}
return super.visit(x);
}
};
}
public String getWhereCondition(SQLExpr where, final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
if (Objects.isNull(where)) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
executeVisit(where, createOutputVisitor(parametersHolder, paramAppenderList, sb));
return sb.toString();
}
public String getWhereCondition(SQLExpr where) {
if (Objects.isNull(where)) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
executeVisit(where, new MySqlOutputVisitor(sb));
return sb.toString();
}
protected String getLimit(SQLStatement sqlStatement, SQLType sqlType, ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
SQLLimit limit = null;
if (SQLType.UPDATE == sqlType) {
limit = ((MySqlUpdateStatement)sqlStatement).getLimit();
} else if (SQLType.DELETE == sqlType) {
limit = ((MySqlDeleteStatement)sqlStatement).getLimit();
}
if (limit != null) {
StringBuilder builder = new StringBuilder(" LIMIT ");
SQLIntegerExpr expr;
if (limit.getOffset() != null) {
if (limit.getOffset() instanceof SQLVariantRefExpr) {
builder.append("?,");
Map<Integer, ArrayList<Object>> parameters = parametersHolder.getParameters();
paramAppenderList.add(parameters.get(parameters.size() - 1));
} else {
expr = (SQLIntegerExpr)limit.getOffset();
builder.append(expr.getNumber()).append(",");
}
}
if (limit.getRowCount() != null) {
if (limit.getRowCount() instanceof SQLVariantRefExpr) {
builder.append("?");
Map<Integer, ArrayList<Object>> parameters = parametersHolder.getParameters();
paramAppenderList.add(parameters.get(parameters.size()));
} else {
expr = (SQLIntegerExpr)limit.getRowCount();
builder.append(expr.getNumber());
}
}
return builder.toString();
}
return null;
}
protected String getOrderBy(SQLStatement sqlStatement, SQLType sqlType) {
SQLOrderBy orderBy = null;
if (SQLType.UPDATE == sqlType) {
orderBy = ((MySqlUpdateStatement)sqlStatement).getOrderBy();
} else if (SQLType.DELETE == sqlType) {
orderBy = ((MySqlDeleteStatement)sqlStatement).getOrderBy();
}
if (orderBy != null) {
String space = " ";
String comma = ",";
StringBuilder builder = new StringBuilder(space).append("ORDER BY").append(space);
List<SQLSelectOrderByItem> items = orderBy.getItems();
for (int i = 0; i < items.size(); i++) {
SQLSelectOrderByItem item = items.get(i);
SQLIdentifierExpr expr = (SQLIdentifierExpr)item.getExpr();
builder.append(expr.getName());
SQLOrderingSpecification specification = item.getType();
if (specification != null) {
builder.append(space);
builder.append(specification.name);
}
if (i + 1 != items.size()) {
builder.append(comma);
}
}
return builder.toString();
}
return null;
}
}

View File

@@ -0,0 +1,123 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.mysql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import io.seata.common.exception.NotSupportYetException;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLDeleteRecognizer;
import io.seata.sqlparser.SQLType;
import java.util.ArrayList;
import java.util.List;
/**
* The type My sql delete recognizer.
*
* @author sharajava
*/
public class MySQLDeleteRecognizer extends BaseMySQLRecognizer implements SQLDeleteRecognizer {
private final MySqlDeleteStatement ast;
/**
* Instantiates a new My sql delete recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public MySQLDeleteRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (MySqlDeleteStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.DELETE;
}
@Override
public String getTableAlias() {
if (ast.getFrom() == null) {
return ast.getTableSource().getAlias();
}
return ast.getFrom().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
@Override
public boolean visit(SQLJoinTableSource x) {
throw new NotSupportYetException("not support the syntax of delete with join table");
}
};
SQLTableSource tableSource;
if (ast.getFrom() == null) {
tableSource = ast.getTableSource();
} else {
tableSource = ast.getFrom();
}
if (tableSource instanceof SQLExprTableSource) {
visitor.visit((SQLExprTableSource) tableSource);
} else if (tableSource instanceof SQLJoinTableSource) {
visitor.visit((SQLJoinTableSource) tableSource);
} else {
throw new NotSupportYetException("not support the syntax of delete with unknow");
}
return sb.toString();
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where);
}
@Override
public String getLimit(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
return super.getLimit(ast, getSQLType(), parametersHolder, paramAppenderList);
}
@Override
public String getOrderBy() {
return super.getOrderBy(ast, getSQLType());
}
}

View File

@@ -0,0 +1,138 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.mysql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import io.seata.common.util.CollectionUtils;
import io.seata.sqlparser.SQLInsertRecognizer;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.struct.NotPlaceholderExpr;
import io.seata.sqlparser.struct.Null;
import io.seata.sqlparser.struct.SqlMethodExpr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* The type My sql insert recognizer.
*
* @author sharajava
*/
public class MySQLInsertRecognizer extends BaseMySQLRecognizer implements SQLInsertRecognizer {
private final MySqlInsertStatement ast;
/**
* Instantiates a new My sql insert recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public MySQLInsertRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (MySqlInsertStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.INSERT;
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit(ast.getTableSource());
return sb.toString();
}
@Override
public boolean insertColumnsIsEmpty() {
return CollectionUtils.isEmpty(ast.getColumns());
}
@Override
public List<String> getInsertColumns() {
List<SQLExpr> columnSQLExprs = ast.getColumns();
if (columnSQLExprs.isEmpty()) {
// INSERT INTO ta VALUES (...), without fields clarified
return null;
}
List<String> list = new ArrayList<>(columnSQLExprs.size());
for (SQLExpr expr : columnSQLExprs) {
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr)expr).getName());
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public List<List<Object>> getInsertRows(Collection<Integer> primaryKeyIndex) {
List<SQLInsertStatement.ValuesClause> valuesClauses = ast.getValuesList();
List<List<Object>> rows = new ArrayList<>(valuesClauses.size());
for (SQLInsertStatement.ValuesClause valuesClause : valuesClauses) {
List<SQLExpr> exprs = valuesClause.getValues();
List<Object> row = new ArrayList<>(exprs.size());
rows.add(row);
for (int i = 0, len = exprs.size(); i < len; i++) {
SQLExpr expr = exprs.get(i);
if (expr instanceof SQLNullExpr) {
row.add(Null.get());
} else if (expr instanceof SQLValuableExpr) {
row.add(((SQLValuableExpr) expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
row.add(((SQLVariantRefExpr) expr).getName());
} else if (expr instanceof SQLMethodInvokeExpr) {
row.add(SqlMethodExpr.get());
} else {
if (primaryKeyIndex.contains(i)) {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
row.add(NotPlaceholderExpr.get());
}
}
}
return rows;
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.mysql;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.druid.SQLOperateRecognizerHolder;
import io.seata.sqlparser.util.JdbcConstants;
/**
* The class MySqlOperateRecognizerHolder
*
* @author: Zhibei Hao
*/
@LoadLevel(name = JdbcConstants.MYSQL)
public class MySQLOperateRecognizerHolder implements SQLOperateRecognizerHolder {
@Override
public SQLRecognizer getDeleteRecognizer(String sql, SQLStatement ast) {
return new MySQLDeleteRecognizer(sql, ast);
}
@Override
public SQLRecognizer getInsertRecognizer(String sql, SQLStatement ast) {
return new MySQLInsertRecognizer(sql, ast);
}
@Override
public SQLRecognizer getUpdateRecognizer(String sql, SQLStatement ast) {
return new MySQLUpdateRecognizer(sql, ast);
}
@Override
public SQLRecognizer getSelectForUpdateRecognizer(String sql, SQLStatement ast) {
if (((SQLSelectStatement) ast).getSelect().getFirstQueryBlock().isForUpdate()) {
return new MySQLSelectForUpdateRecognizer(sql, ast);
}
return null;
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.mysql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLSelectRecognizer;
import io.seata.sqlparser.SQLType;
import java.util.ArrayList;
import java.util.List;
/**
* The type My sql select for update recognizer.
*
* @author sharajava
*/
public class MySQLSelectForUpdateRecognizer extends BaseMySQLRecognizer implements SQLSelectRecognizer {
private final SQLSelectStatement ast;
/**
* Instantiates a new My sql select for update recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public MySQLSelectForUpdateRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (SQLSelectStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.SELECT_FOR_UPDATE;
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLExpr where = selectQueryBlock.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLExpr where = selectQueryBlock.getWhere();
return super.getWhereCondition(where);
}
private SQLSelectQueryBlock getSelect() {
SQLSelect select = ast.getSelect();
if (select == null) {
throw new SQLParsingException("should never happen!");
}
SQLSelectQueryBlock selectQueryBlock = select.getQueryBlock();
if (selectQueryBlock == null) {
throw new SQLParsingException("should never happen!");
}
return selectQueryBlock;
}
@Override
public String getTableAlias() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLTableSource tableSource = selectQueryBlock.getFrom();
return tableSource.getAlias();
}
@Override
public String getTableName() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLTableSource tableSource = selectQueryBlock.getFrom();
StringBuilder sb = new StringBuilder();
MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit((SQLExprTableSource)tableSource);
return sb.toString();
}
}

View File

@@ -0,0 +1,162 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.mysql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.dialect.mysql.ast.statement.MySqlUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.visitor.MySqlOutputVisitor;
import io.seata.common.exception.NotSupportYetException;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.SQLUpdateRecognizer;
import java.util.ArrayList;
import java.util.List;
/**
* The type My sql update recognizer.
*
* @author sharajava
*/
public class MySQLUpdateRecognizer extends BaseMySQLRecognizer implements SQLUpdateRecognizer {
private MySqlUpdateStatement ast;
/**
* Instantiates a new My sql update recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public MySQLUpdateRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (MySqlUpdateStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.UPDATE;
}
@Override
public List<String> getUpdateColumns() {
List<SQLUpdateSetItem> updateSetItems = ast.getItems();
List<String> list = new ArrayList<>(updateSetItems.size());
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
SQLExpr expr = updateSetItem.getColumn();
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr)expr).getName());
} else if (expr instanceof SQLPropertyExpr) {
// This is alias case, like UPDATE xxx_tbl a SET a.name = ? WHERE a.id = ?
SQLExpr owner = ((SQLPropertyExpr)expr).getOwner();
if (owner instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr)owner).getName() + "." + ((SQLPropertyExpr)expr).getName());
//This is table Field Full path, like update xxx_database.xxx_tbl set xxx_database.xxx_tbl.xxx_field...
} else if (((SQLPropertyExpr)expr).getOwnernName().split("\\.").length > 1) {
list.add(((SQLPropertyExpr)expr).getOwnernName() + "." + ((SQLPropertyExpr)expr).getName());
}
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public List<Object> getUpdateValues() {
List<SQLUpdateSetItem> updateSetItems = ast.getItems();
List<Object> list = new ArrayList<>(updateSetItems.size());
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
SQLExpr expr = updateSetItem.getValue();
if (expr instanceof SQLValuableExpr) {
list.add(((SQLValuableExpr)expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
list.add(new VMarker());
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where);
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
MySqlOutputVisitor visitor = new MySqlOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
@Override
public boolean visit(SQLJoinTableSource x) {
throw new NotSupportYetException("not support the syntax of update with join table");
}
};
SQLTableSource tableSource = ast.getTableSource();
if (tableSource instanceof SQLExprTableSource) {
visitor.visit((SQLExprTableSource) tableSource);
} else if (tableSource instanceof SQLJoinTableSource) {
visitor.visit((SQLJoinTableSource) tableSource);
} else {
throw new NotSupportYetException("not support the syntax of update with unknow");
}
return sb.toString();
}
@Override
public String getLimit(ParametersHolder parametersHolder, ArrayList<List<Object>> paramAppenderList) {
return super.getLimit(ast, getSQLType(), parametersHolder, paramAppenderList);
}
@Override
public String getOrderBy() {
return super.getOrderBy(ast, getSQLType());
}
}

View File

@@ -0,0 +1,84 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.oracle;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import io.seata.common.util.StringUtils;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.druid.BaseRecognizer;
import io.seata.sqlparser.struct.Null;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author will
*/
public abstract class BaseOracleRecognizer extends BaseRecognizer {
/**
* Instantiates a new oracle base recognizer
*
* @param originalSql the original sql
*/
public BaseOracleRecognizer(String originalSql) {
super(originalSql);
}
public OracleOutputVisitor createOutputVisitor(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList,
final StringBuilder sb) {
return new OracleOutputVisitor(sb) {
@Override
public boolean visit(SQLVariantRefExpr x) {
if ("?".equals(x.getName())) {
ArrayList<Object> oneParamValues = parametersHolder.getParameters().get(x.getIndex() + 1);
if (paramAppenderList.isEmpty()) {
oneParamValues.forEach(t -> paramAppenderList.add(new ArrayList<>()));
}
for (int i = 0; i < oneParamValues.size(); i++) {
Object o = oneParamValues.get(i);
paramAppenderList.get(i).add(o instanceof Null ? null : o);
}
}
return super.visit(x);
}
};
}
public String getWhereCondition(SQLExpr where, final ParametersHolder parametersHolder, final ArrayList<List<Object>> paramAppenderList) {
if (Objects.isNull(where)) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
executeVisit(where, createOutputVisitor(parametersHolder, paramAppenderList, sb));
return sb.toString();
}
public String getWhereCondition(SQLExpr where) {
if (Objects.isNull(where)) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
executeVisit(where, new OracleOutputVisitor(sb));
return sb.toString();
}
}

View File

@@ -0,0 +1,110 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.oracle;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleDeleteStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import io.seata.common.exception.NotSupportYetException;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLDeleteRecognizer;
import io.seata.sqlparser.SQLType;
import java.util.ArrayList;
import java.util.List;
/**
* The type oracle delete recognizer.
*
* @author ccg
*/
public class OracleDeleteRecognizer extends BaseOracleRecognizer implements SQLDeleteRecognizer {
private final OracleDeleteStatement ast;
/**
* Instantiates a new My sql delete recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public OracleDeleteRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (OracleDeleteStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.DELETE;
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
OracleOutputVisitor visitor = new OracleOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
@Override
public boolean visit(SQLJoinTableSource x) {
throw new NotSupportYetException("not support the syntax of delete with join table");
}
};
SQLTableSource tableSource;
if (ast.getFrom() == null) {
tableSource = ast.getTableSource();
} else {
tableSource = ast.getFrom();
}
if (tableSource instanceof SQLExprTableSource) {
visitor.visit((SQLExprTableSource) tableSource);
} else if (tableSource instanceof SQLJoinTableSource) {
visitor.visit((SQLJoinTableSource) tableSource);
} else {
throw new NotSupportYetException("not support the syntax of delete with unknow");
}
return sb.toString();
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where);
}
}

View File

@@ -0,0 +1,144 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.oracle;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleInsertStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import io.seata.common.util.CollectionUtils;
import io.seata.sqlparser.SQLInsertRecognizer;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.struct.NotPlaceholderExpr;
import io.seata.sqlparser.struct.Null;
import io.seata.sqlparser.struct.SqlMethodExpr;
import io.seata.sqlparser.struct.SqlSequenceExpr;
/**
* The type oracle insert recognizer.
*
* @author ccg
*/
public class OracleInsertRecognizer extends BaseOracleRecognizer implements SQLInsertRecognizer {
private final OracleInsertStatement ast;
/**
* Instantiates a new My sql insert recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public OracleInsertRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (OracleInsertStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.INSERT;
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
OracleOutputVisitor visitor = new OracleOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit(ast.getTableSource());
return sb.toString();
}
@Override
public boolean insertColumnsIsEmpty() {
return CollectionUtils.isEmpty(ast.getColumns());
}
@Override
public List<String> getInsertColumns() {
List<SQLExpr> columnSQLExprs = ast.getColumns();
if (columnSQLExprs.isEmpty()) {
// INSERT INTO ta VALUES (...), without fields clarified
return null;
}
List<String> list = new ArrayList<>(columnSQLExprs.size());
for (SQLExpr expr : columnSQLExprs) {
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr)expr).getName());
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public List<List<Object>> getInsertRows(Collection<Integer> primaryKeyIndex) {
List<SQLInsertStatement.ValuesClause> valuesClauses = ast.getValuesList();
List<List<Object>> rows = new ArrayList<>(valuesClauses.size());
for (SQLInsertStatement.ValuesClause valuesClause : valuesClauses) {
List<SQLExpr> exprs = valuesClause.getValues();
List<Object> row = new ArrayList<>(exprs.size());
rows.add(row);
for (int i = 0, len = exprs.size(); i < len; i++) {
SQLExpr expr = exprs.get(i);
if (expr instanceof SQLNullExpr) {
row.add(Null.get());
} else if (expr instanceof SQLValuableExpr) {
row.add(((SQLValuableExpr) expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
row.add(((SQLVariantRefExpr) expr).getName());
} else if (expr instanceof SQLMethodInvokeExpr) {
row.add(SqlMethodExpr.get());
} else if (expr instanceof SQLSequenceExpr) {
SQLSequenceExpr sequenceExpr = (SQLSequenceExpr) expr;
String sequence = sequenceExpr.getSequence().getSimpleName();
String function = sequenceExpr.getFunction().name;
row.add(new SqlSequenceExpr(sequence, function));
} else {
if (primaryKeyIndex.contains(i)) {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
row.add(NotPlaceholderExpr.get());
}
}
}
return rows;
}
}

View File

@@ -0,0 +1,55 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.oracle;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.druid.SQLOperateRecognizerHolder;
import io.seata.sqlparser.util.JdbcConstants;
/**
* The Type OracleOperateRecognizerHolder
*
* @author: Zhibei Hao
*/
@LoadLevel(name = JdbcConstants.ORACLE)
public class OracleOperateRecognizerHolder implements SQLOperateRecognizerHolder {
@Override
public SQLRecognizer getDeleteRecognizer(String sql, SQLStatement ast) {
return new OracleDeleteRecognizer(sql, ast);
}
@Override
public SQLRecognizer getInsertRecognizer(String sql, SQLStatement ast) {
return new OracleInsertRecognizer(sql, ast);
}
@Override
public SQLRecognizer getUpdateRecognizer(String sql, SQLStatement ast) {
return new OracleUpdateRecognizer(sql, ast);
}
@Override
public SQLRecognizer getSelectForUpdateRecognizer(String sql, SQLStatement ast) {
if (((SQLSelectStatement) ast).getSelect().getFirstQueryBlock().isForUpdate()) {
return new OracleSelectForUpdateRecognizer(sql, ast);
}
return null;
}
}

View File

@@ -0,0 +1,111 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.oracle;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLSelectRecognizer;
import io.seata.sqlparser.SQLType;
import java.util.ArrayList;
import java.util.List;
/**
* The type oracle select for update recognizer.
*
* @author ccg
*/
public class OracleSelectForUpdateRecognizer extends BaseOracleRecognizer implements SQLSelectRecognizer {
private final SQLSelectStatement ast;
/**
* Instantiates a new My sql select for update recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public OracleSelectForUpdateRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (SQLSelectStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.SELECT_FOR_UPDATE;
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLExpr where = selectQueryBlock.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLExpr where = selectQueryBlock.getWhere();
return super.getWhereCondition(where);
}
private SQLSelectQueryBlock getSelect() {
SQLSelect select = ast.getSelect();
if (select == null) {
throw new SQLParsingException("should never happen!");
}
SQLSelectQueryBlock selectQueryBlock = select.getQueryBlock();
if (selectQueryBlock == null) {
throw new SQLParsingException("should never happen!");
}
return selectQueryBlock;
}
@Override
public String getTableAlias() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLTableSource tableSource = selectQueryBlock.getFrom();
return tableSource.getAlias();
}
@Override
public String getTableName() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLTableSource tableSource = selectQueryBlock.getFrom();
StringBuilder sb = new StringBuilder();
OracleOutputVisitor visitor = new OracleOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit((SQLExprTableSource)tableSource);
return sb.toString();
}
}

View File

@@ -0,0 +1,151 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.oracle;
import java.util.ArrayList;
import java.util.List;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.dialect.oracle.ast.stmt.OracleUpdateStatement;
import com.alibaba.druid.sql.dialect.oracle.visitor.OracleOutputVisitor;
import io.seata.common.exception.NotSupportYetException;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.SQLUpdateRecognizer;
/**
* The type oracle update recognizer.
*
* @author ccg
*/
public class OracleUpdateRecognizer extends BaseOracleRecognizer implements SQLUpdateRecognizer {
private OracleUpdateStatement ast;
/**
* Instantiates a new My sql update recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public OracleUpdateRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (OracleUpdateStatement)ast;
}
@Override
public SQLType getSQLType() {
return SQLType.UPDATE;
}
@Override
public List<String> getUpdateColumns() {
List<SQLUpdateSetItem> updateSetItems = ast.getItems();
List<String> list = new ArrayList<>(updateSetItems.size());
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
SQLExpr expr = updateSetItem.getColumn();
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr)expr).getName());
} else if (expr instanceof SQLPropertyExpr) {
// This is alias case, like UPDATE xxx_tbl a SET a.name = ? WHERE a.id = ?
SQLExpr owner = ((SQLPropertyExpr)expr).getOwner();
if (owner instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr)owner).getName() + "." + ((SQLPropertyExpr)expr).getName());
//This is table Field Full path, like update xxx_database.xxx_tbl set xxx_database.xxx_tbl.xxx_field...
} else if (((SQLPropertyExpr) expr).getOwnernName().split("\\.").length > 1) {
list.add(((SQLPropertyExpr)expr).getOwnernName() + "." + ((SQLPropertyExpr)expr).getName());
}
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public List<Object> getUpdateValues() {
List<SQLUpdateSetItem> updateSetItems = ast.getItems();
List<Object> list = new ArrayList<>(updateSetItems.size());
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
SQLExpr expr = updateSetItem.getValue();
if (expr instanceof SQLValuableExpr) {
list.add(((SQLValuableExpr)expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
list.add(new VMarker());
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where);
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
OracleOutputVisitor visitor = new OracleOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
@Override
public boolean visit(SQLJoinTableSource x) {
throw new NotSupportYetException("not support the syntax of update with join table");
}
};
SQLTableSource tableSource = ast.getTableSource();
if (tableSource instanceof SQLExprTableSource) {
visitor.visit((SQLExprTableSource) tableSource);
} else if (tableSource instanceof SQLJoinTableSource) {
visitor.visit((SQLJoinTableSource) tableSource);
} else {
throw new NotSupportYetException("not support the syntax of update with unknow");
}
return sb.toString();
}
}

View File

@@ -0,0 +1,85 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.postgresql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import io.seata.common.util.StringUtils;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.druid.BaseRecognizer;
import io.seata.sqlparser.struct.Null;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
/**
* @author will
*/
public abstract class BasePostgresqlRecognizer extends BaseRecognizer {
/**
* Instantiates a new postgresql base recognizer
*
* @param originalSql the original sql
*/
public BasePostgresqlRecognizer(String originalSql) {
super(originalSql);
}
public PGOutputVisitor createOutputVisitor(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList, final StringBuilder sb) {
PGOutputVisitor visitor = new PGOutputVisitor(sb) {
@Override
public boolean visit(SQLVariantRefExpr x) {
if ("?".equals(x.getName())) {
ArrayList<Object> oneParamValues = parametersHolder.getParameters().get(x.getIndex() + 1);
if (paramAppenderList.size() == 0) {
oneParamValues.forEach(t -> paramAppenderList.add(new ArrayList<>()));
}
for (int i = 0; i < oneParamValues.size(); i++) {
Object o = oneParamValues.get(i);
paramAppenderList.get(i).add(o instanceof Null ? null : o);
}
}
return super.visit(x);
}
};
return visitor;
}
public String getWhereCondition(SQLExpr where, final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
if (Objects.isNull(where)) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
executeVisit(where, createOutputVisitor(parametersHolder, paramAppenderList, sb));
return sb.toString();
}
public String getWhereCondition(SQLExpr where) {
if (Objects.isNull(where)) {
return StringUtils.EMPTY;
}
StringBuilder sb = new StringBuilder();
executeVisit(where, new PGOutputVisitor(sb));
return sb.toString();
}
}

View File

@@ -0,0 +1,105 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.postgresql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGDeleteStatement;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import io.seata.common.exception.NotSupportYetException;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLDeleteRecognizer;
import io.seata.sqlparser.SQLType;
import java.util.ArrayList;
import java.util.List;
/**
* @author japsercloud
*/
public class PostgresqlDeleteRecognizer extends BasePostgresqlRecognizer implements SQLDeleteRecognizer {
private final PGDeleteStatement ast;
/**
* Instantiates a new Postgresql delete recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public PostgresqlDeleteRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (PGDeleteStatement) ast;
}
@Override
public SQLType getSQLType() {
return SQLType.DELETE;
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
PGOutputVisitor visitor = new PGOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
@Override
public boolean visit(SQLJoinTableSource x) {
throw new NotSupportYetException("not support the syntax of delete with join table");
}
};
SQLTableSource tableSource;
if (ast.getFrom() == null) {
tableSource = ast.getTableSource();
} else {
tableSource = ast.getFrom();
}
if (tableSource instanceof SQLExprTableSource) {
visitor.visit((SQLExprTableSource) tableSource);
} else if (tableSource instanceof SQLJoinTableSource) {
visitor.visit((SQLJoinTableSource) tableSource);
} else {
throw new NotSupportYetException("not support the syntax of delete with unknow");
}
return sb.toString();
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where);
}
}

View File

@@ -0,0 +1,153 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.postgresql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLDefaultExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLMethodInvokeExpr;
import com.alibaba.druid.sql.ast.expr.SQLNullExpr;
import com.alibaba.druid.sql.ast.expr.SQLSequenceExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGInsertStatement;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import io.seata.common.util.CollectionUtils;
import io.seata.common.util.StringUtils;
import io.seata.sqlparser.SQLInsertRecognizer;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.struct.NotPlaceholderExpr;
import io.seata.sqlparser.struct.Null;
import io.seata.sqlparser.struct.SqlDefaultExpr;
import io.seata.sqlparser.struct.SqlMethodExpr;
import io.seata.sqlparser.struct.SqlSequenceExpr;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
/**
* @author japsercloud
*/
public class PostgresqlInsertRecognizer extends BasePostgresqlRecognizer implements SQLInsertRecognizer {
private final PGInsertStatement ast;
/**
* Instantiates a new Postgresql insert recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public PostgresqlInsertRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (PGInsertStatement) ast;
}
@Override
public SQLType getSQLType() {
return SQLType.INSERT;
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
PGOutputVisitor visitor = new PGOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit(ast.getTableSource());
return sb.toString();
}
@Override
public boolean insertColumnsIsEmpty() {
return CollectionUtils.isEmpty(ast.getColumns());
}
@Override
public List<String> getInsertColumns() {
List<SQLExpr> columnSQLExprs = ast.getColumns();
if (columnSQLExprs.size() == 0) {
// INSERT INTO ta VALUES (...), without fields clarified
return null;
}
List<String> list = new ArrayList<>(columnSQLExprs.size());
for (SQLExpr expr : columnSQLExprs) {
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr) expr).getName());
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public List<List<Object>> getInsertRows(Collection<Integer> primaryKeyIndex) {
List<SQLInsertStatement.ValuesClause> valuesClauses = ast.getValuesList();
List<List<Object>> rows = new ArrayList<>(valuesClauses.size());
for (SQLInsertStatement.ValuesClause valuesClause : valuesClauses) {
List<SQLExpr> exprs = valuesClause.getValues();
List<Object> row = new ArrayList<>(exprs.size());
rows.add(row);
for (int i = 0, len = exprs.size(); i < len; i++) {
SQLExpr expr = exprs.get(i);
if (expr instanceof SQLNullExpr) {
row.add(Null.get());
} else if (expr instanceof SQLValuableExpr) {
row.add(((SQLValuableExpr) expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
row.add(((SQLVariantRefExpr) expr).getName());
} else if (expr instanceof SQLMethodInvokeExpr) {
SQLMethodInvokeExpr sqlMethodInvokeExpr = (SQLMethodInvokeExpr) expr;
String function = sqlMethodInvokeExpr.getMethodName();
if (StringUtils.equalsIgnoreCase(function, "nextval")) {
String sequence = sqlMethodInvokeExpr.getParameters().get(0).toString();
row.add(new SqlSequenceExpr(sequence, function));
} else {
row.add(SqlMethodExpr.get());
}
} else if (expr instanceof SQLSequenceExpr) {
SQLSequenceExpr sequenceExpr = (SQLSequenceExpr) expr;
String sequence = sequenceExpr.getSequence().getSimpleName();
String function = sequenceExpr.getFunction().name;
row.add(new SqlSequenceExpr(sequence, function));
} else if (expr instanceof SQLDefaultExpr) {
row.add(SqlDefaultExpr.get());
} else {
if (primaryKeyIndex.contains(i)) {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
row.add(NotPlaceholderExpr.get());
}
}
}
return rows;
}
}

View File

@@ -0,0 +1,57 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.postgresql;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock;
import io.seata.common.loader.LoadLevel;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.druid.SQLOperateRecognizerHolder;
import io.seata.sqlparser.util.JdbcConstants;
/**
* The type PostgresqlOperateRecognizerHolder
*
* @author will.zjw
*/
@LoadLevel(name = JdbcConstants.POSTGRESQL)
public class PostgresqlOperateRecognizerHolder implements SQLOperateRecognizerHolder {
@Override
public SQLRecognizer getDeleteRecognizer(String sql, SQLStatement ast) {
return new PostgresqlDeleteRecognizer(sql, ast);
}
@Override
public SQLRecognizer getInsertRecognizer(String sql, SQLStatement ast) {
return new PostgresqlInsertRecognizer(sql, ast);
}
@Override
public SQLRecognizer getUpdateRecognizer(String sql, SQLStatement ast) {
return new PostgresqlUpdateRecognizer(sql, ast);
}
@Override
public SQLRecognizer getSelectForUpdateRecognizer(String sql, SQLStatement ast) {
PGSelectQueryBlock selectQueryBlock = (PGSelectQueryBlock) ((SQLSelectStatement) ast).getSelect().getFirstQueryBlock();
if (selectQueryBlock.getForClause() != null && selectQueryBlock.getForClause().getOption().equals(PGSelectQueryBlock.ForClause.Option.UPDATE)) {
return new PostgresqlSelectForUpdateRecognizer(sql, ast);
}
return null;
}
}

View File

@@ -0,0 +1,107 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.postgresql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLSelect;
import com.alibaba.druid.sql.ast.statement.SQLSelectQueryBlock;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLSelectRecognizer;
import io.seata.sqlparser.SQLType;
import java.util.ArrayList;
import java.util.List;
/**
* @author japsercloud
*/
public class PostgresqlSelectForUpdateRecognizer extends BasePostgresqlRecognizer implements SQLSelectRecognizer {
private final SQLSelectStatement ast;
/**
* Instantiates a new Postgresql select for update recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public PostgresqlSelectForUpdateRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (SQLSelectStatement) ast;
}
@Override
public SQLType getSQLType() {
return SQLType.SELECT_FOR_UPDATE;
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLExpr where = selectQueryBlock.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLExpr where = selectQueryBlock.getWhere();
return super.getWhereCondition(where);
}
private SQLSelectQueryBlock getSelect() {
SQLSelect select = ast.getSelect();
if (select == null) {
throw new SQLParsingException("should never happen!");
}
SQLSelectQueryBlock selectQueryBlock = select.getQueryBlock();
if (selectQueryBlock == null) {
throw new SQLParsingException("should never happen!");
}
return selectQueryBlock;
}
@Override
public String getTableAlias() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLTableSource tableSource = selectQueryBlock.getFrom();
return tableSource.getAlias();
}
@Override
public String getTableName() {
SQLSelectQueryBlock selectQueryBlock = getSelect();
SQLTableSource tableSource = selectQueryBlock.getFrom();
StringBuilder sb = new StringBuilder();
PGOutputVisitor visitor = new PGOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
};
visitor.visit((SQLExprTableSource) tableSource);
return sb.toString();
}
}

View File

@@ -0,0 +1,147 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid.postgresql;
import com.alibaba.druid.sql.ast.SQLExpr;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.ast.expr.SQLValuableExpr;
import com.alibaba.druid.sql.ast.expr.SQLVariantRefExpr;
import com.alibaba.druid.sql.ast.statement.SQLExprTableSource;
import com.alibaba.druid.sql.ast.statement.SQLJoinTableSource;
import com.alibaba.druid.sql.ast.statement.SQLTableSource;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGUpdateStatement;
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGOutputVisitor;
import io.seata.common.exception.NotSupportYetException;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.SQLUpdateRecognizer;
import java.util.ArrayList;
import java.util.List;
/**
* @author japsercloud
*/
public class PostgresqlUpdateRecognizer extends BasePostgresqlRecognizer implements SQLUpdateRecognizer {
private PGUpdateStatement ast;
/**
* Instantiates a new Postgresql update recognizer.
*
* @param originalSQL the original sql
* @param ast the ast
*/
public PostgresqlUpdateRecognizer(String originalSQL, SQLStatement ast) {
super(originalSQL);
this.ast = (PGUpdateStatement) ast;
}
@Override
public SQLType getSQLType() {
return SQLType.UPDATE;
}
@Override
public List<String> getUpdateColumns() {
List<SQLUpdateSetItem> updateSetItems = ast.getItems();
List<String> list = new ArrayList<>(updateSetItems.size());
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
SQLExpr expr = updateSetItem.getColumn();
if (expr instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr) expr).getName());
} else if (expr instanceof SQLPropertyExpr) {
// This is alias case, like UPDATE xxx_tbl a SET a.name = ? WHERE a.id = ?
SQLExpr owner = ((SQLPropertyExpr) expr).getOwner();
if (owner instanceof SQLIdentifierExpr) {
list.add(((SQLIdentifierExpr) owner).getName() + "." + ((SQLPropertyExpr) expr).getName());
//This is table Field Full path, like update xxx_database.xxx_tbl set xxx_database.xxx_tbl.xxx_field...
} else if (((SQLPropertyExpr) expr).getOwnernName().split("\\.").length > 1) {
list.add(((SQLPropertyExpr)expr).getOwnernName() + "." + ((SQLPropertyExpr)expr).getName());
}
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public List<Object> getUpdateValues() {
List<SQLUpdateSetItem> updateSetItems = ast.getItems();
List<Object> list = new ArrayList<>(updateSetItems.size());
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
SQLExpr expr = updateSetItem.getValue();
if (expr instanceof SQLValuableExpr) {
list.add(((SQLValuableExpr) expr).getValue());
} else if (expr instanceof SQLVariantRefExpr) {
list.add(new VMarker());
} else {
throw new SQLParsingException("Unknown SQLExpr: " + expr.getClass() + " " + expr);
}
}
return list;
}
@Override
public String getWhereCondition(final ParametersHolder parametersHolder,
final ArrayList<List<Object>> paramAppenderList) {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where, parametersHolder, paramAppenderList);
}
@Override
public String getWhereCondition() {
SQLExpr where = ast.getWhere();
return super.getWhereCondition(where);
}
@Override
public String getTableAlias() {
return ast.getTableSource().getAlias();
}
@Override
public String getTableName() {
StringBuilder sb = new StringBuilder();
PGOutputVisitor visitor = new PGOutputVisitor(sb) {
@Override
public boolean visit(SQLExprTableSource x) {
printTableSourceExpr(x.getExpr());
return false;
}
@Override
public boolean visit(SQLJoinTableSource x) {
throw new NotSupportYetException("not support the syntax of update with join table");
}
};
SQLTableSource tableSource = ast.getTableSource();
if (tableSource instanceof SQLExprTableSource) {
visitor.visit((SQLExprTableSource) tableSource);
} else if (tableSource instanceof SQLJoinTableSource) {
visitor.visit((SQLJoinTableSource) tableSource);
} else {
throw new NotSupportYetException("not support the syntax of update with unknow");
}
return sb.toString();
}
}

View File

@@ -0,0 +1 @@
io.seata.sqlparser.druid.DruidDelegatingSQLRecognizerFactory

View File

@@ -0,0 +1,3 @@
io.seata.sqlparser.druid.mysql.MySQLOperateRecognizerHolder
io.seata.sqlparser.druid.oracle.OracleOperateRecognizerHolder
io.seata.sqlparser.druid.postgresql.PostgresqlOperateRecognizerHolder

View File

@@ -0,0 +1 @@
io.seata.sqlparser.druid.DruidDelegatingDbTypeParser

View File

@@ -0,0 +1,43 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.util.List;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
/**
* The type Abstract my sql recognizer test.
*
* @author hanwen created at 2019-01-25
*/
public abstract class AbstractRecognizerTest {
/**
* Gets sql statement.
*
* @param sql the sql
* @return the sql statement
*/
public SQLStatement getSQLStatement(String sql) {
List<SQLStatement> stats = SQLUtils.parseStatements(sql, getDbType());
return stats.get(0);
}
public abstract String getDbType();
}

View File

@@ -0,0 +1,41 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import io.seata.common.loader.EnhancedServiceLoader;
import io.seata.sqlparser.SqlParserType;
import io.seata.sqlparser.util.DbTypeParser;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* @author ggndnn
*/
public class DruidDbTypeParserTest {
@Test
public void testDruidDbTypeParserLoading() {
String jdbcUrl = "jdbc:mysql://127.0.0.1:3306/seata";
DruidDelegatingDbTypeParser dbTypeParser = (DruidDelegatingDbTypeParser) EnhancedServiceLoader.load(DbTypeParser.class, SqlParserType.SQL_PARSER_TYPE_DRUID);
Assertions.assertNotNull(dbTypeParser);
Assertions.assertEquals(DruidDelegatingDbTypeParser.class, dbTypeParser.getClass());
String dbType = dbTypeParser.parseFromJdbcUrl(jdbcUrl);
Assertions.assertEquals("mysql", dbType);
DruidLoader druidLoaderForTest = new DruidLoaderForTest();
dbTypeParser.setClassLoader(new DruidIsolationClassLoader(druidLoaderForTest));
Assertions.assertThrows(NoClassDefFoundError.class, () -> dbTypeParser.parseFromJdbcUrl(jdbcUrl));
}
}

View File

@@ -0,0 +1,53 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import io.seata.common.loader.EnhancedServiceLoader;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import io.seata.sqlparser.SqlParserType;
import io.seata.sqlparser.util.JdbcConstants;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
/**
* @author ggndnn
*/
public class DruidIsolationTest {
private final static String TEST_SQL = "insert into t_table_1 values(?, ?)";
@Test
public void testDruidIsolation() throws Exception {
DruidDelegatingSQLRecognizerFactory recognizerFactory = (DruidDelegatingSQLRecognizerFactory) EnhancedServiceLoader.load(SQLRecognizerFactory.class, SqlParserType.SQL_PARSER_TYPE_DRUID);
Assertions.assertNotNull(recognizerFactory);
List<SQLRecognizer> sqlRecognizer = recognizerFactory.create(TEST_SQL, JdbcConstants.MYSQL);
Assertions.assertNotNull(sqlRecognizer);
DruidLoader druidLoaderForTest = new DruidLoaderForTest();
recognizerFactory.setClassLoader(new DruidIsolationClassLoader(druidLoaderForTest));
// because druid-test.jar not exists, so NoClassDefFoundError should be threw
Assertions.assertThrows(NoClassDefFoundError.class, () -> recognizerFactory.create(TEST_SQL, JdbcConstants.MYSQL));
}
@AfterAll
public static void afterClass(){
DruidDelegatingSQLRecognizerFactory recognizerFactory = (DruidDelegatingSQLRecognizerFactory) EnhancedServiceLoader.load(SQLRecognizerFactory.class,
SqlParserType.SQL_PARSER_TYPE_DRUID);
recognizerFactory.setClassLoader(DruidIsolationTest.class.getClassLoader());
}
}

View File

@@ -0,0 +1,31 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
class DruidLoaderForTest implements DruidLoader {
@Override
public URL getEmbeddedDruidLocation() {
try {
return URI.create("file://druid-test.jar").toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}
}

View File

@@ -0,0 +1,39 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import io.seata.common.loader.EnhancedServiceLoader;
import io.seata.sqlparser.SQLRecognizer;
import io.seata.sqlparser.SQLRecognizerFactory;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.SqlParserType;
import io.seata.sqlparser.util.JdbcConstants;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import java.util.List;
public class DruidSQLRecognizerFactoryTest {
@Test
public void testSqlRecognizerCreation() {
SQLRecognizerFactory recognizerFactory = EnhancedServiceLoader.load(SQLRecognizerFactory.class, SqlParserType.SQL_PARSER_TYPE_DRUID);
Assertions.assertNotNull(recognizerFactory);
List<SQLRecognizer> recognizers = recognizerFactory.create("delete from t1", JdbcConstants.MYSQL);
Assertions.assertNotNull(recognizers);
Assertions.assertEquals(recognizers.size(),1);
Assertions.assertEquals(SQLType.DELETE, recognizers.get(0).getSQLType());
}
}

View File

@@ -0,0 +1,342 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLDeleteStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.druid.mysql.MySQLDeleteRecognizer;
import io.seata.sqlparser.util.JdbcConstants;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* The type My sql delete recognizer test.
*
* @author hanwen created at 2019-01-25
*/
public class MySQLDeleteRecognizerTest extends AbstractRecognizerTest {
@Test
public void testVMarker() {
Assertions.assertEquals("?", new BaseRecognizer.VMarker().toString());
}
/**
* Delete recognizer test 0.
*/
@Test
public void deleteRecognizerTest_0() {
ParametersHolder parametersHolder = new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
return Collections.EMPTY_MAP;
}
};
String sql = "DELETE FROM t1 WHERE id = 'id1' order by id asc,name desc limit 1,2";
SQLStatement statement = getSQLStatement(sql);
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
String orderBy = mySQLDeleteRecognizer.getOrderBy();
Assertions.assertTrue(orderBy.equalsIgnoreCase(" ORDER BY id asc,name desc"));
Assertions.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLDeleteRecognizer.getTableName());
Assertions.assertEquals("id = 'id1'", mySQLDeleteRecognizer.getWhereCondition());
String limit = mySQLDeleteRecognizer.getLimit(parametersHolder, paramAppenderList);
Assertions.assertEquals(" LIMIT 1,2", limit);
sql = "DELETE FROM t1 WHERE id > 1 order by id ,name desc limit 1";
statement = getSQLStatement(sql);
mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
orderBy = mySQLDeleteRecognizer.getOrderBy();
Assertions.assertTrue(orderBy.equalsIgnoreCase(" order by id,name desc"));
Assertions.assertEquals(" LIMIT 1", mySQLDeleteRecognizer.getLimit(parametersHolder, paramAppenderList));
sql = "DELETE FROM t1 WHERE id > 1";
statement = getSQLStatement(sql);
mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
Assertions.assertEquals(null, mySQLDeleteRecognizer.getLimit(parametersHolder, paramAppenderList));
orderBy = mySQLDeleteRecognizer.getOrderBy();
Assertions.assertEquals(null, mySQLDeleteRecognizer.getOrderBy());
}
/**
* Delete recognizer test 1.
*/
@Test
public void deleteRecognizerTest_1() {
String sql = "DELETE FROM t1 WHERE id = ?";
SQLStatement statement = getSQLStatement(sql);
MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLDeleteRecognizer.getTableName());
// test overflow parameters
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLDeleteRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add("id1");
Map result = new HashMap<>();
result.put(1,idParam);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList);
Assertions.assertEquals("id = ?", whereCondition);
}
/**
* Delete recognizer test 2.
*/
@Test
public void deleteRecognizerTest_2() {
String sql = "DELETE FROM t1 WHERE id IN (?, ?)";
SQLStatement statement = getSQLStatement(sql);
MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLDeleteRecognizer.getTableName());
// test overflow parameters
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLDeleteRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
Map result = new HashMap();
result.put(1, idParam);
result.put(2, id2Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Arrays.asList(Arrays.asList("id1", "id2")), paramAppenderList);
Assertions.assertEquals("id IN (?, ?)", whereCondition);
}
/**
* Delete recognizer test 3.
*/
@Test
public void deleteRecognizerTest_3() {
String sql = "DELETE FROM t1 WHERE id between ? AND ?";
SQLStatement statement = getSQLStatement(sql);
MySQLDeleteRecognizer mySQLDeleteRecognizer = new MySQLDeleteRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLDeleteRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLDeleteRecognizer.getTableName());
// test overflow parameters
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLDeleteRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
Map result = new HashMap();
result.put(1, idParam);
result.put(2, id2Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList);
Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition);
}
@Test
public void testGetSqlType() {
String sql = "delete from t where id = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLDeleteRecognizer recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
Assertions.assertEquals(recognizer.getSQLType(), SQLType.DELETE);
}
@Test
public void testGetTableAlias() {
String sql = "delete from t where id = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLDeleteRecognizer recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
Assertions.assertNull(recognizer.getTableAlias());
}
@Test
public void testGetWhereCondition_0() {
String sql = "delete from t";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLDeleteRecognizer recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
String whereCondition = recognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
return null;
}
}, new ArrayList<>());
//test for no condition
Assertions.assertEquals("", whereCondition);
sql = "delete from t where id = ?";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
whereCondition = recognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add(1);
Map result = new HashMap();
result.put(1, idParam);
return result;
}
}, new ArrayList<>());
//test for normal sql
Assertions.assertEquals("id = ?", whereCondition);
sql = "delete from t where id in (?)";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
whereCondition = recognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add(1);
Map result = new HashMap();
result.put(1, idParam);
return result;
}
}, new ArrayList<>());
//test for sql with in
Assertions.assertEquals("id IN (?)", whereCondition);
sql = "delete from t where id between ? and ?";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
whereCondition = recognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add(1);
ArrayList<Object> idParam2 = new ArrayList<>();
idParam.add(2);
Map result = new HashMap();
result.put(1, idParam);
result.put(2, idParam2);
return result;
}
}, new ArrayList<>());
//test for sql with in
Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition);
//test for exception
Assertions.assertThrows(IllegalArgumentException.class, () -> {
String s = "delete from t where id in (?)";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLDeleteStatement deleteAst = (SQLDeleteStatement) sqlStatements.get(0);
deleteAst.setWhere(new MySqlOrderingExpr());
new MySQLDeleteRecognizer(s, deleteAst).getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
return new HashMap();
}
}, new ArrayList<>());
});
}
@Test
public void testGetWhereCondition_1() {
String sql = "delete from t";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLDeleteRecognizer recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
String whereCondition = recognizer.getWhereCondition();
//test for no condition
Assertions.assertEquals("", whereCondition);
sql = "delete from t where id = 1";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
whereCondition = recognizer.getWhereCondition();
//test for normal sql
Assertions.assertEquals("id = 1", whereCondition);
sql = "delete from t where id in (1)";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
whereCondition = recognizer.getWhereCondition();
//test for sql with in
Assertions.assertEquals("id IN (1)", whereCondition);
sql = "delete from t where id between 1 and 2";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLDeleteRecognizer(sql, asts.get(0));
whereCondition = recognizer.getWhereCondition();
//test for sql with in
Assertions.assertEquals("id BETWEEN 1 AND 2", whereCondition);
//test for exception
Assertions.assertThrows(IllegalArgumentException.class, () -> {
String s = "delete from t where id in (1)";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLDeleteStatement deleteAst = (SQLDeleteStatement) sqlStatements.get(0);
deleteAst.setWhere(new MySqlOrderingExpr());
new MySQLDeleteRecognizer(s, deleteAst).getWhereCondition();
});
}
@Override
public String getDbType() {
return JdbcConstants.MYSQL;
}
}

View File

@@ -0,0 +1,177 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLInsertStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.druid.mysql.MySQLInsertRecognizer;
import io.seata.sqlparser.util.JdbcConstants;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* The type My sql insert recognizer test.
*
* @author hanwen created at 2019-01-25
*/
public class MySQLInsertRecognizerTest extends AbstractRecognizerTest {
private final int pkIndex = 0;
/**
* Insert recognizer test 0.
*/
@Test
public void insertRecognizerTest_0() {
String sql = "INSERT INTO t1 (name) VALUES ('name1')";
SQLStatement statement = getSQLStatement(sql);
MySQLInsertRecognizer mySQLInsertRecognizer = new MySQLInsertRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLInsertRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLInsertRecognizer.getTableName());
Assertions.assertEquals(Collections.singletonList("name"), mySQLInsertRecognizer.getInsertColumns());
Assertions.assertEquals(1, mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).size());
Assertions.assertEquals(Collections.singletonList("name1"), mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(0));
}
/**
* Insert recognizer test 1.
*/
@Test
public void insertRecognizerTest_1() {
String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2')";
SQLStatement statement = getSQLStatement(sql);
MySQLInsertRecognizer mySQLInsertRecognizer = new MySQLInsertRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLInsertRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLInsertRecognizer.getTableName());
Assertions.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertColumns());
Assertions.assertEquals(1, mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).size());
Assertions.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(0));
}
/**
* Insert recognizer test 3.
*/
@Test
public void insertRecognizerTest_3() {
String sql = "INSERT INTO t1 (name1, name2) VALUES ('name1', 'name2'), ('name3', 'name4'), ('name5', 'name6')";
SQLStatement statement = getSQLStatement(sql);
MySQLInsertRecognizer mySQLInsertRecognizer = new MySQLInsertRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLInsertRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLInsertRecognizer.getTableName());
Assertions.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertColumns());
Assertions.assertEquals(3, mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).size());
Assertions.assertEquals(Arrays.asList("name1", "name2"), mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(0));
Assertions.assertEquals(Arrays.asList("name3", "name4"), mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(1));
Assertions.assertEquals(Arrays.asList("name5", "name6"), mySQLInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex)).get(2));
}
@Test
public void testGetSqlType() {
String sql = "insert into t(id) values (?)";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLInsertRecognizer recognizer = new MySQLInsertRecognizer(sql, asts.get(0));
Assertions.assertEquals(recognizer.getSQLType(), SQLType.INSERT);
}
@Test
public void testGetTableAlias() {
String sql = "insert into t(id) values (?)";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLInsertRecognizer recognizer = new MySQLInsertRecognizer(sql, asts.get(0));
Assertions.assertNull(recognizer.getTableAlias());
}
@Test
public void testGetInsertColumns() {
//test for no column
String sql = "insert into t values (?)";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLInsertRecognizer recognizer = new MySQLInsertRecognizer(sql, asts.get(0));
List<String> insertColumns = recognizer.getInsertColumns();
Assertions.assertNull(insertColumns);
//test for normal
sql = "insert into t(a) values (?)";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLInsertRecognizer(sql, asts.get(0));
insertColumns = recognizer.getInsertColumns();
Assertions.assertEquals(1, insertColumns.size());
//test for exception
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "insert into t(a) values (?)";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLInsertStatement sqlInsertStatement = (SQLInsertStatement)sqlStatements.get(0);
sqlInsertStatement.getColumns().add(new MySqlOrderingExpr());
MySQLInsertRecognizer oracleInsertRecognizer = new MySQLInsertRecognizer(s, sqlInsertStatement);
oracleInsertRecognizer.getInsertColumns();
});
}
@Test
public void testGetInsertRows() {
//test for null value
String sql = "insert into t(id, no, name, age, time) values (1, null, 'a', ?, now())";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLInsertRecognizer recognizer = new MySQLInsertRecognizer(sql, asts.get(0));
List<List<Object>> insertRows = recognizer.getInsertRows(Collections.singletonList(pkIndex));
Assertions.assertEquals(1, insertRows.size());
//test for exception
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "insert into t(a) values (?)";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLInsertStatement sqlInsertStatement = (SQLInsertStatement)sqlStatements.get(0);
sqlInsertStatement.getValuesList().get(0).getValues().set(pkIndex, new MySqlOrderingExpr());
MySQLInsertRecognizer mysqlInsertRecognizer = new MySQLInsertRecognizer(s, sqlInsertStatement);
mysqlInsertRecognizer.getInsertRows(Collections.singletonList(pkIndex));
});
}
@Override
public String getDbType() {
return JdbcConstants.MYSQL;
}
}

View File

@@ -0,0 +1,241 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLSelectStatement;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.druid.mysql.MySQLSelectForUpdateRecognizer;
import io.seata.sqlparser.util.JdbcConstants;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* The type My sql select for update recognizer test.
*/
public class MySQLSelectForUpdateRecognizerTest extends AbstractRecognizerTest {
/**
* Select for update recognizer test 0.
*/
@Test
public void selectForUpdateRecognizerTest_0() {
String sql = "SELECT name FROM t1 WHERE id = 'id1' FOR UPDATE";
SQLStatement statement = getSQLStatement(sql);
MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals("id = 'id1'", mySQLUpdateRecognizer.getWhereCondition());
}
/**
* Select for update recognizer test 1.
*/
@Test
public void selectForUpdateRecognizerTest_1() {
String sql = "SELECT name FROM t1 WHERE id = ? FOR UPDATE";
SQLStatement statement = getSQLStatement(sql);
MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add("id1");
Map result = new HashMap();
result.put(1, idParam);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList);
Assertions.assertEquals("id = ?", whereCondition);
}
/**
* Select for update recognizer test 3.
*/
@Test
public void selectForUpdateRecognizerTest_3() {
String sql = "SELECT name1, name2 FROM t1 WHERE id = ? FOR UPDATE";
SQLStatement statement = getSQLStatement(sql);
MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
// test overflow parameters
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> id1Param = new ArrayList<>();
id1Param.add("id1");
Map result = new HashMap();
result.put(1, id1Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList);
Assertions.assertEquals("id = ?", whereCondition);
}
/**
* Select for update recognizer test 4.
*/
@Test
public void selectForUpdateRecognizerTest_4() {
String sql = "SELECT name1, name2 FROM t1 WHERE id IN (?,?) FOR UPDATE";
SQLStatement statement = getSQLStatement(sql);
MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
// test overflow parameters
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> id1Param = new ArrayList<>();
id1Param.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
Map result = new HashMap();
result.put(1, id1Param);
result.put(2, id2Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList);
Assertions.assertEquals("id IN (?, ?)", whereCondition);
}
/**
* Select for update recognizer test 5.
*/
@Test
public void selectForUpdateRecognizerTest_5() {
String sql = "SELECT name1, name2 FROM t1 WHERE id between ? and ? FOR UPDATE";
SQLStatement statement = getSQLStatement(sql);
MySQLSelectForUpdateRecognizer mySQLUpdateRecognizer = new MySQLSelectForUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
// test overflow parameters
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> id1Param = new ArrayList<>();
id1Param.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
Map result = new HashMap();
result.put(1, id1Param);
result.put(2, id2Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList);
Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition);
}
@Test
public void testGetWhereCondition_1() {
String sql = "select * from t for update";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLSelectForUpdateRecognizer recognizer = new MySQLSelectForUpdateRecognizer(sql, asts.get(0));
String whereCondition = recognizer.getWhereCondition();
Assertions.assertEquals("", whereCondition);
//test for select was null
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "select * from t for update";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLSelectStatement selectAst = (SQLSelectStatement) sqlStatements.get(0);
selectAst.setSelect(null);
new MySQLSelectForUpdateRecognizer(s, selectAst).getWhereCondition();
});
//test for query was null
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "select * from t";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLSelectStatement selectAst = (SQLSelectStatement) sqlStatements.get(0);
selectAst.getSelect().setQuery(null);
new MySQLSelectForUpdateRecognizer(s, selectAst).getWhereCondition();
});
}
@Test
public void testGetSqlType() {
String sql = "select * from t where id = ? for update";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLSelectForUpdateRecognizer recognizer = new MySQLSelectForUpdateRecognizer(sql, asts.get(0));
Assertions.assertEquals(recognizer.getSQLType(), SQLType.SELECT_FOR_UPDATE);
}
@Test
public void testGetTableAlias() {
String sql = "select * from t where id = ? for update";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLSelectForUpdateRecognizer recognizer = new MySQLSelectForUpdateRecognizer(sql, asts.get(0));
Assertions.assertNull(recognizer.getTableAlias());
}
@Override
public String getDbType() {
return JdbcConstants.MYSQL;
}
}

View File

@@ -0,0 +1,357 @@
/*
* Copyright 1999-2019 Seata.io Group.
*
* 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 io.seata.sqlparser.druid;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.SQLStatement;
import com.alibaba.druid.sql.ast.statement.SQLUpdateSetItem;
import com.alibaba.druid.sql.ast.statement.SQLUpdateStatement;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlCharExpr;
import com.alibaba.druid.sql.dialect.mysql.ast.expr.MySqlOrderingExpr;
import io.seata.sqlparser.ParametersHolder;
import io.seata.sqlparser.SQLParsingException;
import io.seata.sqlparser.SQLType;
import io.seata.sqlparser.druid.mysql.MySQLUpdateRecognizer;
import io.seata.sqlparser.util.JdbcConstants;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
/**
* The type My sql update recognizer test.
*/
public class MySQLUpdateRecognizerTest extends AbstractRecognizerTest {
/**
* Update recognizer test 0.
*/
@Test
public void updateRecognizerTest_0() {
String sql = "UPDATE t1 SET name = 'name1' WHERE id = 'id1'";
SQLStatement statement = getSQLStatement(sql);
MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals(1, mySQLUpdateRecognizer.getUpdateColumns().size());
Assertions.assertEquals("name", mySQLUpdateRecognizer.getUpdateColumns().get(0));
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
Assertions.assertEquals("id = 'id1'", mySQLUpdateRecognizer.getWhereCondition());
}
/**
* Update recognizer test 1.
*/
@Test
public void updateRecognizerTest_1() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = 'id1'";
SQLStatement statement = getSQLStatement(sql);
MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
Assertions.assertEquals("id = 'id1'", mySQLUpdateRecognizer.getWhereCondition());
}
/**
* Update recognizer test 2.
*/
@Test
public void updateRecognizerTest_2() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id = ?";
SQLStatement statement = getSQLStatement(sql);
MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> idParam = new ArrayList<>();
idParam.add("id1");
Map result = new HashMap();
result.put(1, idParam);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Collections.singletonList("id1")), paramAppenderList);
Assertions.assertEquals("id = ?", whereCondition);
}
/**
* Update recognizer test 3.
*/
@Test
public void updateRecognizerTest_3() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id in (?, ?)";
SQLStatement statement = getSQLStatement(sql);
MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> id1Param = new ArrayList<>();
id1Param.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
Map result = new HashMap();
result.put(1, id1Param);
result.put(2, id2Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList);
Assertions.assertEquals("id IN (?, ?)", whereCondition);
}
/**
* Update recognizer test 4.
*/
@Test
public void updateRecognizerTest_4() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id in (?, ?) and name1 = ?";
SQLStatement statement = getSQLStatement(sql);
MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> id1Param = new ArrayList<>();
id1Param.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
ArrayList<Object> name1Param = new ArrayList<>();
name1Param.add("name");
Map result = new HashMap();
result.put(1, id1Param);
result.put(2, id2Param);
result.put(3, name1Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2", "name")), paramAppenderList);
Assertions.assertEquals("id IN (?, ?)\nAND name1 = ?", whereCondition);
}
/**
* Update recognizer test 5.
*/
@Test
public void updateRecognizerTest_5() {
String sql = "UPDATE t1 SET name1 = 'name1', name2 = 'name2' WHERE id between ? and ?";
SQLStatement statement = getSQLStatement(sql);
MySQLUpdateRecognizer mySQLUpdateRecognizer = new MySQLUpdateRecognizer(sql, statement);
Assertions.assertEquals(sql, mySQLUpdateRecognizer.getOriginalSQL());
Assertions.assertEquals("t1", mySQLUpdateRecognizer.getTableName());
Assertions.assertEquals(2, mySQLUpdateRecognizer.getUpdateColumns().size());
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateColumns().get(0));
Assertions.assertEquals("name1", mySQLUpdateRecognizer.getUpdateValues().get(0));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateColumns().get(1));
Assertions.assertEquals("name2", mySQLUpdateRecognizer.getUpdateValues().get(1));
ArrayList<List<Object>> paramAppenderList = new ArrayList<>();
String whereCondition = mySQLUpdateRecognizer.getWhereCondition(new ParametersHolder() {
@Override
public Map<Integer,ArrayList<Object>> getParameters() {
ArrayList<Object> id1Param = new ArrayList<>();
id1Param.add("id1");
ArrayList<Object> id2Param = new ArrayList<>();
id2Param.add("id2");
Map result = new HashMap();
result.put(1, id1Param);
result.put(2, id2Param);
return result;
}
}, paramAppenderList);
Assertions.assertEquals(Collections.singletonList(Arrays.asList("id1", "id2")), paramAppenderList);
Assertions.assertEquals("id BETWEEN ? AND ?", whereCondition);
}
@Test
public void testGetSqlType() {
String sql = "update t set n = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLUpdateRecognizer recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
Assertions.assertEquals(recognizer.getSQLType(), SQLType.UPDATE);
}
@Test
public void testGetUpdateColumns() {
// test with normal
String sql = "update t set a = ?, b = ?, c = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLUpdateRecognizer recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
List<String> updateColumns = recognizer.getUpdateColumns();
Assertions.assertEquals(updateColumns.size(), 3);
// test with alias
sql = "update t set a.a = ?, a.b = ?, a.c = ?";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
updateColumns = recognizer.getUpdateColumns();
Assertions.assertEquals(updateColumns.size(), 3);
//test with error
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "update t set a = a";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement) sqlStatements.get(0);
List<SQLUpdateSetItem> updateSetItems = sqlUpdateStatement.getItems();
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
updateSetItem.setColumn(new MySqlCharExpr());
}
MySQLUpdateRecognizer oracleUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement);
oracleUpdateRecognizer.getUpdateColumns();
});
}
@Test
public void testGetUpdateDatabaseNameColumns() {
// test with normal
String sql = "update d.t set d.t.a = ?, d.t.b = ?, d.t.c = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLUpdateRecognizer recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
List<String> updateColumns = recognizer.getUpdateColumns();
Assertions.assertEquals(updateColumns.size(), 3);
// test with alias
sql = "update t set a.a = ?, a.b = ?, a.c = ?";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
updateColumns = recognizer.getUpdateColumns();
Assertions.assertEquals(updateColumns.size(), 3);
//test with error
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "update t set a = a";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement) sqlStatements.get(0);
List<SQLUpdateSetItem> updateSetItems = sqlUpdateStatement.getItems();
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
updateSetItem.setColumn(new MySqlCharExpr());
}
MySQLUpdateRecognizer oracleUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement);
oracleUpdateRecognizer.getUpdateColumns();
});
}
@Test
public void testGetUpdateValues() {
// test with normal
String sql = "update t set a = ?, b = ?, c = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLUpdateRecognizer recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
List<Object> updateValues = recognizer.getUpdateValues();
Assertions.assertEquals(updateValues.size(), 3);
// test with values
sql = "update t set a = 1, b = 2, c = 3";
asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
updateValues = recognizer.getUpdateValues();
Assertions.assertEquals(updateValues.size(), 3);
// test with error
Assertions.assertThrows(SQLParsingException.class, () -> {
String s = "update t set a = ?";
List<SQLStatement> sqlStatements = SQLUtils.parseStatements(s, JdbcConstants.MYSQL);
SQLUpdateStatement sqlUpdateStatement = (SQLUpdateStatement)sqlStatements.get(0);
List<SQLUpdateSetItem> updateSetItems = sqlUpdateStatement.getItems();
for (SQLUpdateSetItem updateSetItem : updateSetItems) {
updateSetItem.setValue(new MySqlOrderingExpr());
}
MySQLUpdateRecognizer oracleUpdateRecognizer = new MySQLUpdateRecognizer(s, sqlUpdateStatement);
oracleUpdateRecognizer.getUpdateValues();
});
}
@Test
public void testGetTableAlias() {
String sql = "update t set a = ?, b = ?, c = ?";
List<SQLStatement> asts = SQLUtils.parseStatements(sql, JdbcConstants.MYSQL);
MySQLUpdateRecognizer recognizer = new MySQLUpdateRecognizer(sql, asts.get(0));
Assertions.assertNull(recognizer.getTableAlias());
}
@Override
public String getDbType() {
return JdbcConstants.MYSQL;
}
}