PHOENIX-2785 Do not store NULLs for immutable tables.

Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo
Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/3a8724ee
Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/3a8724ee
Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/3a8724ee

Branch: refs/heads/calcite
Commit: 3a8724eee05aaf477bf6085415e781856990e1c0
Parents: b65e385
Author: Lars Hofhansl <la...@apache.org>
Authored: Wed Sep 7 14:03:56 2016 -0700
Committer: Lars Hofhansl <la...@apache.org>
Committed: Wed Sep 7 14:11:03 2016 -0700

----------------------------------------------------------------------
 .../apache/phoenix/end2end/StoreNullsIT.java    | 40 +++++++++++++++++++-
 .../org/apache/phoenix/schema/PTableImpl.java   | 13 ++++---
 2 files changed, 47 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/3a8724ee/phoenix-core/src/it/java/org/apache/phoenix/end2end/StoreNullsIT.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StoreNullsIT.java 
b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StoreNullsIT.java
index cbce02e..836418c 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/StoreNullsIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/StoreNullsIT.java
@@ -34,7 +34,6 @@ import org.apache.phoenix.query.QueryServices;
 import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.SchemaUtil;
 import org.junit.After;
-import org.junit.Before;
 import org.junit.BeforeClass;
 import org.junit.Test;
 
@@ -63,6 +62,8 @@ public class StoreNullsIT extends 
BaseHBaseManagedTimeTableReuseIT {
     private static final Log LOG = LogFactory.getLog(StoreNullsIT.class);
     private static final String WITH_NULLS = generateRandomString();
     private static final String WITHOUT_NULLS = generateRandomString();
+    private static final String IMMUTABLE_WITH_NULLS = generateRandomString();
+    private static final String IMMUTABLE_WITHOUT_NULLS = 
generateRandomString();
 
     private static Connection conn;
     private static Statement stmt;
@@ -81,6 +82,12 @@ public class StoreNullsIT extends 
BaseHBaseManagedTimeTableReuseIT {
                         "id SMALLINT NOT NULL PRIMARY KEY, " +
                         "name VARCHAR) " +
                 "VERSIONS = 1000, KEEP_DELETED_CELLS = false");
+        stmt.execute("CREATE TABLE " + IMMUTABLE_WITH_NULLS + " ("
+                + "id SMALLINT NOT NULL PRIMARY KEY, name VARCHAR) "
+                + "STORE_NULLS = true, VERSIONS = 1, KEEP_DELETED_CELLS = 
false, IMMUTABLE_ROWS=true");
+        stmt.execute("CREATE TABLE " + IMMUTABLE_WITHOUT_NULLS + " ("
+                + "id SMALLINT NOT NULL PRIMARY KEY, name VARCHAR) "
+                + "VERSIONS = 1, KEEP_DELETED_CELLS = false, 
IMMUTABLE_ROWS=true");
     }
 
     @After
@@ -90,6 +97,37 @@ public class StoreNullsIT extends 
BaseHBaseManagedTimeTableReuseIT {
     }
 
     @Test
+    public void testStoringNulls() throws SQLException, InterruptedException, 
IOException {
+        stmt.executeUpdate("UPSERT INTO " + IMMUTABLE_WITH_NULLS + " VALUES 
(1, 'v1')");
+        stmt.executeUpdate("UPSERT INTO " + IMMUTABLE_WITHOUT_NULLS + " VALUES 
(1, 'v1')");
+        stmt.executeUpdate("UPSERT INTO " + IMMUTABLE_WITH_NULLS + " VALUES 
(2, null)");
+        stmt.executeUpdate("UPSERT INTO " + IMMUTABLE_WITHOUT_NULLS + " VALUES 
(2, null)");
+
+        ensureNullsNotStored(IMMUTABLE_WITH_NULLS);
+        ensureNullsNotStored(IMMUTABLE_WITHOUT_NULLS);
+    }
+
+    private void ensureNullsNotStored(String tableName) throws IOException {
+        tableName = SchemaUtil.normalizeIdentifier(tableName);
+        HTable htable = new HTable(getUtility().getConfiguration(), tableName);
+        Scan s = new Scan();
+        s.setRaw(true);
+        ResultScanner scanner = htable.getScanner(s);
+        // first row has a value for name
+        Result rs = scanner.next();
+        
assertTrue(rs.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, 
Bytes.toBytes("NAME")));
+        assertTrue(rs.size() == 2);
+        // 2nd row has not
+        rs = scanner.next();
+        
assertFalse(rs.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES, 
Bytes.toBytes("NAME")));
+        // and no delete marker either
+        assertTrue(rs.size() == 1);
+        assertNull(scanner.next());
+        scanner.close();
+        htable.close();
+    }
+
+    @Test
     public void testQueryingHistory() throws SQLException, 
InterruptedException, IOException {
         stmt.executeUpdate("UPSERT INTO " + WITH_NULLS + " VALUES (1, 'v1')");
         stmt.executeUpdate("UPSERT INTO " + WITHOUT_NULLS + " VALUES (1, 
'v1')");

http://git-wip-us.apache.org/repos/asf/phoenix/blob/3a8724ee/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java
----------------------------------------------------------------------
diff --git 
a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java 
b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java
index c485a30..b9cec02 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTableImpl.java
@@ -782,6 +782,7 @@ public class PTableImpl implements PTable {
                     if (Bytes.compareTo(kv.getQualifierArray(), 
kv.getQualifierOffset(), kv.getQualifierLength(),
                           qualifier, 0, qualifier.length) == 0) {
                         iterator.remove();
+                        break;
                     }
                 }
             }
@@ -798,13 +799,15 @@ public class PTableImpl implements PTable {
             deleteRow = null;
             byte[] family = column.getFamilyName().getBytes();
             byte[] qualifier = column.getName().getBytes();
-            PDataType type = column.getDataType();
+            PDataType<?> type = column.getDataType();
             // Check null, since some types have no byte representation for 
null
             boolean isNull = type.isNull(byteValue);
-            if (isNull && !getStoreNulls()) {
-                if (!column.isNullable()) {
-                    throw new ConstraintViolationException(name.getString() + 
"." + column.getName().getString() + " may not be null");
-                }
+            if (isNull && !column.isNullable()) {
+                throw new ConstraintViolationException(name.getString() + "." 
+ column.getName().getString() + " may not be null");
+            } else if (isNull && PTableImpl.this.isImmutableRows()) {
+                removeIfPresent(setValues, family, qualifier);
+                removeIfPresent(unsetValues, family, qualifier);
+            } else if (isNull && !getStoreNulls()) {
                 removeIfPresent(setValues, family, qualifier);
                 deleteQuietly(unsetValues, kvBuilder, 
kvBuilder.buildDeleteColumns(keyPtr, column
                             .getFamilyName().getBytesPtr(), 
column.getName().getBytesPtr(), ts));

Reply via email to