Skip to content

test(db): validate manual workaround for string to text conversion on…#61915

Draft
moodyjmz wants to merge 8 commits into
masterfrom
test/oracle-ora22858-workaround-validation
Draft

test(db): validate manual workaround for string to text conversion on…#61915
moodyjmz wants to merge 8 commits into
masterfrom
test/oracle-ora22858-workaround-validation

Conversation

@moodyjmz

@moodyjmz moodyjmz commented Jul 8, 2026

Copy link
Copy Markdown
Contributor

… Oracle

NOT INTENDED TO BE MERGED - VALIDATION TESTING

Two Oracle-only tests (skipped elsewhere) executing against the CI Oracle 18 and 23 containers:

  • testStringToTextConversionWorkaroundOnOracle runs the manual add-copy-drop-rename SQL sequence verbatim, including the DBMS_LOB.COMPARE verification gate and the NOT NULL restore, asserts the data survives byte-for-byte (incl. multibyte), and asserts the resulting column introspects as text so the type guard of Version34000Date20260318095645 no-ops on a re-run of occ upgrade.

  • testChangeStringToTextEmptyTableFailsOnOracle documents that ORA-22858 fires independently of the column's contents, ruling out emptying the table as a workaround.

Scratch branch for empirical validation only, not intended for merge in this form.

Assisted-by: ClaudeCode:claude-fable-5

  • Resolves: #

Summary

TODO

  • ...

Checklist

AI (if applicable)

  • The content of this PR was partly or fully generated using AI

… Oracle

Two Oracle-only tests (skipped elsewhere) executing against the CI
Oracle 18 and 23 containers:

- testStringToTextConversionWorkaroundOnOracle runs the manual
  add-copy-drop-rename SQL sequence verbatim, including the
  DBMS_LOB.COMPARE verification gate and the NOT NULL restore, asserts
  the data survives byte-for-byte (incl. multibyte), and asserts the
  resulting column introspects as text so the type guard of
  Version34000Date20260318095645 no-ops on a re-run of occ upgrade.

- testChangeStringToTextEmptyTableFailsOnOracle documents that
  ORA-22858 fires independently of the column's contents, ruling out
  emptying the table as a workaround.

Scratch branch for empirical validation only, not intended for merge
in this form.

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
@moodyjmz moodyjmz self-assigned this Jul 8, 2026
@moodyjmz moodyjmz requested a review from a team as a code owner July 8, 2026 13:26
@moodyjmz moodyjmz requested review from Altahrim, ArtificialOwl, leftybournes and salmart-dev and removed request for a team July 8, 2026 13:26
@moodyjmz moodyjmz marked this pull request as draft July 8, 2026 13:26
moodyjmz and others added 7 commits July 8, 2026 16:03
On Oracle, Doctrine's listTableColumns() keys columns by their quoted
name, so the plain 'argument' lookup returned null. Go through
OC\DB\SchemaWrapper instead, which is also the interface the real
migration type guard uses.

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
Embeds the PL/SQL block of the customer-facing SQL*Plus script verbatim
and validates it on the CI Oracle containers:

- abort before any change when the backup is not confirmed
- fresh conversion: gate-before-commit copy, column swap, NOT NULL
  restore, data intact byte-for-byte, type guard no-op via SchemaWrapper
- idempotent re-run (already-converted state is a clean no-op)
- resume of a run interrupted between DROP COLUMN and RENAME

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
Fixes from a cold review of the customer script:

- empty input at the backup prompt no longer bypasses the abort
  (TRIM('') is NULL, NULL NOT IN (...) is UNKNOWN): ACCEPT gets a
  DEFAULT 'no' and the check wraps the value in NVL
- a run interrupted between RENAME and the NOT NULL restore is now
  repaired on re-run instead of reported as done (restore_not_null
  runs in the already-converted branch)
- the redo branch only drops an argument2 column of type CLOB; any
  other type aborts as an unexpected state
- the copy column is made NOT NULL before the original is dropped, so
  a straggling writer fails loudly instead of losing a row's argument
- verification gate covers the argument-NULL/argument2-NOT-NULL
  asymmetry; DEFAULT '' is restored on the rebuilt column

The script now lives in tests/data/ and the test reads the PL/SQL
block from it, so CI validates the literal shipped artifact instead
of a manually-synced copy. New coverage: empty-input abort, foreign
argument2 refusal, NOT NULL repair on re-run.

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
…58 script

From a second independent review pass:

- ALTER SESSION SET DDL_LOCK_TIMEOUT = 60 so transient locks are waited
  out instead of failing immediately with ORA-00054
- pre-flight abort when any customer-added index or named constraint
  references the column, since DROP COLUMN would silently remove it;
  the system-generated NOT NULL constraint is excluded
- new test scenario: a named check constraint on the column aborts the
  run with the constraint name in the message

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
Fixes the REUSE compliance check; the PL/SQL block is unchanged.

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
A zero-risk diagnostic script the customer runs before the conversion:
collects the Oracle server version, full column layout, row statistics,
indexes/constraints/triggers/dependencies on the table, mview logs,
flashback enrollment, VPD policies, storage headroom and replication
indicators - degrading gracefully where the schema user lacks
privileges. Turns the runbook's ask-the-customer questions into
collected evidence and covers assumptions the conversion script does
not check itself (triggers, space, server version).

Validated on Oracle 18/23: completes against a real table without
modifying it and against a missing table without throwing.

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
Fixes from a cold review of the diagnostic script:

- version query is now dynamic SQL: product_component_version.version_full
  only exists since 18c, and as static SQL the missing column failed
  compilation of the entire block on 11g/12c - before any exception
  handler could run, collecting zero diagnostics
- table name assignment moved from the DECLARE section into the body so
  initialization errors hit the block's own error handler
- USER_* view handlers no longer claim 'not visible to this user' (the
  owner can always read them): they report the actual error, and the
  row-statistics/storage sections are guarded on table existence, which
  also removes a provably false privilege claim on the missing-table path
- case-sensitivity hint when the table exists in different case
- single scan for row statistics, SYS_NC% note for function-based
  indexes, partitioned-table and autoextend caveats in the storage
  section, error backtrace in the outer handler, LINESIZE/TRIMSPOOL

The test now captures DBMS_OUTPUT and asserts report markers (complete,
found, honest sections) instead of only 'did not throw', which the
script's outer exception handler had made almost unfalsifiable.

Assisted-by: ClaudeCode:claude-fable-5
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Signed-off-by: James Manuel <moodyjmz@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants