[CALCITE-3926] CannotPlanException when an empty LogicalValues requires a certain collation
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
index 497e820..97b6554 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValues.java
@@ -67,7 +67,7 @@
 
   @Override public RelNode copy(RelTraitSet traitSet, List<RelNode> inputs) {
     assert inputs.isEmpty();
-    return create(getCluster(), rowType, tuples);
+    return new EnumerableValues(getCluster(), rowType, tuples, traitSet);
   }
 
   public Result implement(EnumerableRelImplementor implementor, Prefer pref) {
diff --git a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
index 6a71ac0..c981a8b 100644
--- a/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
+++ b/core/src/main/java/org/apache/calcite/adapter/enumerable/EnumerableValuesRule.java
@@ -41,8 +41,11 @@
   }
 
   @Override public RelNode convert(RelNode rel) {
-    LogicalValues values = (LogicalValues) rel;
-    return EnumerableValues.create(values.getCluster(), values.getRowType(),
-        values.getTuples());
+    final LogicalValues logicalValues = (LogicalValues) rel;
+    final EnumerableValues enumerableValues = EnumerableValues.create(
+        logicalValues.getCluster(), logicalValues.getRowType(), logicalValues.getTuples());
+    return enumerableValues.copy(
+        logicalValues.getTraitSet().replace(EnumerableConvention.INSTANCE),
+        enumerableValues.getInputs());
   }
 }
diff --git a/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java b/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
index edbea5d..32b9850 100644
--- a/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
+++ b/core/src/main/java/org/apache/calcite/rel/logical/LogicalValues.java
@@ -20,11 +20,13 @@
 import org.apache.calcite.plan.RelOptCluster;
 import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.rel.RelCollationTraitDef;
+import org.apache.calcite.rel.RelDistributionTraitDef;
 import org.apache.calcite.rel.RelInput;
 import org.apache.calcite.rel.RelNode;
 import org.apache.calcite.rel.RelShuttle;
 import org.apache.calcite.rel.core.Values;
 import org.apache.calcite.rel.metadata.RelMdCollation;
+import org.apache.calcite.rel.metadata.RelMdDistribution;
 import org.apache.calcite.rel.metadata.RelMetadataQuery;
 import org.apache.calcite.rel.type.RelDataType;
 import org.apache.calcite.rex.RexLiteral;
@@ -83,7 +85,9 @@
     final RelMetadataQuery mq = cluster.getMetadataQuery();
     final RelTraitSet traitSet = cluster.traitSetOf(Convention.NONE)
         .replaceIfs(RelCollationTraitDef.INSTANCE,
-            () -> RelMdCollation.values(mq, rowType, tuples));
+            () -> RelMdCollation.values(mq, rowType, tuples))
+        .replaceIf(RelDistributionTraitDef.INSTANCE,
+            () -> RelMdDistribution.values(rowType, tuples));
     return new LogicalValues(cluster, traitSet, rowType, tuples);
   }
 
diff --git a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
index 1fb6b26..88d408d 100644
--- a/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
+++ b/core/src/main/java/org/apache/calcite/rel/rules/PruneEmptyRules.java
@@ -20,6 +20,7 @@
 import org.apache.calcite.plan.RelOptRuleCall;
 import org.apache.calcite.plan.RelOptRuleOperand;
 import org.apache.calcite.plan.RelOptUtil;
+import org.apache.calcite.plan.RelTraitSet;
 import org.apache.calcite.plan.SubstitutionRule;
 import org.apache.calcite.plan.hep.HepRelVertex;
 import org.apache.calcite.plan.volcano.RelSubset;
@@ -42,6 +43,7 @@
 import org.apache.calcite.tools.RelBuilder;
 import org.apache.calcite.tools.RelBuilderFactory;
 
+import java.util.Collections;
 import java.util.List;
 import java.util.function.Predicate;
 
@@ -266,7 +268,7 @@
    * <p>Examples:
    *
    * <ul>
-   * <li>Sort(Empty) becomes Empty
+   * <li>Sort[fetch=0] becomes Empty
    * </ul>
    */
   public static final RelOptRule SORT_FETCH_ZERO_INSTANCE =
@@ -277,7 +279,14 @@
           if (sort.fetch != null
               && !(sort.fetch instanceof RexDynamicParam)
               && RexLiteral.intValue(sort.fetch) == 0) {
-            call.transformTo(call.builder().push(sort).empty().build());
+            RelNode emptyValues = call.builder().push(sort).empty().build();
+            RelTraitSet traits = sort.getTraitSet();
+            // propagate all traits (except convention) from the original sort into the empty values
+            if (emptyValues.getConvention() != null) {
+              traits = traits.replace(emptyValues.getConvention());
+            }
+            emptyValues = emptyValues.copy(traits, Collections.emptyList());
+            call.transformTo(emptyValues);
           }
         }
       };
@@ -375,7 +384,7 @@
     /** Creates a simple RemoveEmptySingleRule. */
     public <R extends SingleRel> RemoveEmptySingleRule(Class<R> clazz,
         String description) {
-      this(clazz, (Predicate<R>) project -> true, RelFactories.LOGICAL_BUILDER,
+      this(clazz, (Predicate<R>) singleRel -> true, RelFactories.LOGICAL_BUILDER,
           description);
     }
 
@@ -399,8 +408,15 @@
     }
 
     public void onMatch(RelOptRuleCall call) {
-      SingleRel single = call.rel(0);
-      call.transformTo(call.builder().push(single).empty().build());
+      SingleRel singleRel = call.rel(0);
+      RelNode emptyValues = call.builder().push(singleRel).empty().build();
+      RelTraitSet traits = singleRel.getTraitSet();
+      // propagate all traits (except convention) from the original singleRel into the empty values
+      if (emptyValues.getConvention() != null) {
+        traits = traits.replace(emptyValues.getConvention());
+      }
+      emptyValues = emptyValues.copy(traits, Collections.emptyList());
+      call.transformTo(emptyValues);
     }
   }
 }
diff --git a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
index cee5808..f096e39 100644
--- a/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelBuilderTest.java
@@ -3463,4 +3463,23 @@
             builder.literal(5));
     assertThat(call.toStringRaw(), is("BETWEEN ASYMMETRIC($0, 1, 5)"));
   }
+
+  /** Test case for
+   * <a href="https://issues.apache.org/jira/browse/CALCITE-3926">[CALCITE-3926]
+   * CannotPlanException when an empty LogicalValues requires a certain collation</a>. */
+  @Test void testEmptyValuesWithCollation() throws Exception {
+    final RelBuilder builder = RelBuilder.create(config().build());
+    final RelNode root =
+        builder
+            .scan("DEPT").empty()
+            .sort(
+                builder.field("DNAME"),
+                builder.field("DEPTNO"))
+            .build();
+    try (PreparedStatement preparedStatement = RelRunners.run(root)) {
+      final String result = CalciteAssert.toString(preparedStatement.executeQuery());
+      final String expectedResult = "";
+      assertThat(result, is(expectedResult));
+    }
+  }
 }
diff --git a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
index 468f509..4ff8902 100644
--- a/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
+++ b/core/src/test/java/org/apache/calcite/test/RelOptRulesTest.java
@@ -3430,6 +3430,7 @@
   @Test void testEmptySort() {
     HepProgram program = new HepProgramBuilder()
         .addRuleInstance(ReduceExpressionsRule.FILTER_INSTANCE)
+        .addRuleInstance(PruneEmptyRules.PROJECT_INSTANCE)
         .addRuleInstance(PruneEmptyRules.SORT_INSTANCE)
         .build();
 
@@ -3437,6 +3438,30 @@
     sql(sql).with(program).check();
   }
 
+  @Test void testEmptySort2() {
+    final RelBuilder relBuilder = RelBuilder.create(RelBuilderTest.config().build());
+    final RelNode relNode = relBuilder
+        .scan("DEPT").empty()
+        .sort(
+            relBuilder.field("DNAME"),
+            relBuilder.field("DEPTNO"))
+        .build();
+
+    final HepProgram program = new HepProgramBuilder()
+        .addRuleInstance(PruneEmptyRules.SORT_INSTANCE)
+        .build();
+
+    final HepPlanner hepPlanner = new HepPlanner(program);
+    hepPlanner.setRoot(relNode);
+    final RelNode output = hepPlanner.findBestExp();
+
+    final String planBefore = NL + RelOptUtil.toString(relNode);
+    final String planAfter = NL + RelOptUtil.toString(output);
+    final DiffRepository diffRepos = getDiffRepos();
+    diffRepos.assertEquals("planBefore", "${planBefore}", planBefore);
+    diffRepos.assertEquals("planAfter", "${planAfter}", planAfter);
+  }
+
   @Test void testEmptySortLimitZero() {
     final String sql = "select * from emp order by deptno limit 0";
     sql(sql).withRule(PruneEmptyRules.SORT_FETCH_ZERO_INSTANCE).check();
diff --git a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
index 4b6d286..2685ee7 100644
--- a/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
+++ b/core/src/test/resources/org/apache/calcite/test/RelOptRulesTest.xml
@@ -3168,9 +3168,20 @@
         </Resource>
         <Resource name="planAfter">
             <![CDATA[
-LogicalSort(sort0=[$7], dir0=[ASC])
-  LogicalProject(EMPNO=[$0], ENAME=[$1], JOB=[$2], MGR=[$3], HIREDATE=[$4], SAL=[$5], COMM=[$6], DEPTNO=[$7], SLACKER=[$8])
-    LogicalValues(tuples=[[]])
+LogicalValues(tuples=[[]])
+]]>
+        </Resource>
+    </TestCase>
+    <TestCase name="testEmptySort2">
+        <Resource name="planBefore">
+            <![CDATA[
+LogicalSort(sort0=[$1], sort1=[$0], dir0=[ASC], dir1=[ASC])
+  LogicalValues(tuples=[[]])
+]]>
+        </Resource>
+        <Resource name="planAfter">
+            <![CDATA[
+LogicalValues(tuples=[[]])
 ]]>
         </Resource>
     </TestCase>