PHOENIX-4933 DELETE FROM throws NPE when a local index is present.
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/81d679e3 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/81d679e3 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/81d679e3 Branch: refs/heads/4.14-cdh5.13 Commit: 81d679e38c47e2944a9b2fe4296fd8456a898ea6 Parents: a606065 Author: Lars Hofhansl <la...@apache.org> Authored: Mon Oct 1 19:57:44 2018 +0100 Committer: Pedro Boado <pbo...@apache.org> Committed: Wed Oct 17 20:38:39 2018 +0100 ---------------------------------------------------------------------- .../phoenix/end2end/index/LocalIndexIT.java | 22 +++++++++++++++++ .../tuple/EncodedColumnQualiferCellsList.java | 25 +++++++++++++------- 2 files changed, 39 insertions(+), 8 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/81d679e3/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java index 0dcf1d5..796d5a2 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/index/LocalIndexIT.java @@ -78,7 +78,29 @@ public class LocalIndexIT extends BaseLocalIndexIT { public LocalIndexIT(boolean isNamespaceMapped) { super(isNamespaceMapped); } + + @Test + public void testDeleteFromLocalIndex() throws Exception { + String tableName = schemaName + "." + generateUniqueName(); + String indexName = "IDX_" + generateUniqueName(); + Connection conn = getConnection(); + conn.setAutoCommit(true); + if (isNamespaceMapped) { + conn.createStatement().execute("CREATE SCHEMA IF NOT EXISTS " + schemaName); + } + + conn.createStatement().execute("CREATE TABLE " + tableName + " (pk INTEGER PRIMARY KEY, v1 FLOAT, v2 FLOAT)"); + conn.createStatement().execute("CREATE LOCAL INDEX " + indexName + " ON " + tableName + "(v2)"); + conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES(1, rand(), rand())"); + // This would fail with an NPE before PHOENIX-4933 + conn.createStatement().execute("DELETE FROM " + tableName + " WHERE v1 < 1"); + ResultSet rs = conn.createStatement().executeQuery("SELECT COUNT(*) FROM "+tableName); + rs.next(); + assertEquals(0, rs.getInt(1)); + rs.close(); + } + @Test public void testLocalIndexRoundTrip() throws Exception { String tableName = schemaName + "." + generateUniqueName(); http://git-wip-us.apache.org/repos/asf/phoenix/blob/81d679e3/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/EncodedColumnQualiferCellsList.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/EncodedColumnQualiferCellsList.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/EncodedColumnQualiferCellsList.java index 10329fb..db3647d 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/EncodedColumnQualiferCellsList.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/tuple/EncodedColumnQualiferCellsList.java @@ -175,14 +175,7 @@ public class EncodedColumnQualiferCellsList implements List<Cell> { firstNonNullElementIdx = -1; } else if (firstNonNullElementIdx == i) { // the element being removed was the first non-null element we knew - while (i < array.length && (array[i]) == null) { - i++; - } - if (i < array.length) { - firstNonNullElementIdx = i; - } else { - firstNonNullElementIdx = -1; - } + adjustFirstNonNullElement(); } modCount++; return true; @@ -383,6 +376,18 @@ public class EncodedColumnQualiferCellsList implements List<Cell> { return getCellForColumnQualifier(columnQualifier); } + private void adjustFirstNonNullElement() { + int i = firstNonNullElementIdx; + while (i < array.length && (array[i]) == null) { + i++; + } + if (i < array.length) { + firstNonNullElementIdx = i; + } else { + firstNonNullElementIdx = -1; + } + + } private Cell getCellForColumnQualifier(int columnQualifier) { checkQualifierRange(columnQualifier); int idx = getArrayIndex(columnQualifier); @@ -461,6 +466,10 @@ public class EncodedColumnQualiferCellsList implements List<Cell> { } checkForCoModification(); array[lastRet] = null; + if (firstNonNullElementIdx == lastRet) { + // the element being removed was the first non-null element we knew + adjustFirstNonNullElement(); + } lastRet = -1; numNonNullElements--; modCount++;