|
36 | 36 | import org.json.JSONException; |
37 | 37 | import org.json.JSONObject; |
38 | 38 | import org.junit.jupiter.api.AfterEach; |
| 39 | +import org.junit.jupiter.api.Assertions; |
39 | 40 | import org.junit.jupiter.api.BeforeEach; |
40 | 41 | import org.junit.jupiter.api.Disabled; |
41 | 42 | import org.junit.jupiter.api.Test; |
@@ -3585,6 +3586,72 @@ public void testTextMatchesWithSearchEnabledOnSchemaChange() throws Exception { |
3585 | 3586 | }); |
3586 | 3587 | } |
3587 | 3588 |
|
| 3589 | + @Test |
| 3590 | + public void testSchemaChangeFromEntityIdToEntityIdListWithNullCell() throws Exception { |
| 3591 | + // PLFM-9706: converting ENTITYID -> ENTITYID_LIST when a row has a null cell |
| 3592 | + // caused the column to be unqueryable because at conversion-time, JSON_ARRAY(NULL) |
| 3593 | + // produces [null], which ListStringParser rejects during the index rebuild. |
| 3594 | + // |
| 3595 | + // If MySQL full text search is enabled on the table, it also enters the PROCESSING_FAILED |
| 3596 | + // state for the same reason. |
| 3597 | + schema = Lists.newArrayList( |
| 3598 | + columnManager.createColumnModel(adminUserInfo, new ColumnModel().setColumnType(ColumnType.STRING).setName("string")), |
| 3599 | + columnManager.createColumnModel(adminUserInfo, new ColumnModel().setColumnType(ColumnType.ENTITYID).setName("id")) |
| 3600 | + ); |
| 3601 | + |
| 3602 | + headers = TableModelUtils.getIds(schema); |
| 3603 | + |
| 3604 | + // Search must be enabled for processing to fail, otherwise it just fails at query-time |
| 3605 | + tableId = asyncHelper.createTable(adminUserInfo, UUID.randomUUID().toString(), projectId, headers, true).getId(); |
| 3606 | + |
| 3607 | + // One row with a real entity-id value, one row with a null cell. |
| 3608 | + List<Row> rows = Arrays.asList( |
| 3609 | + TableModelTestUtils.createRow(null, null, "valuePresent", (String) "syn123"), |
| 3610 | + TableModelTestUtils.createRow(null, null, "valueAbsent", (String) null) |
| 3611 | + ); |
| 3612 | + |
| 3613 | + RowSet rowSet = new RowSet(); |
| 3614 | + rowSet.setRows(rows); |
| 3615 | + rowSet.setHeaders(TableModelUtils.getSelectColumns(schema)); |
| 3616 | + rowSet.setTableId(tableId); |
| 3617 | + |
| 3618 | + referenceSet = appendRows(adminUserInfo, tableId, rowSet, mockProgressCallback); |
| 3619 | + |
| 3620 | + assertEquals(TableState.AVAILABLE, waitForTableProcessing(tableId).getState()); |
| 3621 | + |
| 3622 | + // Change the column type from ENTITYID to ENTITYID_LIST via a TableUpdateTransactionRequest. |
| 3623 | + ColumnModel idListColumn = columnManager.createColumnModel(adminUserInfo, |
| 3624 | + new ColumnModel().setColumnType(ColumnType.ENTITYID_LIST).setName("id")); |
| 3625 | + |
| 3626 | + ColumnChange idColumnChange = new ColumnChange(); |
| 3627 | + idColumnChange.setOldColumnId(schema.get(1).getId()); |
| 3628 | + idColumnChange.setNewColumnId(idListColumn.getId()); |
| 3629 | + |
| 3630 | + TableSchemaChangeRequest schemaChangeRequest = new TableSchemaChangeRequest(); |
| 3631 | + schemaChangeRequest.setChanges(Collections.singletonList(idColumnChange)); |
| 3632 | + schemaChangeRequest.setEntityId(tableId); |
| 3633 | + |
| 3634 | + TableUpdateTransactionRequest transactionRequest = new TableUpdateTransactionRequest(); |
| 3635 | + transactionRequest.setChanges(Collections.singletonList((TableUpdateRequest) schemaChangeRequest)); |
| 3636 | + transactionRequest.setEntityId(tableId); |
| 3637 | + |
| 3638 | + // call under test |
| 3639 | + asyncHelper.assertJobResponse(adminUserInfo, transactionRequest, Assertions::assertNotNull, MAX_WAIT_MS); |
| 3640 | + |
| 3641 | + // The table must reach AVAILABLE, not PROCESSING_FAILED. |
| 3642 | + assertEquals(TableState.AVAILABLE, waitForTableProcessing(tableId).getState()); |
| 3643 | + |
| 3644 | + |
| 3645 | + // Verify the data round-trips correctly: the non-null row should have a |
| 3646 | + // single-element list and the null row should remain null. |
| 3647 | + waitForConsistentQuery(adminUserInfo, "select * from " + tableId + " order by row_id", null, null, (queryResult) -> { |
| 3648 | + List<Row> resultRows = queryResult.getQueryResults().getRows(); |
| 3649 | + assertEquals(2, resultRows.size()); |
| 3650 | + assertEquals("[\"syn123\"]", resultRows.get(0).getValues().get(1), "expected [\"syn123\"] for row with syn123, got: " + resultRows.get(0).getValues().get(1)); |
| 3651 | + assertNull(resultRows.get(1).getValues().get(1)); |
| 3652 | + }); |
| 3653 | + } |
| 3654 | + |
3588 | 3655 | @Test |
3589 | 3656 | public void testWorkerRunInReadOnlyMode() throws Exception { |
3590 | 3657 | asyncHelper.runInReadOnlyMode(()->{ |
|
0 commit comments