You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@drill.apache.org by ja...@apache.org on 2013/08/06 01:47:44 UTC

[2/3] git commit: Implement negative substring offset

Implement negative substring offset


Project: http://git-wip-us.apache.org/repos/asf/incubator-drill/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-drill/commit/068a1dfd
Tree: http://git-wip-us.apache.org/repos/asf/incubator-drill/tree/068a1dfd
Diff: http://git-wip-us.apache.org/repos/asf/incubator-drill/diff/068a1dfd

Branch: refs/heads/master
Commit: 068a1dfddde0ef16db9b003cf7b28a79911417b5
Parents: ce7cf0d
Author: Ben Becker <be...@gmail.com>
Authored: Fri Aug 2 12:31:16 2013 -0700
Committer: Jacques Nadeau <ja...@apache.org>
Committed: Mon Aug 5 16:44:57 2013 -0700

----------------------------------------------------------------------
 .../drill/exec/expr/fn/impl/Substring.java      | 37 +++++++++++++++++--
 .../exec/physical/impl/TestSimpleFunctions.java | 38 ++++++++++++++++++++
 .../test/resources/functions/testSubstring.json |  2 +-
 .../functions/testSubstringNegative.json        | 37 +++++++++++++++++++
 4 files changed, 110 insertions(+), 4 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/068a1dfd/sandbox/prototype/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/Substring.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/Substring.java b/sandbox/prototype/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/Substring.java
index 785ed7d..5466159 100644
--- a/sandbox/prototype/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/Substring.java
+++ b/sandbox/prototype/exec/java-exec/src/main/java/org/apache/drill/exec/expr/fn/impl/Substring.java
@@ -30,8 +30,22 @@ import org.apache.drill.exec.record.RecordBatch;
 import org.apache.drill.exec.vector.*;
 
 // TODO: implement optional length parameter
-//       implement negative start position
+//       implement UTF-8 and UTF-16 support
 
+/**
+ * Evaluate a substring expression for a given value; specifying the start
+ * position, and optionally the end position.
+ *
+ *  - If the start position is negative, start from abs(start) characters from
+ *    the end of the buffer.
+ *
+ *  - If no length is specified, continue to the end of the string.
+ *
+ *  - If the substring expression's length exceeds the value's upward bound, the
+ *    value's length will be used.
+ *
+ *  - If the substring is invalid, return an empty string.
+ */
 @FunctionTemplate(name = "substring",
                   scope = FunctionTemplate.FunctionScope.SIMPLE,
                   nulls = FunctionTemplate.NullHandling.NULL_IF_NULL)
