Impala
Impalaistheopensource,nativeanalyticdatabaseforApacheHadoop.
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros
UdfExecutorTest.java
Go to the documentation of this file.
1 // Copyright 2012 Cloudera Inc.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 package com.cloudera.impala.hive.executor;
16 
17 import static org.junit.Assert.assertArrayEquals;
18 import static org.junit.Assert.assertEquals;
19 import static org.junit.Assert.assertTrue;
20 
21 import java.lang.reflect.Method;
22 import java.net.MalformedURLException;
23 import java.util.ArrayList;
24 
25 import org.apache.hadoop.hive.ql.udf.UDFAcos;
26 import org.apache.hadoop.hive.ql.udf.UDFAscii;
27 import org.apache.hadoop.hive.ql.udf.UDFAsin;
28 import org.apache.hadoop.hive.ql.udf.UDFAtan;
29 import org.apache.hadoop.hive.ql.udf.UDFBin;
30 import org.apache.hadoop.hive.ql.udf.UDFConv;
31 import org.apache.hadoop.hive.ql.udf.UDFCos;
32 import org.apache.hadoop.hive.ql.udf.UDFDegrees;
33 import org.apache.hadoop.hive.ql.udf.UDFE;
34 import org.apache.hadoop.hive.ql.udf.UDFExp;
35 import org.apache.hadoop.hive.ql.udf.UDFFindInSet;
36 import org.apache.hadoop.hive.ql.udf.UDFHex;
37 import org.apache.hadoop.hive.ql.udf.UDFLength;
38 import org.apache.hadoop.hive.ql.udf.UDFLn;
39 import org.apache.hadoop.hive.ql.udf.UDFLog;
40 import org.apache.hadoop.hive.ql.udf.UDFLog10;
41 import org.apache.hadoop.hive.ql.udf.UDFLog2;
42 import org.apache.hadoop.hive.ql.udf.UDFPI;
43 import org.apache.hadoop.hive.ql.udf.UDFRadians;
44 import org.apache.hadoop.hive.ql.udf.UDFRand;
45 import org.apache.hadoop.hive.ql.udf.UDFRepeat;
46 import org.apache.hadoop.hive.ql.udf.UDFReverse;
47 import org.apache.hadoop.hive.ql.udf.UDFSign;
48 import org.apache.hadoop.hive.ql.udf.UDFSin;
49 import org.apache.hadoop.hive.ql.udf.UDFSpace;
50 import org.apache.hadoop.hive.ql.udf.UDFSqrt;
51 import org.apache.hadoop.hive.ql.udf.UDFSubstr;
52 import org.apache.hadoop.hive.ql.udf.UDFTan;
53 import org.apache.hadoop.hive.ql.udf.UDFUnhex;
54 import org.apache.hadoop.io.BytesWritable;
55 import org.apache.hadoop.io.Text;
56 import org.apache.hadoop.io.Writable;
57 import org.junit.Test;
58 
63 import com.google.common.base.Preconditions;
64 import com.google.common.collect.Lists;
65 
66 @SuppressWarnings("restriction")
67 public class UdfExecutorTest {
68  private final String HIVE_BUILTIN_JAR = System.getenv("HIVE_HOME") + "/" +
69  "lib/hive-exec-" + System.getenv("IMPALA_HIVE_VERSION") + ".jar";
70 
71  // Allocations from the native heap. These are freed in bulk.
72  ArrayList<Long> allocations_ = Lists.newArrayList();
73 
74  // Allocates 'byteSize' from the native heap and returns the ptr. The allocation
75  // is added to allocations_.
76  long allocate(int byteSize) {
77  long ptr = UnsafeUtil.UNSAFE.allocateMemory(byteSize);
78  allocations_.add(ptr);
79  return ptr;
80  }
81 
82  // Creates a string value object (in the native heap) for v.
83  long createStringValue(String v) {
84  byte[] array = v.getBytes();
85  long ptr = allocate(16);
86  UnsafeUtil.UNSAFE.putInt(ptr + 8, 0);
88  sw.set(array, 0, array.length);
89  return ptr;
90  }
91 
92  // Frees all allocations in allocations
93  void freeAllocations() {
94  for (Long l: allocations_) {
95  UnsafeUtil.UNSAFE.freeMemory(l.longValue());
96  }
97  allocations_.clear();
98  }
99 
100  // Creates the Impala wrapper Writable object.
101  Writable createObject(PrimitiveType t, Object o) {
102  long ptr = allocate(t.getSlotSize());
103  switch (t) {
104  case BOOLEAN: {
106  w.set((Boolean)o);
107  return w;
108  }
109  case TINYINT: {
111  w.set((byte)((Integer)o).intValue());
112  return w;
113  }
114  case SMALLINT: {
116  w.set(((Integer)o).shortValue());
117  return w;
118  }
119  case INT: {
121  w.set((Integer)o);
122  return w;
123  }
124  case BIGINT: {
126  w.set((Long)o);
127  return w;
128  }
129  case FLOAT: {
131  w.set((Float)o);
132  return w;
133  }
134  case DOUBLE: {
136  w.set((Double)o);
137  return w;
138  }
139  }
140  return null;
141  }
142 
143  Writable createBoolean(boolean v) { return createObject(PrimitiveType.BOOLEAN, v); }
144  Writable createTinyInt(int v) { return createObject(PrimitiveType.TINYINT, v); }
145  Writable createSmallInt(int v) { return createObject(PrimitiveType.SMALLINT, v); }
146  Writable createInt(int v) { return createObject(PrimitiveType.INT, v); }
147  Writable createBigInt(long v) { return createObject(PrimitiveType.BIGINT, v); }
148  Writable createFloat(float v) { return createObject(PrimitiveType.FLOAT, v); }
149  Writable createDouble(double v) { return createObject(PrimitiveType.DOUBLE, v); }
150  Writable createBytes(String v) {
151  ImpalaBytesWritable w = new ImpalaBytesWritable(createStringValue(v));
152  return w;
153  }
154 
155  Writable createText(String v) {
156  ImpalaTextWritable w = new ImpalaTextWritable(createStringValue(v));
157  return w;
158  }
159 
160  // Returns the primitive type for w
161  Type getType(Object w) {
162  if (w instanceof ImpalaBooleanWritable) {
163  return Type.BOOLEAN;
164  } else if (w instanceof ImpalaTinyIntWritable) {
165  return Type.TINYINT;
166  } else if (w instanceof ImpalaSmallIntWritable) {
167  return Type.SMALLINT;
168  } else if (w instanceof ImpalaIntWritable) {
169  return Type.INT;
170  } else if (w instanceof ImpalaBigIntWritable) {
171  return Type.BIGINT;
172  } else if (w instanceof ImpalaFloatWritable) {
173  return Type.FLOAT;
174  } else if (w instanceof ImpalaDoubleWritable) {
175  return Type.DOUBLE;
176  } else if (w instanceof ImpalaBytesWritable || w instanceof ImpalaTextWritable
177  || w instanceof String) {
178  return Type.STRING;
179  }
180  Preconditions.checkArgument(false);
181  return Type.INVALID;
182  }
183 
184  // Runs the hive udf contained in c. Validates that c.evaluate(args) == retValue.
185  // Arguments and return value cannot be NULL.
186  void TestUdfImpl(String jar, Class<?> c, Object expectedValue,
187  Type expectedType, boolean validate, Object... args)
188  throws MalformedURLException, ImpalaRuntimeException {
189  Type[] argTypes = new Type[args.length];
190  for (int i = 0; i < args.length; ++i) {
191  Preconditions.checkNotNull(args[i]);
192  argTypes[i] = getType(args[i]);
193  }
194 
195  UdfExecutor e = new UdfExecutor(jar, c.getName(), expectedType, argTypes);
196  Method method = e.getMethod();
197  Object[] inputArgs = new Object[args.length];
198  for (int i = 0; i < args.length; ++i) {
199  if (args[i] instanceof String) {
200  // For authoring the test, we'll just pass string and make the proper
201  // object here.
202  if (method.getParameterTypes()[i] == Text.class) {
203  inputArgs[i] = createText((String)args[i]);
204  } else if (method.getParameterTypes()[i] == BytesWritable.class) {
205  inputArgs[i] = createBytes((String)args[i]);
206  } else {
207  Preconditions.checkState(method.getParameterTypes()[i] == String.class);
208  inputArgs[i] = args[i];
209  }
210  } else {
211  inputArgs[i] = args[i];
212  }
213  }
214 
215  // Run the executor a few times to make sure nothing gets messed up
216  // between runs.
217  for (int i = 0; i < 10; ++i) {
218  long r = e.evaluate(inputArgs);
219  if (validate) {
220  switch (expectedType.getPrimitiveType()) {
221  case BOOLEAN: {
222  boolean v = UnsafeUtil.UNSAFE.getByte(r) != 0;
223  assertTrue(v == ((ImpalaBooleanWritable)expectedValue).get());
224  break;
225  }
226  case TINYINT:
227  assertEquals(UnsafeUtil.UNSAFE.getByte(r),
228  ((ImpalaTinyIntWritable)expectedValue).get());
229  break;
230  case SMALLINT:
231  assertEquals(UnsafeUtil.UNSAFE.getShort(r),
232  ((ImpalaSmallIntWritable)expectedValue).get());
233  break;
234  case INT:
235  assertEquals(UnsafeUtil.UNSAFE.getInt(r),
236  ((ImpalaIntWritable)expectedValue).get());
237  break;
238  case BIGINT:
239  assertEquals(UnsafeUtil.UNSAFE.getLong(r),
240  ((ImpalaBigIntWritable)expectedValue).get());
241  break;
242  case FLOAT:
243  assertEquals(UnsafeUtil.UNSAFE.getFloat(r),
244  ((ImpalaFloatWritable)expectedValue).get(), 0);
245  break;
246  case DOUBLE:
247  assertEquals(UnsafeUtil.UNSAFE.getDouble(r),
248  ((ImpalaDoubleWritable)expectedValue).get(), 0);
249  break;
250  case STRING: {
251  byte[] expectedBytes = null;
252  if (expectedValue instanceof ImpalaBytesWritable) {
253  expectedBytes = ((ImpalaBytesWritable)expectedValue).getBytes();
254  } else if (expectedValue instanceof ImpalaTextWritable) {
255  expectedBytes = ((ImpalaTextWritable)expectedValue).getBytes();
256  } else if (expectedValue instanceof String) {
257  expectedBytes = ((String)expectedValue).getBytes();
258  } else {
259  Preconditions.checkState(false);
260  }
262  assertArrayEquals(sw.getBytes(), expectedBytes);
263  break;
264  }
265  default:
266  Preconditions.checkArgument(false);
267  }
268  }
269  }
270  }
271 
272  void TestUdf(String jar, Class<?> c, Writable expectedValue, Object... args)
273  throws MalformedURLException, ImpalaRuntimeException {
274  TestUdfImpl(jar, c, expectedValue, getType(expectedValue), true, args);
275  }
276 
277  void TestUdf(String jar, Class<?> c, String expectedValue, Object... args)
278  throws MalformedURLException, ImpalaRuntimeException {
279  TestUdfImpl(jar, c, expectedValue, getType(expectedValue), true, args);
280  }
281 
282  void TestHiveUdf(Class<?> c, Writable expectedValue, Object... args)
283  throws MalformedURLException, ImpalaRuntimeException {
284  TestUdfImpl(HIVE_BUILTIN_JAR, c, expectedValue, getType(expectedValue), true, args);
285  }
286 
287  void TestHiveUdfNoValidate(Class<?> c, Writable expectedValue, Object... args)
288  throws MalformedURLException, ImpalaRuntimeException {
289  TestUdfImpl(HIVE_BUILTIN_JAR, c, expectedValue, getType(expectedValue), false, args);
290  }
291 
292  @Test
293  // Tests all the hive math UDFs. We are not trying to thoroughly test that the Hive
294  // UDFs are correct (i.e. replicate expr-test). The most interesting thing to test for
295  // here is that we can drive all the UDFs.
296  public void HiveMathTest()
297  throws ImpalaRuntimeException, MalformedURLException {
298  TestHiveUdfNoValidate(UDFRand.class, createDouble(0));
299  TestHiveUdfNoValidate(UDFRand.class, createDouble(0), createBigInt(10));
300  TestHiveUdf(UDFExp.class, createDouble(Math.exp(10)), createDouble(10));
301  TestHiveUdf(UDFLn.class, createDouble(Math.log(10)), createDouble(10));
302  TestHiveUdf(UDFLog10.class, createDouble(Math.log10(10)), createDouble(10));
303  TestHiveUdf(UDFLog2.class, createDouble(Math.log(10) / Math.log(2)),
304  createDouble(10));
305  TestHiveUdf(UDFLog.class, createDouble(Math.log(3) / Math.log(10)),
306  createDouble(10), createDouble(3));
307  TestHiveUdf(UDFSqrt.class, createDouble(Math.sqrt(3)), createDouble(3));
308  TestHiveUdf(UDFSin.class, createDouble(Math.sin(1)), createDouble(1));
309  TestHiveUdf(UDFAsin.class, createDouble(Math.asin(1)), createDouble(1));
310  TestHiveUdf(UDFCos.class, createDouble(Math.cos(1)), createDouble(1));
311  TestHiveUdf(UDFAcos.class, createDouble(Math.acos(1)), createDouble(1));
312  TestHiveUdf(UDFTan.class, createDouble(Math.tan(1)), createDouble(1));
313  TestHiveUdf(UDFAtan.class, createDouble(Math.atan(1)), createDouble(1));
314  TestHiveUdf(UDFDegrees.class, createDouble(0), createDouble(0));
315  TestHiveUdf(UDFRadians.class, createDouble(0), createDouble(0));
316 
317  TestHiveUdf(UDFPI.class, createDouble(Math.PI));
318  TestHiveUdf(UDFE.class, createDouble(Math.E));
319  TestHiveUdf(UDFSign.class, createDouble(1), createDouble(3));
320 
321  TestHiveUdf(UDFBin.class, createBytes("1100100"), createBigInt(100));
322 
323  TestHiveUdf(UDFHex.class, createBytes("1F4"), createBigInt(500));
324  TestHiveUdf(UDFHex.class, createBytes("3E8"), createBigInt(1000));
325 
326  TestHiveUdf(UDFHex.class, createText("31303030"), "1000");
327  TestHiveUdf(UDFUnhex.class, createText("aAzZ"), "61417A5A");
328  TestHiveUdf(UDFConv.class, createText("1111011"),
329  "123", createInt(10), createInt(2));
330  freeAllocations();
331  }
332 
333  @Test
334  // Tests all the hive string UDFs. We are not testing for correctness of the UDFs
335  // so it is sufficient to just cover the types.
336  public void HiveStringsTest() throws ImpalaRuntimeException, MalformedURLException {
337  TestHiveUdf(UDFAscii.class, createInt('1'), "123");
338  TestHiveUdf(UDFFindInSet.class, createInt(2), "31", "12,31,23");
339  TestHiveUdf(UDFLength.class, createInt(5), createText("Hello"));
340  TestHiveUdf(UDFRepeat.class, createText("abcabc"), "abc", createInt(2));
341  TestHiveUdf(UDFReverse.class, createText("cba"), "abc");
342  TestHiveUdf(UDFSpace.class, createText(" "), createInt(4));
343  TestHiveUdf(UDFSubstr.class, createText("World"),
344  "HelloWorld", createInt(6), createInt(5));
345  freeAllocations();
346  }
347 
348  @Test
349  // Test identity for all types
350  public void BasicTest() throws ImpalaRuntimeException, MalformedURLException {
351  TestUdf(null, TestUdf.class, createBoolean(true), createBoolean(true));
352  TestUdf(null, TestUdf.class, createTinyInt(1), createTinyInt(1));
353  TestUdf(null, TestUdf.class, createSmallInt(1), createSmallInt(1));
354  TestUdf(null, TestUdf.class, createInt(1), createInt(1));
355  TestUdf(null, TestUdf.class, createBigInt(1), createBigInt(1));
356  TestUdf(null, TestUdf.class, createFloat(1.1f), createFloat(1.1f));
357  TestUdf(null, TestUdf.class, createDouble(1.1), createDouble(1.1));
358  TestUdf(null, TestUdf.class, createBytes("ABCD"), "ABCD");
359  TestUdf(null, TestUdf.class, "ABCD", "ABCD");
360  TestUdf(null, TestUdf.class, createDouble(3),
361  createDouble(1), createDouble(2));
362  TestUdf(null, TestUdf.class, "ABCXYZ", "ABC", "XYZ");
363  freeAllocations();
364  }
365 }
static final ScalarType BIGINT
Definition: Type.java:50
void TestUdfImpl(String jar, Class<?> c, Object expectedValue, Type expectedType, boolean validate, Object...args)
Writable createObject(PrimitiveType t, Object o)
static final ScalarType STRING
Definition: Type.java:53
PrimitiveType getPrimitiveType()
Definition: Type.java:188
static final ScalarType BOOLEAN
Definition: Type.java:46
void TestHiveUdfNoValidate(Class<?> c, Writable expectedValue, Object...args)
void TestUdf(String jar, Class<?> c, Writable expectedValue, Object...args)
static final ScalarType SMALLINT
Definition: Type.java:48
static final ScalarType FLOAT
Definition: Type.java:51
void TestUdf(String jar, Class<?> c, String expectedValue, Object...args)
PrimitiveType
Definition: types.h:27
static final ScalarType DOUBLE
Definition: Type.java:52
static final ScalarType TINYINT
Definition: Type.java:47
void TestHiveUdf(Class<?> c, Writable expectedValue, Object...args)
static final ScalarType INT
Definition: Type.java:49
uint64_t Test(T *ht, const ProbeTuple *input, uint64_t num_tuples)
static final ScalarType INVALID
Definition: Type.java:44