Adapt schema validator

This commit is contained in:
jbajic 2022-11-14 14:25:20 +01:00
parent ef755e466c
commit 618237cc96
4 changed files with 52 additions and 73 deletions

View File

@ -17,6 +17,7 @@
#include <string_view>
#include <unordered_map>
#include "storage/v3/id_types.hpp"
#include "utils/logging.hpp"
#include "utils/skip_list.hpp"
@ -47,6 +48,10 @@ class NameIdMapper final {
return kUnmappedId;
}
const std::string &IdToName(const LabelId label_id) const { return IdToName(label_id.AsInt()); }
const std::string &IdToName(const PropertyId property_id) const { return IdToName(property_id.AsInt()); }
const std::string &IdToName(const uint64_t id) const {
auto it = id_to_name_.find(id);
MG_ASSERT(it != id_to_name_.end(), "Id not know in mapper!");

View File

@ -16,67 +16,60 @@
#include <ranges>
#include "common/types.hpp"
#include "storage/v3/name_id_mapper.hpp"
#include "storage/v3/result.hpp"
#include "storage/v3/schemas.hpp"
namespace memgraph::storage::v3 {
bool operator==(const SchemaViolation &lhs, const SchemaViolation &rhs) {
return lhs.status == rhs.status && lhs.label == rhs.label &&
lhs.violated_schema_property == rhs.violated_schema_property &&
lhs.violated_property_value == rhs.violated_property_value;
}
SchemaValidator::SchemaValidator(Schemas &schemas, const NameIdMapper &name_id_mapper)
: schemas_{&schemas}, name_id_mapper_{&name_id_mapper} {}
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label) : status{status}, label{label} {}
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property)
: status{status}, label{label}, violated_schema_property{violated_schema_property} {}
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property,
PropertyValue violated_property_value)
: status{status},
label{label},
violated_schema_property{violated_schema_property},
violated_property_value{violated_property_value} {}
SchemaValidator::SchemaValidator(Schemas &schemas) : schemas_{schemas} {}
std::optional<SchemaViolation> SchemaValidator::ValidateVertexCreate(
std::optional<ShardError> SchemaValidator::ValidateVertexCreate(
LabelId primary_label, const std::vector<LabelId> &labels,
const std::vector<PropertyValue> &primary_properties) const {
// Schema on primary label
const auto *schema = schemas_.GetSchema(primary_label);
const auto *schema = schemas_->GetSchema(primary_label);
if (schema == nullptr) {
return SchemaViolation(SchemaViolation::ValidationStatus::NO_SCHEMA_DEFINED_FOR_LABEL, primary_label);
return SHARD_ERROR(ErrorCode::SCHEMA_NO_SCHEMA_DEFINED_FOR_LABEL,
fmt::format("Schema not defined for label :{}", name_id_mapper_->IdToName(primary_label)));
}
// Is there another primary label among secondary labels
for (const auto &secondary_label : labels) {
if (schemas_.GetSchema(secondary_label)) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, secondary_label);
if (schemas_->GetSchema(secondary_label)) {
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_SECONDARY_LABEL_IS_PRIMARY,
fmt::format("Cannot add label :{}, since it is defined as a primary label",
name_id_mapper_->IdToName(secondary_label)));
}
}
// Quick size check
if (schema->second.size() != primary_properties.size()) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PRIMARY_PROPERTIES_UNDEFINED, primary_label);
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_PRIMARY_PROPERTIES_UNDEFINED,
fmt::format("Not all primary properties have been specified for :{} vertex",
name_id_mapper_->IdToName(primary_label)));
}
// Check only properties defined by schema
for (size_t i{0}; i < schema->second.size(); ++i) {
// Check schema property type
if (auto property_schema_type = PropertyTypeToSchemaType(primary_properties[i]);
property_schema_type && *property_schema_type != schema->second[i].type) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, primary_label,
schema->second[i], primary_properties[i]);
return SHARD_ERROR(
ErrorCode::SCHEMA_VERTEX_PROPERTY_WRONG_TYPE,
fmt::format("Property {} is of wrong type, expected {}, actual {}",
name_id_mapper_->IdToName(schema->second[i].property_id),
SchemaTypeToString(schema->second[i].type), SchemaTypeToString(*property_schema_type)));
}
}
return std::nullopt;
}
std::optional<SchemaViolation> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_label,
const PropertyId property_id) const {
std::optional<ShardError> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_label,
const PropertyId property_id) const {
// Verify existence of schema on primary label
const auto *schema = schemas_.GetSchema(primary_label);
const auto *schema = schemas_->GetSchema(primary_label);
MG_ASSERT(schema, "Cannot validate against non existing schema!");
// Verify that updating property is not part of schema
@ -84,16 +77,19 @@ std::optional<SchemaViolation> SchemaValidator::ValidatePropertyUpdate(const Lab
schema->second,
[property_id](const auto &schema_property) { return property_id == schema_property.property_id; });
schema_property != schema->second.end()) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, primary_label,
*schema_property);
return SHARD_ERROR(
ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_KEY,
fmt::format("Cannot update primary property {} of schema on label :{}",
name_id_mapper_->IdToName(schema_property->property_id), name_id_mapper_->IdToName(primary_label)));
}
return std::nullopt;
}
std::optional<SchemaViolation> SchemaValidator::ValidateLabelUpdate(const LabelId label) const {
const auto *schema = schemas_.GetSchema(label);
std::optional<ShardError> SchemaValidator::ValidateLabelUpdate(const LabelId label) const {
const auto *schema = schemas_->GetSchema(label);
if (schema) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_LABEL, label);
return SHARD_ERROR(ErrorCode::SCHEMA_VERTEX_UPDATE_PRIMARY_LABEL,
fmt::format("Cannot add/remove primary label :{}", name_id_mapper_->IdToName(label)));
}
return std::nullopt;
}
@ -103,15 +99,15 @@ const Schemas::Schema *SchemaValidator::GetSchema(LabelId label) const { return
VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const LabelId primary_label)
: schema_validator{&schema_validator}, primary_label_{primary_label} {}
std::optional<SchemaViolation> VertexValidator::ValidatePropertyUpdate(PropertyId property_id) const {
std::optional<ShardError> VertexValidator::ValidatePropertyUpdate(PropertyId property_id) const {
return schema_validator->ValidatePropertyUpdate(primary_label_, property_id);
};
std::optional<SchemaViolation> VertexValidator::ValidateAddLabel(LabelId label) const {
std::optional<ShardError> VertexValidator::ValidateAddLabel(LabelId label) const {
return schema_validator->ValidateLabelUpdate(label);
}
std::optional<SchemaViolation> VertexValidator::ValidateRemoveLabel(LabelId label) const {
std::optional<ShardError> VertexValidator::ValidateRemoveLabel(LabelId label) const {
return schema_validator->ValidateLabelUpdate(label);
}

View File

@ -14,65 +14,42 @@
#include <optional>
#include <variant>
#include "storage/v2/result.hpp"
#include "storage/v3/id_types.hpp"
#include "storage/v3/name_id_mapper.hpp"
#include "storage/v3/property_value.hpp"
#include "storage/v3/result.hpp"
#include "storage/v3/schemas.hpp"
namespace memgraph::storage::v3 {
struct SchemaViolation {
enum class ValidationStatus : uint8_t {
NO_SCHEMA_DEFINED_FOR_LABEL,
VERTEX_PROPERTY_WRONG_TYPE,
VERTEX_UPDATE_PRIMARY_KEY,
VERTEX_UPDATE_PRIMARY_LABEL,
VERTEX_SECONDARY_LABEL_IS_PRIMARY,
VERTEX_PRIMARY_PROPERTIES_UNDEFINED,
};
SchemaViolation(ValidationStatus status, LabelId label);
SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property);
SchemaViolation(ValidationStatus status, LabelId label, SchemaProperty violated_schema_property,
PropertyValue violated_property_value);
friend bool operator==(const SchemaViolation &lhs, const SchemaViolation &rhs);
ValidationStatus status;
LabelId label;
std::optional<SchemaProperty> violated_schema_property;
std::optional<PropertyValue> violated_property_value;
};
class SchemaValidator {
public:
explicit SchemaValidator(Schemas &schemas);
explicit SchemaValidator(Schemas &schemas, const NameIdMapper &name_id_mapper);
[[nodiscard]] std::optional<SchemaViolation> ValidateVertexCreate(
[[nodiscard]] std::optional<ShardError> ValidateVertexCreate(
LabelId primary_label, const std::vector<LabelId> &labels,
const std::vector<PropertyValue> &primary_properties) const;
[[nodiscard]] std::optional<SchemaViolation> ValidatePropertyUpdate(LabelId primary_label,
PropertyId property_id) const;
[[nodiscard]] std::optional<ShardError> ValidatePropertyUpdate(LabelId primary_label, PropertyId property_id) const;
[[nodiscard]] std::optional<SchemaViolation> ValidateLabelUpdate(LabelId label) const;
[[nodiscard]] std::optional<ShardError> ValidateLabelUpdate(LabelId label) const;
const Schemas::Schema *GetSchema(LabelId label) const;
private:
Schemas &schemas_;
Schemas *schemas_;
const NameIdMapper *name_id_mapper_;
};
struct VertexValidator {
explicit VertexValidator(const SchemaValidator &schema_validator, LabelId primary_label);
[[nodiscard]] std::optional<SchemaViolation> ValidatePropertyUpdate(PropertyId property_id) const;
[[nodiscard]] std::optional<ShardError> ValidatePropertyUpdate(PropertyId property_id) const;
[[nodiscard]] std::optional<SchemaViolation> ValidateAddLabel(LabelId label) const;
[[nodiscard]] std::optional<ShardError> ValidateAddLabel(LabelId label) const;
[[nodiscard]] std::optional<SchemaViolation> ValidateRemoveLabel(LabelId label) const;
[[nodiscard]] std::optional<ShardError> ValidateRemoveLabel(LabelId label) const;
const SchemaValidator *schema_validator;

View File

@ -31,6 +31,7 @@
#include "storage/v3/indices.hpp"
#include "storage/v3/key_store.hpp"
#include "storage/v3/mvcc.hpp"
#include "storage/v3/name_id_mapper.hpp"
#include "storage/v3/property_value.hpp"
#include "storage/v3/schema_validator.hpp"
#include "storage/v3/shard_operation_result.hpp"
@ -327,7 +328,7 @@ Shard::Shard(const LabelId primary_label, const PrimaryKey min_primary_key,
: primary_label_{primary_label},
min_primary_key_{min_primary_key},
max_primary_key_{max_primary_key},
schema_validator_{schemas_},
schema_validator_{schemas_, name_id_mapper_},
vertex_validator_{schema_validator_, primary_label},
indices_{config.items, vertex_validator_},
isolation_level_{config.transaction.isolation_level},