@@ -48,8 +62,25 @@ public class Substring implements DrillFunc {
   @Override
   public void eval() {
     out.buffer = string.buffer;
-    out.start = (int)offset.value;
-    out.end = (int)length.value;
+
+    // handle invalid values; e.g. SUBSTRING(value, 0, x) or SUBSTRING(value, x, 0)
+    if (offset.value == 0 || length.value <= 0) {
+      out.start = 0;
+      out.end = 0;
+      return;
+    }
+
+    // handle negative and positive offset values
+    if (offset.value < 0)
+      out.start = string.end + (int)offset.value;
+    else
+      out.start = (int)offset.value - 1;
+
+    // calculate end position from length and truncate to upper value bounds
+    if (out.start + length.value > string.end)
+      out.end = string.end;
+    else
+      out.end = out.start + (int)length.value;
   }
 
   public static class Provider implements CallProvider {

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/068a1dfd/sandbox/prototype/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestSimpleFunctions.java
----------------------------------------------------------------------
diff --git a/sandbox/prototype/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestSimpleFunctions.java b/sandbox/prototype/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestSimpleFunctions.java
index bed976c..17932e7 100644
--- a/sandbox/prototype/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestSimpleFunctions.java
+++ b/sandbox/prototype/exec/java-exec/src/test/java/org/apache/drill/exec/physical/impl/TestSimpleFunctions.java
@@ -143,6 +143,44 @@ public class TestSimpleFunctions {
 
   }
 
+  @Test
+  public void testSubstringNegative(@Injectable final DrillbitContext bitContext,
+                                    @Injectable UserServer.UserClientConnection connection) throws Throwable{
+
+    new NonStrictExpectations(){{
+      bitContext.getMetrics(); result = new MetricRegistry("test");
+      bitContext.getAllocator(); result = BufferAllocator.getAllocator(c);
+    }};
+
+    PhysicalPlanReader reader = new PhysicalPlanReader(c, c.getMapper(), CoordinationProtos.DrillbitEndpoint.getDefaultInstance());
+    PhysicalPlan plan = reader.readPhysicalPlan(Files.toString(FileUtils.getResourceAsFile("/functions/testSubstringNegative.json"), Charsets.UTF_8));
+    FunctionImplementationRegistry registry = new FunctionImplementationRegistry(c);
+    FragmentContext context = new FragmentContext(bitContext, ExecProtos.FragmentHandle.getDefaultInstance(), connection, null, registry);
+    SimpleRootExec exec = new SimpleRootExec(ImplCreator.getExec(context, (FragmentRoot) plan.getSortedOperators(false).iterator().next()));
+
+    while(exec.next()){
+      NullableVarCharVector c1 = exec.getValueVectorById(new SchemaPath("col3", ExpressionPosition.UNKNOWN), NullableVarCharVector.class);
+      NullableVarCharVector.Accessor a1;
+      a1 = c1.getAccessor();
+
+      int count = 0;
+      for(int i = 0; i < c1.getAccessor().getValueCount(); i++){
+        if (!a1.isNull(i)) {
+          NullableVarCharHolder holder = new NullableVarCharHolder();
+          a1.get(i, holder);
+          assertEquals("aa", holder.toString());
+          ++count;
+        }
+      }
+      assertEquals(50, count);
+    }
+
+    if(context.getFailureCause() != null){
+      throw context.getFailureCause();
+    }
+    assertTrue(!context.isFailed());
+
+  }
 
   @After
   public void tearDown() throws Exception{

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/068a1dfd/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstring.json
----------------------------------------------------------------------
diff --git a/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstring.json b/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstring.json
index 33b0da0..08a8ece 100644
--- a/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstring.json
+++ b/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstring.json
@@ -25,7 +25,7 @@
             child: 1,
             pop:"project",
             exprs: [
-              { ref: "col3", expr:"substring(yellow, 0, 4)" }
+              { ref: "col3", expr:"substring(yellow, 1, 4)" }
             ]
         },
         {

http://git-wip-us.apache.org/repos/asf/incubator-drill/blob/068a1dfd/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstringNegative.json
----------------------------------------------------------------------
diff --git a/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstringNegative.json b/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstringNegative.json
new file mode 100644
index 0000000..4951913
--- /dev/null
+++ b/sandbox/prototype/exec/java-exec/src/test/resources/functions/testSubstringNegative.json
@@ -0,0 +1,37 @@
+{
+    head:{
+        type:"APACHE_DRILL_PHYSICAL",
+        version:"1",
+        generator:{
+            type:"manual"
+        }
+    },
+    graph:[
+        {
+            @id:1,
+            pop:"mock-scan",
+            url: "http://apache.org",
+            entries:[
+            	{records: 100, types: [
+            	  {name: "blue", type: "INT", mode: "REQUIRED"},
+            	  {name: "red", type: "BIGINT", mode: "REQUIRED"},
+            	  {name: "yellow", type: "VARCHAR", mode: "OPTIONAL"},
+            	  {name: "green", type: "INT", mode: "REQUIRED"}
+            	]}
+            ]
+        },
+        {
+            @id:2,
+            child: 1,
+            pop:"project",
+            exprs: [
+              { ref: "col3", expr:"substring(yellow, -3, 2)" }
+            ]
+        },
+        {
+            @id: 3,
+            child: 2,
+            pop: "screen"
+        }
+    ]
+}
\ No newline at end of file