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

View File

@ -16,67 +16,60 @@
#include <ranges> #include <ranges>
#include "common/types.hpp" #include "common/types.hpp"
#include "storage/v3/name_id_mapper.hpp"
#include "storage/v3/result.hpp"
#include "storage/v3/schemas.hpp" #include "storage/v3/schemas.hpp"
namespace memgraph::storage::v3 { namespace memgraph::storage::v3 {
bool operator==(const SchemaViolation &lhs, const SchemaViolation &rhs) { SchemaValidator::SchemaValidator(Schemas &schemas, const NameIdMapper &name_id_mapper)
return lhs.status == rhs.status && lhs.label == rhs.label && : schemas_{&schemas}, name_id_mapper_{&name_id_mapper} {}
lhs.violated_schema_property == rhs.violated_schema_property &&
lhs.violated_property_value == rhs.violated_property_value;
}
SchemaViolation::SchemaViolation(ValidationStatus status, LabelId label) : status{status}, label{label} {} std::optional<ShardError> SchemaValidator::ValidateVertexCreate(
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(
LabelId primary_label, const std::vector<LabelId> &labels, LabelId primary_label, const std::vector<LabelId> &labels,
const std::vector<PropertyValue> &primary_properties) const { const std::vector<PropertyValue> &primary_properties) const {
// Schema on primary label // Schema on primary label
const auto *schema = schemas_.GetSchema(primary_label); const auto *schema = schemas_->GetSchema(primary_label);
if (schema == nullptr) { 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 // Is there another primary label among secondary labels
for (const auto &secondary_label : labels) { for (const auto &secondary_label : labels) {
if (schemas_.GetSchema(secondary_label)) { if (schemas_->GetSchema(secondary_label)) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_SECONDARY_LABEL_IS_PRIMARY, 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 // Quick size check
if (schema->second.size() != primary_properties.size()) { 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 // Check only properties defined by schema
for (size_t i{0}; i < schema->second.size(); ++i) { for (size_t i{0}; i < schema->second.size(); ++i) {
// Check schema property type // Check schema property type
if (auto property_schema_type = PropertyTypeToSchemaType(primary_properties[i]); if (auto property_schema_type = PropertyTypeToSchemaType(primary_properties[i]);
property_schema_type && *property_schema_type != schema->second[i].type) { property_schema_type && *property_schema_type != schema->second[i].type) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_PROPERTY_WRONG_TYPE, primary_label, return SHARD_ERROR(
schema->second[i], primary_properties[i]); 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; return std::nullopt;
} }
std::optional<SchemaViolation> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_label, std::optional<ShardError> SchemaValidator::ValidatePropertyUpdate(const LabelId primary_label,
const PropertyId property_id) const { const PropertyId property_id) const {
// Verify existence of schema on primary label // 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!"); MG_ASSERT(schema, "Cannot validate against non existing schema!");
// Verify that updating property is not part of schema // Verify that updating property is not part of schema
@ -84,16 +77,19 @@ std::optional<SchemaViolation> SchemaValidator::ValidatePropertyUpdate(const Lab
schema->second, schema->second,
[property_id](const auto &schema_property) { return property_id == schema_property.property_id; }); [property_id](const auto &schema_property) { return property_id == schema_property.property_id; });
schema_property != schema->second.end()) { schema_property != schema->second.end()) {
return SchemaViolation(SchemaViolation::ValidationStatus::VERTEX_UPDATE_PRIMARY_KEY, primary_label, return SHARD_ERROR(
*schema_property); 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; return std::nullopt;
} }
std::optional<SchemaViolation> SchemaValidator::ValidateLabelUpdate(const LabelId label) const { std::optional<ShardError> SchemaValidator::ValidateLabelUpdate(const LabelId label) const {
const auto *schema = schemas_.GetSchema(label); const auto *schema = schemas_->GetSchema(label);
if (schema) { 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; 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) VertexValidator::VertexValidator(const SchemaValidator &schema_validator, const LabelId primary_label)
: schema_validator{&schema_validator}, primary_label_{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); 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); 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); return schema_validator->ValidateLabelUpdate(label);
} }

View File

@ -14,65 +14,42 @@
#include <optional> #include <optional>
#include <variant> #include <variant>
#include "storage/v2/result.hpp"
#include "storage/v3/id_types.hpp" #include "storage/v3/id_types.hpp"
#include "storage/v3/name_id_mapper.hpp"
#include "storage/v3/property_value.hpp" #include "storage/v3/property_value.hpp"
#include "storage/v3/result.hpp" #include "storage/v3/result.hpp"
#include "storage/v3/schemas.hpp" #include "storage/v3/schemas.hpp"
namespace memgraph::storage::v3 { 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 { class SchemaValidator {
public: 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, LabelId primary_label, const std::vector<LabelId> &labels,
const std::vector<PropertyValue> &primary_properties) const; const std::vector<PropertyValue> &primary_properties) const;
[[nodiscard]] std::optional<SchemaViolation> ValidatePropertyUpdate(LabelId primary_label, [[nodiscard]] std::optional<ShardError> ValidatePropertyUpdate(LabelId primary_label, PropertyId property_id) const;
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; const Schemas::Schema *GetSchema(LabelId label) const;
private: private:
Schemas &schemas_; Schemas *schemas_;
const NameIdMapper *name_id_mapper_;
}; };
struct VertexValidator { struct VertexValidator {
explicit VertexValidator(const SchemaValidator &schema_validator, LabelId primary_label); 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; const SchemaValidator *schema_validator;

View File

@ -31,6 +31,7 @@
#include "storage/v3/indices.hpp" #include "storage/v3/indices.hpp"
#include "storage/v3/key_store.hpp" #include "storage/v3/key_store.hpp"
#include "storage/v3/mvcc.hpp" #include "storage/v3/mvcc.hpp"
#include "storage/v3/name_id_mapper.hpp"
#include "storage/v3/property_value.hpp" #include "storage/v3/property_value.hpp"
#include "storage/v3/schema_validator.hpp" #include "storage/v3/schema_validator.hpp"
#include "storage/v3/shard_operation_result.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}, : primary_label_{primary_label},
min_primary_key_{min_primary_key}, min_primary_key_{min_primary_key},
max_primary_key_{max_primary_key}, max_primary_key_{max_primary_key},
schema_validator_{schemas_}, schema_validator_{schemas_, name_id_mapper_},
vertex_validator_{schema_validator_, primary_label}, vertex_validator_{schema_validator_, primary_label},
indices_{config.items, vertex_validator_}, indices_{config.items, vertex_validator_},
isolation_level_{config.transaction.isolation_level}, isolation_level_{config.transaction.isolation_level},