Skip to content

Oracle: index and foreign key drift is invisible to the migration path #474

Description

@jeremydmiller

What

On Oracle, Table.CreateDeltaAsync(DbDataReader) reads columns only. It says so on the method:

/// Creates a delta from a DbDataReader. Oracle limitation: this only reads columns,
/// not PKs, FKs, or indexes, since Oracle doesn't support multiple result sets.
/// For full schema detection, use FindDeltaAsync instead.

That is the method SchemaMigration.DetermineAsync calls — which is what ApplyChangesAsync, ApplyAllConfiguredChangesToDatabaseAsync and AssertDatabaseMatchesConfigurationAsync all go through.

So on Oracle, the migration path never sees an index, a foreign key or a primary key. A declared index that is missing from the database is never created after the initial table creation, a changed index is never corrected, and an index the model no longer declares is never dropped. AssertDatabaseMatchesConfigurationAsync reports a match.

Table.FindDeltaAsync(OracleConnection) — which uses FetchExistingAsync and issues one query per object kind — sees all of it. It is the only path that does.

How it surfaced

The shared index scenario matrix in #449. Oracle failed eight of eleven scenarios where the other four providers passed, and the manual query confirmed the index was in all_indexes all along — Weasel just never asked. The matrix now routes Oracle through FindDeltaAsync with a comment pointing here, so the index behaviour is covered while this gap stays visible.

The fix

CommandBuilderBase already has the seam: StartNewCommand() and CompileCommands() exist precisely for "a provider whose driver cannot execute several statements from one command overrides this to close the current statement and start a new one, so CompileCommands hands back one command per boundary."

SchemaMigration.DetermineAsync does not use it — it calls conn.ExecuteReaderAsync(builder, ct), one command, and walks result sets with NextResultAsync. Making it compile and execute per-command, with ISchemaObject.CreateDeltaAsync reading across the boundary, would let Oracle's ConfigureQueryCommand register the four queries FetchExistingAsync already issues.

Work

  • SchemaMigration.DetermineAsync executes CompileCommands() rather than assuming one command
  • OracleDbCommandBuilder splits on StartNewCommand()
  • Oracle Table.ConfigureQueryCommand registers the index / FK / PK queries
  • Remove the FindDeltaAsync override from Weasel.Oracle.Tests.Tables.index_scenarios — the matrix should pass through the ordinary path

Part of #455.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions