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
Part of #455.
What
On Oracle,
Table.CreateDeltaAsync(DbDataReader)reads columns only. It says so on the method:That is the method
SchemaMigration.DetermineAsynccalls — which is whatApplyChangesAsync,ApplyAllConfiguredChangesToDatabaseAsyncandAssertDatabaseMatchesConfigurationAsyncall 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.
AssertDatabaseMatchesConfigurationAsyncreports a match.Table.FindDeltaAsync(OracleConnection)— which usesFetchExistingAsyncand 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_indexesall along — Weasel just never asked. The matrix now routes Oracle throughFindDeltaAsyncwith a comment pointing here, so the index behaviour is covered while this gap stays visible.The fix
CommandBuilderBasealready has the seam:StartNewCommand()andCompileCommands()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, soCompileCommandshands back one command per boundary."SchemaMigration.DetermineAsyncdoes not use it — it callsconn.ExecuteReaderAsync(builder, ct), one command, and walks result sets withNextResultAsync. Making it compile and execute per-command, withISchemaObject.CreateDeltaAsyncreading across the boundary, would let Oracle'sConfigureQueryCommandregister the four queriesFetchExistingAsyncalready issues.Work
SchemaMigration.DetermineAsyncexecutesCompileCommands()rather than assuming one commandOracleDbCommandBuildersplits onStartNewCommand()Table.ConfigureQueryCommandregisters the index / FK / PK queriesFindDeltaAsyncoverride fromWeasel.Oracle.Tests.Tables.index_scenarios— the matrix should pass through the ordinary pathPart of #455.