Fixes #29492: persist column extensions in bulk entity create path#29495
Fixes #29492: persist column extensions in bulk entity create path#29495ivnvMkhl wants to merge 4 commits into
Conversation
❌ PR checklist incompleteThis PR cannot be merged until the following are addressed on its linked issue:
The fields live on the linked issue in the Shipping project (open the issue → right sidebar → Projects). After you set them, re-run this check (or push a commit) — issue/project changes do not re-trigger it automatically. Maintainers can bypass this check by adding the |
|
Hi there 👋 Thanks for your contribution! The OpenMetadata team will review the PR shortly! Once it has been labeled as Let us know if you need any help! |
🔴 Playwright Results — 4 pipeline/setup failure(s)✅ 0 passed · ❌ 0 failed · 🟡 0 flaky · ⏭️ 0 skipped Pipeline and setup failures
How to debug locally# Download playwright-test-results-<shard> artifact and unzip
npx playwright show-trace path/to/trace.zip # view trace |
|
|
…reate path createManyEntitiesFlushBody called storeExtensions (table-level) but never storeColumnExtensions, so column custom properties were silently dropped on PUT /v1/tables/bulk. The single-entity createNewEntityFlush path was not affected. Mirrors the fix already applied to createNewEntityFlush.
d3b542a to
365ebe5
Compare
|
@ivnvMkhl cna you please add integration-test for this |
Per review feedback (harshach): regression test for open-metadata#29492 covering PUT /v1/tables/bulk. test_tableColumn_bulkCreatePersistsExtension exercises the all-new-FQN path through createManyEntitiesFlushBody and would fail without the storeColumnExtensions fix. Also adds test_tableColumn_bulkUpdatePersistsExtension as a smoke check on the neighboring bulk-update path (existing FQNs go through createOrUpdate per entity, not the batch-create method this PR touches), to guard against regressions there.
|
@harshach Added an integration test — |
|
@gitar-bot Looked into the CSV import path more closely before mirroring the fix there.
Fixing just the repository method without also teaching the CSV format/parser to carry Happy to turn that into a proper issue/PR (plus the CSV format work) if the team wants it prioritized — for now keeping focus on this PR and #29496/#29497. |
Per gitar-bot review: createManyEntitiesForImport and updateManyEntitiesForImport run the same storeEntities/storeExtensions sequence as createManyEntitiesFlushBody (fixed above for open-metadata#29492) but were missing the storeColumnExtensions call. Note: the CSV row schema for entityType=column has no column.extension header today, so every Column parsed from CSV currently has extension == null and this is a no-op in practice — but it brings the two methods in line with their sibling and stops silently dropping column extensions the moment CSV gains that field or any other caller populates it through this path.
|
@gitar-bot Both findings from this review addressed:
|
Code Review 👍 Approved with suggestions 1 resolved / 2 findingsPersists column extensions in bulk creation by mirroring the single-entity persistence logic in 💡 Quality: writeEpochById/writeEpochByName read rather than write📄 openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java:382-390 The new ✅ 1 resolved✅ Bug: CSV import path still drops column custom properties
🤖 Prompt for agentsOptionsDisplay: compact → Showing less information. Comment with these commands to change the behavior for this request:
Was this helpful? React with 👍 / 👎 | Gitar |



Description of Changes
Fixes #29492
createManyEntitiesFlushBody(the bulkPUT /v1/tables/bulkcreate path) calledstoreExtensionsfor table-level custom properties but never calledstoreColumnExtensions, so column-level custom properties were silently dropped on bulk create. The single-entitycreateNewEntityFlushpath was not affected.The fix mirrors what
createNewEntityFlushalready does — iterating entities and callingstoreColumnExtensions(entity.getId(), getColumnsForExtensionPersistence(entity))inside thestoreEntitiesphase.Type of Change
High-level Design
N/A — 3-line change, no architectural impact. Adds the missing
storeColumnExtensionsloop tocreateManyEntitiesFlushBodyto match the single-entity create path.Testing Coverage
PUT /v1/tables/bulk, confirmed properties are persisted inentity_extensionand visible in the Custom Properties tab.storeColumnExtensionscover the logic; no new test infrastructure required for this call-site addition.UI Evidence
Not applicable — backend-only fix.
Checklist
Fixes #<issue>: <description>formatSummary by Gitar
storeColumnExtensionscall tocreateManyEntitiesFlushBodyto ensure column-level custom properties persist during bulk operations.storeColumnExtensionspersistence tocreateManyEntitiesForImportandupdateManyEntitiesForImportto prevent column extension data loss during CSV imports.ColumnCustomPropertiesITcovering bulk creation and bulk updates of tables with column extensions.This will update automatically on new commits.
Greptile Summary
This PR fixes a silent data loss bug where column-level custom properties were dropped on all bulk entity paths. The single-entity
createNewEntityFlushpath already calledstoreColumnExtensions; the three bulk paths (createManyEntitiesFlushBody,createManyEntitiesForImport, andupdateManyEntitiesForImport) were missing this call.storeColumnExtensionsloop tocreateManyEntitiesFlushBody(thePUT /v1/tables/bulkpath),createManyEntitiesForImport(CSV import create), andupdateManyEntitiesForImport(CSV import update), each mirroring the already-correct single-entity path.ColumnCustomPropertiesITcovering bulk create and bulk update of tables with column-level custom properties via thebulkCreateOrUpdateclient method.Confidence Score: 5/5
Safe to merge — the three-line additions are additive, each mirroring a call that already existed and was already tested in the single-entity path.
Each added loop calls
storeColumnExtensions, which is an upsert and a no-op for entity types that do not overridegetColumnsForExtensionPersistence. The change is isolated to the bulk write path, does not alter read logic, and the two new integration tests validate both the create and update scenarios end-to-end.No files require special attention beyond the one minor test assertion noted in
ColumnCustomPropertiesIT.Important Files Changed
storeColumnExtensionsloop in three bulk paths (createManyEntitiesFlushBody, createManyEntitiesForImport, updateManyEntitiesForImport) to match the single-entity create/update behavior; all three previous P1 findings are resolved.getColumns().get(0)in the update test.Sequence Diagram
%%{init: {'theme': 'neutral'}}%% sequenceDiagram participant Client participant BulkAPI as PUT /v1/tables/bulk participant Repo as EntityRepository participant DB as entity_extension Client->>BulkAPI: PUT /v1/tables/bulk [tables with column extensions] BulkAPI->>Repo: createManyEntitiesFlushBody(entities) Repo->>DB: storeEntities(entities) Repo->>DB: storeExtensions(entities) — table-level custom props loop for each entity [NEW] Repo->>DB: storeColumnExtensions(entity.getId(), columns) — column-level custom props end Repo->>DB: storeRelationshipsInternal(entities) BulkAPI-->>Client: 200 OK (column extensions now persisted) note over Repo,DB: Same fix applied to createManyEntitiesForImport (CSV create) and updateManyEntitiesForImport (CSV update)%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%% sequenceDiagram participant Client participant BulkAPI as PUT /v1/tables/bulk participant Repo as EntityRepository participant DB as entity_extension Client->>BulkAPI: PUT /v1/tables/bulk [tables with column extensions] BulkAPI->>Repo: createManyEntitiesFlushBody(entities) Repo->>DB: storeEntities(entities) Repo->>DB: storeExtensions(entities) — table-level custom props loop for each entity [NEW] Repo->>DB: storeColumnExtensions(entity.getId(), columns) — column-level custom props end Repo->>DB: storeRelationshipsInternal(entities) BulkAPI-->>Client: 200 OK (column extensions now persisted) note over Repo,DB: Same fix applied to createManyEntitiesForImport (CSV create) and updateManyEntitiesForImport (CSV update)Comments Outside Diff (3)
openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java, line 3763-3768 (link)createManyEntitiesForImporthas the same missingstoreColumnExtensionscallcreateManyEntitiesForImport(the CSV import path) callsstoreEntities→storeExtensions→storeRelationshipsInternalinside its transaction but never callsstoreColumnExtensions. This is structurally identical to the bug being fixed increateManyEntitiesFlushBody— column-level custom properties will be silently dropped when tables (or dashboard data models) are bulk-created via CSV import, just as they were viaPUT /v1/tables/bulkbefore this patch.openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java, line 3847-3852 (link)createManyEntitiesForImporthas the same missingstoreColumnExtensionscallcreateManyEntitiesForImport(the CSV import path) callsstoreExtensionsbut neverstoreColumnExtensionsinside its transaction. This is structurally identical to the bug fixed increateManyEntitiesFlushBody— column-level custom properties on tables (and dashboard data models) will be silently dropped when entities are bulk-created via CSV import, just as they were viaPUT /v1/tables/bulkbefore this patch.openmetadata-service/src/main/java/org/openmetadata/service/jdbi3/EntityRepository.java, line 3896-3909 (link)updateManyEntitiesForImportdeletes column extensions and never restores themremoveExtensions(originals)callsdeleteAllBatchon each entity's ID, which removes every row inentity_extensionfor that entity — including column-level extensions stored under column FQN hashes.storeExtensions(updatedEntities)then re-writes only entity-level custom properties. Column-level extensions are permanently deleted on every CSV import update, which is structurally worse than the create-side omission fixed in this PR.Reviews (6): Last reviewed commit: "Mirrors storeColumnExtensions into CSV-i..." | Re-trigger Greptile