This is an automated email from the ASF dual-hosted git repository.

maytasm pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/druid.git


The following commit(s) were added to refs/heads/master by this push:
     new 0d22462  Document unsupported Join on multi-value column (#9948)
0d22462 is described below

commit 0d22462e07bef0d162a81c4f1a061c83c6f733d0
Author: Maytas Monsereenusorn <[email protected]>
AuthorDate: Wed Jun 3 09:55:52 2020 -1000

    Document unsupported Join on multi-value column (#9948)
    
    * Document Unsupported Join on multi-value column
    
    * Document Unsupported Join on multi-value column
    
    * address comments
    
    * Add unit tests
    
    * address comments
    
    * add tests
---
 docs/querying/datasource.md                        |  2 +
 docs/querying/sql.md                               |  2 +
 .../druid/query/QueryUnsupportedException.java     | 70 ++++++++++++++++++
 .../segment/join/lookup/LookupJoinMatcher.java     |  8 ++-
 .../join/table/IndexedTableJoinMatcher.java        | 15 ++--
 .../join/table/IndexedTableJoinMatcherTest.java    | 83 ++++++++++++++++++++++
 .../segment/join/table/LookupJoinMatcherTest.java  | 36 ++++++++++
 .../org/apache/druid/server/QueryResource.java     | 13 ++++
 .../org/apache/druid/server/QueryResourceTest.java | 28 ++++++++
 .../org/apache/druid/sql/http/SqlResource.java     |  6 ++
 .../apache/druid/sql/calcite/CalciteQueryTest.java | 18 +++++
 .../org/apache/druid/sql/http/SqlResourceTest.java | 17 +++++
 12 files changed, 292 insertions(+), 6 deletions(-)

diff --git a/docs/querying/datasource.md b/docs/querying/datasource.md
index 66cc905..d6c478d 100644
--- a/docs/querying/datasource.md
+++ b/docs/querying/datasource.md
@@ -348,3 +348,5 @@ future versions:
 always be correct.
 - Performance-related optimizations as mentioned in the [previous 
section](#join-performance).
 - Join algorithms other than broadcast hash-joins.
+- Join condition on a column compared to a constant value.
+- Join conditions on a column containing a multi-value dimension.
diff --git a/docs/querying/sql.md b/docs/querying/sql.md
index 9a49009..7b84e4a 100644
--- a/docs/querying/sql.md
+++ b/docs/querying/sql.md
@@ -709,6 +709,8 @@ Druid does not support all SQL features. In particular, the 
following features a
 
 - JOIN between native datasources (table, lookup, subquery) and system tables.
 - JOIN conditions that are not an equality between expressions from the left- 
and right-hand sides.
+- JOIN conditions containing a constant value inside the condition.
+- JOIN conditions on a column which contains a multi-value dimension.
 - OVER clauses, and analytic functions such as `LAG` and `LEAD`.
 - OFFSET clauses.
 - DDL and DML.
diff --git 
a/processing/src/main/java/org/apache/druid/query/QueryUnsupportedException.java
 
b/processing/src/main/java/org/apache/druid/query/QueryUnsupportedException.java
new file mode 100644
index 0000000..41126dc
--- /dev/null
+++ 
b/processing/src/main/java/org/apache/druid/query/QueryUnsupportedException.java
@@ -0,0 +1,70 @@
+/*
+ * 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.druid.query;
+
+
+import com.fasterxml.jackson.annotation.JsonCreator;
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+import javax.annotation.Nullable;
+import java.net.InetAddress;
+
+/**
+ * This exception is for the query engine to surface when a query cannot be 
run. This can be due to the
+ * following reasons: 1) The query is not supported yet. 2) The query is not 
something Druid would ever supports.
+ * For these cases, the exact causes and details should also be documented in 
Druid user facing documents.
+ *
+ * As a {@link QueryException} it is expected to be serialied to a json 
response, but will be mapped to
+ * {@link #STATUS_CODE} instead of the default HTTP 500 status.
+ */
+public class QueryUnsupportedException extends QueryException
+{
+  private static final String ERROR_CLASS = 
QueryUnsupportedException.class.getName();
+  public static final String ERROR_CODE = "Unsupported query";
+  public static final int STATUS_CODE = 400;
+
+  @JsonCreator
+  public QueryUnsupportedException(
+      @JsonProperty("error") @Nullable String errorCode,
+      @JsonProperty("errorMessage") String errorMessage,
+      @JsonProperty("errorClass") @Nullable String errorClass,
+      @JsonProperty("host") @Nullable String host
+  )
+  {
+    super(errorCode, errorMessage, errorClass, host);
+  }
+
+  public QueryUnsupportedException(String errorMessage)
+  {
+    super(ERROR_CODE, errorMessage, ERROR_CLASS, resolveHostname());
+  }
+
+  private static String resolveHostname()
+  {
+    String host;
+    try {
+      host = InetAddress.getLocalHost().getCanonicalHostName();
+    }
+    catch (Exception e) {
+      host = null;
+    }
+    return host;
+  }
+}
diff --git 
a/processing/src/main/java/org/apache/druid/segment/join/lookup/LookupJoinMatcher.java
 
b/processing/src/main/java/org/apache/druid/segment/join/lookup/LookupJoinMatcher.java
index 624b6bc..a97739b 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/join/lookup/LookupJoinMatcher.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/join/lookup/LookupJoinMatcher.java
@@ -26,6 +26,7 @@ import org.apache.druid.common.guava.SettableSupplier;
 import org.apache.druid.java.util.common.IAE;
 import org.apache.druid.java.util.common.Pair;
 import org.apache.druid.math.expr.Expr;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.query.lookup.LookupExtractor;
 import org.apache.druid.segment.BaseDoubleColumnValueSelector;
 import org.apache.druid.segment.BaseFloatColumnValueSelector;
@@ -71,9 +72,12 @@ public class LookupJoinMatcher implements JoinMatcher
 
             if (row.size() == 1) {
               return selector.lookupName(row.get(0));
-            } else {
-              // Multi-valued rows are not handled by the join system right 
now; treat them as nulls.
+            } else if (row.size() == 0) {
               return null;
+            } else {
+              // Multi-valued rows are not handled by the join system right now
+              // TODO: Remove when https://github.com/apache/druid/issues/9924 
is done
+              throw new QueryUnsupportedException("Joining against a 
multi-value dimension is not supported.");
             }
           };
         }
diff --git 
a/processing/src/main/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcher.java
 
b/processing/src/main/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcher.java
index 685be4b..455f4f1 100644
--- 
a/processing/src/main/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcher.java
+++ 
b/processing/src/main/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcher.java
@@ -30,6 +30,7 @@ import it.unimi.dsi.fastutil.ints.IntRBTreeSet;
 import it.unimi.dsi.fastutil.ints.IntSet;
 import org.apache.druid.common.config.NullHandling;
 import org.apache.druid.java.util.common.IAE;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.segment.BaseDoubleColumnValueSelector;
 import org.apache.druid.segment.BaseFloatColumnValueSelector;
 import org.apache.druid.segment.BaseLongColumnValueSelector;
@@ -326,9 +327,12 @@ public class IndexedTableJoinMatcher implements JoinMatcher
             int dimensionId = row.get(0);
             IntList rowNumbers = getRowNumbers(selector, dimensionId);
             return rowNumbers.iterator();
-          } else {
-            // Multi-valued rows are not handled by the join system right now; 
treat them as nulls.
+          } else if (row.size() == 0) {
             return IntIterators.EMPTY_ITERATOR;
+          } else {
+            // Multi-valued rows are not handled by the join system right now
+            // TODO: Remove when https://github.com/apache/druid/issues/9924 
is done
+            throw new QueryUnsupportedException("Joining against a multi-value 
dimension is not supported.");
           }
         };
       } else {
@@ -341,9 +345,12 @@ public class IndexedTableJoinMatcher implements JoinMatcher
             int dimensionId = row.get(0);
             IntList rowNumbers = getAndCacheRowNumbers(selector, dimensionId);
             return rowNumbers.iterator();
-          } else {
-            // Multi-valued rows are not handled by the join system right now; 
treat them as nulls.
+          } else if (row.size() == 0) {
             return IntIterators.EMPTY_ITERATOR;
+          } else {
+            // Multi-valued rows are not handled by the join system right now
+            // TODO: Remove when https://github.com/apache/druid/issues/9924 
is done
+            throw new QueryUnsupportedException("Joining against a multi-value 
dimension is not supported.");
           }
         };
       }
diff --git 
a/processing/src/test/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcherTest.java
 
b/processing/src/test/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcherTest.java
index e7baaea..45367b2 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcherTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/join/table/IndexedTableJoinMatcherTest.java
@@ -23,14 +23,20 @@ import it.unimi.dsi.fastutil.ints.IntArrayList;
 import it.unimi.dsi.fastutil.ints.IntIterator;
 import it.unimi.dsi.fastutil.ints.IntList;
 import org.apache.druid.common.config.NullHandling;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.segment.ConstantDimensionSelector;
 import org.apache.druid.segment.DimensionDictionarySelector;
+import org.apache.druid.segment.DimensionSelector;
 import org.apache.druid.segment.column.ValueType;
+import org.apache.druid.segment.data.ArrayBasedIndexedInts;
 import org.junit.Assert;
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.experimental.runners.Enclosed;
 import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.Mockito;
+import org.mockito.MockitoAnnotations;
 
 import java.util.Collections;
 import java.util.concurrent.atomic.AtomicLong;
@@ -48,12 +54,89 @@ public class IndexedTableJoinMatcherTest
   {
     public static class MakeDimensionProcessorTest
     {
+      @Mock
+      private DimensionSelector dimensionSelector;
+
       private static final String KEY = "key";
 
       static {
         NullHandling.initializeForTests();
       }
 
+      @SuppressWarnings("ReturnValueIgnored")
+      @Test(expected = QueryUnsupportedException.class)
+      public void 
testMatchMultiValuedRowCardinalityUnknownShouldThrowException()
+      {
+        MockitoAnnotations.initMocks(this);
+        ArrayBasedIndexedInts row = new ArrayBasedIndexedInts(new int[]{2, 4, 
6});
+        Mockito.doReturn(row).when(dimensionSelector).getRow();
+        
Mockito.doReturn(DimensionDictionarySelector.CARDINALITY_UNKNOWN).when(dimensionSelector).getValueCardinality();
+
+        IndexedTableJoinMatcher.ConditionMatcherFactory 
conditionMatcherFactory =
+            new IndexedTableJoinMatcher.ConditionMatcherFactory(
+                ValueType.STRING,
+                IndexedTableJoinMatcherTest::createSingletonIntList
+            );
+        Supplier<IntIterator> dimensionProcessor = 
conditionMatcherFactory.makeDimensionProcessor(dimensionSelector, false);
+        // Test match should throw exception
+        dimensionProcessor.get();
+      }
+
+      @SuppressWarnings("ReturnValueIgnored")
+      @Test(expected = QueryUnsupportedException.class)
+      public void testMatchMultiValuedRowCardinalityKnownShouldThrowException()
+      {
+        MockitoAnnotations.initMocks(this);
+        ArrayBasedIndexedInts row = new ArrayBasedIndexedInts(new int[]{2, 4, 
6});
+        Mockito.doReturn(row).when(dimensionSelector).getRow();
+        Mockito.doReturn(3).when(dimensionSelector).getValueCardinality();
+
+        IndexedTableJoinMatcher.ConditionMatcherFactory 
conditionMatcherFactory =
+            new IndexedTableJoinMatcher.ConditionMatcherFactory(
+                ValueType.STRING,
+                IndexedTableJoinMatcherTest::createSingletonIntList
+            );
+        Supplier<IntIterator> dimensionProcessor = 
conditionMatcherFactory.makeDimensionProcessor(dimensionSelector, false);
+        // Test match should throw exception
+        dimensionProcessor.get();
+      }
+
+      @Test
+      public void testMatchEmptyRowCardinalityUnknown()
+      {
+        MockitoAnnotations.initMocks(this);
+        ArrayBasedIndexedInts row = new ArrayBasedIndexedInts(new int[]{});
+        Mockito.doReturn(row).when(dimensionSelector).getRow();
+        
Mockito.doReturn(DimensionDictionarySelector.CARDINALITY_UNKNOWN).when(dimensionSelector).getValueCardinality();
+
+        IndexedTableJoinMatcher.ConditionMatcherFactory 
conditionMatcherFactory =
+            new IndexedTableJoinMatcher.ConditionMatcherFactory(
+                ValueType.STRING,
+                IndexedTableJoinMatcherTest::createSingletonIntList
+            );
+        Supplier<IntIterator> dimensionProcessor = 
conditionMatcherFactory.makeDimensionProcessor(dimensionSelector, false);
+        Assert.assertNotNull(dimensionProcessor.get());
+        Assert.assertFalse(dimensionProcessor.get().hasNext());
+      }
+
+      @Test
+      public void testMatchEmptyRowCardinalityKnown()
+      {
+        MockitoAnnotations.initMocks(this);
+        ArrayBasedIndexedInts row = new ArrayBasedIndexedInts(new int[]{});
+        Mockito.doReturn(row).when(dimensionSelector).getRow();
+        Mockito.doReturn(0).when(dimensionSelector).getValueCardinality();
+
+        IndexedTableJoinMatcher.ConditionMatcherFactory 
conditionMatcherFactory =
+            new IndexedTableJoinMatcher.ConditionMatcherFactory(
+                ValueType.STRING,
+                IndexedTableJoinMatcherTest::createSingletonIntList
+            );
+        Supplier<IntIterator> dimensionProcessor = 
conditionMatcherFactory.makeDimensionProcessor(dimensionSelector, false);
+        Assert.assertNotNull(dimensionProcessor.get());
+        Assert.assertFalse(dimensionProcessor.get().hasNext());
+      }
+
       @Test
       public void getsCorrectResultWhenSelectorCardinalityUnknown()
       {
diff --git 
a/processing/src/test/java/org/apache/druid/segment/join/table/LookupJoinMatcherTest.java
 
b/processing/src/test/java/org/apache/druid/segment/join/table/LookupJoinMatcherTest.java
index f5f7f3f..08a1a45 100644
--- 
a/processing/src/test/java/org/apache/druid/segment/join/table/LookupJoinMatcherTest.java
+++ 
b/processing/src/test/java/org/apache/druid/segment/join/table/LookupJoinMatcherTest.java
@@ -22,11 +22,13 @@ package org.apache.druid.segment.join.table;
 import com.google.common.collect.ImmutableMap;
 import org.apache.druid.java.util.common.StringUtils;
 import org.apache.druid.math.expr.ExprMacroTable;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.query.dimension.DefaultDimensionSpec;
 import org.apache.druid.query.dimension.DimensionSpec;
 import org.apache.druid.query.lookup.LookupExtractor;
 import org.apache.druid.segment.ColumnSelectorFactory;
 import org.apache.druid.segment.DimensionSelector;
+import org.apache.druid.segment.data.ArrayBasedIndexedInts;
 import org.apache.druid.segment.data.SingleIndexedInt;
 import org.apache.druid.segment.join.JoinConditionAnalysis;
 import org.apache.druid.segment.join.lookup.LookupJoinMatcher;
@@ -150,6 +152,40 @@ public class LookupJoinMatcherTest
     Assert.assertFalse(target.hasMatch());
   }
 
+  @Test(expected = QueryUnsupportedException.class)
+  public void testMatchMultiValuedRowShouldThrowException()
+  {
+    ArrayBasedIndexedInts row = new ArrayBasedIndexedInts(new int[]{2, 4, 6});
+    
Mockito.doReturn(dimensionSelector).when(leftSelectorFactory).makeDimensionSelector(ArgumentMatchers.any(DimensionSpec.class));
+    Mockito.doReturn(row).when(dimensionSelector).getRow();
+
+    JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression(
+        StringUtils.format("\"%sk\" == foo", PREFIX),
+        PREFIX,
+        ExprMacroTable.nil()
+    );
+    target = LookupJoinMatcher.create(extractor, leftSelectorFactory, 
condition, true);
+    // Test match should throw exception
+    target.matchCondition();
+  }
+
+  @Test
+  public void testMatchEmptyRow()
+  {
+    ArrayBasedIndexedInts row = new ArrayBasedIndexedInts(new int[]{});
+    
Mockito.doReturn(dimensionSelector).when(leftSelectorFactory).makeDimensionSelector(ArgumentMatchers.any(DimensionSpec.class));
+    Mockito.doReturn(row).when(dimensionSelector).getRow();
+
+    JoinConditionAnalysis condition = JoinConditionAnalysis.forExpression(
+        StringUtils.format("\"%sk\" == foo", PREFIX),
+        PREFIX,
+        ExprMacroTable.nil()
+    );
+    target = LookupJoinMatcher.create(extractor, leftSelectorFactory, 
condition, true);
+    target.matchCondition();
+    Assert.assertFalse(target.hasMatch());
+  }
+
   private void verifyMatch(String expectedKey, String expectedValue)
   {
     DimensionSelector selector = target.getColumnSelectorFactory()
diff --git a/server/src/main/java/org/apache/druid/server/QueryResource.java 
b/server/src/main/java/org/apache/druid/server/QueryResource.java
index d270799..131ebf1 100644
--- a/server/src/main/java/org/apache/druid/server/QueryResource.java
+++ b/server/src/main/java/org/apache/druid/server/QueryResource.java
@@ -44,6 +44,7 @@ import org.apache.druid.query.Query;
 import org.apache.druid.query.QueryContexts;
 import org.apache.druid.query.QueryInterruptedException;
 import org.apache.druid.query.QueryToolChest;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.query.context.ResponseContext;
 import org.apache.druid.server.metrics.QueryCountStatsProvider;
 import org.apache.druid.server.security.Access;
@@ -315,6 +316,11 @@ public class QueryResource implements 
QueryCountStatsProvider
       queryLifecycle.emitLogsAndMetrics(cap, req.getRemoteAddr(), -1);
       return ioReaderWriter.gotLimited(cap);
     }
+    catch (QueryUnsupportedException unsupported) {
+      failedQueryCount.incrementAndGet();
+      queryLifecycle.emitLogsAndMetrics(unsupported, req.getRemoteAddr(), -1);
+      return ioReaderWriter.gotUnsupported(unsupported);
+    }
     catch (ForbiddenException e) {
       // don't do anything for an authorization failure, 
ForbiddenExceptionMapper will catch this later and
       // send an error response if this is thrown.
@@ -446,6 +452,13 @@ public class QueryResource implements 
QueryCountStatsProvider
                      .entity(newOutputWriter(null, null, 
false).writeValueAsBytes(e))
                      .build();
     }
+
+    Response gotUnsupported(QueryUnsupportedException e) throws IOException
+    {
+      return Response.status(QueryUnsupportedException.STATUS_CODE)
+                     .entity(newOutputWriter(null, null, 
false).writeValueAsBytes(e))
+                     .build();
+    }
   }
 
   @Override
diff --git 
a/server/src/test/java/org/apache/druid/server/QueryResourceTest.java 
b/server/src/test/java/org/apache/druid/server/QueryResourceTest.java
index eface40..35c3a84 100644
--- a/server/src/test/java/org/apache/druid/server/QueryResourceTest.java
+++ b/server/src/test/java/org/apache/druid/server/QueryResourceTest.java
@@ -39,6 +39,7 @@ import org.apache.druid.query.Query;
 import org.apache.druid.query.QueryRunner;
 import org.apache.druid.query.QuerySegmentWalker;
 import org.apache.druid.query.QueryToolChestWarehouse;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.query.Result;
 import org.apache.druid.query.SegmentDescriptor;
 import org.apache.druid.query.timeboundary.TimeBoundaryResultValue;
@@ -340,6 +341,33 @@ public class QueryResourceTest
   }
 
   @Test
