示例#1
0
bool WorkOrderFactory::ProtoIsValid(const serialization::WorkOrder &proto,
                                    const CatalogDatabaseLite &catalog_database,
                                    const QueryContext &query_context) {
  switch (proto.work_order_type()) {
    case serialization::AGGREGATION: {
      return proto.HasExtension(serialization::AggregationWorkOrder::block_id) &&
             proto.HasExtension(serialization::AggregationWorkOrder::aggr_state_index) &&
             query_context.isValidAggregationStateId(
                 proto.GetExtension(serialization::AggregationWorkOrder::aggr_state_index));
    }
    case serialization::BUILD_HASH: {
      if (!proto.HasExtension(serialization::BuildHashWorkOrder::relation_id)) {
        return false;
      }

      const relation_id rel_id = proto.GetExtension(serialization::BuildHashWorkOrder::relation_id);
      if (!catalog_database.hasRelationWithId(rel_id)) {
        return false;
      }

      const CatalogRelationSchema &relation = catalog_database.getRelationSchemaById(rel_id);
      for (int i = 0; i < proto.ExtensionSize(serialization::BuildHashWorkOrder::join_key_attributes); ++i) {
        if (!relation.hasAttributeWithId(
                proto.GetExtension(serialization::BuildHashWorkOrder::join_key_attributes, i))) {
          return false;
        }
      }

      return proto.HasExtension(serialization::BuildHashWorkOrder::any_join_key_attributes_nullable) &&
             proto.HasExtension(serialization::BuildHashWorkOrder::block_id) &&
             proto.HasExtension(serialization::BuildHashWorkOrder::join_hash_table_index) &&
             query_context.isValidJoinHashTableId(
                 proto.GetExtension(serialization::BuildHashWorkOrder::join_hash_table_index));
    }
    case serialization::DELETE: {
      return proto.HasExtension(serialization::DeleteWorkOrder::relation_id) &&
             catalog_database.hasRelationWithId(
                 proto.GetExtension(serialization::DeleteWorkOrder::relation_id)) &&
             proto.HasExtension(serialization::DeleteWorkOrder::predicate_index) &&
             query_context.isValidPredicate(
                 proto.GetExtension(serialization::DeleteWorkOrder::predicate_index)) &&
             proto.HasExtension(serialization::DeleteWorkOrder::block_id) &&
             proto.HasExtension(serialization::DeleteWorkOrder::operator_index);
    }
    case serialization::DESTROY_HASH: {
      return proto.HasExtension(serialization::DestroyHashWorkOrder::join_hash_table_index) &&
             query_context.isValidJoinHashTableId(
                 proto.GetExtension(serialization::DestroyHashWorkOrder::join_hash_table_index));
    }
    case serialization::DROP_TABLE: {
      return true;
    }
    case serialization::FINALIZE_AGGREGATION: {
      return proto.HasExtension(serialization::FinalizeAggregationWorkOrder::aggr_state_index) &&
             query_context.isValidAggregationStateId(
                 proto.GetExtension(serialization::FinalizeAggregationWorkOrder::aggr_state_index)) &&
             proto.HasExtension(serialization::FinalizeAggregationWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::FinalizeAggregationWorkOrder::insert_destination_index));
    }
    case serialization::HASH_JOIN: {
      if (!proto.HasExtension(serialization::HashJoinWorkOrder::hash_join_work_order_type)) {
        return false;
      }

      const auto hash_join_work_order_type =
          proto.GetExtension(serialization::HashJoinWorkOrder::hash_join_work_order_type);
      if (!serialization::HashJoinWorkOrder_HashJoinWorkOrderType_IsValid(hash_join_work_order_type)) {
        return false;
      }

      if (!proto.HasExtension(serialization::HashJoinWorkOrder::build_relation_id) ||
          !proto.HasExtension(serialization::HashJoinWorkOrder::probe_relation_id)) {
        return false;
      }

      const relation_id build_relation_id =
          proto.GetExtension(serialization::HashJoinWorkOrder::build_relation_id);
      if (!catalog_database.hasRelationWithId(build_relation_id)) {
        return false;
      }

      const relation_id probe_relation_id =
          proto.GetExtension(serialization::HashJoinWorkOrder::probe_relation_id);
      if (!catalog_database.hasRelationWithId(probe_relation_id)) {
        return false;
      }

      const CatalogRelationSchema &build_relation = catalog_database.getRelationSchemaById(build_relation_id);
      const CatalogRelationSchema &probe_relation = catalog_database.getRelationSchemaById(probe_relation_id);
      for (int i = 0; i < proto.ExtensionSize(serialization::HashJoinWorkOrder::join_key_attributes); ++i) {
        const attribute_id attr_id =
            proto.GetExtension(serialization::HashJoinWorkOrder::join_key_attributes, i);
        if (!build_relation.hasAttributeWithId(attr_id) ||
            !probe_relation.hasAttributeWithId(attr_id)) {
          return false;
        }
      }

      if (hash_join_work_order_type == serialization::HashJoinWorkOrder::HASH_OUTER_JOIN) {
        if (!proto.HasExtension(serialization::HashJoinWorkOrder::is_selection_on_build)) {
          return false;
        }
      } else {
        if (!proto.HasExtension(serialization::HashJoinWorkOrder::residual_predicate_index) ||
            !query_context.isValidPredicate(
                 proto.GetExtension(serialization::HashJoinWorkOrder::residual_predicate_index))) {
          return false;
        }
      }

      return proto.HasExtension(serialization::HashJoinWorkOrder::any_join_key_attributes_nullable) &&
             proto.HasExtension(serialization::HashJoinWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::HashJoinWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::HashJoinWorkOrder::join_hash_table_index) &&
             query_context.isValidJoinHashTableId(
                 proto.GetExtension(serialization::HashJoinWorkOrder::join_hash_table_index)) &&
             proto.HasExtension(serialization::HashJoinWorkOrder::selection_index) &&
             query_context.isValidScalarGroupId(
                 proto.GetExtension(serialization::HashJoinWorkOrder::selection_index)) &&
             proto.HasExtension(serialization::HashJoinWorkOrder::block_id);
    }
    case serialization::INSERT: {
      return proto.HasExtension(serialization::InsertWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::InsertWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::InsertWorkOrder::tuple_index) &&
             query_context.isValidTupleId(
                 proto.GetExtension(serialization::InsertWorkOrder::tuple_index));
    }
    case serialization::NESTED_LOOP_JOIN: {
      if (!proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::left_relation_id) ||
          !proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::right_relation_id)) {
        return false;
      }

      const relation_id left_relation_id =
          proto.GetExtension(serialization::NestedLoopsJoinWorkOrder::left_relation_id);
      if (!catalog_database.hasRelationWithId(left_relation_id)) {
        return false;
      }

      const relation_id right_relation_id =
          proto.GetExtension(serialization::NestedLoopsJoinWorkOrder::right_relation_id);
      if (!catalog_database.hasRelationWithId(right_relation_id)) {
        return false;
      }

      return proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::left_block_id) &&
             proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::right_block_id) &&
             proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::NestedLoopsJoinWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::join_predicate_index) &&
             query_context.isValidPredicate(
                 proto.GetExtension(serialization::NestedLoopsJoinWorkOrder::join_predicate_index)) &&
             proto.HasExtension(serialization::NestedLoopsJoinWorkOrder::selection_index) &&
             query_context.isValidScalarGroupId(
                 proto.GetExtension(serialization::NestedLoopsJoinWorkOrder::selection_index));
    }
    case serialization::SAMPLE: {
      return catalog_database.hasRelationWithId(proto.GetExtension(serialization::SampleWorkOrder::relation_id)) &&
             proto.HasExtension(serialization::SampleWorkOrder::block_id) &&
             proto.HasExtension(serialization::SampleWorkOrder::is_block_sample) &&
             proto.HasExtension(serialization::SampleWorkOrder::percentage) &&
             proto.HasExtension(serialization::SampleWorkOrder::insert_destination_index);
    }
    case serialization::SAVE_BLOCKS: {
      return proto.HasExtension(serialization::SaveBlocksWorkOrder::block_id) &&
             proto.HasExtension(serialization::SaveBlocksWorkOrder::force);
    }
    case serialization::SELECT: {
      if (!proto.HasExtension(serialization::SelectWorkOrder::relation_id) ||
          !proto.HasExtension(serialization::SelectWorkOrder::simple_projection) ||
          !proto.HasExtension(serialization::SelectWorkOrder::selection_index)) {
        return false;
      }

      const relation_id rel_id = proto.GetExtension(serialization::SelectWorkOrder::relation_id);
      if (!catalog_database.hasRelationWithId(rel_id)) {
        return false;
      }

      const CatalogRelationSchema &relation = catalog_database.getRelationSchemaById(rel_id);
      for (int i = 0; i < proto.ExtensionSize(serialization::SelectWorkOrder::simple_selection); ++i) {
        if (!relation.hasAttributeWithId(
                 proto.GetExtension(serialization::SelectWorkOrder::simple_selection, i))) {
          return false;
        }
      }

      if (proto.GetExtension(serialization::SelectWorkOrder::simple_projection) ==
              query_context.isValidScalarGroupId(
                  proto.GetExtension(serialization::SelectWorkOrder::selection_index))) {
        return false;
      }

      return proto.HasExtension(serialization::SelectWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::SelectWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::SelectWorkOrder::predicate_index) &&
             query_context.isValidPredicate(
                 proto.GetExtension(serialization::SelectWorkOrder::predicate_index)) &&
             proto.HasExtension(serialization::SelectWorkOrder::block_id);
    }
    case serialization::SORT_MERGE_RUN: {
      // In Protobuf 2.6, proto.HasExtension does not work for the repeated
      // message field, but Protobuf 3.0 beta works.
      // TODO(zuyu): Validate serialization::SortMergeRunWorkOrder::runs.
      return proto.HasExtension(serialization::SortMergeRunWorkOrder::sort_config_index) &&
             query_context.isValidSortConfigId(
                 proto.GetExtension(serialization::SortMergeRunWorkOrder::sort_config_index)) &&
             proto.HasExtension(serialization::SortMergeRunWorkOrder::top_k) &&
             proto.HasExtension(serialization::SortMergeRunWorkOrder::merge_level) &&
             proto.HasExtension(serialization::SortMergeRunWorkOrder::relation_id) &&
             catalog_database.hasRelationWithId(
                 proto.GetExtension(serialization::SortMergeRunWorkOrder::relation_id)) &&
             proto.HasExtension(serialization::SortMergeRunWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::SortMergeRunWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::SortMergeRunWorkOrder::operator_index);
    }
    case serialization::SORT_RUN_GENERATION: {
      return proto.HasExtension(serialization::SortRunGenerationWorkOrder::relation_id) &&
             catalog_database.hasRelationWithId(
                 proto.GetExtension(serialization::SortRunGenerationWorkOrder::relation_id)) &&
             proto.HasExtension(serialization::SortRunGenerationWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::SortRunGenerationWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::SortRunGenerationWorkOrder::sort_config_index) &&
             query_context.isValidSortConfigId(
                 proto.GetExtension(serialization::SortRunGenerationWorkOrder::sort_config_index)) &&
             proto.HasExtension(serialization::SortRunGenerationWorkOrder::block_id);
    }
    case serialization::TABLE_GENERATOR: {
      return proto.HasExtension(serialization::TableGeneratorWorkOrder::generator_function_index) &&
             query_context.isValidGeneratorFunctionId(
                 proto.GetExtension(serialization::TableGeneratorWorkOrder::generator_function_index)) &&
             proto.HasExtension(serialization::TableGeneratorWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::TableGeneratorWorkOrder::insert_destination_index));
    }
    case serialization::TEXT_SCAN: {
      if (!proto.HasExtension(serialization::TextScanWorkOrder::field_terminator) ||
          !proto.HasExtension(serialization::TextScanWorkOrder::process_escape_sequences) ||
          !proto.HasExtension(serialization::TextScanWorkOrder::insert_destination_index) ||
          !query_context.isValidInsertDestinationId(
              proto.GetExtension(serialization::TextScanWorkOrder::insert_destination_index))) {
        return false;
      }

      // Two fields are exclusive.
      if (proto.HasExtension(serialization::TextScanWorkOrder::filename) ==
              proto.HasExtension(serialization::TextScanWorkOrder::text_blob)) {
        return false;
      }

      return proto.HasExtension(serialization::TextScanWorkOrder::filename) ||
             proto.GetExtension(serialization::TextScanWorkOrder::text_blob).IsInitialized();
    }
    case serialization::TEXT_SPLIT: {
      return proto.HasExtension(serialization::TextSplitWorkOrder::filename) &&
             proto.HasExtension(serialization::TextSplitWorkOrder::process_escape_sequences) &&
             proto.HasExtension(serialization::TextSplitWorkOrder::operator_index);
    }
    case serialization::UPDATE: {
      return proto.HasExtension(serialization::UpdateWorkOrder::relation_id) &&
             catalog_database.hasRelationWithId(
                 proto.GetExtension(serialization::UpdateWorkOrder::relation_id)) &&
             proto.HasExtension(serialization::UpdateWorkOrder::insert_destination_index) &&
             query_context.isValidInsertDestinationId(
                 proto.GetExtension(serialization::UpdateWorkOrder::insert_destination_index)) &&
             proto.HasExtension(serialization::UpdateWorkOrder::predicate_index) &&
             query_context.isValidPredicate(
                 proto.GetExtension(serialization::UpdateWorkOrder::predicate_index)) &&
             proto.HasExtension(serialization::UpdateWorkOrder::update_group_index) &&
             query_context.isValidUpdateGroupId(
                 proto.GetExtension(serialization::UpdateWorkOrder::update_group_index)) &&
             proto.HasExtension(serialization::UpdateWorkOrder::operator_index) &&
             proto.HasExtension(serialization::UpdateWorkOrder::block_id);
    }
    default:
      return false;
  }
}
bool QueryContext::ProtoIsValid(const serialization::QueryContext &proto,
                                const CatalogDatabaseLite &database) {
  for (int i = 0; i < proto.aggregation_states_size(); ++i) {
    if (!AggregationOperationState::ProtoIsValid(proto.aggregation_states(i).aggregation_state(), database)) {
      return false;
    }
  }

  // Each GeneratorFunctionHandle object is serialized as a function name with
  // a list of arguments. Here checks that the arguments are valid TypedValue's.
  for (int i = 0; i < proto.generator_functions_size(); ++i) {
    const serialization::GeneratorFunctionHandle &func_proto = proto.generator_functions(i);
    for (int j = 0; j < func_proto.args_size(); ++j) {
      if (!TypedValue::ProtoIsValid(func_proto.args(j))) {
        return false;
      }
    }
  }

  for (int i = 0; i < proto.join_hash_tables_size(); ++i) {
    if (!JoinHashTableFactory::ProtoIsValid(proto.join_hash_tables(i).join_hash_table())) {
      return false;
    }
  }

  for (int i = 0; i < proto.insert_destinations_size(); ++i) {
    const serialization::InsertDestination &insert_destination_proto = proto.insert_destinations(i);
    const relation_id rel_id = insert_destination_proto.relation_id();

    if (!database.hasRelationWithId(rel_id) ||
        !InsertDestination::ProtoIsValid(insert_destination_proto,
                                         database.getRelationSchemaById(rel_id))) {
      return false;
    }
  }

  for (int i = 0; i < proto.lip_filters_size(); ++i) {
    if (!LIPFilterFactory::ProtoIsValid(proto.lip_filters(i))) {
      return false;
    }
  }

  for (int i = 0; i < proto.lip_filter_deployments_size(); ++i) {
    if (!LIPFilterDeployment::ProtoIsValid(proto.lip_filter_deployments(i))) {
      return false;
    }
  }

  for (int i = 0; i < proto.predicates_size(); ++i) {
    if (!PredicateFactory::ProtoIsValid(proto.predicates(i), database)) {
      return false;
    }
  }

  for (int i = 0; i < proto.scalar_groups_size(); ++i) {
    const serialization::QueryContext::ScalarGroup &scalar_group_proto = proto.scalar_groups(i);
    for (int j = 0; j < scalar_group_proto.scalars_size(); ++j) {
      if (!ScalarFactory::ProtoIsValid(scalar_group_proto.scalars(j), database)) {
        return false;
      }
    }
  }

  for (int i = 0; i < proto.sort_configs_size(); ++i) {
    if (!SortConfiguration::ProtoIsValid(proto.sort_configs(i), database)) {
      return false;
    }
  }

  for (int i = 0; i < proto.tuples_size(); ++i) {
    if (!Tuple::ProtoIsValid(proto.tuples(i))) {
      return false;
    }
  }

  for (int i = 0; i < proto.update_groups_size(); ++i) {
    const serialization::QueryContext::UpdateGroup &update_group_proto = proto.update_groups(i);

    const relation_id rel_id = update_group_proto.relation_id();
    if (!database.hasRelationWithId(rel_id)) {
      return false;
    }
    const CatalogRelationSchema &rel = database.getRelationSchemaById(rel_id);

    for (int j = 0; j < update_group_proto.update_assignments_size(); ++j) {
      const serialization::QueryContext::UpdateGroup::UpdateAssignment &update_assignment_proto =
          update_group_proto.update_assignments(j);

      if (!rel.hasAttributeWithId(update_assignment_proto.attribute_id()) ||
          !ScalarFactory::ProtoIsValid(update_assignment_proto.scalar(), database)) {
        return false;
      }
    }
  }

  for (int i = 0; i < proto.window_aggregation_states_size(); ++i) {
    if (!WindowAggregationOperationState::ProtoIsValid(proto.window_aggregation_states(i),
                                                       database)) {
      return false;
    }
  }

  return proto.IsInitialized();
}
QueryContext::QueryContext(const serialization::QueryContext &proto,
                           const CatalogDatabaseLite &database,
                           StorageManager *storage_manager,
                           const tmb::client_id scheduler_client_id,
                           tmb::MessageBus *bus) {
  DCHECK(ProtoIsValid(proto, database))
      << "Attempted to create QueryContext from an invalid proto description:\n"
      << proto.DebugString();

  for (int i = 0; i < proto.aggregation_states_size(); ++i) {
    PartitionedAggregationOperationStates partitioned_aggregation_states;
    const serialization::QueryContext::AggregationOperationStateContext &aggr_state_context_proto =
        proto.aggregation_states(i);
    for (std::uint64_t j = 0; j < aggr_state_context_proto.num_partitions(); ++j) {
      partitioned_aggregation_states.emplace_back(
          AggregationOperationState::ReconstructFromProto(aggr_state_context_proto.aggregation_state(),
                                                          database,
                                                          storage_manager));
    }
    aggregation_states_.push_back(move(partitioned_aggregation_states));
  }

  for (int i = 0; i < proto.generator_functions_size(); ++i) {
    const GeneratorFunctionHandle *func_handle =
        GeneratorFunctionFactory::Instance().reconstructFromProto(proto.generator_functions(i));
    DCHECK(func_handle != nullptr);
    generator_functions_.emplace_back(
        std::unique_ptr<const GeneratorFunctionHandle>(func_handle));
  }

  for (int i = 0; i < proto.join_hash_tables_size(); ++i) {
    PartitionedJoinHashTables partitioned_join_hash_tables;

    const serialization::QueryContext::HashTableContext &hash_table_context_proto = proto.join_hash_tables(i);
    for (std::uint64_t j = 0; j < hash_table_context_proto.num_partitions(); ++j) {
      partitioned_join_hash_tables.emplace_back(
          JoinHashTableFactory::CreateResizableFromProto(hash_table_context_proto.join_hash_table(), storage_manager));
    }

    join_hash_tables_.push_back(move(partitioned_join_hash_tables));
  }

  for (int i = 0; i < proto.insert_destinations_size(); ++i) {
    const serialization::InsertDestination &insert_destination_proto = proto.insert_destinations(i);
    insert_destinations_.emplace_back(InsertDestination::ReconstructFromProto(
        proto.query_id(),
        insert_destination_proto,
        database.getRelationSchemaById(insert_destination_proto.relation_id()),
        storage_manager,
        scheduler_client_id,
        bus));
  }

  for (int i = 0; i < proto.lip_filters_size(); ++i) {
    lip_filters_.emplace_back(
        std::unique_ptr<LIPFilter>(
            LIPFilterFactory::ReconstructFromProto(proto.lip_filters(i))));
  }

  for (int i = 0; i < proto.lip_filter_deployments_size(); ++i) {
    lip_deployments_.emplace_back(
        std::make_unique<LIPFilterDeployment>(
            proto.lip_filter_deployments(i), lip_filters_));
  }

  for (int i = 0; i < proto.predicates_size(); ++i) {
    predicates_.emplace_back(
        PredicateFactory::ReconstructFromProto(proto.predicates(i), database));
  }

  for (int i = 0; i < proto.scalar_groups_size(); ++i) {
    vector<unique_ptr<const Scalar>> scalar_group;

    const serialization::QueryContext::ScalarGroup &scalar_group_proto = proto.scalar_groups(i);
    for (int j = 0; j < scalar_group_proto.scalars_size(); ++j) {
      scalar_group.emplace_back(
          ScalarFactory::ReconstructFromProto(scalar_group_proto.scalars(j), database));
    }

    scalar_groups_.push_back(move(scalar_group));
  }

  for (int i = 0; i < proto.sort_configs_size(); ++i) {
    sort_configs_.emplace_back(
        SortConfiguration::ReconstructFromProto(proto.sort_configs(i), database));
  }

  for (int i = 0; i < proto.tuples_size(); ++i) {
    tuples_.emplace_back(Tuple::ReconstructFromProto(proto.tuples(i)));
  }

  for (int i = 0; i < proto.update_groups_size(); ++i) {
    const serialization::QueryContext::UpdateGroup &update_group_proto = proto.update_groups(i);

    std::unordered_map<attribute_id, std::unique_ptr<const Scalar>> update_group;
    for (int j = 0; j < update_group_proto.update_assignments_size(); ++j) {
      const serialization::QueryContext::UpdateGroup::UpdateAssignment &update_assignment_proto =
          update_group_proto.update_assignments(j);

      unique_ptr<const Scalar> scalar(
          ScalarFactory::ReconstructFromProto(update_assignment_proto.scalar(), database));

      update_group.emplace(update_assignment_proto.attribute_id(), move(scalar));
    }

    update_groups_.push_back(move(update_group));
  }

  for (int i = 0; i < proto.window_aggregation_states_size(); ++i) {
    window_aggregation_states_.emplace_back(
        WindowAggregationOperationState::ReconstructFromProto(proto.window_aggregation_states(i),
                                                              database,
                                                              storage_manager));
  }
}
bool ScalarFactory::ProtoIsValid(const serialization::Scalar &proto,
                                 const CatalogDatabaseLite &database) {
  // Check that proto is fully initialized.
  if (!proto.IsInitialized()) {
    return false;
  }

  // Check that the data_source is valid, and extensions if any.
  switch (proto.data_source()) {
    case serialization::Scalar::LITERAL: {
      return proto.HasExtension(serialization::ScalarLiteral::literal)
             && proto.HasExtension(serialization::ScalarLiteral::literal_type)
             && TypedValue::ProtoIsValid(proto.GetExtension(serialization::ScalarLiteral::literal))
             && TypeFactory::ProtoIsValid(proto.GetExtension(serialization::ScalarLiteral::literal_type));
    }
    case serialization::Scalar::ATTRIBUTE: {
      if (proto.HasExtension(serialization::ScalarAttribute::relation_id)
          && proto.HasExtension(serialization::ScalarAttribute::attribute_id)) {
        const relation_id rel_id = proto.GetExtension(serialization::ScalarAttribute::relation_id);
        const attribute_id attr_id = proto.GetExtension(serialization::ScalarAttribute::attribute_id);

        return database.hasRelationWithId(rel_id)
               && database.getRelationSchemaById(rel_id).hasAttributeWithId(attr_id);
      }
      break;
    }
    case serialization::Scalar::UNARY_EXPRESSION: {
      if (proto.HasExtension(serialization::ScalarUnaryExpression::operation)
          && proto.HasExtension(serialization::ScalarUnaryExpression::operand)) {
        return UnaryOperationFactory::ProtoIsValid(proto.GetExtension(serialization::ScalarUnaryExpression::operation))
               && ProtoIsValid(proto.GetExtension(serialization::ScalarUnaryExpression::operand), database);
      }
      break;
    }
    case serialization::Scalar::BINARY_EXPRESSION: {
      if (proto.HasExtension(serialization::ScalarBinaryExpression::operation)
          && proto.HasExtension(serialization::ScalarBinaryExpression::left_operand)
          && proto.HasExtension(serialization::ScalarBinaryExpression::right_operand)) {
        return BinaryOperationFactory::ProtoIsValid(
                   proto.GetExtension(serialization::ScalarBinaryExpression::operation))
               && ProtoIsValid(proto.GetExtension(serialization::ScalarBinaryExpression::left_operand), database)
               && ProtoIsValid(proto.GetExtension(serialization::ScalarBinaryExpression::right_operand), database);
      }
      break;
    }
    case serialization::Scalar::CASE_EXPRESSION: {
      // Check result type.
      if (!(proto.HasExtension(serialization::ScalarCaseExpression::result_type)
            && TypeFactory::ProtoIsValid(proto.GetExtension(
                serialization::ScalarCaseExpression::result_type)))) {
        return false;
      }

      // Check when-predicates and result expressions.
      if (proto.ExtensionSize(serialization::ScalarCaseExpression::when_predicate)
          == proto.ExtensionSize(serialization::ScalarCaseExpression::result_expression)) {
        for (int case_num = 0;
             case_num < proto.ExtensionSize(serialization::ScalarCaseExpression::when_predicate);
             ++case_num) {
          if (!PredicateFactory::ProtoIsValid(
                  proto.GetExtension(
                      serialization::ScalarCaseExpression::when_predicate,
                      case_num),
                  database)) {
            return false;
          }
          if (!ProtoIsValid(
                  proto.GetExtension(serialization::ScalarCaseExpression::result_expression,
                                     case_num),
                  database)) {
            return false;
          }
        }
      } else {
        return false;
      }

      // Check else-result expression.
      if (!(proto.HasExtension(serialization::ScalarCaseExpression::else_result_expression)
            && ProtoIsValid(proto.GetExtension(serialization::ScalarCaseExpression::else_result_expression),
                            database))) {
        return false;
      }

      // Everything checks out.
      return true;
    }
    default: {
      break;
    }
  }

  return false;
}