blob: 2982f839dfc77f4bb9eddb3f9f40c01d3807fd6d [file] [log] [blame]
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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 org.apache.tajo.engine.eval;
import org.apache.tajo.TajoTestingCluster;
import org.apache.tajo.algebra.Expr;
import org.apache.tajo.catalog.*;
import org.apache.tajo.catalog.proto.CatalogProtos;
import org.apache.tajo.datum.NullDatum;
import org.apache.tajo.datum.TextDatum;
import org.apache.tajo.engine.json.CoreGsonHelper;
import org.apache.tajo.engine.parser.SQLAnalyzer;
import org.apache.tajo.engine.planner.*;
import org.apache.tajo.engine.planner.logical.LogicalNode;
import org.apache.tajo.engine.utils.SchemaUtil;
import org.apache.tajo.master.TajoMaster;
import org.apache.tajo.storage.LazyTuple;
import org.apache.tajo.storage.Tuple;
import org.apache.tajo.storage.VTuple;
import org.apache.tajo.util.Bytes;
import org.apache.tajo.util.CommonTestingUtil;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import java.io.IOException;
import java.util.Stack;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
public class ExprTestBase {
private static TajoTestingCluster util;
private static CatalogService cat;
private static SQLAnalyzer analyzer;
private static PreLogicalPlanVerifier preLogicalPlanVerifier;
private static LogicalPlanner planner;
private static LogicalOptimizer optimizer;
private static LogicalPlanVerifier annotatedPlanVerifier;
@BeforeClass
public static void setUp() throws Exception {
util = new TajoTestingCluster();
util.startCatalogCluster();
cat = util.getMiniCatalogCluster().getCatalog();
for (FunctionDesc funcDesc : TajoMaster.initBuiltinFunctions()) {
cat.createFunction(funcDesc);
}
analyzer = new SQLAnalyzer();
preLogicalPlanVerifier = new PreLogicalPlanVerifier(cat);
planner = new LogicalPlanner(cat);
optimizer = new LogicalOptimizer(util.getConfiguration());
annotatedPlanVerifier = new LogicalPlanVerifier(util.getConfiguration(), cat);
}
@AfterClass
public static void tearDown() throws Exception {
util.shutdownCatalogCluster();
}
private static void assertJsonSerDer(EvalNode expr) {
String json = CoreGsonHelper.toJson(expr, EvalNode.class);
EvalNode fromJson = CoreGsonHelper.fromJson(json, EvalNode.class);
assertEquals(expr, fromJson);
}
/**
* verify query syntax and get raw targets.
*
* @param query a query for execution
* @param condition this parameter means whether it is for success case or is not for failure case.
* @return
* @throws PlanningException
*/
private static Target[] getRawTargets(String query, boolean condition) throws PlanningException {
Expr expr = analyzer.parse(query);
VerificationState state = new VerificationState();
preLogicalPlanVerifier.visit(state, new Stack<Expr>(), expr);
if (state.getErrorMessages().size() > 0) {
if (!condition && state.getErrorMessages().size() > 0) {
throw new PlanningException(state.getErrorMessages().get(0));
}
assertFalse(state.getErrorMessages().get(0), true);
}
LogicalPlan plan = planner.createPlan(expr, true);
optimizer.optimize(plan);
annotatedPlanVerifier.visit(state, plan, plan.getRootBlock(), plan.getRootBlock().getRoot(),
new Stack<LogicalNode>());
if (state.getErrorMessages().size() > 0) {
assertFalse(state.getErrorMessages().get(0), true);
}
Target [] targets = plan.getRootBlock().getRawTargets();
if (targets == null) {
throw new PlanningException("Wrong query statement or query plan: " + query);
}
for (Target t : targets) {
assertJsonSerDer(t.getEvalTree());
}
return targets;
}
public void testSimpleEval(String query, String [] expected) throws IOException {
testEval(null, null, null, query, expected);
}
public void testSimpleEval(String query, String [] expected, boolean condition) throws IOException {
testEval(null, null, null, query, expected, ',', condition);
}
public void testEval(Schema schema, String tableName, String csvTuple, String query, String [] expected)
throws IOException {
testEval(schema, tableName, csvTuple, query, expected, ',', true);
}
public void testEval(Schema schema, String tableName, String csvTuple, String query, String [] expected,
char delimiter, boolean condition) throws IOException {
LazyTuple lazyTuple;
VTuple vtuple = null;
Schema inputSchema = null;
if (schema != null) {
inputSchema = SchemaUtil.clone(schema);
inputSchema.setQualifier(tableName);
int targetIdx [] = new int[inputSchema.size()];
for (int i = 0; i < targetIdx.length; i++) {
targetIdx[i] = i;
}
lazyTuple =
new LazyTuple(inputSchema, Bytes.splitPreserveAllTokens(csvTuple.getBytes(), delimiter, targetIdx),0);
vtuple = new VTuple(inputSchema.size());
for (int i = 0; i < inputSchema.size(); i++) {
// If null value occurs, null datum is manually inserted to an input tuple.
if (lazyTuple.get(i) instanceof TextDatum && lazyTuple.get(i).asChars().equals("")) {
vtuple.put(i, NullDatum.get());
} else {
vtuple.put(i, lazyTuple.get(i));
}
}
cat.addTable(new TableDesc(tableName, inputSchema, CatalogProtos.StoreType.CSV, new Options(),
CommonTestingUtil.getTestDir()));
}
Target [] targets;
try {
targets = getRawTargets(query, condition);
Tuple outTuple = new VTuple(targets.length);
for (int i = 0; i < targets.length; i++) {
EvalNode eval = targets[i].getEvalTree();
outTuple.put(i, eval.eval(inputSchema, vtuple));
}
for (int i = 0; i < expected.length; i++) {
assertEquals(query, expected[i], outTuple.get(i).asChars());
}
} catch (PlanningException e) {
// In failure test case, an exception must occur while executing query.
// So, we should check an error message, and return it.
if (!condition) {
assertEquals(expected[0], e.getMessage());
} else {
assertFalse(e.getMessage(), true);
}
} finally {
if (schema != null) {
cat.deleteTable(tableName);
}
}
}
}