+  public void testUnsupportedQueryThrowsException() throws IOException
+  {
+    String errorMessage = "This will be support in Druid 9999";
+    ByteArrayInputStream badQuery = 
EasyMock.createMock(ByteArrayInputStream.class);
+    EasyMock.expect(badQuery.read(EasyMock.anyObject(), EasyMock.anyInt(), 
EasyMock.anyInt())).andThrow(
+        new QueryUnsupportedException(errorMessage));
+    EasyMock.replay(badQuery);
+    EasyMock.replay(testServletRequest);
+    Response response = queryResource.doPost(
+        badQuery,
+        null /*pretty*/,
+        testServletRequest
+    );
+    Assert.assertNotNull(response);
+    Assert.assertEquals(QueryUnsupportedException.STATUS_CODE, 
response.getStatus());
+    QueryUnsupportedException ex;
+    try {
+      ex = JSON_MAPPER.readValue((byte[]) response.getEntity(), 
QueryUnsupportedException.class);
+    }
+    catch (IOException e) {
+      throw new RuntimeException(e);
+    }
+    Assert.assertEquals(errorMessage, ex.getMessage());
+    Assert.assertEquals(QueryUnsupportedException.ERROR_CODE, 
ex.getErrorCode());
+  }
+
+  @Test
   public void testSecuredQuery() throws Exception
   {
     
EasyMock.expect(testServletRequest.getAttribute(AuthConfig.DRUID_AUTHORIZATION_CHECKED))
diff --git a/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java 
b/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
index c09aa85..1c950c9 100644
--- a/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
+++ b/sql/src/main/java/org/apache/druid/sql/http/SqlResource.java
@@ -33,6 +33,7 @@ import org.apache.druid.java.util.common.guava.Yielder;
 import org.apache.druid.java.util.common.guava.Yielders;
 import org.apache.druid.java.util.common.logger.Logger;
 import org.apache.druid.query.QueryInterruptedException;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.server.QueryCapacityExceededException;
 import org.apache.druid.server.security.ForbiddenException;
 import org.apache.druid.sql.SqlLifecycle;
@@ -176,6 +177,11 @@ public class SqlResource
       lifecycle.emitLogsAndMetrics(cap, remoteAddr, -1);
       return 
Response.status(QueryCapacityExceededException.STATUS_CODE).entity(jsonMapper.writeValueAsBytes(cap)).build();
     }
