in backend/actions/generated_column.cc [174:251]
absl::Status GeneratedColumnEffector::Effect(
const MutationOp& op,
std::vector<std::vector<zetasql::Value>>* generated_values,
std::vector<const Column*>* columns_with_generated_values) const {
ZETASQL_RET_CHECK(for_keys_ == true);
columns_with_generated_values->reserve(generated_columns_.size());
// This vector stores column values for each row that can be used to evaluate
// generated columns.
std::vector<zetasql::ParameterValueMap> row_column_values(
op.rows.size(), zetasql::ParameterValueMap());
// Evaluate generated columns in topological order.
for (int i = 0; i < generated_columns_.size(); ++i) {
const Column* generated_column = generated_columns_[i];
if (!generated_column->has_default_value() &&
!IsKeyColumn(generated_column)) {
// skip non-key columns except default columns since generated key columns
// may be depended by default columns values of which would need to be
// evaluated.
continue;
}
auto column_supplied_itr = std::find(op.columns.begin(), op.columns.end(),
generated_column->Name());
bool is_user_supplied_value = column_supplied_itr != op.columns.end();
if (generated_column->has_default_value()) {
// If this column has a default value and the user is supplying a value
// for it, then we don't need to compute its default value.
if (is_user_supplied_value) {
continue;
}
if (IsKeyColumn(generated_column) &&
(op.type == MutationOpType::kUpdate ||
op.type == MutationOpType::kDelete)) {
return error::DefaultPKNeedsExplicitValue(generated_column->FullName(),
"Update/Delete");
}
} else if (generated_column->is_generated() && is_user_supplied_value) {
// If this column is generated column and user is supplying a value for it
// and the user is not supplying values for dependent column values to
// evaluate generated column value, we don't need to compute its generated
// value.
if (!IsAnyDependentColumnPresent(generated_column, op.columns)) {
continue;
}
// Users should supply values for generated columns only in update
// operations.
if (op.type != MutationOpType::kUpdate) {
return error::UserSuppliedValueInNonUpdateGpk(
generated_column->FullName());
}
}
for (int i = 0; i < op.rows.size(); ++i) {
// Calculate values of generated columns for each row.
for (int j = 0; j < op.columns.size(); ++j) {
row_column_values[i][op.columns[j]] = op.rows[i][j];
}
ZETASQL_ASSIGN_OR_RETURN(
zetasql::Value value,
ComputeGeneratedColumnValue(generated_column, row_column_values[i]));
if (generated_column->is_generated() && is_user_supplied_value) {
size_t index = column_supplied_itr - op.columns.begin();
zetasql::Value provided_value = op.rows[i][index];
if (provided_value != value) {
return error::GeneratedPkModified(generated_column->FullName());
}
}
// Update row_column_values so that other dependent columns on this
// generated column can use the value.
row_column_values[i][generated_column->Name()] = value;
generated_values->at(i).push_back(value);
}
columns_with_generated_values->push_back(generated_column);
}
return absl::OkStatus();
}