/** * 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.hadoop.hive.ql.exec.vector.expressions; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import junit.framework.Assert; import org.apache.hadoop.hive.ql.exec.vector.DoubleColumnVector; import org.apache.hadoop.hive.ql.exec.vector.LongColumnVector; import org.apache.hadoop.hive.ql.exec.vector.TestVectorizedRowBatch; import org.apache.hadoop.hive.ql.exec.vector.VectorizedRowBatch; import org.apache.hadoop.hive.ql.exec.vector.expressions.gen.LongScalarModuloLongColumn; import org.apache.hadoop.hive.ql.exec.vector.expressions.gen.LongScalarSubtractLongColumn; import org.junit.Test; /** * Test vectorized expression handling for the case where there is a scalar on * the left and a column vector on the right. */ public class TestVectorScalarColArithmetic { /* Testing for equality of doubles after a math operation is * not always reliable so use this as a tolerance. */ private final double EPS = 1e-7d; private VectorizedRowBatch getVectorizedRowBatchSingleLongVector(int size) { VectorizedRowBatch batch = new VectorizedRowBatch(2, size); LongColumnVector lcv = new LongColumnVector(size); for (int i = 0; i < size; i++) { lcv.vector[i] = i * 37; } batch.cols[0] = lcv; batch.cols[1] = new LongColumnVector(size); batch.size = size; return batch; } private VectorizedRowBatch getBatchSingleLongVectorPositiveNonZero() { VectorizedRowBatch batch = new VectorizedRowBatch(2); final int size = VectorizedRowBatch.DEFAULT_SIZE; LongColumnVector lcv = new LongColumnVector(); for (int i = 0; i < size; i++) { lcv.vector[i] = (i + 1) * 37; } batch.cols[0] = lcv; batch.cols[1] = new LongColumnVector(); batch.size = size; return batch; } @Test public void testLongScalarModuloLongColNoNulls() { VectorizedRowBatch batch = getBatchSingleLongVectorPositiveNonZero(); LongScalarModuloLongColumn expr = new LongScalarModuloLongColumn(100, 0, 1); expr.evaluate(batch); // verify for (int i = 0; i < VectorizedRowBatch.DEFAULT_SIZE; i++) { Assert.assertEquals(100 % ((i + 1) * 37), ((LongColumnVector) batch.cols[1]).vector[i]); } Assert.assertTrue(((LongColumnVector)batch.cols[1]).noNulls); Assert.assertFalse(((LongColumnVector)batch.cols[1]).isRepeating); } @Test public void testLongScalarSubtractLongColNoNulls() { VectorizedRowBatch batch = getVectorizedRowBatchSingleLongVector( VectorizedRowBatch.DEFAULT_SIZE); LongScalarSubtractLongColumn expr = new LongScalarSubtractLongColumn(100, 0, 1); expr.evaluate(batch); //verify for (int i = 0; i < VectorizedRowBatch.DEFAULT_SIZE; i++) { Assert.assertEquals(100 - i * 37, ((LongColumnVector) batch.cols[1]).vector[i]); } Assert.assertTrue(((LongColumnVector)batch.cols[1]).noNulls); Assert.assertFalse(((LongColumnVector)batch.cols[1]).isRepeating); } @Test public void testLongScalarSubtractLongColWithNulls() { VectorizedRowBatch batch = getVectorizedRowBatchSingleLongVector( VectorizedRowBatch.DEFAULT_SIZE); LongColumnVector lcv = (LongColumnVector) batch.cols[0]; TestVectorizedRowBatch.addRandomNulls(lcv); LongScalarSubtractLongColumn expr = new LongScalarSubtractLongColumn(100, 0, 1); expr.evaluate(batch); //verify for (int i=0; i < VectorizedRowBatch.DEFAULT_SIZE; i++) { if (!lcv.isNull[i]) { Assert.assertEquals(100 - i * 37, ((LongColumnVector)batch.cols[1]).vector[i]); } else { Assert.assertTrue(((LongColumnVector)batch.cols[1]).isNull[i]); } } Assert.assertFalse(((LongColumnVector)batch.cols[1]).noNulls); Assert.assertFalse(((LongColumnVector)batch.cols[1]).isRepeating); TestVectorArithmeticExpressions.verifyLongNullDataVectorEntries( (LongColumnVector) batch.cols[1], batch.selected, batch.selectedInUse, batch.size); } @Test public void testLongScalarSubtractLongColWithRepeating() { LongColumnVector in, out; VectorizedRowBatch batch; LongScalarSubtractLongColumn expr; // Case 1: is repeating, no nulls batch = getVectorizedRowBatchSingleLongVector( VectorizedRowBatch.DEFAULT_SIZE); in = (LongColumnVector) batch.cols[0]; in.isRepeating = true; out = (LongColumnVector) batch.cols[1]; out.isRepeating = false; expr = new LongScalarSubtractLongColumn(100, 0, 1); expr.evaluate(batch); // verify Assert.assertTrue(out.isRepeating); Assert.assertTrue(out.noNulls); Assert.assertEquals(out.vector[0], 100 - 0 * 37); // Case 2: is repeating, has nulls batch = getVectorizedRowBatchSingleLongVector( VectorizedRowBatch.DEFAULT_SIZE); in = (LongColumnVector) batch.cols[0]; in.isRepeating = true; in.noNulls = false; in.isNull[0] = true; out = (LongColumnVector) batch.cols[1]; out.isRepeating = false; out.isNull[0] = false; out.noNulls = true; expr = new LongScalarSubtractLongColumn(100, 0, 1); expr.evaluate(batch); // verify Assert.assertTrue(out.isRepeating); Assert.assertFalse(out.noNulls); Assert.assertEquals(true, out.isNull[0]); TestVectorArithmeticExpressions.verifyLongNullDataVectorEntries( out, batch.selected, batch.selectedInUse, batch.size); } private boolean equalsWithinTolerance(double a, double b) { return Math.abs(a - b) < EPS; } @Test public void testLongScalarDivide() { VectorizedRowBatch batch = TestVectorArithmeticExpressions.getVectorizedRowBatch2LongInDoubleOut(); LongColDivideLongScalar expr = new LongColDivideLongScalar(0, 100, 2); batch.cols[0].isNull[0] = true; batch.cols[0].noNulls = false; DoubleColumnVector out = (DoubleColumnVector) batch.cols[2]; out.noNulls = true; // set now so we can verify it changed out.isRepeating = true; expr.evaluate(batch); // verify NULL output in entry 0 is correct assertFalse(out.noNulls); assertTrue(out.isNull[0]); assertTrue(Double.isNaN(out.vector[0])); // check entries beyond first one for (int i = 1; i != batch.size; i++) { assertTrue(equalsWithinTolerance((i * 37) / 100d, out.vector[i])); } assertFalse(out.isRepeating); } @Test public void testScalarLongDivide() { VectorizedRowBatch batch = TestVectorArithmeticExpressions.getVectorizedRowBatch2LongInDoubleOut(); LongScalarDivideLongColumn expr = new LongScalarDivideLongColumn(100, 0, 2); batch.cols[0].isNull[1] = true; batch.cols[0].noNulls = false; DoubleColumnVector out = (DoubleColumnVector) batch.cols[2]; out.noNulls = true; // set now so we can verify it changed out.isRepeating = true; expr.evaluate(batch); // verify zero-divide result for position 0 assertTrue(out.isNull[0]); assertTrue(Double.isNaN(out.vector[0])); // verify NULL output in entry 1 is correct assertTrue(out.isNull[1]); assertTrue(Double.isNaN(out.vector[1])); // check entries beyond 2nd one for (int i = 2; i != batch.size; i++) { assertTrue(equalsWithinTolerance(100d / (i * 37), out.vector[i])); } assertFalse(out.noNulls); assertFalse(out.isRepeating); } @Test public void testBooleanValuedLongIn() { VectorizedRowBatch batch = getBatch(); long[] a = new long[2]; a[0] = 20; a[1] = 1000; batch.size = 2; VectorExpression expr = (new LongColumnInList(0, 1)); ((LongColumnInList) expr).setInListValues(a); expr.evaluate(batch); LongColumnVector out = (LongColumnVector) batch.cols[1]; Assert.assertEquals(0, out.vector[0]); Assert.assertEquals(1, out.vector[1]); } private VectorizedRowBatch getBatch() { VectorizedRowBatch b = new VectorizedRowBatch(2); LongColumnVector v = new LongColumnVector(); v.vector[0] = 10; v.vector[1] = 20; b.cols[0] = v; b.cols[1] = new LongColumnVector(); return b; } }