+    catch (QueryUnsupportedException unsupported) {
+      log.warn(unsupported, "Failed to handle query: %s", sqlQuery);
+      lifecycle.emitLogsAndMetrics(unsupported, remoteAddr, -1);
+      return 
Response.status(QueryUnsupportedException.STATUS_CODE).entity(jsonMapper.writeValueAsBytes(unsupported)).build();
+    }
     catch (ForbiddenException e) {
       throw e; // let ForbiddenExceptionMapper handle this
     }
diff --git 
a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java 
b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
index 94edd22..a26d790 100644
--- a/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/calcite/CalciteQueryTest.java
@@ -42,6 +42,7 @@ import org.apache.druid.query.Druids;
 import org.apache.druid.query.LookupDataSource;
 import org.apache.druid.query.QueryContexts;
 import org.apache.druid.query.QueryDataSource;
+import org.apache.druid.query.QueryException;
 import org.apache.druid.query.ResourceLimitExceededException;
 import org.apache.druid.query.TableDataSource;
 import org.apache.druid.query.aggregation.CountAggregatorFactory;
@@ -1790,6 +1791,23 @@ public class CalciteQueryTest extends 
BaseCalciteQueryTest
     );
   }
 
+  // This query is expected to fail as we do not support join on multi valued 
column
+  // (see issue https://github.com/apache/druid/issues/9924 for more 
information)
+  // TODO: Remove expected Exception when 
https://github.com/apache/druid/issues/9924 is fixed
+  @Test(expected = QueryException.class)
+  @Parameters(source = QueryContextForJoinProvider.class)
+  public void testJoinOnMultiValuedColumnShouldThrowException(Map<String, 
Object> queryContext) throws Exception
+  {
+    final String query = "SELECT dim3, l.v from druid.foo f inner join 
lookup.lookyloo l on f.dim3 = l.k\n";
+
+    testQuery(
+        query,
+        queryContext,
+        ImmutableList.of(),
+        ImmutableList.of()
+    );
+  }
+
   @Test
   public void testAnyAggregatorsDoesNotSkipNulls() throws Exception
   {
diff --git a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java 
b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
index 1f2f286..c4e2de5 100644
--- a/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
+++ b/sql/src/test/java/org/apache/druid/sql/http/SqlResourceTest.java
@@ -41,6 +41,7 @@ import org.apache.druid.math.expr.ExprMacroTable;
 import org.apache.druid.query.QueryException;
 import org.apache.druid.query.QueryInterruptedException;
 import org.apache.druid.query.QueryRunnerFactoryConglomerate;
+import org.apache.druid.query.QueryUnsupportedException;
 import org.apache.druid.query.ResourceLimitExceededException;
 import org.apache.druid.server.QueryCapacityExceededException;
 import org.apache.druid.server.QueryScheduler;
@@ -718,6 +719,22 @@ public class SqlResourceTest extends CalciteTestBase
   }
 
   @Test
+  public void testUnsupportedQueryThrowsException() throws Exception
+  {
+    String errorMessage = "This will be support in Druid 9999";
+    SqlQuery badQuery = EasyMock.createMock(SqlQuery.class);
+    EasyMock.expect(badQuery.getQuery()).andReturn("SELECT ANSWER TO LIFE");
+    EasyMock.expect(badQuery.getContext()).andReturn(ImmutableMap.of());
+    EasyMock.expect(badQuery.getParameterList()).andThrow(new 
QueryUnsupportedException(errorMessage));
+    EasyMock.replay(badQuery);
+    final QueryException exception = doPost(badQuery).lhs;
+
+    Assert.assertNotNull(exception);
+    Assert.assertEquals(exception.getErrorCode(), 
QueryUnsupportedException.ERROR_CODE);
+    Assert.assertEquals(exception.getErrorClass(), 
QueryUnsupportedException.class.getName());
+  }
+
+  @Test
   public void testTooManyRequests() throws Exception
   {
     final int numQueries = 3;


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to