code: public RelDataType getRelDataType(final RelDataTypeFactory typeFactory)
    {
      final RelDataTypeFactory.Builder builder = typeFactory.builder();
      for (final String columnName : columnNames) {
        final ValueType columnType = getColumnType(columnName);
        final RelDataType type;
  
        if (ColumnHolder.TIME_COLUMN_NAME.equals(columnName)) {
          type = Calcites.createSqlType(typeFactory, SqlTypeName.TIMESTAMP);
        } else {
          switch (columnType) {
            case STRING:
              // Note that there is no attempt here to handle multi-value in any special way. Maybe one day...
              type = Calcites.createSqlTypeWithNullability(typeFactory, SqlTypeName.VARCHAR, true);
              break;
            case LONG:
              type = Calcites.createSqlType(typeFactory, SqlTypeName.BIGINT);
              break;
            case FLOAT:
              type = Calcites.createSqlType(typeFactory, SqlTypeName.FLOAT);
              break;
            case DOUBLE:
              type = Calcites.createSqlType(typeFactory, SqlTypeName.DOUBLE);
              break;
            case COMPLEX:
              // Loses information about exactly what kind of complex column this is.
              type = Calcites.createSqlTypeWithNullability(typeFactory, SqlTypeName.OTHER, true);
              break;
            default:
              throw new ISE("WTF?! valueType[%s] not translatable?", columnType);
          }
        }
  
        builder.add(columnName, type);
      }
  
      return builder.build();
    }
docs: Returns a Calcite RelDataType corresponding to this row signature.
  
  @param typeFactory factory for type construction
  
  @return Calcite row type