Skip to content

View the Generated Code for a UDF

Paul Rogers edited this page Jan 6, 2018 · 7 revisions

As we have discussed, Drill's UDF mechanism is just Drill's internal built-in function mechanism with a new name. The mechanism copies the source of our UDF into code that Drill generates. To help us learn the mechanism, or to track down issues, it can be very helpful to examine the generated code.

Enable Logging

The generated code is written to the drillbit.log file when the proper logging level is set:

  • Logger: org.apache.drill.exec.compile.JaninoClassCompiler
  • Level: DEBUG

Enable Logging for Drill Server

To enable the above logging in your Drill server, locate the $DRILL_HOME/conf/logback.xml file. (Or, if you are using a site directory, look in $SITE_DIR/logback.xml.)

Add the following to the end of the file, before the </configuration> line:

  <logger name="org.apache.drill.exec.compile.JaninoClassCompiler" additivity="false">
    <level value="debug" />
    <appender-ref ref="FILE" />
  </logger>

Enable Logging in the Test Framework

You can also see the source file when using the debug framework discussed previously. Just add the following to your test:

  @Test
  public void example() throws Exception {
    LogFixtureBuilder logBuilder = new LogFixtureBuilder()
        .logger("org.apache.drill.exec.compile.JaninoClassCompiler", Level.DEBUG)
        ;
    ClusterFixtureBuilder builder = ClusterFixture.builder(dirTestWatcher)
        .configProperty("drill.classpath.scanning.cache.enabled", false);
    try (LogFixture logFixture = logBuilder.build();
         ClusterFixture cluster = builder.build();
         ClientFixture client = cluster.clientFixture()) {
      // Your test goes here
    }
  }

Example Output

The following is an example of the code for the project operator for the following query:

SELECT a, b + c AS d FROM cp.`example.json`

On this input file:

{a: 1, b: 2, c: 3}

The generated source (somewhat simplified) is below. Notice the inlined add function on line 45. That's where the body of our UDF would go.

1:      
2:      package org.apache.drill.exec.test.generated;
3:      
4:      import org.apache.drill.exec.exception.SchemaChangeException;
5:      import org.apache.drill.exec.expr.holders.NullableBigIntHolder;
6:      import org.apache.drill.exec.ops.FragmentContext;
7:      import org.apache.drill.exec.record.RecordBatch;
8:      import org.apache.drill.exec.vector.NullableBigIntVector;
9:      
10:     public class ProjectorGen0 {
11:     
12:         NullableBigIntVector vv0;
13:         NullableBigIntVector vv4;
14:         NullableBigIntVector vv9;
15:     
16:         public void doEval(int inIndex, int outIndex)
17:             throws SchemaChangeException
18:         {
19:             {
20:                 NullableBigIntHolder out3 = new NullableBigIntHolder();
21:                 {
22:                     out3 .isSet = vv0 .getAccessor().isSet((inIndex));
23:                     if (out3 .isSet == 1) {
24:                         out3 .value = vv0 .getAccessor().get((inIndex));
25:                     }
26:                 }
27:                 NullableBigIntHolder out7 = new NullableBigIntHolder();
28:                 {
29:                     out7 .isSet = vv4 .getAccessor().isSet((inIndex));
30:                     if (out7 .isSet == 1) {
31:                         out7 .value = vv4 .getAccessor().get((inIndex));
32:                     }
33:                 }
34:                 //---- start of eval portion of add function. ----//
35:                 NullableBigIntHolder out8 = new NullableBigIntHolder();
36:                 {
37:                     if ((out3 .isSet*out7 .isSet) == 0) {
38:                         out8 .isSet = 0;
39:                     } else {
40:                         final NullableBigIntHolder out = new NullableBigIntHolder();
41:                         NullableBigIntHolder in1 = out3;
42:                         NullableBigIntHolder in2 = out7;
43:                          
44:     AddFunctions$BigIntBigIntAdd_eval: {
45:         out.value = (long) (in1.value + in2.value);
46:     }
47:      
48:                         out.isSet = 1;
49:                         out8 = out;
50:                         out.isSet = 1;
51:                     }
52:                 }
53:                 //---- end of eval portion of add function. ----//
54:                 if (!(out8 .isSet == 0)) {
55:                     vv9 .getMutator().set((outIndex), out8 .isSet, out8 .value);
56:                 }
57:             }
58:         }
59:     
60:         public void doSetup(FragmentContext context, RecordBatch incoming, RecordBatch outgoing)
61:             throws SchemaChangeException
62:         {
63:             {
64:                 int[] fieldIds1 = new int[ 1 ] ;
65:                 fieldIds1 [ 0 ] = 1;
66:                 Object tmp2 = (incoming).getValueAccessorById(NullableBigIntVector.class, fieldIds1).getValueVector();
...
70:                 vv0 = ((NullableBigIntVector) tmp2);
71:                 int[] fieldIds5 = new int[ 1 ] ;
72:                 fieldIds5 [ 0 ] = 2;
73:                 Object tmp6 = (incoming).getValueAccessorById(NullableBigIntVector.class, fieldIds5).getValueVector();
...
77:                 vv4 = ((NullableBigIntVector) tmp6);
78:                 /** start SETUP for function add **/ 
79:                 {
80:                      {}
81:                 }
82:                 /** end SETUP for function add **/ 
83:                 int[] fieldIds10 = new int[ 1 ] ;
84:                 fieldIds10 [ 0 ] = 1;
85:                 Object tmp11 = (outgoing).getValueAccessorById(NullableBigIntVector.class, fieldIds10).getValueVector();
...
89:                 vv9 = ((NullableBigIntVector) tmp11);
90:             }
91:         }
...
98:     }
Clone this wiki locally