private Global deriveGlobalProperties(
        TableLayout layout,
        Map<ColumnHandle, Symbol> assignments,
        Map<ColumnHandle, NullableValue> constants) {
      Optional<List<Symbol>> partitioning =
          layout
              .getPartitioningColumns()
              .flatMap(columns -> translateToNonConstantSymbols(columns, assignments, constants));

      if (planWithTableNodePartitioning(session) && layout.getNodePartitioning().isPresent()) {
        NodePartitioning nodePartitioning = layout.getNodePartitioning().get();
        if (assignments.keySet().containsAll(nodePartitioning.getPartitioningColumns())) {
          List<Symbol> arguments =
              nodePartitioning
                  .getPartitioningColumns()
                  .stream()
                  .map(assignments::get)
                  .collect(toImmutableList());

          return partitionedOn(nodePartitioning.getPartitioningHandle(), arguments, partitioning);
        }
      }

      if (partitioning.isPresent()) {
        return streamPartitionedOn(partitioning.get());
      }
      return arbitraryPartition();
    }
    @Override
    public ActualProperties visitTableScan(
        TableScanNode node, List<ActualProperties> inputProperties) {
      checkArgument(node.getLayout().isPresent(), "table layout has not yet been chosen");

      TableLayout layout = metadata.getLayout(session, node.getLayout().get());
      Map<ColumnHandle, Symbol> assignments =
          ImmutableBiMap.copyOf(node.getAssignments()).inverse();

      ActualProperties.Builder properties = ActualProperties.builder();

      // Globally constant assignments
      Map<ColumnHandle, NullableValue> globalConstants = new HashMap<>();
      extractFixedValues(node.getCurrentConstraint())
          .orElse(ImmutableMap.of())
          .entrySet()
          .stream()
          .filter(entry -> !entry.getValue().isNull())
          .forEach(entry -> globalConstants.put(entry.getKey(), entry.getValue()));

      Map<Symbol, NullableValue> symbolConstants =
          globalConstants
              .entrySet()
              .stream()
              .filter(entry -> assignments.containsKey(entry.getKey()))
              .collect(toMap(entry -> assignments.get(entry.getKey()), Map.Entry::getValue));
      properties.constants(symbolConstants);

      // Partitioning properties
      properties.global(deriveGlobalProperties(layout, assignments, globalConstants));

      // Append the global constants onto the local properties to maximize their translation
      // potential
      List<LocalProperty<ColumnHandle>> constantAppendedLocalProperties =
          ImmutableList.<LocalProperty<ColumnHandle>>builder()
              .addAll(
                  globalConstants
                      .keySet()
                      .stream()
                      .map(column -> new ConstantProperty<>(column))
                      .iterator())
              .addAll(layout.getLocalProperties())
              .build();
      properties.local(
          LocalProperties.translate(
              constantAppendedLocalProperties,
              column -> Optional.ofNullable(assignments.get(column))));

      return properties.build();
    }
  private InternalTable buildPartitions(
      Session session, String catalogName, Map<String, NullableValue> filters) {
    QualifiedObjectName tableName = extractQualifiedTableName(catalogName, filters);

    InternalTable.Builder table =
        InternalTable.builder(informationSchemaTableColumns(TABLE_INTERNAL_PARTITIONS));

    Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName);
    if (!tableHandle.isPresent()) {
      throw new TableNotFoundException(tableName.asSchemaTableName());
    }

    List<TableLayoutResult> layouts =
        metadata.getLayouts(
            session, tableHandle.get(), Constraint.<ColumnHandle>alwaysTrue(), Optional.empty());

    if (layouts.size() == 1) {
      Map<ColumnHandle, String> columnHandles =
          ImmutableBiMap.copyOf(metadata.getColumnHandles(session, tableHandle.get())).inverse();
      Map<ColumnHandle, MethodHandle> methodHandles = new HashMap<>();
      for (ColumnHandle columnHandle : columnHandles.keySet()) {
        try {
          ColumnMetadata columnMetadata =
              metadata.getColumnMetadata(session, tableHandle.get(), columnHandle);
          Signature operator =
              metadata.getFunctionRegistry().getCoercion(columnMetadata.getType(), VARCHAR);
          MethodHandle methodHandle =
              metadata
                  .getFunctionRegistry()
                  .getScalarFunctionImplementation(operator)
                  .getMethodHandle();
          methodHandles.put(columnHandle, methodHandle);
        } catch (OperatorNotFoundException exception) {
          // Do not put the columnHandle in the map.
        }
      }

      TableLayout layout = Iterables.getOnlyElement(layouts).getLayout();
      layout
          .getDiscretePredicates()
          .ifPresent(
              domains -> {
                int partitionNumber = 1;
                for (TupleDomain<ColumnHandle> domain : domains) {
                  for (Entry<ColumnHandle, NullableValue> entry :
                      TupleDomain.extractFixedValues(domain).get().entrySet()) {
                    ColumnHandle columnHandle = entry.getKey();
                    String columnName = columnHandles.get(columnHandle);
                    String value = null;
                    if (entry.getValue().getValue() != null) {
                      if (methodHandles.containsKey(columnHandle)) {
                        try {
                          value =
                              ((Slice)
                                      methodHandles
                                          .get(columnHandle)
                                          .invokeWithArguments(entry.getValue().getValue()))
                                  .toStringUtf8();
                        } catch (Throwable throwable) {
                          throw Throwables.propagate(throwable);
                        }
                      } else {
                        // OperatorNotFoundException was thrown for this columnHandle
                        value = "<UNREPRESENTABLE VALUE>";
                      }
                    }
                    table.add(
                        catalogName,
                        tableName.getSchemaName(),
                        tableName.getObjectName(),
                        partitionNumber,
                        columnName,
                        value);
                  }
                  partitionNumber++;
                }
              });
    }
    return table.build();
  }
  private InternalTable buildPartitions(
      Session session, String catalogName, Map<String, SerializableNativeValue> filters) {
    QualifiedTableName tableName = extractQualifiedTableName(catalogName, filters);

    InternalTable.Builder table =
        InternalTable.builder(informationSchemaTableColumns(TABLE_INTERNAL_PARTITIONS));

    Optional<TableHandle> tableHandle = metadata.getTableHandle(session, tableName);
    checkArgument(tableHandle.isPresent(), "Table %s does not exist", tableName);
    Map<ColumnHandle, String> columnHandles =
        ImmutableBiMap.copyOf(metadata.getColumnHandles(session, tableHandle.get())).inverse();

    List<TableLayoutResult> layouts =
        metadata.getLayouts(
            session, tableHandle.get(), Constraint.<ColumnHandle>alwaysTrue(), Optional.empty());

    if (layouts.size() == 1) {
      TableLayout layout = Iterables.getOnlyElement(layouts).getLayout();

      layout
          .getDiscretePredicates()
          .ifPresent(
              domains -> {
                int partitionNumber = 1;
                for (TupleDomain<ColumnHandle> domain : domains) {
                  for (Entry<ColumnHandle, SerializableNativeValue> entry :
                      domain.extractNullableFixedValues().entrySet()) {
                    ColumnHandle columnHandle = entry.getKey();
                    String columnName = columnHandles.get(columnHandle);
                    String value = null;
                    if (entry.getValue().getValue() != null) {
                      ColumnMetadata columnMetadata =
                          metadata.getColumnMetadata(session, tableHandle.get(), columnHandle);
                      try {
                        FunctionInfo operator =
                            metadata
                                .getFunctionRegistry()
                                .getCoercion(columnMetadata.getType(), VARCHAR);
                        value =
                            ((Slice)
                                    operator
                                        .getMethodHandle()
                                        .invokeWithArguments(entry.getValue().getValue()))
                                .toStringUtf8();
                      } catch (OperatorNotFoundException e) {
                        value = "<UNREPRESENTABLE VALUE>";
                      } catch (Throwable throwable) {
                        throw Throwables.propagate(throwable);
                      }
                    }
                    table.add(
                        catalogName,
                        tableName.getSchemaName(),
                        tableName.getTableName(),
                        partitionNumber,
                        columnName,
                        value);
                  }
                  partitionNumber++;
                }
              });
    }
    return table.build();
  }