Created
February 4, 2022 06:54
-
-
Save junwen12221/73557f335b4ef5ffdd1b504539f25b36 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package io.sqlengine; | |
import com.alibaba.druid.DbType; | |
import com.alibaba.druid.sql.SQLUtils; | |
import com.alibaba.druid.sql.ast.*; | |
import com.alibaba.druid.sql.ast.expr.*; | |
import com.alibaba.druid.sql.ast.statement.*; | |
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectQueryBlock; | |
import com.alibaba.druid.sql.dialect.postgresql.ast.stmt.PGSelectStatement; | |
import com.alibaba.druid.sql.dialect.postgresql.visitor.PGASTVisitorAdapter; | |
import com.alibaba.druid.sql.visitor.SQLASTVisitor; | |
import com.alibaba.druid.sql.visitor.SQLASTVisitorAdapter; | |
import com.alibaba.druid.util.FnvHash; | |
import com.google.common.collect.ImmutableSet; | |
import org.apache.calcite.jdbc.CalciteSchema; | |
import org.apache.calcite.plan.RelOptTable; | |
import org.apache.calcite.plan.RelOptUtil; | |
import org.apache.calcite.rel.RelCollations; | |
import org.apache.calcite.rel.RelFieldCollation; | |
import org.apache.calcite.rel.RelNode; | |
import org.apache.calcite.rel.core.CorrelationId; | |
import org.apache.calcite.rel.core.JoinRelType; | |
import org.apache.calcite.rel.logical.LogicalTableScan; | |
import org.apache.calcite.rex.RexCorrelVariable; | |
import org.apache.calcite.rex.RexNode; | |
import org.apache.calcite.rex.RexSlot; | |
import org.apache.calcite.rex.RexSubQuery; | |
import org.apache.calcite.sql.SqlOperator; | |
import org.apache.calcite.sql.fun.SqlStdOperatorTable; | |
import org.apache.calcite.tools.FrameworkConfig; | |
import org.apache.calcite.tools.Frameworks; | |
import org.apache.calcite.tools.RelBuilder; | |
import org.apache.calcite.util.Holder; | |
import org.apache.calcite.util.NameMap; | |
import java.util.*; | |
import java.util.function.Function; | |
import java.util.stream.Collectors; | |
import static org.apache.calcite.sql.fun.SqlStdOperatorTable.IS_NULL; | |
public class CalciteMySqlNodeVisitor extends PGASTVisitorAdapter implements SQLASTVisitor { | |
final CalciteSchema rootSchema; | |
public CalciteMySqlNodeVisitor( CalciteSchema rootSchema) { | |
this.rootSchema = rootSchema; | |
} | |
public RelBuilder getRelBuilder (){ | |
FrameworkConfig config = Frameworks.newConfigBuilder().defaultSchema(rootSchema.plus()).build(); | |
RelBuilder relBuilder = RelBuilder.create(config); | |
return relBuilder; | |
} | |
public static RelNode convert(String defaultSchema, String sql) { | |
CalciteSchema rootSchema = CalciteSchema.createRootSchema(true); | |
SQLStatement statement = SQLUtils.parseSingleStatement(sql, DbType.postgresql); | |
CalciteMySqlNodeVisitor calciteMySqlNodeVisitor = new CalciteMySqlNodeVisitor(rootSchema); | |
RelScope rootScope = RelScope.createNewRootScope(defaultSchema); | |
if (statement instanceof PGSelectStatement) { | |
PGSelectStatement pgSelectStatement = (PGSelectStatement) statement; | |
SQLSelect select = pgSelectStatement.getSelect(); | |
SQLSelectQuery query = select.getQuery(); | |
RelNode relNode; | |
if (query instanceof PGSelectQueryBlock) { | |
return calciteMySqlNodeVisitor.convertSelectQueryBlock(rootScope, (PGSelectQueryBlock) query); | |
} | |
} | |
return null; | |
} | |
public static void main(String[] args) { | |
// String defaultSchema = null; | |
// FrameworkConfig config = Frameworks.newConfigBuilder().build(); | |
// RelBuilder relBuilder = RelBuilder.create(config); | |
// CalciteMySqlNodeVisitor calciteMySqlNodeVisitor = new CalciteMySqlNodeVisitor(relBuilder, new NameMap<>()); | |
// SQLStatement sqlStatement = SQLUtils.parseSingleStatement("select 1", DbType.postgresql); | |
// if (sqlStatement instanceof PGSelectStatement) { | |
// PGSelectStatement pgSelectStatement = (PGSelectStatement) sqlStatement; | |
// SQLSelect select = pgSelectStatement.getSelect(); | |
// // convertSQLSelect(defaultSchema, relBuilder, select); | |
// } | |
// sqlStatement.accept(calciteMySqlNodeVisitor); | |
// | |
// System.out.println(); | |
} | |
private RelNode convertSQLSelect(RelScope relScope, SQLSelect select) { | |
SQLSelectQuery query = select.getQuery(); | |
RelNode relNode; | |
if (query instanceof PGSelectQueryBlock) { | |
return convertSelectQueryBlock(relScope, (PGSelectQueryBlock) query); | |
} | |
return null; | |
} | |
private static class AggregationStatVisitor extends SQLASTVisitorAdapter { | |
private boolean aggregation = false; | |
List<SQLAggregateExpr> exprs = new ArrayList<>(); | |
public AggregationStatVisitor(RelBuilder relBuilder, int size) { | |
} | |
public boolean visit(SQLAggregateExpr x) { | |
aggregation = true; | |
exprs.add(x); | |
return false; | |
} | |
} | |
; | |
private RelNode convertSelectQueryBlock(RelScope parentRelScope , PGSelectQueryBlock query) { | |
RelBuilder relBuilder = getRelBuilder(); | |
RelNode relNode; | |
PGSelectQueryBlock pgSelectQueryBlock = query; | |
SQLTableSource from = pgSelectQueryBlock.getFrom(); | |
relNode = convertTableSource(parentRelScope, from); | |
////////////////////////////////////////////////////////////////////////////////////////// | |
String alias = from.computeAlias(); | |
RelScope curScope = parentRelScope.createNewScope(alias, relNode, getRelBuilder()); | |
//////////////////////////////////////////////////////////////////////////////////////// | |
SQLExpr where = pgSelectQueryBlock.getWhere(); | |
if (where != null) { | |
SubQueryContext subQueryContext = convertSubQuery(curScope, relBuilder, where, relNode); | |
Set<CorrelationId> variablesSet = subQueryContext.getVariablesSet(); | |
RexNode predicates = subQueryContext.getExpr(); | |
if (curScope.getRefColumns().isEmpty()) { | |
relNode = relBuilder.push(relNode).filter(variablesSet, predicates).build(); | |
} else { | |
relNode = relBuilder.push(relNode).filter(ImmutableSet.of(curScope.getRexCorrelVariable().id), predicates).build(); | |
} | |
} | |
List<SQLSelectItem> selectList = pgSelectQueryBlock.getSelectList(); | |
AggregationStatVisitor aggregationStatVisitor = new AggregationStatVisitor(relBuilder, selectList.size()); | |
pgSelectQueryBlock.accept(aggregationStatVisitor); | |
final boolean hasSelectAggregation = aggregationStatVisitor.aggregation; | |
if (hasSelectAggregation || pgSelectQueryBlock.getGroupBy() != null) { | |
relBuilder.push(relNode); | |
SQLSelectGroupByClause groupByClause = pgSelectQueryBlock.getGroupBy(); | |
RelBuilder.GroupKey groupKey; | |
SQLExpr having = null; | |
if (groupByClause != null) { | |
List<SQLExpr> items = groupByClause.getItems(); | |
ArrayList<RexNode> keys = new ArrayList<>(); | |
for (SQLExpr item : items) { | |
keys.add(convertExpr(parentRelScope, item)); | |
} | |
groupKey = relBuilder.groupKey(keys); | |
having = groupByClause.getHaving(); | |
} else { | |
groupKey = relBuilder.groupKey(); | |
} | |
List<RelBuilder.AggCall> calls = new ArrayList<>(); | |
for (SQLAggregateExpr expr : aggregationStatVisitor.exprs) { | |
RelBuilder.AggCall call = convertAggOrExpr(curScope, relBuilder, expr); | |
calls.add(call); | |
} | |
RelBuilder aggregate = relBuilder.aggregate(groupKey, calls); | |
if (having != null) { | |
aggregate.filter(convertExpr(curScope, having)); | |
} | |
relNode = aggregate.build(); | |
} | |
relBuilder.push(relNode); | |
if (selectList.size() == 1 && selectList.get(0).getExpr() instanceof SQLAllColumnExpr) { | |
relNode = relBuilder.build(); | |
} else { | |
// Set<String> curTableAlias = getCurTableAlias(relNode); | |
// HashSet<String> curTableSet = getCurTableSet(); | |
List<SQLSelectItem> orginalProject = new ArrayList<>(selectList); | |
// Map<Boolean, List<SQLSelectItem>> collect = selectList.stream().collect(Collectors.partitioningBy(i -> !curScope.isCol(i.getExpr()))); | |
List<SQLSelectItem> pure =orginalProject; | |
List<SQLSelectItem> col = new ArrayList<>(); | |
List<RexNode> pureProjects = getRexNodes(curScope, pure, relBuilder, relNode); | |
List<RexNode> corProjects = getRexNodes(curScope, col, relBuilder, relNode); | |
if (!corProjects.isEmpty()) { | |
relBuilder.push(relNode); | |
Holder<RexCorrelVariable> v = Holder.empty(); | |
relBuilder.variable(v); | |
RelNode corProject = relBuilder.values(new String[]{"X"}, "x").project(corProjects).build(); | |
relBuilder.push(corProject); | |
relNode = relBuilder.join(JoinRelType.LEFT, relBuilder.literal(true), ImmutableSet.of(v.get().id)).build(); | |
relBuilder.push(relNode); | |
List<RexNode> columns = new ArrayList<>(); | |
for (SQLSelectItem sqlSelectItem : orginalProject) { | |
RexNode field = relBuilder.field(sqlSelectItem.computeAlias()); | |
columns.add(field); | |
} | |
return relBuilder.project(columns).build(); | |
} | |
relNode = relBuilder.project(pureProjects).build(); | |
} | |
SQLOrderBy orderBy = pgSelectQueryBlock.getOrderBy(); | |
if (orderBy != null) { | |
relBuilder.push(relNode); | |
List<SQLSelectOrderByItem> items = orderBy.getItems(); | |
RelFieldCollation[] fieldCollations = new RelFieldCollation[items.size()]; | |
for (int i = 0; i < items.size(); i++) { | |
SQLSelectOrderByItem sqlSelectOrderByItem = items.get(i); | |
SQLExpr expr = sqlSelectOrderByItem.getExpr(); | |
SQLSelectOrderByItem.NullsOrderType nullsOrderType = sqlSelectOrderByItem.getNullsOrderType(); | |
SQLOrderingSpecification type = sqlSelectOrderByItem.getType(); | |
RexSlot rexNode = (RexSlot) convertExpr(curScope, expr); | |
int fieldIndex = rexNode.getIndex(); | |
RelFieldCollation.Direction direction = RelFieldCollation.Direction.ASCENDING; | |
RelFieldCollation.NullDirection nullDirection = RelFieldCollation.NullDirection.UNSPECIFIED; | |
if (type != null) { | |
switch (type) { | |
case ASC: | |
direction = RelFieldCollation.Direction.ASCENDING; | |
break; | |
case DESC: | |
direction = RelFieldCollation.Direction.DESCENDING; | |
break; | |
default: | |
throw new IllegalStateException("Unexpected value: " + type); | |
} | |
} | |
if (nullsOrderType != null) { | |
switch (nullsOrderType) { | |
case NullsFirst: | |
nullDirection = RelFieldCollation.NullDirection.FIRST; | |
break; | |
case NullsLast: | |
nullDirection = RelFieldCollation.NullDirection.LAST; | |
break; | |
} | |
} | |
fieldCollations[i] = new RelFieldCollation(fieldIndex, direction, nullDirection); | |
} | |
relNode = relBuilder.sort(RelCollations.of(fieldCollations)).build(); | |
} | |
SQLLimit limit = pgSelectQueryBlock.getLimit(); | |
if (limit != null) { | |
relBuilder.push(relNode); | |
int rowCount = Optional.ofNullable(limit.getRowCount()).map(sqlExpr -> ((SQLIntegerExpr) sqlExpr).getNumber().intValue()).orElse(Integer.MAX_VALUE); | |
int offset = Optional.ofNullable(limit.getOffset()).map(sqlExpr -> ((SQLIntegerExpr) sqlExpr).getNumber().intValue()).orElse(0); | |
relNode = relBuilder.limit(offset, rowCount).build(); | |
} | |
return relNode; | |
} | |
private List<RexNode> getRexNodes(RelScope relScope, List<SQLSelectItem> col, RelBuilder relBuilder, RelNode relNode) { | |
List<RexNode> corProjects = new ArrayList<>(); | |
for (SQLSelectItem sqlSelectItem : col) { | |
SQLExpr expr = sqlSelectItem.getExpr(); | |
String s = sqlSelectItem.computeAlias(); | |
SubQueryContext subQueryContext = convertSubQuery(relScope, relBuilder, expr, relNode); | |
RexNode rexNode = subQueryContext.getExpr(); | |
if (s != null) { | |
rexNode = relBuilder.alias(rexNode, s); | |
} | |
corProjects.add(rexNode); | |
} | |
return corProjects; | |
} | |
private SubQueryContext convertSubQuery(RelScope relScope, RelBuilder relBuilder, SQLExpr sqlExpr, RelNode relNode) { | |
// Set<String> outerTableSet = getCurTableSet(); | |
// Set<String> curTableAlias = getCurTableAlias(relNode); | |
// boolean col = Util.isCol(outerTableSet, sqlExpr); | |
// Set<CorrelationId> variablesSet; | |
// if (col && !this.refMap.containsKey(curTableAlias.iterator().next(), false)) { | |
// relBuilder.push(relNode); | |
// Holder<RexCorrelVariable> v = Holder.of(null); | |
// relBuilder.variable(v); | |
// for (String tableAlias : curTableAlias) { | |
// this.refMap.put(tableAlias, new ColInfo(v.get(), relNode)); | |
// } | |
// variablesSet = ImmutableSet.of(v.get().id); | |
// } else { | |
// variablesSet = ImmutableSet.of(); | |
// } | |
RexNode rexNode = convertExpr(relScope, sqlExpr); | |
return new SubQueryContext(ImmutableSet.of(), rexNode); | |
} | |
// | |
// private Set<String> getCurTableAlias(RelNode relNode) { | |
// Set<String> set = new HashSet<>(); | |
// for (Map.Entry<String, RelNode> entry : aliasMap.map().entrySet()) { | |
// if (entry.getValue() == relNode) { | |
// set.add(entry.getKey()); | |
// } | |
// } | |
// return set; | |
// } | |
// | |
// private HashSet<String> getCurTableSet() { | |
// return new HashSet<>(aliasMap.map().keySet()); | |
// } | |
static class BottomProjects { | |
List<SQLExpr> projects = new ArrayList<>(); | |
} | |
private RelBuilder.AggCall convertAggOrExpr(RelScope relScope, RelBuilder relBuilder, | |
SQLAggregateExpr expr | |
) { | |
SQLAggregateExpr sqlAggregateExpr = (SQLAggregateExpr) expr; | |
SQLAggregateOption option = sqlAggregateExpr.getOption(); | |
SQLKeep keep = sqlAggregateExpr.getKeep(); | |
SQLExpr filter = sqlAggregateExpr.getFilter(); | |
SQLOver over = sqlAggregateExpr.getOver(); | |
SQLName overRef = sqlAggregateExpr.getOverRef(); | |
SQLOrderBy orderBy = sqlAggregateExpr.getOrderBy(); | |
boolean withinGroup = sqlAggregateExpr.isWithinGroup(); | |
Boolean ignoreNulls = sqlAggregateExpr.getIgnoreNulls(); | |
String methodName = SQLUtils.normalize(sqlAggregateExpr.getMethodName()).toUpperCase(); | |
String alias = expr.toString(); | |
RelBuilder.AggCall call; | |
switch (methodName) { | |
case "COUNT": { | |
List<SQLExpr> arguments = sqlAggregateExpr.getArguments(); | |
if (arguments.size() == 1 && arguments.get(0) instanceof SQLAllColumnExpr) { | |
call = relBuilder.countStar(null); | |
} else { | |
List<RexNode> rexNodes = new ArrayList<>(); | |
for (SQLExpr argument : arguments) { | |
rexNodes.add(convertExpr(relScope, argument)); | |
} | |
call = relBuilder.count(rexNodes); | |
} | |
break; | |
} | |
default: { | |
throw new UnsupportedOperationException(); | |
} | |
} | |
return call.as(alias); | |
} | |
private static boolean isSqlAllExpr(SQLExpr x) { | |
return x.getClass() == SQLAllExpr.class; | |
} | |
private static boolean isAnyOrSomeExpr(SQLExpr x) { | |
return x.getClass() == SQLAnyExpr.class || x.getClass() == SQLSomeExpr.class; | |
} | |
private RexNode convertExpr(RelScope relScope, SQLExpr expr) { | |
RelBuilder relBuilder = getRelBuilder(); | |
relBuilder.push(relScope.getCurRelNode()); | |
if (expr instanceof SQLIntegerExpr) { | |
return relBuilder.literal(((SQLIntegerExpr) expr).getValue()); | |
} | |
if (expr instanceof SQLCharExpr) { | |
return relBuilder.literal(((SQLCharExpr) expr).getValue()); | |
} | |
if (expr instanceof SQLAggregateExpr) { | |
return relBuilder.field(expr.toString()); | |
} | |
if (expr instanceof SQLBinaryOpExpr) { | |
SQLBinaryOpExpr sqlBinaryOpExpr = (SQLBinaryOpExpr) expr; | |
SQLExpr leftExpr = sqlBinaryOpExpr.getLeft(); | |
SQLExpr rightExpr = sqlBinaryOpExpr.getRight(); | |
RexNode leftRex = convertExpr(relScope, leftExpr); | |
RexNode rightRex = convertExpr(relScope, rightExpr); | |
SqlOperator someOrAllOperator; | |
SqlOperator operator = null; | |
switch (sqlBinaryOpExpr.getOperator()) { | |
case Equality: | |
if (isSqlAllExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.ALL_EQ; | |
} else if (isAnyOrSomeExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.SOME_EQ; | |
} else { | |
operator = SqlStdOperatorTable.EQUALS; | |
} | |
break; | |
case GreaterThan: | |
if (isSqlAllExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.ALL_GT; | |
} else if (isAnyOrSomeExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.SOME_GT; | |
} else { | |
operator = SqlStdOperatorTable.GREATER_THAN; | |
} | |
break; | |
case GreaterThanOrEqual: | |
if (isSqlAllExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.ALL_GE; | |
} else if (isAnyOrSomeExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.SOME_GE; | |
} else { | |
operator = SqlStdOperatorTable.GREATER_THAN_OR_EQUAL; | |
} | |
break; | |
case LessThan: | |
if (isSqlAllExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.ALL_LT; | |
} else if (isAnyOrSomeExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.SOME_LT; | |
} else { | |
operator = SqlStdOperatorTable.LESS_THAN; | |
} | |
break; | |
case LessThanOrEqual: | |
if (isSqlAllExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.ALL_LE; | |
} else if (isAnyOrSomeExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.SOME_LE; | |
} else { | |
operator = SqlStdOperatorTable.LESS_THAN_OR_EQUAL; | |
} | |
break; | |
case NotEqual: | |
case LessThanOrGreater: | |
if (isSqlAllExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.ALL_NE; | |
} else if (isAnyOrSomeExpr(rightExpr)) { | |
someOrAllOperator = SqlStdOperatorTable.SOME_NE; | |
} else { | |
operator = SqlStdOperatorTable.NOT_EQUALS; | |
} | |
break; | |
case Add: | |
operator = SqlStdOperatorTable.PLUS; | |
break; | |
case Subtract: | |
operator = SqlStdOperatorTable.MINUS; | |
break; | |
case Union: | |
operator = SqlStdOperatorTable.UNION; | |
break; | |
case COLLATE: { | |
throw new UnsupportedOperationException(); | |
} | |
case BitwiseXor: | |
operator = SqlStdOperatorTable.BIT_XOR; | |
break; | |
case BitwiseXorEQ: | |
break; | |
case Multiply: | |
operator = SqlStdOperatorTable.MULTIPLY; | |
break; | |
case Divide: | |
operator = SqlStdOperatorTable.DIVIDE; | |
break; | |
case DIV: | |
operator = SqlStdOperatorTable.DIVIDE_INTEGER; | |
break; | |
case Modulus: | |
operator = SqlStdOperatorTable.MOD; | |
break; | |
case Like: | |
operator = SqlStdOperatorTable.LIKE; | |
break; | |
case NotLike: | |
operator = SqlStdOperatorTable.NOT_LIKE; | |
break; | |
case BooleanAnd: | |
operator = SqlStdOperatorTable.AND; | |
break; | |
case BooleanOr: | |
operator = SqlStdOperatorTable.OR; | |
break; | |
case Concat: | |
operator = SqlStdOperatorTable.CONCAT; | |
break; | |
case Is: { | |
if (rightExpr instanceof SQLNullExpr) { | |
operator = IS_NULL; | |
} else if (rightExpr instanceof SQLIdentifierExpr) { | |
long hashCode64 = ((SQLIdentifierExpr) rightExpr).nameHashCode64(); | |
if (hashCode64 == FnvHash.Constants.JSON | |
|| hashCode64 == JSON_VALUE) { | |
operator = SqlStdOperatorTable.IS_JSON_VALUE; | |
} else if (hashCode64 == JSON_OBJECT) { | |
operator = SqlStdOperatorTable.IS_JSON_OBJECT; | |
} else if (hashCode64 == JSON_ARRAY) { | |
operator = SqlStdOperatorTable.IS_JSON_ARRAY; | |
} else if (hashCode64 == JSON_SCALAR) { | |
operator = SqlStdOperatorTable.IS_JSON_SCALAR; | |
} else if (hashCode64 == FnvHash.Constants.UNKNOWN) { | |
operator = SqlStdOperatorTable.IS_UNKNOWN; | |
} | |
} else if (rightExpr instanceof SQLBooleanExpr) { | |
if (((SQLBooleanExpr) rightExpr).getValue()) { | |
operator = SqlStdOperatorTable.IS_TRUE; | |
} else { | |
operator = SqlStdOperatorTable.IS_FALSE; | |
} | |
} | |
} | |
break; | |
case IsNot: | |
if (rightExpr instanceof SQLNullExpr) { | |
operator = SqlStdOperatorTable.IS_NOT_NULL; | |
} else if (rightExpr instanceof SQLIdentifierExpr) { | |
long hashCode64 = ((SQLIdentifierExpr) rightExpr).nameHashCode64(); | |
if (hashCode64 == FnvHash.Constants.JSON | |
|| hashCode64 == JSON_VALUE) { | |
operator = SqlStdOperatorTable.IS_NOT_JSON_VALUE; | |
} else if (hashCode64 == JSON_OBJECT) { | |
operator = SqlStdOperatorTable.IS_NOT_JSON_OBJECT; | |
} else if (hashCode64 == JSON_ARRAY) { | |
operator = SqlStdOperatorTable.IS_NOT_JSON_ARRAY; | |
} else if (hashCode64 == JSON_SCALAR) { | |
operator = SqlStdOperatorTable.IS_NOT_JSON_SCALAR; | |
} else if (hashCode64 == FnvHash.Constants.UNKNOWN) { | |
operator = SqlStdOperatorTable.IS_NOT_UNKNOWN; | |
} | |
} else if (rightExpr instanceof SQLBooleanExpr) { | |
if (((SQLBooleanExpr) rightExpr).getValue()) { | |
operator = SqlStdOperatorTable.IS_NOT_TRUE; | |
} else { | |
operator = SqlStdOperatorTable.IS_NOT_FALSE; | |
} | |
} | |
break; | |
case Escape: | |
case BitwiseOr: | |
case LessThanOrEqualOrGreaterThan: | |
case NotRegExp: | |
case RLike: | |
case RegExp: | |
case SoudsLike: | |
case Mod: | |
case SubGt: | |
case SubGtGt: | |
case PoundGt: | |
case PoundGtGt: | |
case QuesQues: | |
case QuesBar: | |
case QuesAmp: | |
case LeftShift: | |
case RightShift: | |
case BitwiseAnd: | |
case IsDistinctFrom: | |
case IsNotDistinctFrom: | |
case ILike: | |
case NotILike: | |
case AT_AT: | |
case SIMILAR_TO: | |
case POSIX_Regular_Match: | |
case POSIX_Regular_Match_Insensitive: | |
case POSIX_Regular_Not_Match: | |
case POSIX_Regular_Not_Match_POSIX_Regular_Match_Insensitive: | |
case Array_Contains: | |
case Array_ContainedBy: | |
case SAME_AS: | |
case JSONContains: | |
case NotRLike: | |
case NotLessThan: | |
case NotGreaterThan: | |
case BitwiseNot: | |
case BooleanXor: | |
case Assignment: | |
case PG_And: | |
case PG_ST_DISTANCE: | |
default: | |
} | |
return relBuilder.call(operator, leftRex, rightRex); | |
} | |
if (expr instanceof SQLQueryExpr) { | |
SQLQueryExpr sqlQueryExpr = (SQLQueryExpr) expr; | |
RelNode relNode = relBuilder.peek(); | |
boolean col = relScope.checkCol(sqlQueryExpr); | |
SQLSelect select = sqlQueryExpr.getSubQuery(); | |
RexSubQuery rexSubQuery = relBuilder.scalarQuery(relBuilder1 -> { | |
return convertSQLSelect(relScope, select); | |
}); | |
if (col) { | |
return rexSubQuery; | |
} else { | |
return rexSubQuery; | |
} | |
} | |
if (expr instanceof SQLInSubQueryExpr) { | |
SQLInSubQueryExpr sqlQueryExpr = (SQLInSubQueryExpr) expr; | |
SQLExpr sqlQueryExprExpr = sqlQueryExpr.getExpr(); | |
SQLSelect select = sqlQueryExpr.getSubQuery(); | |
return relBuilder.in(convertExpr(relScope, sqlQueryExprExpr), new Function<RelBuilder, RelNode>() { | |
@Override | |
public RelNode apply(RelBuilder relBuilder) { | |
return convertSQLSelect(relScope, select); | |
} | |
}); | |
} | |
if (expr instanceof SQLIdentifierExpr) { | |
String name = SQLUtils.normalize(((SQLIdentifierExpr) expr).getName()); | |
List<String> fieldNames = relBuilder.peek().getRowType().getFieldNames(); | |
if (fieldNames.contains(name)) { | |
return relBuilder.field(name); | |
} else { | |
throw new UnsupportedOperationException(); | |
} | |
} | |
if (expr instanceof SQLPropertyExpr) { | |
List<String> path = Arrays.asList(expr.toString().split("\\.")).stream().map(i -> i.replaceAll("`", "")).collect(Collectors.toList()); | |
return relScope.findColumn(relBuilder, path); | |
// String column; | |
// SQLPropertyExpr sqlPropertyExpr = (SQLPropertyExpr) expr; | |
// SQLExpr owner = sqlPropertyExpr.getOwner(); | |
// | |
// String uniqueName = owner.toString().replaceAll("`", ""); | |
// column = SQLUtils.normalize(sqlPropertyExpr.getSimpleName()); | |
// if (!refMap.map().isEmpty()) { | |
// for (ColInfo rexCorrelVariable : this.refMap.range(uniqueName, false).values()) { | |
// return relBuilder.field(rexCorrelVariable.getRexCorrelVariable(), column); | |
// } | |
// } | |
// int size = relBuilder.size(); | |
// for (int i = 0; i < size; i++) { | |
// RelNode relNode = relBuilder.peek(i); | |
// List<String> fieldNames = relNode.getRowType().getFieldNames(); | |
// int index = 0; | |
// for (String fieldName : fieldNames) { | |
// if (fieldName.equalsIgnoreCase(column)) { | |
// for (RelNode node : this.aliasMap.range(uniqueName, false).values()) { | |
// if (relNode == node) { | |
// return relBuilder.field(size, i, index); | |
// } | |
// } | |
// } | |
// index++; | |
// } | |
// } | |
// for (ColInfo rexCorrelVariable : this.refMap.range(uniqueName, false).values()) { | |
// return relBuilder.field(rexCorrelVariable.getRexCorrelVariable(), column); | |
// } | |
} | |
throw new UnsupportedOperationException(); | |
} | |
private RelNode convertTableSource(RelScope relScope, SQLTableSource from) { | |
RelBuilder relBuilder = getRelBuilder(); | |
RelNode tableScan = null; | |
if (from == null) { | |
tableScan = relBuilder.values(new String[]{"x"}, "x").build(); | |
} | |
if (from instanceof SQLExprTableSource) { | |
SQLExprTableSource exprTableSource = (SQLExprTableSource) from; | |
String schemaName = SQLUtils.normalize( | |
Optional.ofNullable(exprTableSource.getSchema()).orElse(relScope.getDefaultSchema())); | |
String tableName = SQLUtils.normalize(exprTableSource.getName().getSimpleName()); | |
tableScan = relBuilder.scan(schemaName, tableName).build(); | |
} else if (from instanceof SQLJoinTableSource) { | |
SQLJoinTableSource sqlJoinTableSource = (SQLJoinTableSource) from; | |
SQLTableSource left = sqlJoinTableSource.getLeft(); | |
SQLJoinTableSource.JoinType joinType = sqlJoinTableSource.getJoinType(); | |
SQLTableSource right = sqlJoinTableSource.getRight(); | |
SQLExpr condition = sqlJoinTableSource.getCondition(); | |
final List<SQLExpr> using = sqlJoinTableSource.getUsing(); | |
boolean natural = sqlJoinTableSource.isNatural(); | |
RelNode leftRelNode = convertTableSource(relScope, left); | |
RelNode rightRelNode = convertTableSource(relScope, right); | |
relBuilder.push(leftRelNode).push(rightRelNode); | |
String[] usingColumns = using.stream().map(i -> SQLUtils.normalize(i.toString())).toArray(value -> new String[value]); | |
JoinRelType joinRelType; | |
switch (joinType) { | |
case COMMA: | |
case JOIN: | |
case INNER_JOIN: | |
case NATURAL_JOIN: | |
case CROSS_JOIN: | |
case NATURAL_CROSS_JOIN: | |
joinRelType = JoinRelType.INNER; | |
break; | |
case LEFT_OUTER_JOIN: | |
joinRelType = JoinRelType.LEFT; | |
break; | |
case RIGHT_OUTER_JOIN: | |
joinRelType = JoinRelType.RIGHT; | |
break; | |
case FULL_OUTER_JOIN: | |
joinRelType = JoinRelType.FULL; | |
break; | |
default: | |
throw new UnsupportedOperationException("unsupported : " + joinType); | |
} | |
if (condition == null && using.isEmpty()) { | |
tableScan = relBuilder.join(joinRelType, Collections.emptyList()).build(); | |
} else if (condition != null) { | |
tableScan = relBuilder.join(joinRelType, convertExpr(relScope, condition)).build(); | |
} else if (!using.isEmpty()) { | |
tableScan = relBuilder.join(joinRelType, usingColumns).build(); | |
} | |
} | |
return tableScan; | |
} | |
static long JSON_VALUE = FnvHash.fnv1a_64_lower("JSON VALUE"); | |
static long JSON_OBJECT = FnvHash.fnv1a_64_lower("JSON OBJECT"); | |
static long JSON_ARRAY = FnvHash.fnv1a_64_lower("JSON ARRAY"); | |
static long JSON_SCALAR = FnvHash.fnv1a_64_lower("JSON SCALAR"); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment