
com.alibaba.druid.sql.ast.statement.SQLJoinTableSource Maven / Gradle / Ivy
/*
* Copyright 1999-2017 Alibaba Group Holding Ltd.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.alibaba.druid.sql.ast.statement;
import com.alibaba.druid.FastsqlColumnAmbiguousException;
import com.alibaba.druid.FastsqlException;
import com.alibaba.druid.sql.SQLUtils;
import com.alibaba.druid.sql.ast.*;
import com.alibaba.druid.sql.ast.expr.SQLBinaryOpExpr;
import com.alibaba.druid.sql.ast.expr.SQLIdentifierExpr;
import com.alibaba.druid.sql.ast.expr.SQLPropertyExpr;
import com.alibaba.druid.sql.repository.SchemaResolveVisitor;
import com.alibaba.druid.sql.visitor.SQLASTVisitor;
import com.alibaba.druid.util.FnvHash;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
public class SQLJoinTableSource extends SQLTableSourceImpl implements SQLReplaceable {
protected SQLTableSource left;
protected JoinType joinType;
protected SQLTableSource right;
protected SQLExpr condition;
protected final List using = new ArrayList();
protected boolean natural;
protected UDJ udj; // for maxcompute
protected boolean asof; // for clickhouse
protected boolean global; // for clickhouse
public SQLJoinTableSource(String alias) {
super(alias);
}
public SQLJoinTableSource() {
}
public SQLJoinTableSource(SQLTableSource left, JoinType joinType, SQLTableSource right, SQLExpr condition) {
this.setLeft(left);
this.setJoinType(joinType);
this.setRight(right);
this.setCondition(condition);
}
protected void accept0(SQLASTVisitor visitor) {
if (visitor.visit(this)) {
if (left != null) {
left.accept(visitor);
}
if (right != null) {
right.accept(visitor);
}
if (condition != null) {
condition.accept(visitor);
}
for (int i = 0; i < using.size(); i++) {
SQLExpr item = using.get(i);
if (item != null) {
item.accept(visitor);
}
}
if (udj != null) {
udj.accept(visitor);
}
}
visitor.endVisit(this);
}
public UDJ getUdj() {
return udj;
}
public void setUdj(UDJ x) {
if (x != null) {
x.setParent(this);
}
this.udj = x;
}
public boolean isAsof() {
return asof;
}
public void setAsof(boolean asof) {
this.asof = asof;
}
public JoinType getJoinType() {
return this.joinType;
}
public void setJoinType(JoinType joinType) {
this.joinType = joinType;
}
public void setImplicitJoinToCross() {
if (joinType == JoinType.COMMA) {
joinType = JoinType.CROSS_JOIN;
}
if (left instanceof SQLJoinTableSource) {
((SQLJoinTableSource) left).setImplicitJoinToCross();
}
if (right instanceof SQLJoinTableSource) {
((SQLJoinTableSource) right).setImplicitJoinToCross();
}
}
public SQLTableSource getLeft() {
return this.left;
}
public void setLeft(SQLTableSource left) {
if (left != null) {
left.setParent(this);
}
this.left = left;
}
public void setLeft(String tableName, String alias) {
SQLExprTableSource tableSource;
if (tableName == null || tableName.length() == 0) {
tableSource = null;
} else {
tableSource = new SQLExprTableSource(new SQLIdentifierExpr(tableName), alias);
}
this.setLeft(tableSource);
}
public void setRight(String tableName, String alias) {
SQLExprTableSource tableSource;
if (tableName == null || tableName.length() == 0) {
tableSource = null;
} else {
tableSource = new SQLExprTableSource(new SQLIdentifierExpr(tableName), alias);
}
this.setRight(tableSource);
}
public SQLTableSource getRight() {
return this.right;
}
public void setRight(SQLTableSource right) {
if (right != null) {
right.setParent(this);
}
this.right = right;
}
public SQLExpr getCondition() {
return this.condition;
}
public void setCondition(SQLExpr condition) {
if (condition != null) {
condition.setParent(this);
}
this.condition = condition;
}
public void addCondition(SQLExpr condition) {
if (this.condition == null) {
this.condition = condition;
setImplicitJoinToCross();
return;
}
this.condition = SQLBinaryOpExpr.and(this.condition, condition);
}
public void addConditionnIfAbsent(SQLExpr condition) {
if (this.containsCondition(condition)) {
return;
}
this.condition = SQLBinaryOpExpr.and(this.condition, condition);
}
public boolean containsCondition(SQLExpr condition) {
if (this.condition == null) {
return false;
}
if (this.condition.equals(condition)) {
return false;
}
if (this.condition instanceof SQLBinaryOpExpr) {
return ((SQLBinaryOpExpr) this.condition).contains(condition);
}
return false;
}
public List getUsing() {
return this.using;
}
public boolean isNatural() {
return natural;
}
public void setNatural(boolean natural) {
this.natural = natural;
}
public void output(Appendable buf) {
try {
this.left.output(buf);
buf.append(' ');
buf.append(JoinType.toString(this.joinType));
buf.append(' ');
this.right.output(buf);
if (this.condition != null) {
buf.append(" ON ");
this.condition.output(buf);
}
} catch (IOException ex) {
throw new FastsqlException("output error", ex);
}
}
@Override
public boolean replace(SQLExpr expr, SQLExpr target) {
if (condition == expr) {
setCondition(target);
return true;
}
for (int i = 0; i < using.size(); i++) {
if (using.get(i) == expr) {
target.setParent(this);
using.set(i, target);
return true;
}
}
return false;
}
public boolean replace(SQLTableSource cmp, SQLTableSource target) {
if (left == cmp) {
if (target == null) {
SQLUtils.replaceInParent(this, right);
} else {
setLeft(target);
}
return true;
} else if (right == cmp) {
if (target == null) {
SQLUtils.replaceInParent(this, left);
} else {
setRight(target);
}
return true;
}
return false;
}
public static enum JoinType {
COMMA(","),
JOIN("JOIN"),
INNER_JOIN("INNER JOIN"),
CROSS_JOIN("CROSS JOIN"),
NATURAL_JOIN("NATURAL JOIN"),
NATURAL_CROSS_JOIN("NATURAL CROSS JOIN"),
NATURAL_LEFT_JOIN("NATURAL LEFT JOIN"),
NATURAL_RIGHT_JOIN("NATURAL RIGHT JOIN"),
NATURAL_INNER_JOIN("NATURAL INNER JOIN"),
LEFT_OUTER_JOIN("LEFT JOIN"),
LEFT_SEMI_JOIN("LEFT SEMI JOIN"),
LEFT_ANTI_JOIN("LEFT ANTI JOIN"),
RIGHT_OUTER_JOIN("RIGHT JOIN"),
FULL_OUTER_JOIN("FULL JOIN"),
STRAIGHT_JOIN("STRAIGHT_JOIN"),
OUTER_APPLY("OUTER APPLY"),
CROSS_APPLY("CROSS APPLY");
public final String name;
public final String nameLCase;
JoinType(String name) {
this.name = name;
this.nameLCase = name.toLowerCase();
}
public static String toString(JoinType joinType) {
return joinType.name;
}
}
public void cloneTo(SQLJoinTableSource x) {
x.alias = alias;
if (left != null) {
x.setLeft(left.clone());
}
x.joinType = joinType;
if (right != null) {
x.setRight(right.clone());
}
if (condition != null) {
x.setCondition(condition.clone());
}
for (SQLExpr item : using) {
SQLExpr item2 = item.clone();
item2.setParent(x);
x.using.add(item2);
}
x.natural = natural;
x.asof = asof;
if (udj != null) {
x.udj = udj.clone();
}
}
public SQLJoinTableSource clone() {
SQLJoinTableSource x = new SQLJoinTableSource();
cloneTo(x);
return x;
}
public void reverse() {
SQLTableSource temp = left;
left = right;
right = temp;
if (left instanceof SQLJoinTableSource) {
((SQLJoinTableSource) left).reverse();
}
if (right instanceof SQLJoinTableSource) {
((SQLJoinTableSource) right).reverse();
}
}
/**
* a inner_join (b inner_join c) -< a inner_join b innre_join c
*/
public void rearrangement() {
if (joinType != JoinType.COMMA && joinType != JoinType.INNER_JOIN) {
return;
}
if (right instanceof SQLJoinTableSource) {
SQLJoinTableSource rightJoin = (SQLJoinTableSource) right;
if (rightJoin.joinType != JoinType.COMMA && rightJoin.joinType != JoinType.INNER_JOIN) {
return;
}
SQLTableSource a = left;
SQLTableSource b = rightJoin.getLeft();
SQLTableSource c = rightJoin.getRight();
SQLExpr on_ab = condition;
SQLExpr on_bc = rightJoin.condition;
setLeft(rightJoin);
rightJoin.setLeft(a);
rightJoin.setRight(b);
boolean on_ab_match = false;
if (on_ab instanceof SQLBinaryOpExpr) {
SQLBinaryOpExpr on_ab_binaryOpExpr = (SQLBinaryOpExpr) on_ab;
if (on_ab_binaryOpExpr.getLeft() instanceof SQLPropertyExpr
&& on_ab_binaryOpExpr.getRight() instanceof SQLPropertyExpr) {
String leftOwnerName = ((SQLPropertyExpr) on_ab_binaryOpExpr.getLeft()).getOwnernName();
String rightOwnerName = ((SQLPropertyExpr) on_ab_binaryOpExpr.getRight()).getOwnernName();
if (rightJoin.containsAlias(leftOwnerName) && rightJoin.containsAlias(rightOwnerName)) {
on_ab_match = true;
}
}
}
if (on_ab_match) {
rightJoin.setCondition(on_ab);
} else {
rightJoin.setCondition(null);
on_bc = SQLBinaryOpExpr.and(on_bc, on_ab);
}
setRight(c);
setCondition(on_bc);
}
}
public boolean contains(SQLTableSource tableSource, SQLExpr condition) {
if (right.equals(tableSource)) {
if (this.condition == condition) {
return true;
}
return this.condition != null && this.condition.equals(condition);
}
if (left instanceof SQLJoinTableSource) {
SQLJoinTableSource joinLeft = (SQLJoinTableSource) left;
if (tableSource instanceof SQLJoinTableSource) {
SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
if (join.right.equals(right) && this.condition.equals(condition) && joinLeft.right.equals(join.left)) {
return true;
}
}
return joinLeft.contains(tableSource, condition);
}
return false;
}
public boolean contains(SQLTableSource tableSource, SQLExpr condition, JoinType joinType) {
if (right.equals(tableSource)) {
if (this.condition == condition) {
return true;
}
return this.condition != null && this.condition.equals(condition) && this.joinType == joinType;
}
if (left instanceof SQLJoinTableSource) {
SQLJoinTableSource joinLeft = (SQLJoinTableSource) left;
if (tableSource instanceof SQLJoinTableSource) {
SQLJoinTableSource join = (SQLJoinTableSource) tableSource;
if (join.right.equals(right)
&& this.condition != null && this.condition.equals(join.condition)
&& joinLeft.right.equals(join.left)
&& this.joinType == join.joinType
&& joinLeft.condition != null && joinLeft.condition.equals(condition)
&& joinLeft.joinType == joinType) {
return true;
}
}
return joinLeft.contains(tableSource, condition, joinType);
}
return false;
}
public SQLJoinTableSource findJoin(SQLTableSource tableSource, JoinType joinType) {
if (right.equals(tableSource)) {
if (this.joinType == joinType) {
return this;
}
return null;
}
if (left instanceof SQLJoinTableSource) {
return ((SQLJoinTableSource) left).findJoin(tableSource, joinType);
}
return null;
}
public boolean containsAlias(String alias) {
if (SQLUtils.nameEquals(this.alias, alias)) {
return true;
}
if (left != null && left.containsAlias(alias)) {
return true;
}
if (right != null && right.containsAlias(alias)) {
return true;
}
return false;
}
public SQLColumnDefinition findColumn(String columnName) {
long hash = FnvHash.hashCode64(columnName);
return findColumn(hash);
}
public SQLColumnDefinition findColumn(long columnNameHash) {
SQLObject column = resolveColum(columnNameHash);
if (column instanceof SQLColumnDefinition) {
return (SQLColumnDefinition) column;
}
return null;
}
public SQLObject resolveColum(long columnNameHash) {
if (left != null) {
SQLObject column = left.resolveColum(columnNameHash);
if (column != null) {
return column;
}
}
if (right != null) {
return right.resolveColum(columnNameHash);
}
return null;
}
@Override
public SQLTableSource findTableSourceWithColumn(String columnName) {
long hash = FnvHash.hashCode64(columnName);
return findTableSourceWithColumn(hash, columnName, 0);
}
public SQLJoinTableSource findTableSourceWithColumn(SQLName a, SQLName b) {
if (left.findTableSourceWithColumn(a) != null
&& right.findTableSourceWithColumn(b) != null) {
return this;
}
if (right.findTableSourceWithColumn(a) != null
&& left.findTableSourceWithColumn(b) != null) {
return this;
}
if (left instanceof SQLJoinTableSource) {
return ((SQLJoinTableSource) left).findTableSourceWithColumn(a, b);
}
if (right instanceof SQLJoinTableSource) {
return ((SQLJoinTableSource) right).findTableSourceWithColumn(a, b);
}
return null;
}
public SQLTableSource findTableSourceWithColumn(long columnNameHash, String name, int option) {
SQLTableSource leftMatch = null;
if (left != null) {
leftMatch = left.findTableSourceWithColumn(columnNameHash, name, option);
}
boolean checkColumnAmbiguous = (option & SchemaResolveVisitor.Option.CheckColumnAmbiguous.mask) != 0;
if (leftMatch != null && !checkColumnAmbiguous) {
return leftMatch;
}
SQLTableSource rightMatch = null;
if (right != null) {
rightMatch = right.findTableSourceWithColumn(columnNameHash, name, option);
}
if (leftMatch == null) {
return rightMatch;
}
if (rightMatch == null) {
return leftMatch;
}
if (name != null) {
String msg = "Column '" + name + "' is ambiguous";
throw new FastsqlColumnAmbiguousException(msg);
}
throw new FastsqlColumnAmbiguousException();
}
public boolean match(String alias_a, String alias_b) {
if (left == null || right == null) {
return false;
}
if (left.containsAlias(alias_a)
&& right.containsAlias(alias_b)) {
return true;
}
return right.containsAlias(alias_a)
&& left.containsAlias(alias_b);
}
public boolean conditionContainsTable(String alias) {
if (condition == null) {
return false;
}
if (condition instanceof SQLBinaryOpExpr) {
return ((SQLBinaryOpExpr) condition).conditionContainsTable(alias);
}
return false;
}
public SQLJoinTableSource join(SQLTableSource right, JoinType joinType, SQLExpr condition) {
SQLJoinTableSource joined = new SQLJoinTableSource(this, joinType, right, condition);
return joined;
}
public SQLTableSource findTableSource(long alias_hash) {
if (alias_hash == 0) {
return null;
}
if (aliasHashCode64() == alias_hash) {
return this;
}
SQLTableSource result = left.findTableSource(alias_hash);
if (result != null) {
return result;
}
return right.findTableSource(alias_hash);
}
public SQLTableSource other(SQLTableSource x) {
if (left == x) {
return right;
}
if (right == x) {
return left;
}
return null;
}
public boolean isGlobal() {
return global;
}
public void setGlobal(boolean global) {
this.global = global;
}
@Override
public int hashCode() {
int result = left != null ? left.hashCode() : 0;
result = 31 * result + (joinType != null ? joinType.hashCode() : 0);
result = 31 * result + (right != null ? right.hashCode() : 0);
result = 31 * result + (condition != null ? condition.hashCode() : 0);
result = 31 * result + using.hashCode();
result = 31 * result + (natural ? 1 : 0);
result = 31 * result + (global ? 1 : 0);
return result;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
if (!super.equals(o)) {
return false;
}
SQLJoinTableSource that = (SQLJoinTableSource) o;
if (natural != that.natural) {
return false;
}
if (asof != that.asof) {
return false;
}
if (global != that.global) {
return false;
}
if (left != null ? !left.equals(that.left) : that.left != null) {
return false;
}
if (joinType != that.joinType) {
return false;
}
if (right != null ? !right.equals(that.right) : that.right != null) {
return false;
}
if (condition != null ? !condition.equals(that.condition) : that.condition != null) {
return false;
}
if (using != null ? !using.equals(that.using) : that.using != null) {
return false;
}
return udj != null ? udj.equals(that.udj) : that.udj == null;
}
public void splitTo(List outTableSources, JoinType joinType) {
if (joinType == this.joinType) {
if (left instanceof SQLJoinTableSource) {
((SQLJoinTableSource) left).splitTo(outTableSources, joinType);
} else {
outTableSources.add(left);
}
if (right instanceof SQLJoinTableSource) {
((SQLJoinTableSource) right).splitTo(outTableSources, joinType);
} else {
outTableSources.add(right);
}
} else {
outTableSources.add(this);
}
}
public static class UDJ extends SQLObjectImpl {
protected SQLExpr function;
protected final List arguments = new ArrayList();
protected String alias;
protected final List columns = new ArrayList();
protected List sortBy = new ArrayList();
protected List properties = new ArrayList();
public UDJ() {
}
@Override
protected void accept0(SQLASTVisitor v) {
if (v.visit(this)) {
acceptChild(v, arguments);
acceptChild(v, columns);
}
v.endVisit(this);
}
public List getSortBy() {
return sortBy;
}
public UDJ(SQLExpr function) {
this.function = function;
}
public UDJ clone() {
UDJ x = new UDJ();
x.function = function.clone();
for (SQLExpr arg : arguments) {
SQLExpr t = arg.clone();
t.setParent(x);
x.arguments.add(t);
}
x.alias = alias;
for (SQLName column : columns) {
SQLName t = column.clone();
t.setParent(x);
x.columns.add(t);
}
for (SQLAssignItem property : properties) {
SQLAssignItem c = property.clone();
c.setParent(x);
x.properties.add(c);
}
return x;
}
public SQLExpr getFunction() {
return function;
}
public void setFunction(SQLExpr function) {
this.function = function;
}
public List getArguments() {
return arguments;
}
public List getColumns() {
return columns;
}
public String getAlias() {
return alias;
}
public void setAlias(String alias) {
this.alias = alias;
}
public List getProperties() {
return properties;
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy