| 152 | } |
| 153 | |
| 154 | absl::Status Database::UpdateSchema( |
| 155 | const SchemaChangeOperation& schema_change_operation, |
| 156 | int* num_succesful_statements, absl::Time* commit_timestamp, |
| 157 | absl::Status* backfill_status) { |
| 158 | if (schema_change_operation.statements.empty()) { |
| 159 | return error::UpdateDatabaseMissingStatements(); |
| 160 | } |
| 161 | |
| 162 | // Make an exclusive lock request for the database. If there are any |
| 163 | // concurrent transactions it will be denied and the operation aborted. |
| 164 | ScopedSchemaChangeLock lock{transaction_id_generator_.NextId(), |
| 165 | lock_manager_.get()}; |
| 166 | GOOGLESQL_RETURN_IF_ERROR(lock.Wait()); |
| 167 | |
| 168 | // Reserve a commit timestamp for the schema changes. Even if the |
| 169 | // schema change fails, it will result in a no-op commit that will |
| 170 | // be invisible to other read-only/read-write transactions. |
| 171 | GOOGLESQL_ASSIGN_OR_RETURN(auto update_timestamp, lock.ReserveCommitTimestamp()); |
| 172 | |
| 173 | auto context = GetSchemaChangeContext(); |
| 174 | context.schema_change_timestamp = update_timestamp; |
| 175 | const Schema* existing_schema = versioned_catalog_->GetLatestSchema(); |
| 176 | SchemaUpdater updater; |
| 177 | GOOGLESQL_ASSIGN_OR_RETURN(auto result, |
| 178 | updater.UpdateSchemaFromDDL( |
| 179 | existing_schema, schema_change_operation, context)); |
| 180 | *commit_timestamp = update_timestamp; |
| 181 | *num_succesful_statements = result.num_successful_statements; |
| 182 | *backfill_status = result.backfill_status; |
| 183 | |
| 184 | // We update the schema even if the backfill status was not OK, the returned |
| 185 | // schema will be the schema for the last valid statement before the statement |
| 186 | // for which the backfill/verification failed. |
| 187 | if (result.updated_schema != nullptr) { |
| 188 | GOOGLESQL_RETURN_IF_ERROR(versioned_catalog_->AddSchema( |
| 189 | update_timestamp, std::move(result.updated_schema))); |
| 190 | action_manager_->AddActionsForSchema(versioned_catalog_->GetLatestSchema(), |
| 191 | query_engine_->function_catalog(), |
| 192 | query_engine_->type_factory()); |
| 193 | } |
| 194 | change_stream_partition_churner_->Update( |
| 195 | versioned_catalog_->GetLatestSchema()); |
| 196 | |
| 197 | // Some functions need to access the schema (e.g. sequence functions), so |
| 198 | // set the latest schema to the function catalog here. |
| 199 | query_engine_->SetLatestSchemaForFunctionCatalog( |
| 200 | versioned_catalog_->GetLatestSchema()); |
| 201 | |
| 202 | storage_->SetVersionRetentionPeriod( |
| 203 | versioned_catalog_->version_retention_period()); |
| 204 | |
| 205 | // Enforce the retention period. |
| 206 | storage_->CleanUpDeletedTables(update_timestamp); |
| 207 | storage_->CleanUpDeletedColumns(update_timestamp); |
| 208 | versioned_catalog_->RemoveExpiredSchemas(update_timestamp); |
| 209 | |
| 210 | return absl::OkStatus(); |
| 211 | } |