absl::Status GeneratedColumnEffector::Effect()

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();
}