backend/actions/manager.cc (193 lines of code) (raw):
//
// Copyright 2020 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
#include "backend/actions/manager.h"
#include <memory>
#include <string>
#include <vector>
#include "zetasql/public/types/type_factory.h"
#include "zetasql/public/value.h"
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/status/status.h"
#include "absl/status/statusor.h"
#include "absl/strings/str_cat.h"
#include "absl/synchronization/mutex.h"
#include "backend/access/write.h"
#include "backend/actions/check_constraint.h"
#include "backend/actions/column_value.h"
#include "backend/actions/context.h"
#include "backend/actions/existence.h"
#include "backend/actions/foreign_key.h"
#include "backend/actions/foreign_key_actions.h"
#include "backend/actions/generated_column.h"
#include "backend/actions/index.h"
#include "backend/actions/interleave.h"
#include "backend/actions/ops.h"
#include "backend/actions/unique_index.h"
#include "backend/query/analyzer_options.h"
#include "backend/query/function_catalog.h"
#include "backend/schema/catalog/check_constraint.h"
#include "backend/schema/catalog/column.h"
#include "backend/schema/catalog/foreign_key.h"
#include "backend/schema/catalog/index.h"
#include "backend/schema/catalog/placement.h"
#include "backend/schema/catalog/schema.h"
#include "common/errors.h"
#include "zetasql/base/status_macros.h"
namespace google {
namespace spanner {
namespace emulator {
namespace backend {
absl::Status ActionRegistry::ExecuteValidators(const ActionContext* ctx,
const WriteOp& op) {
for (auto& validator : table_validators_[TableOf(op)]) {
ZETASQL_RETURN_IF_ERROR(validator->Validate(ctx, op));
}
return absl::OkStatus();
}
absl::Status ActionRegistry::ExecuteEffectors(const ActionContext* ctx,
const WriteOp& op) {
for (auto& effector : table_effectors_[TableOf(op)]) {
ZETASQL_RETURN_IF_ERROR(effector->Effect(ctx, op));
}
return absl::OkStatus();
}
absl::Status ActionRegistry::ExecuteGeneratedKeyEffectors(
const MutationOp& op,
std::vector<std::vector<zetasql::Value>>* generated_values,
std::vector<const Column*>* columns_with_generated_values) {
if (table_generated_key_effectors_.find(op.table) ==
table_generated_key_effectors_.end()) {
return absl::OkStatus();
}
ZETASQL_RETURN_IF_ERROR(table_generated_key_effectors_[op.table]->Effect(
op, generated_values, columns_with_generated_values));
return absl::OkStatus();
}
absl::Status ActionRegistry::ExecuteModifiers(const ActionContext* ctx,
const WriteOp& op) {
for (auto& modifier : table_modifiers_[TableOf(op)]) {
ZETASQL_RETURN_IF_ERROR(modifier->Modify(ctx, op));
}
return absl::OkStatus();
}
absl::Status ActionRegistry::ExecuteVerifiers(const ActionContext* ctx,
const WriteOp& op) {
for (auto& verifier : table_verifiers_[TableOf(op)]) {
ZETASQL_RETURN_IF_ERROR(verifier->Verify(ctx, op));
}
return absl::OkStatus();
}
ActionRegistry::ActionRegistry(const Schema* schema,
const FunctionCatalog* function_catalog,
zetasql::TypeFactory* type_factory_)
: schema_(schema),
catalog_(schema, function_catalog, type_factory_,
MakeGoogleSqlAnalyzerOptions(schema->default_time_zone())) {
BuildActionRegistry();
}
void ActionRegistry::BuildActionRegistry() {
for (const Table* table : schema_->tables()) {
// Column value checks for all tables.
absl::flat_hash_set<std::string> placements;
for (const Placement* placement : schema_->placements()) {
placements.insert(placement->PlacementName());
}
table_validators_[table].emplace_back(
std::make_unique<ColumnValueValidator>(placements));
// Row existence checks for all tables.
table_validators_[table].emplace_back(
std::make_unique<RowExistenceValidator>());
// Interleave actions for child tables.
for (const Table* child : table->children()) {
table_validators_[table].emplace_back(
std::make_unique<InterleaveParentValidator>(table, child));
table_effectors_[table].emplace_back(
std::make_unique<InterleaveParentEffector>(table, child));
}
// Interleave actions for parent table.
if (table->parent() != nullptr) {
table_validators_[table].emplace_back(
std::make_unique<InterleaveChildValidator>(table->parent(), table));
}
// Actions for Index.
for (const Index* index : table->indexes()) {
// Index effects.
if (index->is_search_index()) {
continue;
}
table_effectors_[table].emplace_back(
std::make_unique<IndexEffector>(index));
// Index uniqueness checks.
if (index->is_unique()) {
table_verifiers_[index->index_data_table()].emplace_back(
std::make_unique<UniqueIndexVerifier>(index));
}
}
// Actions for foreign keys.
for (const ForeignKey* foreign_key : table->foreign_keys()) {
if (!foreign_key->enforced()) {
// Not enforced foreign keys doesn't verify referential integrity on
// data.
continue;
}
table_verifiers_[foreign_key->referencing_data_table()].emplace_back(
std::make_unique<ForeignKeyReferencingVerifier>(foreign_key));
}
for (const ForeignKey* foreign_key : table->referencing_foreign_keys()) {
if (!foreign_key->enforced()) {
// Not enforced foreign keys has no actions, and doesn't verify
// referential integrity on data.
continue;
}
table_verifiers_[foreign_key->referenced_data_table()].emplace_back(
std::make_unique<ForeignKeyReferencedVerifier>(foreign_key));
if (foreign_key->on_delete_action() == ForeignKey::Action::kCascade) {
table_effectors_[table].emplace_back(
std::make_unique<ForeignKeyActionEffector>(foreign_key));
}
}
// Actions for check constraints.
for (const CheckConstraint* check_constraint : table->check_constraints()) {
table_verifiers_[table].emplace_back(
std::make_unique<CheckConstraintVerifier>(
check_constraint,
MakeGoogleSqlAnalyzerOptions(schema_->default_time_zone()),
&catalog_));
}
// A set containing key columns with default/generated values.
absl::flat_hash_set<std::string> default_or_generated_key_columns;
// Effector for primary key default and generated columns.
for (const Column* column : table->columns()) {
if ((column->has_default_value()
|| column->is_generated()
) &&
table->FindKeyColumn(column->Name()) != nullptr) {
default_or_generated_key_columns.insert(column->Name());
table_generated_key_effectors_[table->Name()] =
std::make_unique<GeneratedColumnEffector>(
table,
MakeGoogleSqlAnalyzerOptions(schema_->default_time_zone()),
&catalog_,
/*for_keys=*/true);
break;
}
}
// Effector for non-key generated and default columns.
for (const Column* column : table->columns()) {
if (!default_or_generated_key_columns.contains(column->Name()) &&
(column->is_generated() || column->has_default_value())) {
table_effectors_[table].emplace_back(
std::make_unique<GeneratedColumnEffector>(
table,
MakeGoogleSqlAnalyzerOptions(schema_->default_time_zone()),
&catalog_));
break;
}
}
}
}
void ActionManager::AddActionsForSchema(const Schema* schema,
const FunctionCatalog* function_catalog,
zetasql::TypeFactory* type_factory) {
absl::MutexLock l(&mutex_);
registry_[schema] =
std::make_unique<ActionRegistry>(schema, function_catalog, type_factory);
}
absl::StatusOr<ActionRegistry*> ActionManager::GetActionsForSchema(
const Schema* schema) const {
absl::MutexLock l(&mutex_);
auto itr = registry_.find(schema);
if (itr == registry_.end()) {
return error::Internal(
absl::StrCat("Schema generation ", schema->generation(),
" was not registered with the Action Manager"));
}
return itr->second.get();
}
} // namespace backend
} // namespace emulator
} // namespace spanner
} // namespace google