Repository: prestodb/presto
Issue: DISTINCT fails for JSON type when optimizeHashGeneration=true

``` sql
SELECT DISTINCT CAST(ARRAY[1] AS JSON);
```

fails with:

```
com.facebook.presto.spi.PrestoException: Unexpected parameters (json) for function $operator$hash_code. Expected: $operator$hash_code(boolean), $operator$hash_code(bigint), $operator$hash_code(double), $operator$hash_code(varchar), $operator$hash_code(varbinary), $operator$hash_code(date), $operator$hash_code(time), $operator$hash_code(timestamp), $operator$hash_code(interval day to second), $operator$hash_code(interval year to month), $operator$hash_code(time with time zone), $operator$hash_code(timestamp with time zone)
    at com.facebook.presto.metadata.FunctionRegistry.resolveFunction(FunctionRegistry.java:428)
    at com.facebook.presto.metadata.MetadataManager.resolveFunction(MetadataManager.java:147)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitFunctionCall(ExpressionAnalyzer.java:601)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitFunctionCall(ExpressionAnalyzer.java:180)
    at com.facebook.presto.sql.tree.FunctionCall.accept(FunctionCall.java:67)
    at com.facebook.presto.sql.tree.AstVisitor.process(AstVisitor.java:24)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.process(ExpressionAnalyzer.java:198)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitFunctionCall(ExpressionAnalyzer.java:598)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer$Visitor.visitFunctionCall(ExpressionAnalyzer.java:180)
    at com.facebook.presto.sql.tree.FunctionCall.accept(FunctionCall.java:67)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.analyze(ExpressionAnalyzer.java:177)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.analyzeExpressions(ExpressionAnalyzer.java:928)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.analyzeExpressionsWithInputs(ExpressionAnalyzer.java:916)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypesFromInput(ExpressionAnalyzer.java:877)
    at com.facebook.presto.sql.analyzer.ExpressionAnalyzer.getExpressionTypesFromInput(ExpressionAnalyzer.java:867)
    at com.facebook.presto.sql.planner.InterpretedProjectionFunction.<init>(InterpretedProjectionFunction.java:57)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitScanFilterAndProject(LocalExecutionPlanner.java:852)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitProject(LocalExecutionPlanner.java:723)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitProject(LocalExecutionPlanner.java:344)
    at com.facebook.presto.sql.planner.plan.ProjectNode.accept(ProjectNode.java:81)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitAggregation(LocalExecutionPlanner.java:648)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitAggregation(LocalExecutionPlanner.java:344)
    at com.facebook.presto.sql.planner.plan.AggregationNode.accept(AggregationNode.java:165)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitOutput(LocalExecutionPlanner.java:367)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner$Visitor.visitOutput(LocalExecutionPlanner.java:344)
    at com.facebook.presto.sql.planner.plan.OutputNode.accept(OutputNode.java:79)
    at com.facebook.presto.sql.planner.LocalExecutionPlanner.plan(LocalExecutionPlanner.java:226)
    at com.facebook.presto.execution.SqlTaskExecution.<init>(SqlTaskExecution.java:147)
    at com.facebook.presto.execution.SqlTaskExecution.createSqlTaskExecution(SqlTaskExecution.java:109)
    at com.facebook.presto.execution.SqlTaskExecutionFactory.create(SqlTaskExecutionFactory.java:101)
    at com.facebook.presto.execution.SqlTask.updateTask(SqlTask.java:219)
    at com.facebook.presto.execution.SqlTaskManager.updateTask(SqlTaskManager.java:223)
    at com.facebook.presto.server.TaskResource.createOrUpdateTask(TaskResource.java:104)
    at sun.reflect.GeneratedMethodAccessor142.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.glassfish.jersey.server.model.internal.ResourceMethodInvocationHandlerFactory$1.invoke(ResourceMethodInvocationHandlerFactory.java:81)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher$1.run(AbstractJavaResourceMethodDispatcher.java:151)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.invoke(AbstractJavaResourceMethodDispatcher.java:171)
    at org.glassfish.jersey.server.model.internal.JavaResourceMethodDispatcherProvider$ResponseOutInvoker.doDispatch(JavaResourceMethodDispatcherProvider.java:152)
    at org.glassfish.jersey.server.model.internal.AbstractJavaResourceMethodDispatcher.dispatch(AbstractJavaResourceMethodDispatcher.java:104)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:387)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:331)
    at org.glassfish.jersey.server.model.ResourceMethodInvoker.apply(ResourceMethodInvoker.java:103)
    at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271)
    at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:315)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:297)
    at org.glassfish.jersey.internal.Errors.process(Errors.java:267)
    at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:297)
    at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:254)
    at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:1030)
    at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:373)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:381)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:344)
    at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:221)
    at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:769)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1667)
    at org.eclipse.jetty.servlets.UserAgentFilter.doFilter(UserAgentFilter.java:83)
    at org.eclipse.jetty.servlets.GzipFilter.doFilter(GzipFilter.java:300)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
    at io.airlift.http.server.TraceTokenFilter.doFilter(TraceTokenFilter.java:62)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
    at io.airlift.http.server.TimingFilter.doFilter(TimingFilter.java:51)
    at org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1650)
    at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
    at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1125)
    at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:515)
    at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1059)
    at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
    at org.eclipse.jetty.server.handler.HandlerCollection.handle(HandlerCollection.java:110)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.handler.StatisticsHandler.handle(StatisticsHandler.java:159)
    at org.eclipse.jetty.server.handler.HandlerList.handle(HandlerList.java:52)
    at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:97)
    at org.eclipse.jetty.server.Server.handle(Server.java:485)
    at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:290)
    at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:248)
    at org.eclipse.jetty.io.AbstractConnection$2.run(AbstractConnection.java:540)
    at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:606)
    at org.eclipse.jetty.util.thread.QueuedThreadPool$3.run(QueuedThreadPool.java:535)
    at java.lang.Thread.run(Thread.java:745)
```


Changed files:
presto-main/src/main/java/com/facebook/presto/operator/scalar/JsonOperators.java

diff --git a/presto-main/src/main/java/com/facebook/presto/operator/scalar/JsonOperators.java b/presto-main/src/main/java/com/facebook/presto/operator/scalar/JsonOperators.java
index c2551f7bc7..e19fddd773 100644
--- a/presto-main/src/main/java/com/facebook/presto/operator/scalar/JsonOperators.java
+++ b/presto-main/src/main/java/com/facebook/presto/operator/scalar/JsonOperators.java
@@ -18,6 +18,7 @@ import com.facebook.presto.type.SqlType;
 import io.airlift.slice.Slice;
 
 import static com.facebook.presto.metadata.OperatorType.EQUAL;
+import static com.facebook.presto.metadata.OperatorType.HASH_CODE;
 import static com.facebook.presto.metadata.OperatorType.NOT_EQUAL;
 
 public final class JsonOperators
@@ -26,6 +27,13 @@ public final class JsonOperators
     {
     }
 
+    @ScalarOperator(HASH_CODE)
+    @SqlType(StandardTypes.BIGINT)
+    public static long hashCode(@SqlType(StandardTypes.JSON) Slice value)
+    {
+        return value.hashCode();
+    }
+
     @ScalarOperator(EQUAL)
     @SqlType(StandardTypes.BOOLEAN)
     public static boolean equals(@SqlType(StandardTypes.JSON) Slice leftJson, @SqlType(StandardTypes.JSON) Slice rightJson)