diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2026.08.11__Normalize_metadata_language.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2026.08.11__Normalize_metadata_language.sql new file mode 100644 index 00000000000..66593f23601 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/h2/V7.6_2026.08.11__Normalize_metadata_language.sql @@ -0,0 +1,34 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- ufal/clarin-dspace#1406 +-- +-- Metadata rows written before the 7.6.5 upgrade carry text_lang = '*' (Item.ANY), because the +-- language argument of addMetadata() was passed through verbatim. Since 7.6.5 +-- MetadataValue.setLanguage() normalizes '*' -> NULL on write, so this migration only repairs +-- pre-existing rows; no code path can create new ones. +-- +-- Stale '*' rows break the metadata-export -> metadata-import round trip (the export emits +-- rejected [*] headers) and make OAI store , from which oai_openaire emits an +-- invalid xml:lang="*". +-- +-- Only '*' is normalized. Empty-string languages are legal and round-trip correctly - leave them. + +-- Step 1 must run before step 2: it uses the '*' marker to find the affected items. +-- Bumping last_modified is what makes the reindex happen without a forced full rebuild: +-- `dspace oai import` selects items with last_modified > watermark, and `dspace index-discovery` +-- (no flags) reindexes documents whose search.lastindexed predates last_modified. +UPDATE item SET last_modified = CURRENT_TIMESTAMP + WHERE uuid IN (SELECT dspace_object_id FROM metadatavalue WHERE text_lang = '*'); + +-- Step 2 is deliberately not restricted to items. Rows on collections, communities and +-- bitstreams are normalized too and need no reindex: those tables have no last_modified column, +-- they are not in OAI or in metadata-export, and no indexing path reads the language of a +-- non-item DSO (SolrServiceMetadataBrowseIndexingPlugin bails on non-items, and the container +-- index factories never call getLanguage()). +UPDATE metadatavalue SET text_lang = NULL WHERE text_lang = '*'; diff --git a/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2026.08.11__Normalize_metadata_language.sql b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2026.08.11__Normalize_metadata_language.sql new file mode 100644 index 00000000000..66593f23601 --- /dev/null +++ b/dspace-api/src/main/resources/org/dspace/storage/rdbms/sqlmigration/postgres/V7.6_2026.08.11__Normalize_metadata_language.sql @@ -0,0 +1,34 @@ +-- +-- The contents of this file are subject to the license and copyright +-- detailed in the LICENSE and NOTICE files at the root of the source +-- tree and available online at +-- +-- http://www.dspace.org/license/ +-- + +-- ufal/clarin-dspace#1406 +-- +-- Metadata rows written before the 7.6.5 upgrade carry text_lang = '*' (Item.ANY), because the +-- language argument of addMetadata() was passed through verbatim. Since 7.6.5 +-- MetadataValue.setLanguage() normalizes '*' -> NULL on write, so this migration only repairs +-- pre-existing rows; no code path can create new ones. +-- +-- Stale '*' rows break the metadata-export -> metadata-import round trip (the export emits +-- rejected [*] headers) and make OAI store , from which oai_openaire emits an +-- invalid xml:lang="*". +-- +-- Only '*' is normalized. Empty-string languages are legal and round-trip correctly - leave them. + +-- Step 1 must run before step 2: it uses the '*' marker to find the affected items. +-- Bumping last_modified is what makes the reindex happen without a forced full rebuild: +-- `dspace oai import` selects items with last_modified > watermark, and `dspace index-discovery` +-- (no flags) reindexes documents whose search.lastindexed predates last_modified. +UPDATE item SET last_modified = CURRENT_TIMESTAMP + WHERE uuid IN (SELECT dspace_object_id FROM metadatavalue WHERE text_lang = '*'); + +-- Step 2 is deliberately not restricted to items. Rows on collections, communities and +-- bitstreams are normalized too and need no reindex: those tables have no last_modified column, +-- they are not in OAI or in metadata-export, and no indexing path reads the language of a +-- non-item DSO (SolrServiceMetadataBrowseIndexingPlugin bails on non-items, and the container +-- index factories never call getLanguage()). +UPDATE metadatavalue SET text_lang = NULL WHERE text_lang = '*';