This is an automated email from the ASF dual-hosted git repository.
duanzhengqiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
The following commit(s) were added to refs/heads/master by this push:
new d03e3cec8ed Support select distinct(column) encrypt rewrite and
refactor SubstitutableColumnNameToken build logic (#32344)
d03e3cec8ed is described below
commit d03e3cec8ed84d0f32bb97ba3b38e24e394f6264
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Wed Jul 31 18:44:38 2024 +0800
Support select distinct(column) encrypt rewrite and refactor
SubstitutableColumnNameToken build logic (#32344)
* Support select distinct(column) encrypt rewrite and refactor
SubstitutableColumnNameToken build logic
* remove useless param
---
.../EncryptIndexColumnTokenGenerator.java | 4 +-
.../EncryptProjectionTokenGenerator.java | 81 ++++++++++++++--------
.../select/projection/engine/ProjectionEngine.java | 3 +-
.../select/projection/impl/ColumnProjection.java | 29 +++++++-
.../expression/type/ColumnSegmentBinder.java | 3 +-
.../pojo/generic/SubstitutableColumnNameToken.java | 6 +-
.../visitor/statement/DorisStatementVisitor.java | 4 +-
.../visitor/statement/MySQLStatementVisitor.java | 6 +-
.../core/segment/dml/column/ColumnSegment.java | 25 ++++++-
.../core/segment/generic/ParenthesesSegment.java | 4 +-
.../asserts/segment/generic/ParenthesesAssert.java | 2 +-
.../segment/projection/ProjectionAssert.java | 27 ++++++--
.../segment/impl/generic/ExpectedParentheses.java | 4 +-
.../impl/column/ExpectedColumnProjection.java | 9 +--
.../parser/src/main/resources/case/dml/select.xml | 9 ++-
.../sql/supported/dml/select-distinct.xml | 4 +-
.../dml/select/select-distinct.xml | 12 ++++
17 files changed, 169 insertions(+), 63 deletions(-)
diff --git
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptIndexColumnTokenGenerator.java
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptIndexColumnTokenGenerator.java
index bd7631bf68c..6baef50288f 100644
---
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptIndexColumnTokenGenerator.java
+++
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/EncryptIndexColumnTokenGenerator.java
@@ -22,15 +22,15 @@ import lombok.Setter;
import org.apache.shardingsphere.encrypt.rewrite.aware.DatabaseTypeAware;
import org.apache.shardingsphere.encrypt.rewrite.aware.EncryptRuleAware;
import org.apache.shardingsphere.encrypt.rule.EncryptRule;
-import org.apache.shardingsphere.encrypt.rule.table.EncryptTable;
import org.apache.shardingsphere.encrypt.rule.column.EncryptColumn;
+import org.apache.shardingsphere.encrypt.rule.table.EncryptTable;
import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.Projection;
import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.impl.ColumnProjection;
import
org.apache.shardingsphere.infra.binder.context.statement.SQLStatementContext;
import org.apache.shardingsphere.infra.binder.context.type.IndexAvailable;
import org.apache.shardingsphere.infra.binder.context.type.TableAvailable;
-import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import
org.apache.shardingsphere.infra.database.core.metadata.database.enums.QuoteCharacter;
+import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import
org.apache.shardingsphere.infra.rewrite.sql.token.generator.CollectionSQLTokenGenerator;
import org.apache.shardingsphere.infra.rewrite.sql.token.pojo.SQLToken;
import
org.apache.shardingsphere.infra.rewrite.sql.token.pojo.generic.SubstitutableColumnNameToken;
diff --git
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
index 69ec9740e0d..2aadf69e135 100644
---
a/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
+++
b/features/encrypt/core/src/main/java/org/apache/shardingsphere/encrypt/rewrite/token/generator/projection/EncryptProjectionTokenGenerator.java
@@ -39,6 +39,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.Colu
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParenthesesSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
import java.util.Collection;
@@ -98,9 +99,10 @@ public final class EncryptProjectionTokenGenerator {
Optional<EncryptTable> encryptTable =
encryptRule.findEncryptTable(columnProjection.getOriginalTable().getValue());
if (encryptTable.isPresent() &&
encryptTable.get().isEncryptColumn(columnName) &&
!selectStatementContext.containsTableSubquery()) {
EncryptColumn encryptColumn =
encryptTable.get().getEncryptColumn(columnName);
- Collection<Projection> projections =
generateProjections(encryptColumn, columnProjection,
selectStatementContext.getSubqueryType(), false);
- int startIndex = columnSegment.getColumn().getOwner().isPresent()
? columnSegment.getColumn().getOwner().get().getStopIndex() + 2 :
columnSegment.getColumn().getStartIndex();
- int stopIndex = columnSegment.getStopIndex();
+ Collection<Projection> projections =
generateProjections(encryptColumn, columnProjection,
selectStatementContext.getSubqueryType());
+ int startIndex = getStartIndex(columnSegment);
+ int stopIndex = getStopIndex(columnSegment);
+ previousSQLTokens.removeIf(each -> each.getStartIndex() ==
startIndex);
return Optional.of(new SubstitutableColumnNameToken(startIndex,
stopIndex, projections, databaseType));
}
return Optional.empty();
@@ -115,7 +117,7 @@ public final class EncryptProjectionTokenGenerator {
Optional<EncryptTable> encryptTable =
encryptRule.findEncryptTable(columnProjection.getOriginalTable().getValue());
if (encryptTable.isPresent() &&
encryptTable.get().isEncryptColumn(columnProjection.getOriginalColumn().getValue())
&& !selectStatementContext.containsTableSubquery()) {
EncryptColumn encryptColumn =
encryptTable.get().getEncryptColumn(columnProjection.getOriginalColumn().getValue());
- projections.addAll(generateProjections(encryptColumn,
columnProjection, subqueryType, true));
+ projections.addAll(generateProjections(encryptColumn,
columnProjection, subqueryType));
continue;
}
}
@@ -127,69 +129,92 @@ public final class EncryptProjectionTokenGenerator {
return new SubstitutableColumnNameToken(startIndex,
segment.getStopIndex(), projections, selectStatementContext.getDatabaseType());
}
+ private int getStartIndex(final ColumnProjectionSegment columnSegment) {
+ if (columnSegment.getColumn().getLeftParentheses().isPresent()) {
+ return
columnSegment.getColumn().getLeftParentheses().get().getStartIndex();
+ }
+ return columnSegment.getColumn().getOwner().isPresent() ?
columnSegment.getColumn().getOwner().get().getStartIndex() :
columnSegment.getColumn().getStartIndex();
+ }
+
+ private int getStopIndex(final ColumnProjectionSegment columnSegment) {
+ if (columnSegment.getAliasSegment().isPresent()) {
+ return columnSegment.getAliasSegment().get().getStopIndex();
+ }
+ return columnSegment.getColumn().getRightParentheses().isPresent() ?
columnSegment.getColumn().getRightParentheses().get().getStopIndex() :
columnSegment.getColumn().getStopIndex();
+ }
+
private ColumnProjection buildColumnProjection(final
ColumnProjectionSegment segment) {
IdentifierValue owner =
segment.getColumn().getOwner().map(OwnerSegment::getIdentifier).orElse(null);
- ColumnProjection result = new ColumnProjection(owner,
segment.getColumn().getIdentifier(), segment.getAliasName().isPresent() ?
segment.getAlias().orElse(null) : null, databaseType);
+ ColumnProjection result = new ColumnProjection(owner,
segment.getColumn().getIdentifier(), segment.getAliasName().isPresent() ?
segment.getAlias().orElse(null) : null, databaseType,
+ segment.getColumn().getLeftParentheses().orElse(null),
segment.getColumn().getRightParentheses().orElse(null));
result.setOriginalColumn(segment.getColumn().getColumnBoundInfo().getOriginalColumn());
result.setOriginalTable(segment.getColumn().getColumnBoundInfo().getOriginalTable());
return result;
}
private Collection<Projection> generateProjections(final EncryptColumn
encryptColumn, final ColumnProjection columnProjection,
- final SubqueryType
subqueryType, final boolean shorthandProjection) {
+ final SubqueryType
subqueryType) {
if (null == subqueryType || SubqueryType.PROJECTION == subqueryType) {
- return Collections.singleton(generateProjection(encryptColumn,
columnProjection, shorthandProjection));
+ return Collections.singleton(generateProjection(encryptColumn,
columnProjection));
}
if (SubqueryType.TABLE == subqueryType || SubqueryType.JOIN ==
subqueryType) {
- return generateProjectionsInTableSegmentSubquery(encryptColumn,
columnProjection, shorthandProjection, subqueryType);
+ return generateProjectionsInTableSegmentSubquery(encryptColumn,
columnProjection, subqueryType);
}
if (SubqueryType.PREDICATE == subqueryType) {
- return
Collections.singleton(generateProjectionInPredicateSubquery(encryptColumn,
columnProjection, shorthandProjection));
+ return
Collections.singleton(generateProjectionInPredicateSubquery(encryptColumn,
columnProjection));
}
if (SubqueryType.INSERT_SELECT == subqueryType) {
- return generateProjectionsInInsertSelectSubquery(encryptColumn,
columnProjection, shorthandProjection);
+ return generateProjectionsInInsertSelectSubquery(encryptColumn,
columnProjection);
}
throw new UnsupportedSQLOperationException(
"Projections not in simple select, table subquery, join
subquery, predicate subquery and insert select subquery are not supported in
encrypt feature.");
}
- private ColumnProjection generateProjection(final EncryptColumn
encryptColumn, final ColumnProjection columnProjection, final boolean
shorthandProjection) {
- IdentifierValue encryptColumnOwner = shorthandProjection ?
columnProjection.getOwner().orElse(null) : null;
+ private ColumnProjection generateProjection(final EncryptColumn
encryptColumn, final ColumnProjection columnProjection) {
IdentifierValue cipherColumnName = new
IdentifierValue(encryptColumn.getCipher().getName(),
columnProjection.getName().getQuoteCharacter());
- return new ColumnProjection(encryptColumnOwner, cipherColumnName,
columnProjection.getAlias().orElse(columnProjection.getName()), databaseType);
+ return new ColumnProjection(columnProjection.getOwner().orElse(null),
cipherColumnName,
columnProjection.getAlias().orElse(columnProjection.getName()), databaseType,
+ columnProjection.getLeftParentheses().orElse(null),
columnProjection.getRightParentheses().orElse(null));
}
- private Collection<Projection>
generateProjectionsInTableSegmentSubquery(final EncryptColumn encryptColumn,
final ColumnProjection columnProjection,
-
final boolean shorthandProjection, final SubqueryType subqueryType) {
+ private Collection<Projection>
generateProjectionsInTableSegmentSubquery(final EncryptColumn encryptColumn,
final ColumnProjection columnProjection, final SubqueryType subqueryType) {
Collection<Projection> result = new LinkedList<>();
- IdentifierValue encryptColumnOwner = shorthandProjection ?
columnProjection.getOwner().orElse(null) : null;
QuoteCharacter quoteCharacter =
columnProjection.getName().getQuoteCharacter();
IdentifierValue cipherColumnName = new
IdentifierValue(encryptColumn.getCipher().getName(), quoteCharacter);
IdentifierValue alias = SubqueryType.JOIN == subqueryType ? null :
columnProjection.getAlias().orElse(columnProjection.getName());
- result.add(new ColumnProjection(encryptColumnOwner, cipherColumnName,
alias, databaseType));
+ ParenthesesSegment leftParentheses =
columnProjection.getLeftParentheses().orElse(null);
+ ParenthesesSegment rightParentheses =
columnProjection.getRightParentheses().orElse(null);
+ result.add(new
ColumnProjection(columnProjection.getOwner().orElse(null), cipherColumnName,
alias, databaseType, leftParentheses, rightParentheses));
IdentifierValue assistedColumOwner =
columnProjection.getOwner().orElse(null);
- encryptColumn.getAssistedQuery().ifPresent(optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType)));
- encryptColumn.getLikeQuery().ifPresent(optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType)));
+ encryptColumn.getAssistedQuery().ifPresent(
+ optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType, leftParentheses, rightParentheses)));
+ encryptColumn.getLikeQuery().ifPresent(
+ optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType, leftParentheses, rightParentheses)));
return result;
}
- private ColumnProjection generateProjectionInPredicateSubquery(final
EncryptColumn encryptColumn, final ColumnProjection columnProjection, final
boolean shorthandProjection) {
- IdentifierValue owner = shorthandProjection ?
columnProjection.getOwner().orElse(null) : null;
+ private ColumnProjection generateProjectionInPredicateSubquery(final
EncryptColumn encryptColumn, final ColumnProjection columnProjection) {
QuoteCharacter quoteCharacter =
columnProjection.getName().getQuoteCharacter();
- return encryptColumn.getAssistedQuery().map(optional -> new
ColumnProjection(owner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType))
+ ParenthesesSegment leftParentheses =
columnProjection.getLeftParentheses().orElse(null);
+ ParenthesesSegment rightParentheses =
columnProjection.getRightParentheses().orElse(null);
+ IdentifierValue owner = columnProjection.getOwner().orElse(null);
+ return encryptColumn.getAssistedQuery()
+ .map(optional -> new ColumnProjection(owner, new
IdentifierValue(optional.getName(), quoteCharacter), null, databaseType,
leftParentheses, rightParentheses))
.orElseGet(() -> new ColumnProjection(owner, new
IdentifierValue(encryptColumn.getCipher().getName(), quoteCharacter),
columnProjection.getAlias().orElse(columnProjection.getName()),
- databaseType));
+ databaseType, leftParentheses, rightParentheses));
}
- private Collection<Projection>
generateProjectionsInInsertSelectSubquery(final EncryptColumn encryptColumn,
final ColumnProjection columnProjection, final boolean shorthandProjection) {
+ private Collection<Projection>
generateProjectionsInInsertSelectSubquery(final EncryptColumn encryptColumn,
final ColumnProjection columnProjection) {
QuoteCharacter quoteCharacter =
columnProjection.getName().getQuoteCharacter();
IdentifierValue columnName = new
IdentifierValue(encryptColumn.getCipher().getName(), quoteCharacter);
Collection<Projection> result = new LinkedList<>();
- IdentifierValue encryptColumnOwner = shorthandProjection ?
columnProjection.getOwner().orElse(null) : null;
- result.add(new ColumnProjection(encryptColumnOwner, columnName, null,
databaseType));
+ ParenthesesSegment leftParentheses =
columnProjection.getLeftParentheses().orElse(null);
+ ParenthesesSegment rightParentheses =
columnProjection.getRightParentheses().orElse(null);
+ result.add(new
ColumnProjection(columnProjection.getOwner().orElse(null), columnName, null,
databaseType, leftParentheses, rightParentheses));
IdentifierValue assistedColumOwner =
columnProjection.getOwner().orElse(null);
- encryptColumn.getAssistedQuery().ifPresent(optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType)));
- encryptColumn.getLikeQuery().ifPresent(optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType)));
+ encryptColumn.getAssistedQuery().ifPresent(
+ optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType, leftParentheses, rightParentheses)));
+ encryptColumn.getLikeQuery().ifPresent(
+ optional -> result.add(new
ColumnProjection(assistedColumOwner, new IdentifierValue(optional.getName(),
quoteCharacter), null, databaseType, leftParentheses, rightParentheses)));
return result;
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/engine/ProjectionEngine.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/engine/ProjectionEngine.java
index 41452ad7f64..f6b86183941 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/engine/ProjectionEngine.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/engine/ProjectionEngine.java
@@ -108,7 +108,8 @@ public final class ProjectionEngine {
private ColumnProjection createProjection(final ColumnProjectionSegment
projectionSegment) {
IdentifierValue owner =
projectionSegment.getColumn().getOwner().isPresent() ?
projectionSegment.getColumn().getOwner().get().getIdentifier() : null;
IdentifierValue alias = projectionSegment.getAliasName().isPresent() ?
projectionSegment.getAlias().orElse(null) : null;
- ColumnProjection result = new ColumnProjection(owner,
projectionSegment.getColumn().getIdentifier(), alias, databaseType);
+ ColumnProjection result = new ColumnProjection(owner,
projectionSegment.getColumn().getIdentifier(), alias, databaseType,
projectionSegment.getColumn().getLeftParentheses().orElse(null),
+
projectionSegment.getColumn().getRightParentheses().orElse(null));
result.setOriginalColumn(projectionSegment.getColumn().getColumnBoundInfo().getOriginalColumn());
result.setOriginalTable(projectionSegment.getColumn().getColumnBoundInfo().getOriginalTable());
return result;
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/impl/ColumnProjection.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/impl/ColumnProjection.java
index 1f46f86b3e7..4813648975a 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/impl/ColumnProjection.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/context/segment/select/projection/impl/ColumnProjection.java
@@ -28,6 +28,7 @@ import
org.apache.shardingsphere.infra.binder.context.segment.select.projection.
import
org.apache.shardingsphere.infra.database.core.metadata.database.enums.QuoteCharacter;
import org.apache.shardingsphere.infra.database.core.type.DatabaseType;
import org.apache.shardingsphere.infra.database.mysql.type.MySQLDatabaseType;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParenthesesSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
import java.util.Optional;
@@ -50,13 +51,21 @@ public final class ColumnProjection implements Projection {
private final DatabaseType databaseType;
+ private final ParenthesesSegment leftParentheses;
+
+ private final ParenthesesSegment rightParentheses;
+
private IdentifierValue originalTable;
private IdentifierValue originalColumn;
public ColumnProjection(final String owner, final String name, final
String alias, final DatabaseType databaseType) {
this(null == owner ? null : new IdentifierValue(owner,
QuoteCharacter.NONE), new IdentifierValue(name, QuoteCharacter.NONE),
- null == alias ? null : new IdentifierValue(alias,
QuoteCharacter.NONE), databaseType);
+ null == alias ? null : new IdentifierValue(alias,
QuoteCharacter.NONE), databaseType, null, null);
+ }
+
+ public ColumnProjection(final IdentifierValue owner, final IdentifierValue
name, final IdentifierValue alias, final DatabaseType databaseType) {
+ this(owner, name, alias, databaseType, null, null);
}
@Override
@@ -110,4 +119,22 @@ public final class ColumnProjection implements Projection {
public IdentifierValue getOriginalColumn() {
return null == originalColumn ||
Strings.isNullOrEmpty(originalColumn.getValue()) ? name : originalColumn;
}
+
+ /**
+ * Get left parentheses.
+ *
+ * @return left parentheses
+ */
+ public Optional<ParenthesesSegment> getLeftParentheses() {
+ return Optional.ofNullable(leftParentheses);
+ }
+
+ /**
+ * Get right parentheses.
+ *
+ * @return right parentheses
+ */
+ public Optional<ParenthesesSegment> getRightParentheses() {
+ return Optional.ofNullable(rightParentheses);
+ }
}
diff --git
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
index 18fe0ad7cda..527957067bf 100644
---
a/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
+++
b/infra/binder/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/expression/type/ColumnSegmentBinder.java
@@ -86,7 +86,8 @@ public final class ColumnSegmentBinder {
private static ColumnSegment copy(final ColumnSegment segment) {
ColumnSegment result = new ColumnSegment(segment.getStartIndex(),
segment.getStopIndex(), segment.getIdentifier());
segment.getOwner().ifPresent(result::setOwner);
- result.getParentheses().addAll(segment.getParentheses());
+ segment.getLeftParentheses().ifPresent(result::setLeftParentheses);
+ segment.getRightParentheses().ifPresent(result::setRightParentheses);
return result;
}
diff --git
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/pojo/generic/SubstitutableColumnNameToken.java
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/pojo/generic/SubstitutableColumnNameToken.java
index 6a60f337de3..6587868b099 100644
---
a/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/pojo/generic/SubstitutableColumnNameToken.java
+++
b/infra/rewrite/src/main/java/org/apache/shardingsphere/infra/rewrite/sql/token/pojo/generic/SubstitutableColumnNameToken.java
@@ -57,8 +57,8 @@ public final class SubstitutableColumnNameToken extends
SQLToken implements Subs
public SubstitutableColumnNameToken(final int startIndex, final int
stopIndex, final Collection<Projection> projections, final DatabaseType
databaseType) {
super(startIndex);
this.stopIndex = stopIndex;
- this.lastColumn = false;
- this.quoteCharacter = new
DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData().getQuoteCharacter();
+ lastColumn = false;
+ quoteCharacter = new
DatabaseTypeRegistry(databaseType).getDialectDatabaseMetaData().getQuoteCharacter();
this.projections = projections;
}
@@ -103,12 +103,14 @@ public final class SubstitutableColumnNameToken extends
SQLToken implements Subs
}
private void appendColumnProjection(final ColumnProjection
columnProjection, final Map<String, String> logicActualTableNames, final
StringBuilder builder) {
+ columnProjection.getLeftParentheses().ifPresent(optional ->
builder.append("("));
if (columnProjection.getOwner().isPresent()) {
IdentifierValue owner = columnProjection.getOwner().get();
String actualTableOwner =
logicActualTableNames.getOrDefault(owner.getValue(), owner.getValue());
builder.append(getValueWithQuoteCharacters(new
IdentifierValue(actualTableOwner, owner.getQuoteCharacter()))).append('.');
}
builder.append(getValueWithQuoteCharacters(columnProjection.getName()));
+ columnProjection.getRightParentheses().ifPresent(optional ->
builder.append(")"));
if (columnProjection.getAlias().isPresent()) {
builder.append(" AS
").append(getValueWithQuoteCharacters(columnProjection.getAlias().get()));
}
diff --git
a/parser/sql/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/doris/visitor/statement/DorisStatementVisitor.java
b/parser/sql/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/doris/visitor/statement/DorisStatementVisitor.java
index bf2b281dc0d..7f9e7fafffb 100644
---
a/parser/sql/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/doris/visitor/statement/DorisStatementVisitor.java
+++
b/parser/sql/dialect/doris/src/main/java/org/apache/shardingsphere/sql/parser/doris/visitor/statement/DorisStatementVisitor.java
@@ -643,8 +643,8 @@ public abstract class DorisStatementVisitor extends
DorisStatementBaseVisitor<AS
if (null != ctx.LP_() && 1 == ctx.expr().size()) {
ASTNode result = visit(ctx.expr(0));
if (result instanceof ColumnSegment) {
- ((ColumnSegment) result).getParentheses().add(new
ParenthesesSegment(ctx.LP_().getSymbol().getStartIndex(),
ctx.LP_().getSymbol().getStopIndex(), true));
- ((ColumnSegment) result).getParentheses().add(new
ParenthesesSegment(ctx.RP_().getSymbol().getStartIndex(),
ctx.RP_().getSymbol().getStopIndex(), false));
+ ((ColumnSegment) result).setLeftParentheses(new
ParenthesesSegment(ctx.LP_().getSymbol().getStartIndex(),
ctx.LP_().getSymbol().getStopIndex(), ctx.LP_().getSymbol().getText()));
+ ((ColumnSegment) result).setRightParentheses(new
ParenthesesSegment(ctx.RP_().getSymbol().getStartIndex(),
ctx.RP_().getSymbol().getStopIndex(), ctx.RP_().getSymbol().getText()));
}
return result;
}
diff --git
a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
index ced409d5982..648a744b71e 100644
---
a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
+++
b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
@@ -51,6 +51,7 @@ import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.Convert
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CteClauseContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.CurrentUserFunctionContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DataTypeContext;
+import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DatabaseNameContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DeleteContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DuplicateSpecificationContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.EngineRefContext;
@@ -110,7 +111,6 @@ import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.Replace
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceSelectClauseContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ReplaceValuesClauseContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowConstructorListContext;
-import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.DatabaseNameContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectSpecificationContext;
import
org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectWithIntoContext;
@@ -643,8 +643,8 @@ public abstract class MySQLStatementVisitor extends
MySQLStatementBaseVisitor<AS
if (null != ctx.LP_() && 1 == ctx.expr().size()) {
ASTNode result = visit(ctx.expr(0));
if (result instanceof ColumnSegment) {
- ((ColumnSegment) result).getParentheses().add(new
ParenthesesSegment(ctx.LP_().getSymbol().getStartIndex(),
ctx.LP_().getSymbol().getStopIndex(), true));
- ((ColumnSegment) result).getParentheses().add(new
ParenthesesSegment(ctx.RP_().getSymbol().getStartIndex(),
ctx.RP_().getSymbol().getStopIndex(), false));
+ ((ColumnSegment) result).setLeftParentheses(new
ParenthesesSegment(ctx.LP_().getSymbol().getStartIndex(),
ctx.LP_().getSymbol().getStopIndex(), ctx.LP_().getSymbol().getText()));
+ ((ColumnSegment) result).setRightParentheses(new
ParenthesesSegment(ctx.RP_().getSymbol().getStartIndex(),
ctx.RP_().getSymbol().getStopIndex(), ctx.RP_().getSymbol().getText()));
}
return result;
}
diff --git
a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/column/ColumnSegment.java
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/column/ColumnSegment.java
index 1b0eb5f7a97..b114279424f 100644
---
a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/column/ColumnSegment.java
+++
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dml/column/ColumnSegment.java
@@ -20,13 +20,12 @@ package
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column;
import lombok.Getter;
import lombok.Setter;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
-import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParenthesesSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerAvailable;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParenthesesSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.bound.ColumnSegmentBoundInfo;
import
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
-import java.util.LinkedList;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;
@@ -54,7 +53,9 @@ public final class ColumnSegment implements
ExpressionSegment, OwnerAvailable {
private boolean isVariable;
- private List<ParenthesesSegment> parentheses = new LinkedList<>();
+ private ParenthesesSegment leftParentheses;
+
+ private ParenthesesSegment rightParentheses;
public ColumnSegment(final int startIndex, final int stopIndex, final
IdentifierValue identifier) {
this.startIndex = startIndex;
@@ -99,4 +100,22 @@ public final class ColumnSegment implements
ExpressionSegment, OwnerAvailable {
public String getText() {
return getExpression();
}
+
+ /**
+ * Get left parentheses.
+ *
+ * @return left parentheses
+ */
+ public Optional<ParenthesesSegment> getLeftParentheses() {
+ return Optional.ofNullable(leftParentheses);
+ }
+
+ /**
+ * Get right parentheses.
+ *
+ * @return right parentheses
+ */
+ public Optional<ParenthesesSegment> getRightParentheses() {
+ return Optional.ofNullable(rightParentheses);
+ }
}
diff --git
a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/ParenthesesSegment.java
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/ParenthesesSegment.java
index ceefc0765f7..927ce2d3cbe 100644
---
a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/ParenthesesSegment.java
+++
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/generic/ParenthesesSegment.java
@@ -17,6 +17,7 @@
package org.apache.shardingsphere.sql.parser.statement.core.segment.generic;
+import lombok.EqualsAndHashCode;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
import org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment;
@@ -26,11 +27,12 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment;
*/
@RequiredArgsConstructor
@Getter
+@EqualsAndHashCode
public final class ParenthesesSegment implements SQLSegment {
private final int startIndex;
private final int stopIndex;
- private final boolean left;
+ private final String parentheses;
}
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/generic/ParenthesesAssert.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/generic/ParenthesesAssert.java
index b3340015011..10ae6147584 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/generic/ParenthesesAssert.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/generic/ParenthesesAssert.java
@@ -41,7 +41,7 @@ public final class ParenthesesAssert {
* @param expected expected parentheses
*/
public static void assertIs(final SQLCaseAssertContext assertContext,
final ParenthesesSegment actual, final ExpectedParentheses expected) {
- assertThat(assertContext.getText("Left brackets assertion error: "),
actual.isLeft(), is(expected.isLeft()));
+ assertThat(assertContext.getText("Parentheses assertion error: "),
actual.getParentheses(), is(expected.getParentheses()));
SQLSegmentAssert.assertIs(assertContext, actual, expected);
}
}
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/projection/ProjectionAssert.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/projection/ProjectionAssert.java
index b0df5d78b06..7a8fbe2a079 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/projection/ProjectionAssert.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/projection/ProjectionAssert.java
@@ -30,7 +30,6 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.Subq
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.rownum.NumberLiteralRowNumberValueSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.rownum.ParameterMarkerRowNumberValueSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.top.TopProjectionSegment;
-import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ParenthesesSegment;
import
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.SQLCaseAssertContext;
import
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.SQLSegmentAssert;
import
org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.expression.ExpressionAssert;
@@ -49,7 +48,6 @@ import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.projection.impl.top.ExpectedTopProjection;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.sql.type.SQLCaseType;
-import java.util.Iterator;
import java.util.List;
import static org.hamcrest.CoreMatchers.instanceOf;
@@ -139,11 +137,8 @@ public final class ProjectionAssert {
} else {
IdentifierValueAssert.assertIs(assertContext,
actual.getColumn().getIdentifier(), expected, "Column projection");
}
- if (!expected.getParentheses().isEmpty()) {
- assertThat(expected.getParentheses().size(),
is(actual.getColumn().getParentheses().size()));
- Iterator<ParenthesesSegment> iterator =
actual.getColumn().getParentheses().iterator();
- expected.getParentheses().forEach(each ->
ParenthesesAssert.assertIs(assertContext, iterator.next(), each));
- }
+ assertLeftParentheses(assertContext, actual, expected);
+ assertRightParentheses(assertContext, actual, expected);
if (null == expected.getOwner()) {
assertFalse(actual.getColumn().getOwner().isPresent(),
assertContext.getText("Actual owner should not exist."));
} else {
@@ -152,6 +147,24 @@ public final class ProjectionAssert {
}
}
+ private static void assertLeftParentheses(final SQLCaseAssertContext
assertContext, final ColumnProjectionSegment actual, final
ExpectedColumnProjection expected) {
+ if (null == expected.getLeftParentheses()) {
+ assertFalse(actual.getColumn().getLeftParentheses().isPresent(),
assertContext.getText("Actual left parentheses should not exist."));
+ } else {
+ assertTrue(actual.getColumn().getLeftParentheses().isPresent(),
assertContext.getText("Actual left parentheses should exist."));
+ ParenthesesAssert.assertIs(assertContext,
actual.getColumn().getLeftParentheses().get(), expected.getLeftParentheses());
+ }
+ }
+
+ private static void assertRightParentheses(final SQLCaseAssertContext
assertContext, final ColumnProjectionSegment actual, final
ExpectedColumnProjection expected) {
+ if (null == expected.getRightParentheses()) {
+ assertFalse(actual.getColumn().getRightParentheses().isPresent(),
assertContext.getText("Actual right parentheses should not exist."));
+ } else {
+ assertTrue(actual.getColumn().getRightParentheses().isPresent(),
assertContext.getText("Actual right parentheses should exist."));
+ ParenthesesAssert.assertIs(assertContext,
actual.getColumn().getRightParentheses().get(), expected.getRightParentheses());
+ }
+ }
+
private static void assertAggregationProjection(final SQLCaseAssertContext
assertContext, final AggregationProjectionSegment actual, final
ExpectedAggregationProjection expected) {
assertThat(assertContext.getText("Aggregation projection type
assertion error: "), actual.getType().name(), is(expected.getType()));
assertThat(assertContext.getText("Aggregation projection inner
expression assertion error: "), actual.getExpression(),
is(expected.getExpression()));
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/generic/ExpectedParentheses.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/generic/ExpectedParentheses.java
index cb3c8f44358..31d671f0a6b 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/generic/ExpectedParentheses.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/generic/ExpectedParentheses.java
@@ -30,6 +30,6 @@ import javax.xml.bind.annotation.XmlAttribute;
@Setter
public final class ExpectedParentheses extends AbstractExpectedSQLSegment {
- @XmlAttribute(name = "left")
- private boolean left;
+ @XmlAttribute(name = "parentheses")
+ private String parentheses;
}
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/projection/impl/column/ExpectedColumnProjection.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/projection/impl/column/ExpectedColumnProjection.java
index ef22e08dd2a..565e140fd47 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/projection/impl/column/ExpectedColumnProjection.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/projection/impl/column/ExpectedColumnProjection.java
@@ -26,8 +26,6 @@ import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
-import java.util.LinkedList;
-import java.util.List;
/**
* Expected column projection.
@@ -42,6 +40,9 @@ public final class ExpectedColumnProjection extends
AbstractExpectedIdentifierSQ
@XmlElement
private ExpectedOwner owner;
- @XmlElement(name = "parentheses")
- private List<ExpectedParentheses> parentheses = new LinkedList<>();
+ @XmlElement(name = "left-parentheses")
+ private ExpectedParentheses leftParentheses;
+
+ @XmlElement(name = "right-parentheses")
+ private ExpectedParentheses rightParentheses;
}
diff --git a/test/it/parser/src/main/resources/case/dml/select.xml
b/test/it/parser/src/main/resources/case/dml/select.xml
index 355d31ac6d2..ea7418f5938 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -2889,8 +2889,8 @@
</from>
<projections start-index="16" stop-index="24" distinct-row="true">
<column-projection name="item_id" start-index="17" stop-index="23">
- <parentheses left = "true" start-index = "16" stop-index =
"16" />
- <parentheses left = "false" start-index = "24" stop-index =
"24" />
+ <left-parentheses parentheses = "(" start-index = "16"
stop-index = "16" />
+ <right-parentheses parentheses = ")" start-index = "24"
stop-index = "24" />
</column-projection>
</projections>
</select>
@@ -3243,7 +3243,10 @@
<simple-table name="t_order_item" start-index="30" stop-index="41"
/>
</from>
<projections distinct-row="true" start-index="15" stop-index="23">
- <column-projection start-index="16" stop-index="22" name="item_id"
/>
+ <column-projection start-index="16" stop-index="22" name="item_id">
+ <left-parentheses parentheses="(" start-index="15"
stop-index="15" />
+ <right-parentheses parentheses=")" start-index="23"
stop-index="23" />
+ </column-projection>
</projections>
<order-by>
<column-item name="item_id" start-index="52" stop-index="58" />
diff --git
a/test/it/parser/src/main/resources/sql/supported/dml/select-distinct.xml
b/test/it/parser/src/main/resources/sql/supported/dml/select-distinct.xml
index 92c9e835ce0..8901e853b06 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select-distinct.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select-distinct.xml
@@ -28,7 +28,6 @@
<sql-case id="select_distinct_with_owner_star_without_order_by"
value="SELECT DISTINCT t_order.*, t_order_item.order_id FROM t_order,
t_order_item WHERE t_order.order_id = t_order_item.order_id" db-types="MySQL" />
<!-- for with owner column with group by without order by -->
<sql-case id="select_distinct_with_owner_column_with_group_by"
value="SELECT DISTINCT t_order.order_id FROM t_order GROUP BY t_order.order_id"
db-types="MySQL" />
-
<sql-case id="select_distinct_with_single_column" value="SELECT DISTINCT
item_id FROM t_order_item ORDER BY item_id" />
<sql-case id="select_distinct_with_multi_column" value="SELECT DISTINCT
order_id, user_id, status FROM t_order ORDER BY order_id" />
<sql-case id="select_distinct_with_owner_column" value="SELECT DISTINCT
t_order.order_id FROM t_order ORDER BY order_id" />
@@ -41,7 +40,8 @@
<sql-case id="select_distinct_with_count_sum" value="SELECT COUNT(DISTINCT
order_id), SUM(DISTINCT order_id) FROM t_order WHERE order_id < 1100"
db-types="MySQL" />
<sql-case id="select_distinct_with_single_count_group_by" value="SELECT
order_id, COUNT(DISTINCT order_id) c FROM t_order WHERE order_id < 1100
GROUP BY order_id ORDER BY order_id" />
<sql-case id="select_distinct_with_count_group_by" value="SELECT
COUNT(DISTINCT order_id) c, order_id FROM t_order GROUP BY order_id ORDER BY
order_id" />
- <sql-case id="select_distinct_function" value="SELECT DISTINCT(item_id)
FROM t_order_item ORDER BY item_id"
db-types="H2,MySQL,PostgreSQL,openGauss,Oracle,SQLServer" />
+ <!-- TODO support more database type like
PostgreSQL,openGauss,Oracle,SQLServer-->
+ <sql-case id="select_distinct_function" value="SELECT DISTINCT(item_id)
FROM t_order_item ORDER BY item_id" db-types="H2,MySQL,Doris" />
<sql-case id="select_distinct_function_nulls_last" value="SELECT
DISTINCT(item_id) FROM t_order_item ORDER BY item_id"
db-types="PostgreSQL,openGauss,Oracle" />
<sql-case id="select_distinct_with_count_calculation" value="SELECT
COUNT(DISTINCT user_id + order_id) c FROM t_order WHERE order_id < 1100" />
<sql-case id="select_distinct_with_aggregation_functions" value="SELECT
SUM(DISTINCT order_id),count(DISTINCT order_id),count(order_id) FROM t_order
WHERE order_id < 1100" />
diff --git
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-distinct.xml
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-distinct.xml
index 793b33f56a1..f1ec58a176c 100644
---
a/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-distinct.xml
+++
b/test/it/rewriter/src/test/resources/scenario/encrypt/case/query-with-cipher/dml/select/select-distinct.xml
@@ -21,4 +21,16 @@
<input sql="SELECT distinct amount FROM t_account" />
<output sql="SELECT distinct cipher_amount AS amount FROM t_account" />
</rewrite-assertion>
+ <rewrite-assertion id="select_distinct_cipher_field_with_parentheses"
db-types="MySQL">
+ <input sql="SELECT distinct (amount) FROM t_account" />
+ <output sql="SELECT distinct (cipher_amount) AS amount FROM t_account"
/>
+ </rewrite-assertion>
+ <rewrite-assertion
id="select_distinct_cipher_field_with_parentheses_with_alias" db-types="MySQL">
+ <input sql="SELECT distinct (amount) as a FROM t_account" />
+ <output sql="SELECT distinct (cipher_amount) AS a FROM t_account" />
+ </rewrite-assertion>
+ <rewrite-assertion
id="select_distinct_cipher_field_with_parentheses_with_owner" db-types="MySQL">
+ <input sql="SELECT distinct (a.amount) from t_account a" />
+ <output sql="SELECT distinct (a.cipher_amount) AS amount from
t_account a" />
+ </rewrite-assertion>
</rewrite-assertions>