/*
* Copyright (c) 2011-2015 EPFL DATA Laboratory
* Copyright (c) 2014-2015 The Squall Collaboration (see NOTICE)
*
* All rights reserved.
*
* 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 ch.epfl.data.squall.api.sql.optimizers.index;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import net.sf.jsqlparser.expression.Expression;
import ch.epfl.data.squall.api.sql.optimizers.CompGen;
import ch.epfl.data.squall.api.sql.schema.Schema;
import ch.epfl.data.squall.api.sql.util.ParserUtil;
import ch.epfl.data.squall.api.sql.visitors.jsql.SQLVisitor;
import ch.epfl.data.squall.api.sql.visitors.squall.IndexJoinHashVisitor;
import ch.epfl.data.squall.components.Component;
import ch.epfl.data.squall.components.DataSourceComponent;
import ch.epfl.data.squall.components.EquiJoinComponent;
import ch.epfl.data.squall.expressions.ValueExpression;
import ch.epfl.data.squall.query_plans.QueryBuilder;
import ch.epfl.data.squall.utilities.SystemParameters;
/*
* It is necessary that this class operates with Tables,
* since we don't want multiple CG sharing the same copy of DataSourceComponent.
*/
public class IndexCompGen implements CompGen {
private final SQLVisitor _pq;
private final Schema _schema;
private final String _dataPath;
private final String _extension;
private final QueryBuilder _queryBuilder = new QueryBuilder();
// List of Components which are already added throughEquiJoinComponent and
// OperatorComponent
private final List<Component> _subPlans = new ArrayList<Component>();
public IndexCompGen(Schema schema, SQLVisitor pq, Map map) {
_schema = schema;
_pq = pq;
_dataPath = SystemParameters.getString(map, "DIP_DATA_PATH");
_extension = SystemParameters.getString(map, "DIP_EXTENSION");
}
// set hash for this component, knowing its position in the query plan.
// Conditions are related only to parents of join,
// but we have to filter who belongs to my branch in IndexJoinHashVisitor.
// We don't want to hash on something which will be used to join with same
// later component in the hierarchy.
private void addHash(Component component, List<Expression> joinCondition) {
final IndexJoinHashVisitor joinOn = new IndexJoinHashVisitor(_schema,
component, _pq.getTan());
for (final Expression exp : joinCondition)
exp.accept(joinOn);
final List<ValueExpression> hashExpressions = joinOn.getExpressions();
if (ParserUtil.isAllColumnRefs(hashExpressions)) {
// all the join conditions are represented through columns, no
// ValueExpression (neither in joined component)
// guaranteed that both joined components will have joined columns
// visited in the same order
// i.e R.A=S.A and R.B=S.B, the columns are (R.A, R.B), (S.A, S.B),
// respectively
final List<Integer> hashIndexes = ParserUtil
.extractColumnIndexes(hashExpressions);
// hash indexes in join condition
component.setOutputPartKey(hashIndexes);
} else
// hahs expressions in join condition
component.setHashExpressions(hashExpressions);
}
/*
* adding a DataSourceComponent to the list of components
*/
@Override
public DataSourceComponent generateDataSource(String tableCompName) {
final String tableSchemaName = _pq.getTan()
.getSchemaName(tableCompName);
final String sourceFile = tableSchemaName.toLowerCase();
final DataSourceComponent relation = new DataSourceComponent(
tableCompName, _dataPath + sourceFile + _extension);
_queryBuilder.add(relation);
_subPlans.add(relation);
return relation;
}
/*
* Join between two components List<Expression> is a set of join conditions
* between two components.
*/
@Override
public Component generateEquiJoin(Component left, Component right) {
final EquiJoinComponent joinComponent = new EquiJoinComponent(left,
right);
_queryBuilder.add(joinComponent);
// compute join condition
final List<Expression> joinCondition = ParserUtil.getJoinCondition(_pq,
left, right);
if (joinCondition == null)
throw new RuntimeException(
"There is no join conditition between components "
+ left.getName() + " and " + right.getName());
// set hashes for two parents
addHash(left, joinCondition);
addHash(right, joinCondition);
_subPlans.remove(left);
_subPlans.remove(right);
_subPlans.add(joinComponent);
return joinComponent;
}
@Override
public QueryBuilder getQueryBuilder() {
return _queryBuilder;
}
@Override
public List<Component> getSubPlans() {
return _subPlans;
}
}