diff --git a/hsweb-commons/hsweb-commons-crud/pom.xml b/hsweb-commons/hsweb-commons-crud/pom.xml index 8b53d6d44..3e3892d55 100644 --- a/hsweb-commons/hsweb-commons-crud/pom.xml +++ b/hsweb-commons/hsweb-commons-crud/pom.xml @@ -12,6 +12,57 @@ hsweb-commons-crud ${project.artifactId} + + + + org.jacoco + jacoco-maven-plugin + + + net/sf/jsqlparser/** + org/hswebframework/web/crud/shaded/jsqlparser/** + + + + + org.apache.maven.plugins + maven-shade-plugin + 3.5.1 + + + package + + shade + + + + + com.github.jsqlparser:jsqlparser + + + + + net.sf.jsqlparser + org.hswebframework.web.crud.shaded.jsqlparser + + + + + *:* + + META-INF/*.SF + META-INF/*.DSA + META-INF/*.RSA + + + + + + + + + + @@ -148,7 +199,7 @@ com.github.jsqlparser jsqlparser - 4.6 + 5.3 @@ -166,4 +217,4 @@ - \ No newline at end of file + diff --git a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/query/QueryAnalyzerImpl.java b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/query/QueryAnalyzerImpl.java index fb5e13d48..5dc4cc5c7 100644 --- a/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/query/QueryAnalyzerImpl.java +++ b/hsweb-commons/hsweb-commons-crud/src/main/java/org/hswebframework/web/crud/query/QueryAnalyzerImpl.java @@ -3,12 +3,11 @@ import lombok.Getter; import lombok.SneakyThrows; import net.sf.jsqlparser.expression.*; -import net.sf.jsqlparser.expression.operators.relational.ExpressionList; import net.sf.jsqlparser.parser.CCJSqlParserUtil; import net.sf.jsqlparser.schema.Column; import net.sf.jsqlparser.schema.Table; +import net.sf.jsqlparser.statement.piped.FromQuery; import net.sf.jsqlparser.statement.select.*; -import net.sf.jsqlparser.statement.values.ValuesStatement; import org.apache.commons.collections4.CollectionUtils; import org.hswebframework.ezorm.core.meta.FeatureSupportedMetadata; import org.hswebframework.ezorm.core.param.Sort; @@ -24,29 +23,51 @@ import java.util.*; -import static net.sf.jsqlparser.statement.select.PlainSelect.getFormatedList; +import static net.sf.jsqlparser.statement.select.Select.getFormattedList; import static org.hswebframework.ezorm.rdb.operator.builder.fragments.TermFragmentBuilder.createFeatureId; -class QueryAnalyzerImpl implements FromItemVisitor, SelectItemVisitor, SelectVisitor, QueryAnalyzer { +class QueryAnalyzerImpl implements FromItemVisitor, SelectItemVisitor, SelectVisitor, QueryAnalyzer { + + private static final String UNSUPPORTED_DISTANCE_OPERATOR = "<=>"; + + private static final List PARSER_OPERATOR_PLACEHOLDERS = Arrays.asList("!~*", "~*", "@@", "@>", "<@", "&&", "~"); private final DatabaseOperator database; private String sql; - private final SelectBody parsed; + private final net.sf.jsqlparser.statement.select.Select parsed; + + private String parserOperatorPlaceholder; private QueryAnalyzer.Select select; private final Map joins = new LinkedHashMap<>(); - private final List withItems = new ArrayList<>(); + private final List> withItems = new ArrayList<>(); private QueryRefactor injector; private volatile Map columnMappings; private final Map virtualTable = new HashMap<>(); + private static T acceptFromItem(FromItem fromItem, FromItemVisitor visitor) { + return fromItem.accept(visitor, null); + } + + private static T acceptSelect(net.sf.jsqlparser.statement.select.Select select, SelectVisitor visitor) { + return select.accept(visitor, null); + } + + private static T acceptWithItem(WithItem withItem, SelectVisitor visitor) { + return withItem.accept(visitor, null); + } + + private static T acceptSelectItem(SelectItem selectItem, SelectItemVisitor visitor) { + return selectItem.accept(visitor, null); + } + @Override public String originalSql() { return sql; @@ -88,6 +109,11 @@ public List joins() { this.sql = sql; } + private QueryAnalyzerImpl(DatabaseOperator database, ParsedSelect parsed) { + this(database, parsed.select); + this.parserOperatorPlaceholder = parsed.operatorPlaceholder; + } + public boolean columnIsExpression(String name, int index) { @@ -178,48 +204,69 @@ private Column getColumnOrSelectColumn(String name) { } @SneakyThrows - private static net.sf.jsqlparser.statement.select.Select parse(String sql) { - return ((net.sf.jsqlparser.statement.select.Select) CCJSqlParserUtil.parse(sql)); + private static ParsedSelect parse(String sql) { + String operatorPlaceholder = null; + String sqlToParse = sql; + if (sql.contains(UNSUPPORTED_DISTANCE_OPERATOR)) { + operatorPlaceholder = PARSER_OPERATOR_PLACEHOLDERS + .stream() + .filter(candidate -> !sql.contains(candidate)) + .findFirst() + .orElseThrow(() -> new IllegalArgumentException("Unable to parse sql with operator " + UNSUPPORTED_DISTANCE_OPERATOR)); + sqlToParse = sql.replace(UNSUPPORTED_DISTANCE_OPERATOR, operatorPlaceholder); + } + return new ParsedSelect( + ((net.sf.jsqlparser.statement.select.Select) CCJSqlParserUtil.parse(sqlToParse)), + operatorPlaceholder + ); } - QueryAnalyzerImpl(DatabaseOperator database, SelectBody selectBody, QueryAnalyzerImpl parent) { - this.database = database; - this.virtualTable.putAll(parent.virtualTable); - if (null != selectBody) { - this.parsed = selectBody; - selectBody.accept(this); - } else { - this.parsed = null; + private static net.sf.jsqlparser.statement.select.Select unwrapParenthesedSelect(net.sf.jsqlparser.statement.select.Select select) { + while (select instanceof ParenthesedSelect parenthesedSelect) { + select = parenthesedSelect.getSelect(); } + return select; + } + + private String restoreParserPlaceholders(Object sql) { + return sql == null ? null : restoreParserPlaceholders(sql.toString()); } - QueryAnalyzerImpl(DatabaseOperator database, SubSelect select, QueryAnalyzerImpl parent) { - this.parsed = select.getSelectBody(); + private String restoreParserPlaceholders(String sql) { + if (parserOperatorPlaceholder == null || sql == null) { + return sql; + } + return sql.replace(parserOperatorPlaceholder, UNSUPPORTED_DISTANCE_OPERATOR); + } + + QueryAnalyzerImpl(DatabaseOperator database, net.sf.jsqlparser.statement.select.Select selectBody, QueryAnalyzerImpl parent) { this.database = database; this.virtualTable.putAll(parent.virtualTable); - //with ... - if (CollectionUtils.isNotEmpty(select.getWithItemsList())) { - for (WithItem withItem : select.getWithItemsList()) { - withItem.accept(this); + if (null != selectBody) { + this.parsed = selectBody; + if (CollectionUtils.isNotEmpty(selectBody.getWithItemsList())) { + for (WithItem withItem : selectBody.getWithItemsList()) { + acceptWithItem(withItem, this); + } } - } - if (this.parsed != null) { - this.parsed.accept(this); + acceptSelect(selectBody, this); + } else { + this.parsed = null; } } QueryAnalyzerImpl(DatabaseOperator database, net.sf.jsqlparser.statement.select.Select select) { - this.parsed = select.getSelectBody(); + this.parsed = select; this.database = database; //with ... if (CollectionUtils.isNotEmpty(select.getWithItemsList())) { - for (WithItem withItem : select.getWithItemsList()) { - withItem.accept(this); + for (WithItem withItem : select.getWithItemsList()) { + acceptWithItem(withItem, this); } } if (this.parsed != null) { - this.parsed.accept(this); + acceptSelect(this.parsed, this); } } @@ -239,7 +286,7 @@ private String parsePlainName(String name) { } @Override - public void visit(net.sf.jsqlparser.schema.Table tableName) { + public Void visit(net.sf.jsqlparser.schema.Table tableName, S context) { String schema = parsePlainName(tableName.getSchemaName()); String name = parsePlainName(tableName.getName()); @@ -273,17 +320,28 @@ public void visit(net.sf.jsqlparser.schema.Table tableName) { ); select = new QueryAnalyzer.Select(new ArrayList<>(), table); - + return null; } // select * from ( select a,b,c from table ) t @Override - public void visit(SubSelect subSelect) { - visit(subSelect, subSelect.getAlias() == null ? null : subSelect.getAlias().getName()); + public Void visit(ParenthesedSelect select, S context) { + visit(select, select.getAlias() == null ? null : select.getAlias().getName()); + return null; + } + + @Override + public void visit(ParenthesedSelect select) { + visit(select, (Object) null); } - public void visit(SubSelect subSelect, String alias) { - SelectBody body = subSelect.getSelectBody(); + private void visit(ParenthesedSelect subSelect, String alias) { + net.sf.jsqlparser.statement.select.Select body = subSelect.getSelect(); + if (body instanceof Values values) { + visitValues(values, subSelect.getAlias() == null ? values.getAlias() : subSelect.getAlias()); + return; + } + QueryAnalyzerImpl sub = new QueryAnalyzerImpl(database, body, this); Map columnMap = new LinkedHashMap<>(); for (Column column : sub.select.getColumnList()) { @@ -327,36 +385,28 @@ public void visit(SubSelect subSelect, String alias) { } @Override - public void visit(SubJoin subjoin) { - for (net.sf.jsqlparser.statement.select.Join join : subjoin.getJoinList()) { - join.getRightItem().accept(this); - } + public Void visit(LateralSubSelect lateralSubSelect, S context) { + this.visit((ParenthesedSelect) lateralSubSelect, + lateralSubSelect.getAlias() == null ? null : lateralSubSelect.getAlias().getName()); + return null; } @Override public void visit(LateralSubSelect lateralSubSelect) { - this.visit(lateralSubSelect.getSubSelect(), - lateralSubSelect.getAlias() == null ? null : lateralSubSelect.getAlias().getName()); + visit(lateralSubSelect, (Object) null); } - @Override - public void visit(ValuesList valuesList) { - if (valuesList.getAlias() == null) { - throw new IllegalArgumentException("valuesList[" + valuesList + "] must have alias"); + private void visitValues(Values values, Alias alias) { + if (alias == null) { + throw new IllegalArgumentException("values[" + values + "] must have alias"); } - String name = parsePlainName(valuesList.getAlias().getName()); + String name = parsePlainName(alias.getName()); FakeTable view = new FakeTable(); view.setSchema(database.getMetadata().getCurrentSchema()); - if (valuesList.getColumnNames() != null) { - //获取会自动创建列 - for (String columnName : valuesList.getColumnNames()) { - RDBColumnMetadata ignore = view.getColumn(parsePlainName(columnName)).orElse(null); - } - } - if (valuesList.getAlias().getAliasColumns() != null) { - for (Alias.AliasColumn alias : valuesList.getAlias().getAliasColumns()) { - RDBColumnMetadata ignore = view.getColumn(parsePlainName(alias.name)).orElse(null); + if (alias.getAliasColumns() != null) { + for (Alias.AliasColumn aliasColumn : alias.getAliasColumns()) { + RDBColumnMetadata ignore = view.getColumn(parsePlainName(aliasColumn.name)).orElse(null); } } @@ -371,7 +421,7 @@ public void visit(ValuesList valuesList) { } @Override - public void visit(TableFunction tableFunction) { + public Void visit(TableFunction tableFunction, S context) { if (tableFunction.getAlias() == null) { throw new IllegalArgumentException("table function[" + tableFunction + "] must have alias"); } @@ -386,19 +436,42 @@ public void visit(TableFunction tableFunction) { Table table = new Table(name, view); select = new QueryAnalyzer.Select(new ArrayList<>(), table); - + return null; } @Override - public void visit(ParenthesisFromItem aThis) { - aThis.getFromItem().accept(this); + public Void visit(ParenthesedFromItem aThis, S context) { + if (aThis.getFromItem() instanceof Values values) { + visitValues(values, aThis.getAlias()); + } else { + acceptFromItem(aThis.getFromItem(), this); + } + if (CollectionUtils.isNotEmpty(aThis.getJoins())) { + for (net.sf.jsqlparser.statement.select.Join join : aThis.getJoins()) { + FromItem fromItem = join.getRightItem(); + QueryAnalyzerImpl joinAn = new QueryAnalyzerImpl(database, (net.sf.jsqlparser.statement.select.Select) null, this); + acceptFromItem(fromItem, joinAn); + + Join.Type type; + if (join.isLeft()) { + type = Join.Type.left; + } else if (join.isRight()) { + type = Join.Type.right; + } else if (join.isInner()) { + type = Join.Type.inner; + } else { + type = null; + } + joins.put(joinAn.select.table.alias, new Join(joinAn.select.table.alias, type, joinAn.select.table)); + } + } String alias = parsePlainName(aThis.getAlias() == null ? null : aThis.getAlias().getName()); if (alias != null) { this.select = select.newSelectAlias(alias); } + return null; } - @Override public void visit(AllColumns allColumns) { putSelectColumns(select.table, select.columnList); @@ -435,7 +508,6 @@ private void putSelectColumns(QueryAnalyzer.Table table, List expr; - public ExpressionColumn(String alias, String owner, RDBColumnMetadata metadata, SelectItem expr) { + public ExpressionColumn(String alias, String owner, RDBColumnMetadata metadata, SelectItem expr) { super(alias, alias, owner, metadata); this.expr = expr; } @@ -501,8 +573,17 @@ private void refactorAlias(Alias alias) { } @Override - public void visit(SelectExpressionItem selectExpressionItem) { + public Void visit(SelectItem selectExpressionItem, S context) { Expression expr = selectExpressionItem.getExpression(); + if (expr instanceof AllColumns allColumns) { + visit(allColumns); + return null; + } + if (expr instanceof AllTableColumns allTableColumns) { + visit(allTableColumns); + return null; + } + Alias alias = selectExpressionItem.getAlias(); if (!(expr instanceof net.sf.jsqlparser.schema.Column column)) { @@ -510,7 +591,7 @@ public void visit(SelectExpressionItem selectExpressionItem) { refactorAlias(alias); select.columnList.add(new ExpressionColumn(aliasName, null, null, selectExpressionItem)); - return; + return null; } String columnName = parsePlainName(column.getColumnName()); @@ -530,7 +611,7 @@ public void visit(SelectExpressionItem selectExpressionItem) { if (null != c) { if (c.metadata == null) { select.columnList.add(new QueryAnalyzer.Column(c.getName(), aliasName, table.alias, null)); - return; + return null; } metadata = c.metadata; } @@ -542,19 +623,18 @@ public void visit(SelectExpressionItem selectExpressionItem) { } select.columnList.add(new QueryAnalyzer.Column(metadata.getRealName(), aliasName, table.alias, metadata)); - - + return null; } @Override - public void visit(PlainSelect select) { + public Void visit(PlainSelect select, S context) { FromItem from = select.getFromItem(); if (from == null) { throw new IllegalArgumentException("select can not be without 'from'"); } - from.accept(this); + acceptFromItem(from, this); List joinList = select.getJoins(); @@ -562,8 +642,8 @@ public void visit(PlainSelect select) { if (joinList != null) { for (net.sf.jsqlparser.statement.select.Join join : joinList) { FromItem fromItem = join.getRightItem(); - QueryAnalyzerImpl joinAn = new QueryAnalyzerImpl(database, (SelectBody) null, this); - fromItem.accept(joinAn); + QueryAnalyzerImpl joinAn = new QueryAnalyzerImpl(database, (net.sf.jsqlparser.statement.select.Select) null, this); + acceptFromItem(fromItem, joinAn); Join.Type type; if (join.isLeft()) { @@ -579,34 +659,44 @@ public void visit(PlainSelect select) { } } - for (SelectItem selectItem : select.getSelectItems()) { - selectItem.accept(this); + for (SelectItem selectItem : select.getSelectItems()) { + acceptSelectItem(selectItem, this); } + return null; } @Override - public void visit(SetOperationList setOpList) { + public void visit(PlainSelect select) { + visit(select, (Object) null); + } + + @Override + public Void visit(SetOperationList setOpList, S context) { //union - for (SelectBody body : setOpList.getSelects()) { - body.accept(this); + for (net.sf.jsqlparser.statement.select.Select body : setOpList.getSelects()) { + acceptSelect(body, this); // break; } + return null; + } - + @Override + public void visit(SetOperationList setOpList) { + visit(setOpList, (Object) null); } @Override - public void visit(WithItem withItem) { + public Void visit(WithItem withItem, S context) { withItems.add(withItem); - String name = withItem.getName(); + String name = withItem.getAlias().getName(); RDBViewMetadata view = new RDBViewMetadata(); view.setName(name); view.setSchema(database.getMetadata().getCurrentSchema()); virtualTable.put(name, view); - if (withItem.getSubSelect() != null) { - QueryAnalyzerImpl analyzer = new QueryAnalyzerImpl(database, withItem.getSubSelect(), this); + if (withItem.getSelect() != null) { + QueryAnalyzerImpl analyzer = new QueryAnalyzerImpl(database, unwrapParenthesedSelect(withItem.getSelect()), this); for (Column column : analyzer.select.getColumnList()) { RDBColumnMetadata metadata; if (column.getMetadata() == null) { @@ -619,18 +709,39 @@ public void visit(WithItem withItem) { view.addColumn(metadata); } } + return null; + } + + @Override + public Void visit(Values values, S context) { + visitValues(values, values.getAlias()); + return null; + } + + @Override + public void visit(Values values) { + visit(values, (Object) null); + } + + @Override + public Void visit(TableStatement tableStatement, S context) { + return null; } @Override - public void visit(ValuesStatement aThis) { + public void visit(TableStatement tableStatement) { + } + @Override + public Void visit(FromQuery fromQuery, S context) { + throw new UnsupportedOperationException("Pipe query syntax is not supported"); } private void initInjector() { SimpleQueryRefactor injector = new SimpleQueryRefactor(); - parsed.accept(injector); - for (WithItem withItem : withItems) { - withItem.accept(injector); + acceptSelect(parsed, injector); + for (WithItem withItem : withItems) { + acceptWithItem(withItem, injector); } this.injector = injector; } @@ -708,7 +819,7 @@ public SqlFragments createTermFragments(QueryAnalyzerImpl impl, Term term) { static QueryAnalyzerTermsFragmentBuilder TERMS_BUILDER = new QueryAnalyzerTermsFragmentBuilder(); - class SimpleQueryRefactor implements QueryRefactor, SelectVisitor { + class SimpleQueryRefactor implements QueryRefactor, SelectVisitor { private String prefix = ""; private String from; @@ -748,7 +859,7 @@ private void initColumns(StringBuilder columns) { columns.append(","); } if (column instanceof ExpressionColumn) { - columns.append(((ExpressionColumn) column).expr); + columns.append(restoreParserPlaceholders(((ExpressionColumn) column).expr)); fastCount = false; continue; } @@ -762,7 +873,7 @@ private void initColumns(StringBuilder columns) { } @Override - public void visit(PlainSelect plainSelect) { + public Void visit(PlainSelect plainSelect, S context) { StringBuilder from = new StringBuilder(); StringBuilder columns = new StringBuilder(); @@ -779,8 +890,8 @@ public void visit(PlainSelect plainSelect) { if (plainSelect.getSelectItems() != null) { PrepareStatementVisitor visitor = new PrepareStatementVisitor(); - for (SelectItem selectItem : plainSelect.getSelectItems()) { - selectItem.accept(visitor); + for (SelectItem selectItem : plainSelect.getSelectItems()) { + acceptSelectItem(selectItem, visitor); } prefixParameters += visitor.parameterSize; } @@ -788,9 +899,9 @@ public void visit(PlainSelect plainSelect) { if (plainSelect.getFromItem() != null) { from.append("FROM "); - from.append(plainSelect.getFromItem()); + from.append(restoreParserPlaceholders(plainSelect.getFromItem())); PrepareStatementVisitor visitor = new PrepareStatementVisitor(); - plainSelect.getFromItem().accept(visitor); + acceptFromItem(plainSelect.getFromItem(), visitor); prefixParameters += visitor.parameterSize; } @@ -798,12 +909,12 @@ public void visit(PlainSelect plainSelect) { PrepareStatementVisitor visitor = new PrepareStatementVisitor(); for (net.sf.jsqlparser.statement.select.Join join : plainSelect.getJoins()) { if (join.isSimple()) { - from.append(", ").append(join); + from.append(", ").append(restoreParserPlaceholders(join)); } else { - from.append(" ").append(join); + from.append(" ").append(restoreParserPlaceholders(join)); } if (null != join.getRightItem()) { - join.getRightItem().accept(visitor); + acceptFromItem(join.getRightItem(), visitor); } if (null != join.getOnExpressions()) { for (Expression onExpression : join.getOnExpressions()) { @@ -818,7 +929,7 @@ public void visit(PlainSelect plainSelect) { PrepareStatementVisitor visitor = new PrepareStatementVisitor(); plainSelect.getWhere().accept(visitor); prefixParameters += visitor.parameterSize; - where = plainSelect.getWhere().toString(); + where = restoreParserPlaceholders(plainSelect.getWhere()); } if (plainSelect.getOrderByElements() != null) { @@ -827,12 +938,12 @@ public void visit(PlainSelect plainSelect) { orderByElement.getExpression().accept(visitor); } suffixParameters = visitor.parameterSize; - orderBy = getFormatedList(plainSelect.getOrderByElements(), ""); + orderBy = restoreParserPlaceholders(getFormattedList(plainSelect.getOrderByElements(), "")); } if (plainSelect.getGroupBy() != null) { fastCount = false; - suffix.append(' ').append(plainSelect.getGroupBy()); + suffix.append(' ').append(restoreParserPlaceholders(plainSelect.getGroupBy())); PrepareStatementVisitor visitor = new PrepareStatementVisitor(); plainSelect.getGroupBy().getGroupByExpressionList().accept(visitor); @@ -844,48 +955,73 @@ public void visit(PlainSelect plainSelect) { PrepareStatementVisitor visitor = new PrepareStatementVisitor(); plainSelect.getHaving().accept(visitor); suffixParameters = visitor.parameterSize; - suffix.append(" HAVING ").append(plainSelect.getHaving()); + suffix.append(" HAVING ").append(restoreParserPlaceholders(plainSelect.getHaving())); } this.columns = columns.toString(); this.from = from.toString(); this.suffix = suffix.toString(); - + return null; } @Override - public void visit(SetOperationList setOpList) { + public Void visit(SetOperationList setOpList, S context) { StringBuilder from = new StringBuilder(); StringBuilder columns = new StringBuilder(); initColumns(columns); from.append("FROM ("); - from.append(setOpList); + from.append(restoreParserPlaceholders(setOpList)); from.append(") "); from.append(select.table.alias); this.from = from.toString(); this.columns = columns.toString(); this.suffix = ""; + return null; + } + @Override + public Void visit(ParenthesedSelect select, S context) { + if (select.getSelect() != null) { + acceptSelect(select.getSelect(), this); + } + return null; } @Override - public void visit(WithItem withItem) { + public Void visit(WithItem withItem, S context) { if (!StringUtils.hasText(prefix)) { prefix += "WITH "; } - prefix += withItem; + prefix += restoreParserPlaceholders(withItem); PrepareStatementVisitor visitor = new PrepareStatementVisitor(); - withItem.accept(visitor); + acceptWithItem(withItem, visitor); prefixParameters += visitor.parameterSize; + return null; } @Override - public void visit(ValuesStatement aThis) { + public Void visit(Values values, S context) { PrepareStatementVisitor visitor = new PrepareStatementVisitor(); - aThis.accept(visitor); + values.getExpressions().accept(visitor); + return null; + } + + @Override + public Void visit(LateralSubSelect lateralSubSelect, S context) { + return visit((ParenthesedSelect) lateralSubSelect, context); + } + + @Override + public Void visit(TableStatement tableStatement, S context) { + return null; + } + + @Override + public Void visit(FromQuery fromQuery, S context) { + throw new UnsupportedOperationException("Pipe query syntax is not supported"); } public Object[] getPrefixParameters(Object... args) { @@ -1074,7 +1210,7 @@ private void appendWhere(AppendableSqlFragments sql, QueryParamEntity param) { @Getter - static class PrepareStatementVisitor extends ExpressionVisitorAdapter implements FromItemVisitor, SelectVisitor { + static class PrepareStatementVisitor extends ExpressionVisitorAdapter implements FromItemVisitor, SelectVisitor { private int parameterSize; public PrepareStatementVisitor() { @@ -1082,73 +1218,80 @@ public PrepareStatementVisitor() { } @Override - public void visit(JdbcParameter parameter) { + public Void visit(JdbcParameter parameter, S context) { parameterSize++; - super.visit(parameter); + return super.visit(parameter, context); } @Override - public void visit(net.sf.jsqlparser.schema.Table tableName) { - + public Void visit(net.sf.jsqlparser.schema.Table tableName, S context) { + return null; } @Override - public void visit(SubJoin subjoin) { - if (subjoin.getLeft() != null) { - subjoin.getLeft().accept(this); + public Void visit(ParenthesedFromItem fromItem, S context) { + if (fromItem.getFromItem() != null) { + acceptFromItem(fromItem.getFromItem(), this); } - if (CollectionUtils.isNotEmpty(subjoin.getJoinList())) { - for (net.sf.jsqlparser.statement.select.Join join : subjoin.getJoinList()) { + if (CollectionUtils.isNotEmpty(fromItem.getJoins())) { + for (net.sf.jsqlparser.statement.select.Join join : fromItem.getJoins()) { if (join.getRightItem() != null) { - join.getRightItem().accept(this); + acceptFromItem(join.getRightItem(), this); } if (join.getOnExpressions() != null) { join.getOnExpressions().forEach(expr -> expr.accept(this)); } } } + return null; } @Override - public void visit(LateralSubSelect lateralSubSelect) { - if (lateralSubSelect.getSubSelect() != null) { - lateralSubSelect.getSubSelect().accept((ExpressionVisitor) this); + public Void visit(LateralSubSelect lateralSubSelect, S context) { + if (lateralSubSelect.getSelect() != null) { + acceptSelect(lateralSubSelect.getSelect(), this); } + return null; } @Override - public void visit(ValuesList valuesList) { - if (valuesList.getMultiExpressionList() != null) { - for (ExpressionList expressionList : valuesList.getMultiExpressionList().getExpressionLists()) { - expressionList.getExpressions().forEach(expr -> expr.accept(this)); - } + public void visit(LateralSubSelect lateralSubSelect) { + visit(lateralSubSelect, (Object) null); + } + + @Override + public Void visit(Values values, S context) { + if (values.getExpressions() != null) { + values.getExpressions().accept(this); } + return null; } @Override - public void visit(TableFunction tableFunction) { - tableFunction.getFunction().accept(this); + public void visit(Values values) { + visit(values, (Object) null); } @Override - public void visit(ParenthesisFromItem aThis) { - aThis.getFromItem().accept(this); + public Void visit(TableFunction tableFunction, S context) { + tableFunction.getFunction().accept(this); + return null; } @Override - public void visit(PlainSelect plainSelect) { - plainSelect.getFromItem().accept(this); + public Void visit(PlainSelect plainSelect, S context) { + acceptFromItem(plainSelect.getFromItem(), this); if (plainSelect.getJoins() != null) { for (net.sf.jsqlparser.statement.select.Join join : plainSelect.getJoins()) { - join.getRightItem().accept(this); + acceptFromItem(join.getRightItem(), this); if (join.getOnExpressions() != null) { join.getOnExpressions().forEach(expr -> expr.accept(this)); } } } if (plainSelect.getSelectItems() != null) { - for (SelectItem selectItem : plainSelect.getSelectItems()) { - selectItem.accept(this); + for (SelectItem selectItem : plainSelect.getSelectItems()) { + acceptSelectItem(selectItem, this); } } if (plainSelect.getWhere() != null) { @@ -1159,7 +1302,7 @@ public void visit(PlainSelect plainSelect) { } if (plainSelect.getDistinct() != null && plainSelect.getDistinct().getOnSelectItems() != null) { - plainSelect.getDistinct().getOnSelectItems().forEach(expr -> expr.accept(this)); + plainSelect.getDistinct().getOnSelectItems().forEach(item -> item.getExpression().accept(this)); } if (plainSelect.getOrderByElements() != null) { @@ -1169,17 +1312,23 @@ public void visit(PlainSelect plainSelect) { } if (plainSelect.getGroupBy() != null) { - for (Expression expression : plainSelect.getGroupBy().getGroupByExpressionList().getExpressions()) { - expression.accept(this); + for (Object expression : plainSelect.getGroupBy().getGroupByExpressionList()) { + ((Expression) expression).accept(this); } } + return null; } @Override - public void visit(SetOperationList setOpList) { + public void visit(PlainSelect plainSelect) { + visit(plainSelect, (Object) null); + } + + @Override + public Void visit(SetOperationList setOpList, S context) { if (CollectionUtils.isNotEmpty(setOpList.getSelects())) { - for (SelectBody select : setOpList.getSelects()) { - select.accept(this); + for (net.sf.jsqlparser.statement.select.Select select : setOpList.getSelects()) { + acceptSelect(select, this); } } if (setOpList.getOffset() != null) { @@ -1193,25 +1342,73 @@ public void visit(SetOperationList setOpList) { setOpList.getLimit().getOffset().accept(this); } } + return null; + } + + @Override + public void visit(SetOperationList setOpList) { + visit(setOpList, (Object) null); } @Override - public void visit(WithItem withItem) { + public Void visit(WithItem withItem, S context) { if (CollectionUtils.isNotEmpty(withItem.getWithItemList())) { - for (SelectItem selectItem : withItem.getWithItemList()) { - selectItem.accept(this); + for (SelectItem selectItem : withItem.getWithItemList()) { + acceptSelectItem(selectItem, this); } } - if (withItem.getSubSelect() != null) { - withItem.getSubSelect().accept((ExpressionVisitor) this); + if (withItem.getSelect() != null) { + acceptSelect(withItem.getSelect(), this); + } + return null; + } + + @Override + public Void visit(ParenthesedSelect select, S context) { + if (select.getSelect() != null) { + acceptSelect(select.getSelect(), this); + } + return null; + } + + @Override + public void visit(ParenthesedSelect select) { + visit(select, (Object) null); + } + + @Override + public Void visit(TableStatement tableStatement, S context) { + return null; + } + + @Override + public void visit(TableStatement tableStatement) { + } + + @Override + public Void visit(FromQuery fromQuery, S context) { + if (fromQuery.getFromItem() != null) { + acceptFromItem(fromQuery.getFromItem(), this); + } + if (CollectionUtils.isNotEmpty(fromQuery.getJoins())) { + for (net.sf.jsqlparser.statement.select.Join join : fromQuery.getJoins()) { + if (join.getRightItem() != null) { + acceptFromItem(join.getRightItem(), this); + } + if (join.getOnExpressions() != null) { + join.getOnExpressions().forEach(expr -> expr.accept(this)); + } + } } + return null; } @Override - public void visit(ValuesStatement aThis) { - if (aThis.getExpressions() != null) { - aThis.getExpressions().accept(this); + public Void visit(SelectItem selectItem, S context) { + if (selectItem.getExpression() != null) { + selectItem.getExpression().accept(this); } + return null; } } @@ -1230,6 +1427,16 @@ public Optional getColumn(String name) { } } + private static class ParsedSelect { + final net.sf.jsqlparser.statement.select.Select select; + final String operatorPlaceholder; + + private ParsedSelect(net.sf.jsqlparser.statement.select.Select select, String operatorPlaceholder) { + this.select = select; + this.operatorPlaceholder = operatorPlaceholder; + } + } + private interface QueryRefactor { SqlRequest refactor(QueryParamEntity param, Object... args); diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/DefaultQueryHelperTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/DefaultQueryHelperTest.java index c5d7844ee..dab376a3d 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/DefaultQueryHelperTest.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/DefaultQueryHelperTest.java @@ -337,9 +337,9 @@ public void test() { DefaultQueryHelper helper = new DefaultQueryHelper(database); helper.select(TestInfo.class) - // .all(EventTestEntity.class, TestInfo::setEventList) + // .all(EventTestEntity.class, TestInfo::setEventList) .all("e2", TestInfo::setEvent) - .as("e2.name",TestInfo::setE2Name) + .as("e2.name", TestInfo::setE2Name) .all(TestEntity.class) .from(TestEntity.class) // .leftJoin(EventTestEntity.class, @@ -353,8 +353,8 @@ public void test() { .alias("e2") .is(EventTestEntity::getId, TestEntity::getId) .nest() - .is(EventTestEntity::getId,TestEntity::getId) - .is(EventTestEntity::getAge,10) + .is(EventTestEntity::getId, TestEntity::getId) + .is(EventTestEntity::getAge, 10) .end() ) .where(dsl -> dsl.is(EventTestEntity::getName, "Ename") diff --git a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/QueryAnalyzerImplTest.java b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/QueryAnalyzerImplTest.java index 0beab09f8..1d813a153 100644 --- a/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/QueryAnalyzerImplTest.java +++ b/hsweb-commons/hsweb-commons-crud/src/test/java/org/hswebframework/web/crud/query/QueryAnalyzerImplTest.java @@ -6,11 +6,13 @@ import org.hswebframework.web.api.crud.entity.QueryParamEntity; import org.hswebframework.web.crud.TestApplication; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; +import reactor.core.publisher.Flux; import reactor.test.StepVerifier; import static org.junit.jupiter.api.Assertions.*; @@ -21,6 +23,18 @@ public class QueryAnalyzerImplTest { @Autowired private DatabaseOperator database; + @Before + public void before() { + Flux.concat( + database.sql().reactive().update("delete from test_tree_sort"), + database.sql().reactive().update("delete from s_test_event"), + database.sql().reactive().update("delete from s_test") + ) + .then() + .as(StepVerifier::create) + .verifyComplete(); + } + /** * 执行SQL并验证是否有错误 */ @@ -1093,4 +1107,4 @@ public void testAggregateFunctions() { // 验证SQL可以执行 executeAndVerify(request); } -} \ No newline at end of file +}