[fix](join)join reorder by mistake (#12113)
This commit is contained in:
@ -44,12 +44,24 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
|
||||
private boolean analyzed = false;
|
||||
private boolean needToSql = false;
|
||||
|
||||
// the tables positions may be changed by 'join reorder' optimization
|
||||
// after reset, the original order information is lost
|
||||
// in the next re-analyze phase, the mis-ordered tables may lead to 'unable to find column xxx' error
|
||||
// now we use originalTableRefOrders to keep track of table order information
|
||||
// so that in reset method, we can recover the original table orders.
|
||||
private final ArrayList<TableRef> originalTableRefOrders = new ArrayList<TableRef>();
|
||||
|
||||
public FromClause(List<TableRef> tableRefs) {
|
||||
tablerefs = Lists.newArrayList(tableRefs);
|
||||
// Set left table refs to ensure correct toSql() before analysis.
|
||||
for (int i = 1; i < tablerefs.size(); ++i) {
|
||||
tablerefs.get(i).setLeftTblRef(tablerefs.get(i - 1));
|
||||
}
|
||||
// save the tableRef's order, will use in reset method later
|
||||
originalTableRefOrders.clear();
|
||||
for (int i = 0; i < tablerefs.size(); ++i) {
|
||||
originalTableRefOrders.add(tablerefs.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
public FromClause() {
|
||||
@ -129,6 +141,12 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
|
||||
changeTblRefToNullable(analyzer);
|
||||
|
||||
analyzed = true;
|
||||
|
||||
// save the tableRef's order, will use in reset method later
|
||||
originalTableRefOrders.clear();
|
||||
for (int i = 0; i < tablerefs.size(); ++i) {
|
||||
originalTableRefOrders.add(tablerefs.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
// set null-side inlinve view column
|
||||
@ -154,13 +172,21 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
|
||||
for (TableRef tblRef : tablerefs) {
|
||||
clone.add(tblRef.clone());
|
||||
}
|
||||
return new FromClause(clone);
|
||||
FromClause result = new FromClause(clone);
|
||||
for (int i = 0; i < clone.size(); ++i) {
|
||||
result.originalTableRefOrders.add(clone.get(i));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public void reset() {
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
get(i).reset();
|
||||
}
|
||||
// recover original table orders
|
||||
for (int i = 0; i < size(); ++i) {
|
||||
tablerefs.set(i, originalTableRefOrders.get(i));
|
||||
}
|
||||
this.analyzed = false;
|
||||
}
|
||||
|
||||
@ -206,17 +232,32 @@ public class FromClause implements ParseNode, Iterable<TableRef> {
|
||||
|
||||
public void set(int i, TableRef tableRef) {
|
||||
tablerefs.set(i, tableRef);
|
||||
originalTableRefOrders.set(i, tableRef);
|
||||
}
|
||||
|
||||
public void add(TableRef t) {
|
||||
tablerefs.add(t);
|
||||
// join reorder will call add method after call clear method.
|
||||
// we want to keep tableRefPositions unchanged in that case
|
||||
// in other cases, tablerefs.size() would larger than tableRefPositions.size()
|
||||
// then we can update tableRefPositions. same logic in addAll method.
|
||||
if (tablerefs.size() > originalTableRefOrders.size()) {
|
||||
originalTableRefOrders.add(t);
|
||||
}
|
||||
}
|
||||
|
||||
public void addAll(List<TableRef> t) {
|
||||
tablerefs.addAll(t);
|
||||
if (tablerefs.size() > originalTableRefOrders.size()) {
|
||||
for (int i = originalTableRefOrders.size(); i < tablerefs.size(); ++i) {
|
||||
originalTableRefOrders.add(tablerefs.get(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
// this method on be called in reorder table
|
||||
// we want to keep tableRefPositions, only clear tablerefs
|
||||
tablerefs.clear();
|
||||
}
|
||||
}
|
||||
|
||||
@ -733,12 +733,12 @@ public class SelectStmt extends QueryStmt {
|
||||
|
||||
protected void reorderTable(Analyzer analyzer) throws AnalysisException {
|
||||
List<Pair<TableRef, Long>> candidates = Lists.newArrayList();
|
||||
List<TableRef> originOrderBackUp = Lists.newArrayList(fromClause.getTableRefs());
|
||||
ArrayList<TableRef> originOrderBackUp = Lists.newArrayList(fromClause.getTableRefs());
|
||||
// New pair of table ref and row count
|
||||
for (TableRef tblRef : fromClause) {
|
||||
if (tblRef.getJoinOp() != JoinOperator.INNER_JOIN || tblRef.hasJoinHints()) {
|
||||
// Unsupported reorder outer join
|
||||
return;
|
||||
break;
|
||||
}
|
||||
long rowCount = 0;
|
||||
if (tblRef.getTable().getType() == TableType.OLAP) {
|
||||
@ -747,6 +747,11 @@ public class SelectStmt extends QueryStmt {
|
||||
}
|
||||
candidates.add(Pair.of(tblRef, rowCount));
|
||||
}
|
||||
int reorderTableCount = candidates.size();
|
||||
if (reorderTableCount < originOrderBackUp.size()) {
|
||||
fromClause.clear();
|
||||
fromClause.addAll(originOrderBackUp.subList(0, reorderTableCount));
|
||||
}
|
||||
// give InlineView row count
|
||||
long last = 0;
|
||||
for (int i = candidates.size() - 1; i >= 0; --i) {
|
||||
@ -765,6 +770,9 @@ public class SelectStmt extends QueryStmt {
|
||||
// as long as one scheme success, we return this scheme immediately.
|
||||
// in this scheme, candidate.first will be consider to be the big table in star schema.
|
||||
// this scheme might not be fit for snowflake schema.
|
||||
if (reorderTableCount < originOrderBackUp.size()) {
|
||||
fromClause.addAll(originOrderBackUp.subList(reorderTableCount, originOrderBackUp.size()));
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
@ -819,18 +827,7 @@ public class SelectStmt extends QueryStmt {
|
||||
List<Expr> candidateEqJoinPredicates = analyzer.getEqJoinConjunctsExcludeAuxPredicates(tid);
|
||||
for (Expr candidateEqJoinPredicate : candidateEqJoinPredicates) {
|
||||
List<TupleId> candidateTupleList = Lists.newArrayList();
|
||||
List<Expr> candidateEqJoinPredicateList = Lists.newArrayList(candidateEqJoinPredicate);
|
||||
// If a large table or view has joinClause is ranked first,
|
||||
// and the joinClause is not judged here,
|
||||
// the column in joinClause may not be found during reanalyzing.
|
||||
// for example:
|
||||
// select * from t1 inner join t2 on t1.a = t2.b inner join t3 on t3.c = t2.b;
|
||||
// If t3 is a large table, it will be placed first after the reorderTable,
|
||||
// and the problem that t2.b does not exist will occur in reanalyzing
|
||||
if (candidateTableRef.getOnClause() != null) {
|
||||
candidateEqJoinPredicateList.add(candidateTableRef.getOnClause());
|
||||
}
|
||||
Expr.getIds(candidateEqJoinPredicateList, candidateTupleList, null);
|
||||
Expr.getIds(Lists.newArrayList(candidateEqJoinPredicate), candidateTupleList, null);
|
||||
int count = candidateTupleList.size();
|
||||
for (TupleId tupleId : candidateTupleList) {
|
||||
if (validTupleId.contains(tupleId) || tid.equals(tupleId)) {
|
||||
|
||||
Reference in New Issue
Block a user