/**
* 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.drill.exec.expr;
import static org.junit.Assert.assertEquals;
import mockit.Expectations;
import mockit.Injectable;
import mockit.NonStrict;
import mockit.NonStrictExpectations;
import org.antlr.runtime.ANTLRStringStream;
import org.antlr.runtime.CommonTokenStream;
import org.antlr.runtime.RecognitionException;
import org.apache.drill.common.config.DrillConfig;
import org.apache.drill.common.exceptions.ExpressionParsingException;
import org.apache.drill.common.expression.ErrorCollector;
import org.apache.drill.common.expression.ErrorCollectorImpl;
import org.apache.drill.common.expression.ExpressionPosition;
import org.apache.drill.common.expression.LogicalExpression;
import org.apache.drill.common.expression.SchemaPath;
import org.apache.drill.common.expression.parser.ExprLexer;
import org.apache.drill.common.expression.parser.ExprParser;
import org.apache.drill.common.expression.parser.ExprParser.parse_return;
import org.apache.drill.common.types.TypeProtos;
import org.apache.drill.common.types.TypeProtos.MinorType;
import org.apache.drill.common.types.Types;
import org.apache.drill.exec.ExecTest;
import org.apache.drill.exec.expr.fn.FunctionImplementationRegistry;
import org.apache.drill.exec.memory.RootAllocatorFactory;
import org.apache.drill.exec.physical.impl.project.Projector;
import org.apache.drill.exec.record.MaterializedField;
import org.apache.drill.exec.record.RecordBatch;
import org.apache.drill.exec.record.TypedFieldId;
import org.apache.drill.exec.record.VectorWrapper;
import org.apache.drill.exec.vector.IntVector;
import org.apache.drill.exec.vector.ValueVector;
import org.junit.Test;
public class ExpressionTest extends ExecTest {
private static final org.slf4j.Logger logger = org.slf4j.LoggerFactory.getLogger(ExpressionTest.class);
private final DrillConfig c = DrillConfig.create();
private final FunctionImplementationRegistry registry = new FunctionImplementationRegistry(c);
@Test
public void testBasicExpression(@Injectable RecordBatch batch) throws Exception {
System.out.println(getExpressionCode("if(true) then 1 else 0 end", batch));
}
@Test
public void testExprParseUpperExponent(@Injectable RecordBatch batch) throws Exception {
getExpressionCode("multiply(`$f0`, 1.0E-4)", batch);
}
@Test
public void testExprParseLowerExponent(@Injectable RecordBatch batch) throws Exception {
getExpressionCode("multiply(`$f0`, 1.0e-4)", batch);
}
@Test
public void testSpecial(final @Injectable RecordBatch batch, @Injectable ValueVector vector) throws Exception {
final TypeProtos.MajorType type = Types.optional(MinorType.INT);
final TypedFieldId tfid = new TypedFieldId(type, false, 0);
new NonStrictExpectations() {
@NonStrict VectorWrapper<?> wrapper;
{
batch.getValueVectorId(new SchemaPath("alpha", ExpressionPosition.UNKNOWN));
result = tfid;
batch.getValueAccessorById(IntVector.class, tfid.getFieldIds());
result = wrapper;
wrapper.getValueVector();
result = new IntVector(MaterializedField.create("result", type), RootAllocatorFactory.newRoot(c));
}
};
System.out.println(getExpressionCode("1 + 1", batch));
}
@Test
public void testSchemaExpression(final @Injectable RecordBatch batch) throws Exception {
final TypedFieldId tfid = new TypedFieldId(Types.optional(MinorType.BIGINT), false, 0);
new Expectations() {
{
batch.getValueVectorId(new SchemaPath("alpha", ExpressionPosition.UNKNOWN));
result = tfid;
// batch.getValueVectorById(tfid); result = new Fixed4(null, null);
}
};
System.out.println(getExpressionCode("1 + alpha", batch));
}
@Test(expected = ExpressionParsingException.class)
public void testExprParseError(@Injectable RecordBatch batch) throws Exception {
getExpressionCode("less than(1, 2)", batch);
}
@Test
public void testExprParseNoError(@Injectable RecordBatch batch) throws Exception {
getExpressionCode("equal(1, 2)", batch);
}
// HELPER METHODS //
private String getExpressionCode(String expression, RecordBatch batch) throws Exception {
final LogicalExpression expr = parseExpr(expression);
final ErrorCollector error = new ErrorCollectorImpl();
final LogicalExpression materializedExpr = ExpressionTreeMaterializer.materialize(expr, batch, error, registry);
if (error.getErrorCount() != 0) {
logger.error("Failure while materializing expression [{}]. Errors: {}", expression, error);
assertEquals(0, error.getErrorCount());
}
FunctionImplementationRegistry funcReg = new FunctionImplementationRegistry(DrillConfig.create());
final ClassGenerator<Projector> cg = CodeGenerator.get(Projector.TEMPLATE_DEFINITION, funcReg, null).getRoot();
cg.addExpr(new ValueVectorWriteExpression(new TypedFieldId(materializedExpr.getMajorType(), -1), materializedExpr));
return cg.getCodeGenerator().generateAndGet();
}
}