gu.sql2java.parser.ParserSupport Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sql2java-manager Show documentation
Show all versions of sql2java-manager Show documentation
sql2java manager class package for accessing database
package gu.sql2java.parser;
import gu.sql2java.pagehelper.PageException;
import net.sf.jsqlparser.JSQLParserException;
import net.sf.jsqlparser.parser.CCJSqlParser;
import net.sf.jsqlparser.parser.CCJSqlParserUtil;
import net.sf.jsqlparser.parser.CCJSqlParserVisitor;
import net.sf.jsqlparser.parser.SimpleNode;
import net.sf.jsqlparser.parser.StringProvider;
import net.sf.jsqlparser.schema.Column;
import net.sf.jsqlparser.statement.Statement;
import net.sf.jsqlparser.statement.select.PlainSelect;
import net.sf.jsqlparser.statement.select.Select;
import net.sf.jsqlparser.statement.select.SelectBody;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import java.lang.reflect.InvocationTargetException;
import java.util.regex.Pattern;
import com.google.common.base.Throwables;
public class ParserSupport {
private static final CountSqlParser countSqlParser = new CountSqlParser();
/**
* 解析SELECT SQL语句,解析失败或非SELECT语句则抛出异常
* @param sql
*/
public static Select parseSelect(String sql){
Statement stmt;
try {
stmt = CCJSqlParserUtil.parse(checkNotNull(sql,"sql is null"));
} catch (JSQLParserException e) {
throw new PageException(e);
}
checkArgument(stmt instanceof Select,"%s is not SELECT statment",sql);
Select select = (Select)stmt;
SelectBody selectBody = select.getSelectBody();
// 暂时只支持简单的SELECT xxxx FROM ....语句不支持复杂语句如WITH
checkArgument(selectBody instanceof PlainSelect,"ONLY SUPPORT plain select statement %s",sql);
return (Select)stmt;
}
/**
* 解析SELECT SQL语句,解析失败或非SELECT语句则
* @param sql
*/
public static Select parseSelectUnchecked(String sql){
try {
return parseSelect(sql);
} catch (Exception e) {
return null;
}
}
/**
* 生成 count 查询 SQL,如果{@code select}为空则返回{@code null}
* @param select
* @param countColumn 列名,默认 0
*/
public static String countSql(Select select, String countColumn){
if(null != select){
SelectBody selectBody = select.getSelectBody();
/**
* count查询时,忽略SQL语句中的分页语句
*/
if(selectBody instanceof PlainSelect){
PlainSelect plainSelect = (PlainSelect)selectBody;
// 删除OFFSET设置
plainSelect.setOffset(null);
// 删除LIMIT设置
plainSelect.setLimit(null);
}
return countSqlParser.getSmartCountSql(select,isNullOrEmpty(countColumn)? "0" : countColumn);
}
return null;
}
/**
* 生成 count 查询 SQL,如果{@code sql}为空或不是SELECT语句不能生成count语句则返回{@code null}
* @param sql
* @param countColumn 列名,默认 0
*/
public static String countSql(String sql, String countColumn){
Select select;
if(!isNullOrEmpty(sql) && null != (select = parseSelectUnchecked(sql))){
return countSql(select,countColumn);
}
return null;
}
/**
* 实现SQL语句解析,解析成功则返回解析后的{@link Statement},
* 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
* @param sql SQL语句
* @param visitor 遍历所有节点的{@link SimpleNode}接口实例,为{@code null}忽略
* @param sqlSyntaxNormalizer SQL语句分析转换器,为{@code null}忽略
* @throws JSQLParserException 输入的SQL语句有语法错误
* @see #parse0(String, CCJSqlParserVisitor, SqlSyntaxNormalizer)
*/
public static Statement parse(String sql,CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxNormalizer) throws JSQLParserException{
return parse0(sql,visitor, sqlSyntaxNormalizer).statement;
}
/**
* 参照{@link CCJSqlParserUtil#parseAST(String)}和{@link CCJSqlParserUtil#parse(String)}实现SQL语句解析,
* 解析成功则返回解析后的{@link SqlParserInfo}对象,
* 并通过{@code visitor}参数提供基于AST(抽象语法树)的遍历所有节点的能力。
* @param sql SQL语句
* @param visitor 遍历所有节点的{@link SimpleNode}接口实例,为{@code null}忽略
* @param sqlSyntaxAnalyzer SQL语句分析转换器,为{@code null}忽略
* @throws JSQLParserException 输入的SQL语句有语法错误
* @see net.sf.jsqlparser.parser.Node#jjtAccept(CCJSqlParserVisitor, Object)
*/
public static SqlParserInfo parse0(String sql,CCJSqlParserVisitor visitor, SqlSyntaxNormalizer sqlSyntaxAnalyzer) throws JSQLParserException{
checkArgument(null != sql,"sql is null");
boolean allowComplexParsing = CCJSqlParserUtil.getNestingDepth(sql)<=CCJSqlParserUtil.ALLOWED_NESTING_DEPTH;
CCJSqlParser parser = CCJSqlParserUtil.newParser(sql).withAllowComplexParsing(allowComplexParsing);
Statement stmt;
try {
stmt = parser.Statement();
} catch (Exception ex) {
throw new JSQLParserException(ex);
}
if(null != visitor){
parser.getASTRoot().jjtAccept(visitor, null);
}
if(null != sqlSyntaxAnalyzer){
stmt.accept(sqlSyntaxAnalyzer.resetChanged());
}
return new SqlParserInfo(stmt.toString(), stmt, (SimpleNode) parser.getASTRoot());
}
/**
* 调用{@link CCJSqlParser}解析SQL语句部件返回解析生成的对象,如{@code 'ORDER BY id DESC'}
* @param
* @param input
* @param method 指定调用的{@link CCJSqlParser}解析方法
* @param targetType 返回的解析对象类型
* @since 3.18.3
*/
public static T parseComponent(String input,String method,Class targetType){
try {
CCJSqlParser parser = new CCJSqlParser(new StringProvider(input));
try {
return checkNotNull(targetType,"targetType is null").cast(parser.getClass().getMethod(method).invoke(parser));
} catch (InvocationTargetException e) {
Throwables.throwIfUnchecked(e.getTargetException());
throw new RuntimeException(e.getTargetException());
}
} catch (IllegalAccessException | NoSuchMethodException | SecurityException e) {
Throwables.throwIfUnchecked(e);
throw new RuntimeException(e);
}
}
/**
* 调用{@link CCJSqlParser}解析SQL语句部件返回解析生成的对象,
* 使用{@code targetType}的类名作为解析方法名
* @see #parseComponent(String, String, Class)
* @since 3.18.3
*/
public static T parseComponent(String input,Class targetType){
return parseComponent(input,
checkNotNull(targetType,"targetType is null").getSimpleName(),
targetType);
}
/**
* 如果{@link Column}没有定义table,且字段名为true/false(不区分大小写)则视为布尔常量
* @param column
*/
public static boolean isBoolean(Column column){
return null != column && null == column.getTable() &&
Pattern.compile("(true|false)", Pattern.CASE_INSENSITIVE).matcher(column.getColumnName()).matches();
}
public static class SqlParserInfo {
final String nativeSql;
final Statement statement;
final SimpleNode simpleNode;
SqlParserInfo(String nativeSql, Statement statement, SimpleNode simpleNode) {
this.nativeSql = nativeSql;
this.statement = statement;
this.simpleNode = simpleNode;
}
}
}