You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by td...@apache.org on 2016/05/10 23:05:15 UTC

[1/2] phoenix git commit: PHOENIX-2791 Support append only schema declaration

Repository: phoenix
Updated Branches:
  refs/heads/master a8a3616fe -> a0504fba1


http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/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 076264a..70414d5 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
@@ -140,6 +140,7 @@ public class PTableImpl implements PTable {
     private long updateCacheFrequency;
     private boolean isNamespaceMapped;
     private String autoPartitionSeqName;
+    private boolean isAppendOnlySchema;
 
     public PTableImpl() {
         this.indexes = Collections.emptyList();
@@ -185,7 +186,7 @@ public class PTableImpl implements PTable {
         init(tenantId, this.schemaName, this.tableName, PTableType.INDEX, state, timeStamp, sequenceNumber, pkName, bucketNum, columns,
             PTableStats.EMPTY_STATS, this.schemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
             null, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
-            isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMpped, null);
+            isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMpped, null, false);
     }
 
     public PTableImpl(long timeStamp) { // For delete marker
@@ -228,7 +229,8 @@ public class PTableImpl implements PTable {
                 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), getColumnsToClone(table), parentSchemaName, table.getParentTableName(),
                 indexes, table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), viewStatement,
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
-                table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), 
+                table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTableImpl makePTable(PTable table, List<PColumn> columns) throws SQLException {
@@ -237,7 +239,8 @@ public class PTableImpl implements PTable {
                 table.getSequenceNumber(), table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
                 table.getIndexes(), table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
-                table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(),
+                table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, List<PColumn> columns) throws SQLException {
@@ -246,7 +249,8 @@ public class PTableImpl implements PTable {
                 sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
                 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(), table.isWALDisabled(),
                 table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), table.getTableStats(),
-                table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), 
+                table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, List<PColumn> columns, boolean isImmutableRows) throws SQLException {
@@ -255,7 +259,8 @@ public class PTableImpl implements PTable {
                 sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
                 table.getIndexes(), isImmutableRows, table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(),
-                table.getIndexType(), table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getIndexType(), table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), 
+                table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
     
     public static PTableImpl makePTable(PTable table, long timeStamp, long sequenceNumber, List<PColumn> columns, boolean isImmutableRows, boolean isWalDisabled,
@@ -265,7 +270,8 @@ public class PTableImpl implements PTable {
                 sequenceNumber, table.getPKName(), table.getBucketNum(), columns, table.getParentSchemaName(), table.getParentTableName(),
                 table.getIndexes(), isImmutableRows, table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
                 isWalDisabled, isMultitenant, storeNulls, table.getViewType(), table.getViewIndexId(), table.getIndexType(), table.getTableStats(),
-                table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), isTransactional, updateCacheFrequency, table.getIndexDisableTimestamp(), isNamespaceMapped, table.getAutoPartitionSeqName());
+                table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), isTransactional, updateCacheFrequency, table.getIndexDisableTimestamp(), 
+                isNamespaceMapped, table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
     
     public static PTableImpl makePTable(PTable table, PIndexState state) throws SQLException {
@@ -275,7 +281,8 @@ public class PTableImpl implements PTable {
                 table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
                 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(),
-                table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getTableStats(), table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(),
+                table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTableImpl makePTable(PTable table, boolean rowKeyOrderOptimizable) throws SQLException {
@@ -285,7 +292,8 @@ public class PTableImpl implements PTable {
                 table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
                 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), table.getTableStats(),
-                table.getBaseColumnCount(), rowKeyOrderOptimizable, table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getBaseColumnCount(), rowKeyOrderOptimizable, table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), 
+                table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTableImpl makePTable(PTable table, PTableStats stats) throws SQLException {
@@ -295,7 +303,8 @@ public class PTableImpl implements PTable {
                 table.getParentSchemaName(), table.getParentTableName(), table.getIndexes(),
                 table.isImmutableRows(), table.getPhysicalNames(), table.getDefaultFamilyName(), table.getViewStatement(),
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(), table.getViewIndexId(), table.getIndexType(), stats,
-                table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getBaseColumnCount(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), 
+                table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type,
@@ -304,12 +313,12 @@ public class PTableImpl implements PTable {
             boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression,
             boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
             IndexType indexType, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency,
-            long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName) throws SQLException {
+            long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema) throws SQLException {
         return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns, dataSchemaName,
                 dataTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
                 viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId,
                 indexType, PTableStats.EMPTY_STATS, QueryConstants.BASE_TABLE_BASE_COLUMN_COUNT, rowKeyOrderOptimizable, isTransactional,
-                updateCacheFrequency,indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName);
+                updateCacheFrequency,indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema);
     }
 
     public static PTableImpl makePTable(PName tenantId, PName schemaName, PName tableName, PTableType type,
@@ -318,12 +327,14 @@ public class PTableImpl implements PTable {
             boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression,
             boolean disableWAL, boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
             IndexType indexType, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency,
-            @NotNull PTableStats stats, int baseColumnCount, long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName)
+            @NotNull PTableStats stats, int baseColumnCount, long indexDisableTimestamp, boolean isNamespaceMapped, 
+            String autoPartitionSeqName, boolean isAppendOnlySchema)
             throws SQLException {
         return new PTableImpl(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName,
                 bucketNum, columns, dataSchemaName, dataTableName, indexes, isImmutableRows, physicalNames,
                 defaultFamilyName, viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId,
-                indexType, stats, baseColumnCount, rowKeyOrderOptimizable, isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName);
+                indexType, stats, baseColumnCount, rowKeyOrderOptimizable, isTransactional, updateCacheFrequency, 
+                indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema);
     }
 
     private PTableImpl(PName tenantId, PName schemaName, PName tableName, PTableType type, PIndexState state,
@@ -331,11 +342,12 @@ public class PTableImpl implements PTable {
             PName parentSchemaName, PName parentTableName, List<PTable> indexes, boolean isImmutableRows,
             List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL, boolean multiTenant,
             boolean storeNulls, ViewType viewType, Short viewIndexId, IndexType indexType,
-            PTableStats stats, int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName) throws SQLException {
+            PTableStats stats, int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, 
+            long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema) throws SQLException {
         init(tenantId, schemaName, tableName, type, state, timeStamp, sequenceNumber, pkName, bucketNum, columns,
                 stats, schemaName, parentTableName, indexes, isImmutableRows, physicalNames, defaultFamilyName,
                 viewExpression, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
-                isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName);
+                isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoPartitionSeqName, isAppendOnlySchema);
     }
     
     @Override
@@ -368,7 +380,8 @@ public class PTableImpl implements PTable {
             PName pkName, Integer bucketNum, List<PColumn> columns, PTableStats stats, PName parentSchemaName, PName parentTableName,
             List<PTable> indexes, boolean isImmutableRows, List<PName> physicalNames, PName defaultFamilyName, String viewExpression, boolean disableWAL,
             boolean multiTenant, boolean storeNulls, ViewType viewType, Short viewIndexId,
-            IndexType indexType , int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, long indexDisableTimestamp, boolean isNamespaceMapped, String autoPartitionSeqName) throws SQLException {
+            IndexType indexType , int baseColumnCount, boolean rowKeyOrderOptimizable, boolean isTransactional, long updateCacheFrequency, long indexDisableTimestamp, 
+            boolean isNamespaceMapped, String autoPartitionSeqName, boolean isAppendOnlySchema) throws SQLException {
         Preconditions.checkNotNull(schemaName);
         Preconditions.checkArgument(tenantId==null || tenantId.getBytes().length > 0); // tenantId should be null or not empty
         int estimatedSize = SizedUtil.OBJECT_SIZE * 2 + 23 * SizedUtil.POINTER_SIZE + 4 * SizedUtil.INT_SIZE + 2 * SizedUtil.LONG_SIZE + 2 * SizedUtil.INT_OBJECT_SIZE +
@@ -404,6 +417,7 @@ public class PTableImpl implements PTable {
         this.updateCacheFrequency = updateCacheFrequency;
         this.isNamespaceMapped = isNamespaceMapped;
         this.autoPartitionSeqName = autoPartitionSeqName;
+        this.isAppendOnlySchema = isAppendOnlySchema;
         List<PColumn> pkColumns;
         PColumn[] allColumns;
         
@@ -1110,6 +1124,10 @@ public class PTableImpl implements PTable {
       if (table.hasAutoParititonSeqName()) {
           autoParititonSeqName = table.getAutoParititonSeqName();
       }
+      boolean isAppendOnlySchema = false;
+      if (table.hasIsAppendOnlySchema()) {
+          isAppendOnlySchema = table.getIsAppendOnlySchema();
+      }
       
       try {
         PTableImpl result = new PTableImpl();
@@ -1117,7 +1135,7 @@ public class PTableImpl implements PTable {
             (bucketNum == NO_SALTING) ? null : bucketNum, columns, stats, schemaName,dataTableName, indexes,
             isImmutableRows, physicalNames, defaultFamilyName, viewStatement, disableWAL,
             multiTenant, storeNulls, viewType, viewIndexId, indexType, baseColumnCount, rowKeyOrderOptimizable,
-            isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoParititonSeqName);
+            isTransactional, updateCacheFrequency, indexDisableTimestamp, isNamespaceMapped, autoParititonSeqName, isAppendOnlySchema);
         return result;
       } catch (SQLException e) {
         throw new RuntimeException(e); // Impossible
@@ -1212,6 +1230,7 @@ public class PTableImpl implements PTable {
       if (table.getAutoPartitionSeqName()!= null) {
           builder.setAutoParititonSeqName(table.getAutoPartitionSeqName());
       }
+      builder.setIsAppendOnlySchema(table.isAppendOnlySchema());
       return builder.build();
     }
 
@@ -1255,7 +1274,13 @@ public class PTableImpl implements PTable {
         return isNamespaceMapped;
     }
     
+    @Override
     public String getAutoPartitionSeqName() {
         return autoPartitionSeqName;
     }
+    
+    @Override
+    public boolean isAppendOnlySchema() {
+        return isAppendOnlySchema;
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java
index abfc8a5..7e521e6 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java
@@ -69,9 +69,10 @@ public enum TableProperty {
 	},
 	
 	AUTO_PARTITION_SEQ(PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, false),
+	
+	APPEND_ONLY_SCHEMA(PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, true),
     ;
 
-
 	private final String propertyName;
 	private final SQLExceptionCode colFamSpecifiedException;
 	private final boolean isMutable; // whether or not a property can be changed through statements like ALTER TABLE.

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
index 52c5c71..995f44b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/MetaDataUtil.java
@@ -36,6 +36,7 @@ import java.util.Set;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.Cell;
+import org.apache.hadoop.hbase.HColumnDescriptor;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.HRegionLocation;
 import org.apache.hadoop.hbase.HTableDescriptor;
@@ -69,6 +70,7 @@ import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.schema.SequenceKey;
 import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.TableNotFoundException;
+import org.apache.phoenix.schema.TableProperty;
 import org.apache.phoenix.schema.types.PBoolean;
 import org.apache.phoenix.schema.types.PDataType;
 import org.apache.phoenix.schema.types.PLong;
@@ -533,7 +535,7 @@ public class MetaDataUtil {
     }
 
     public static String getAutoPartitionColumnName(PTable parentTable) {
-        List<PColumn> parentTableColumns = parentTable.getColumns();
+        List<PColumn> parentTableColumns = parentTable.getPKColumns();
         PColumn column = parentTableColumns.get(getAutoPartitionColIndex(parentTable));
         return column.getName().getString();
     }
@@ -555,4 +557,12 @@ public class MetaDataUtil {
             + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + zkClientPort
             + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + zkParentNode;
     }
+
+    public static boolean isHColumnProperty(String propName) {
+        return HColumnDescriptor.getDefaultValues().containsKey(propName);
+    }
+
+    public static boolean isHTableProperty(String propName) {
+        return !isHColumnProperty(propName) && !TableProperty.isPhoenixTableProperty(propName);
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java b/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java
index aaf158a..62aafa5 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/execute/CorrelatePlanTest.java
@@ -256,7 +256,7 @@ public class CorrelatePlanTest {
                     PTableType.SUBQUERY, null, MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM,
                     null, null, columns, null, null, Collections.<PTable>emptyList(),
                     false, Collections.<PName>emptyList(), null, null, false, false, false, null,
-                    null, null, true, false, 0, 0L, Boolean.FALSE, null);
+                    null, null, true, false, 0, 0L, Boolean.FALSE, null, false);
             TableRef sourceTable = new TableRef(pTable);
             List<ColumnRef> sourceColumnRefs = Lists.<ColumnRef> newArrayList();
             for (PColumn column : sourceTable.getTable().getColumns()) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java b/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java
index 04ed6b4..1b16d40 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/execute/LiteralResultIteratorPlanTest.java
@@ -177,7 +177,7 @@ public class LiteralResultIteratorPlanTest {
             PTable pTable = PTableImpl.makePTable(null, PName.EMPTY_NAME, PName.EMPTY_NAME, PTableType.SUBQUERY, null,
                     MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, null, null, columns, null, null,
                     Collections.<PTable> emptyList(), false, Collections.<PName> emptyList(), null, null, false, false,
-                    false, null, null, null, true, false, 0, 0L, false, null);
+                    false, null, null, null, true, false, 0, 0L, false, null, false);
             TableRef sourceTable = new TableRef(pTable);
             List<ColumnRef> sourceColumnRefs = Lists.<ColumnRef> newArrayList();
             for (PColumn column : sourceTable.getTable().getColumns()) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-protocol/src/main/PTable.proto
----------------------------------------------------------------------
diff --git a/phoenix-protocol/src/main/PTable.proto b/phoenix-protocol/src/main/PTable.proto
index 9521fba..2696430 100644
--- a/phoenix-protocol/src/main/PTable.proto
+++ b/phoenix-protocol/src/main/PTable.proto
@@ -92,4 +92,5 @@ message PTable {
   optional int64 indexDisableTimestamp = 29;
   optional bool isNamespaceMapped = 30;
   optional string autoParititonSeqName = 31;
+  optional bool isAppendOnlySchema = 32;
 }


[2/2] phoenix git commit: PHOENIX-2791 Support append only schema declaration

Posted by td...@apache.org.
PHOENIX-2791 Support append only schema declaration


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

Branch: refs/heads/master
Commit: a0504fba12363eaa27ea3fd224671e92cb11a468
Parents: a8a3616
Author: Thomas D'Silva <td...@salesforce.com>
Authored: Thu May 5 15:38:18 2016 -0700
Committer: Thomas D'Silva <tw...@gmail.com>
Committed: Tue May 10 15:10:25 2016 -0700

----------------------------------------------------------------------
 .../phoenix/end2end/AppendOnlySchemaIT.java     | 330 +++++++++++++++++++
 .../phoenix/end2end/AutoPartitionViewsIT.java   |   6 +-
 .../apache/phoenix/compile/FromCompiler.java    |   2 +-
 .../apache/phoenix/compile/JoinCompiler.java    |   3 +-
 .../compile/TupleProjectionCompiler.java        |   5 +-
 .../apache/phoenix/compile/UnionCompiler.java   |   2 +-
 .../coprocessor/MetaDataEndpointImpl.java       |  17 +-
 .../coprocessor/generated/PTableProtos.java     | 103 +++++-
 .../phoenix/exception/SQLExceptionCode.java     |   4 +
 .../phoenix/jdbc/PhoenixDatabaseMetaData.java   |   3 +
 .../org/apache/phoenix/parse/ColumnDef.java     |   7 +-
 .../query/ConnectionQueryServicesImpl.java      |  26 +-
 .../apache/phoenix/query/QueryConstants.java    |   2 +
 .../apache/phoenix/schema/DelegateTable.java    |   6 +
 .../apache/phoenix/schema/MetaDataClient.java   | 203 +++++++++---
 .../java/org/apache/phoenix/schema/PTable.java  |   9 +-
 .../org/apache/phoenix/schema/PTableImpl.java   |  59 +++-
 .../apache/phoenix/schema/TableProperty.java    |   3 +-
 .../org/apache/phoenix/util/MetaDataUtil.java   |  12 +-
 .../phoenix/execute/CorrelatePlanTest.java      |   2 +-
 .../execute/LiteralResultIteratorPlanTest.java  |   2 +-
 phoenix-protocol/src/main/PTable.proto          |   1 +
 22 files changed, 706 insertions(+), 101 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java
new file mode 100644
index 0000000..d764445
--- /dev/null
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java
@@ -0,0 +1,330 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.phoenix.end2end;
+
+import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.Matchers.any;
+import static org.mockito.Matchers.anyList;
+import static org.mockito.Matchers.anyListOf;
+import static org.mockito.Matchers.anyLong;
+import static org.mockito.Matchers.anyMap;
+import static org.mockito.Matchers.eq;
+import static org.mockito.Matchers.isNull;
+import static org.mockito.Mockito.atMost;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
+import static org.mockito.Mockito.verify;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.hadoop.hbase.client.Mutation;
+import org.apache.hadoop.hbase.util.Bytes;
+import org.apache.phoenix.exception.SQLExceptionCode;
+import org.apache.phoenix.jdbc.PhoenixConnection;
+import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver;
+import org.apache.phoenix.query.ConnectionQueryServices;
+import org.apache.phoenix.schema.PColumn;
+import org.apache.phoenix.schema.PName;
+import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTableKey;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.schema.TableAlreadyExistsException;
+import org.apache.phoenix.util.PropertiesUtil;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+public class AppendOnlySchemaIT extends BaseHBaseManagedTimeIT {
+    
+    private void createTableWithSameSchema(boolean notExists, boolean sameClient) throws Exception {
+        // use a spyed ConnectionQueryServices so we can verify calls to getTable
+        ConnectionQueryServices connectionQueryServices =
+                Mockito.spy(driver.getConnectionQueryServices(getUrl(),
+                    PropertiesUtil.deepCopy(TEST_PROPERTIES)));
+        Properties props = new Properties();
+        props.putAll(PhoenixEmbeddedDriver.DEFFAULT_PROPS.asMap());
+
+        try (Connection conn1 = connectionQueryServices.connect(getUrl(), props);
+                Connection conn2 = sameClient ? conn1 : connectionQueryServices.connect(getUrl(), props)) {
+            // create sequence for auto partition
+            conn1.createStatement().execute("CREATE SEQUENCE metric_id_seq CACHE 1");
+            // create base table
+            conn1.createStatement().execute("CREATE TABLE metric_table (metricId INTEGER NOT NULL, metricVal DOUBLE, CONSTRAINT PK PRIMARY KEY(metricId))" 
+                    + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=1, AUTO_PARTITION_SEQ=metric_id_seq");
+            // create view
+            String ddl =
+                    "CREATE VIEW " + (notExists ? "IF NOT EXISTS" : "")
+                            + " view1( hostName varchar NOT NULL,"
+                            + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (hostName))"
+                            + " AS SELECT * FROM metric_table"
+                            + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000";
+            conn1.createStatement().execute(ddl);
+            conn1.createStatement().execute("UPSERT INTO view1(hostName, metricVal) VALUES('host1', 1.0)");
+            conn1.commit();
+            reset(connectionQueryServices);
+
+            // execute same ddl
+            try {
+                conn2.createStatement().execute(ddl);
+                if (!notExists) {
+                    fail("Create Table should fail");
+                }
+            }
+            catch (TableAlreadyExistsException e) {
+                if (notExists) {
+                    fail("Create Table should not fail");
+                }
+            }
+            
+            // verify getTable rpcs
+            verify(connectionQueryServices, sameClient ? never() : atMost(1)).getTable((PName)isNull(), eq(new byte[0]), eq(Bytes.toBytes("VIEW1")), anyLong(), anyLong());
+            
+            // verify create table rpcs
+            verify(connectionQueryServices, never()).createTable(anyListOf(Mutation.class),
+                any(byte[].class), any(PTableType.class), anyMap(), anyList(), any(byte[][].class),
+                eq(false));
+
+            // upsert one row
+            conn2.createStatement().execute("UPSERT INTO view1(hostName, metricVal) VALUES('host2', 2.0)");
+            conn2.commit();
+            // verify data in base table
+            ResultSet rs = conn2.createStatement().executeQuery("SELECT * from metric_table");
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(1.0, rs.getDouble(2), 1e-6);
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(2.0, rs.getDouble(2), 1e-6);
+            assertFalse(rs.next());
+            // verify data in view
+            rs = conn2.createStatement().executeQuery("SELECT * from view1");
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(1.0, rs.getDouble(2), 1e-6);
+            assertEquals("host1", rs.getString(3));
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(2.0, rs.getDouble(2), 1e-6);
+            assertEquals("host2", rs.getString(3));
+            assertFalse(rs.next());
+        }
+    }
+
+    @Test
+    public void testSameSchemaWithNotExistsSameClient() throws Exception {
+        createTableWithSameSchema(true, true);
+    }
+    
+    @Test
+    public void testSameSchemaWithNotExistsDifferentClient() throws Exception {
+        createTableWithSameSchema(true, false);
+    }
+    
+    @Test
+    public void testSameSchemaSameClient() throws Exception {
+        createTableWithSameSchema(false, true);
+    }
+    
+    @Test
+    public void testSameSchemaDifferentClient() throws Exception {
+        createTableWithSameSchema(false, false);
+    }
+
+    private void createTableAddColumns(boolean sameClient) throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        try (Connection conn1 = DriverManager.getConnection(getUrl(), props);
+                Connection conn2 = sameClient ? conn1 : DriverManager.getConnection(getUrl(), props)) {
+            // create sequence for auto partition
+            conn1.createStatement().execute("CREATE SEQUENCE metric_id_seq CACHE 1");
+            // create base table
+            conn1.createStatement().execute("CREATE TABLE metric_table (metricId INTEGER NOT NULL, metricVal DOUBLE, CONSTRAINT PK PRIMARY KEY(metricId))" 
+                    + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=1, AUTO_PARTITION_SEQ=metric_id_seq");
+            // create view
+            String ddl =
+                    "CREATE VIEW IF NOT EXISTS"
+                            + " view1( hostName varchar NOT NULL,"
+                            + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (hostName))"
+                            + " AS SELECT * FROM metric_table"
+                            + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000";
+            conn1.createStatement().execute(ddl);
+            
+            conn1.createStatement().execute("UPSERT INTO view1(hostName, metricVal) VALUES('host1', 1.0)");
+            conn1.commit();
+
+            // execute ddl adding a pk column and regular column
+            ddl =
+                    "CREATE VIEW IF NOT EXISTS"
+                            + " view1( hostName varchar NOT NULL, instanceName varchar, metricVal2 double"
+                            + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (hostName, instancename))"
+                            + " AS SELECT * FROM metric_table"
+                            + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000";
+            conn2.createStatement().execute(ddl);
+
+            conn2.createStatement().execute(
+                "UPSERT INTO view1(hostName, instanceName, metricVal, metricval2) VALUES('host2', 'instance2', 21.0, 22.0)");
+            conn2.commit();
+            
+            conn1.createStatement().execute("UPSERT INTO view1(hostName, metricVal) VALUES('host3', 3.0)");
+            conn1.commit();
+            
+            // verify data exists
+            ResultSet rs = conn2.createStatement().executeQuery("SELECT * from view1");
+            
+            // verify the two columns were added correctly
+            PTable table =
+                    conn2.unwrap(PhoenixConnection.class).getTable(new PTableKey(null, "VIEW1"));
+            List<PColumn> pkColumns = table.getPKColumns();
+            assertEquals(3,table.getPKColumns().size());
+            assertEquals("METRICID", pkColumns.get(0).getName().getString());
+            assertEquals("HOSTNAME", pkColumns.get(1).getName().getString());
+            assertEquals("INSTANCENAME", pkColumns.get(2).getName().getString());
+            List<PColumn> columns = table.getColumns();
+            assertEquals("METRICID", columns.get(0).getName().getString());
+            assertEquals("METRICVAL", columns.get(1).getName().getString());
+            assertEquals("HOSTNAME", columns.get(2).getName().getString());
+            assertEquals("INSTANCENAME", columns.get(3).getName().getString());
+            assertEquals("METRICVAL2", columns.get(4).getName().getString());
+            
+            // verify the data
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(1.0, rs.getDouble(2), 1e-6);
+            assertEquals("host1", rs.getString(3));
+            assertEquals(null, rs.getString(4));
+            assertEquals(0.0, rs.getDouble(5), 1e-6);
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(21.0, rs.getDouble(2), 1e-6);
+            assertEquals("host2", rs.getString(3));
+            assertEquals("instance2", rs.getString(4));
+            assertEquals(22.0, rs.getDouble(5), 1e-6);
+            assertTrue(rs.next());
+            assertEquals(1, rs.getInt(1));
+            assertEquals(3.0, rs.getDouble(2), 1e-6);
+            assertEquals("host3", rs.getString(3));
+            assertEquals(null, rs.getString(4));
+            assertEquals(0.0, rs.getDouble(5), 1e-6);
+            assertFalse(rs.next());
+        }
+    }
+    
+    @Test
+    public void testCreateTableAddColumnsSameClient() throws Exception {
+        createTableAddColumns(true);
+    }
+    
+    @Test
+    public void testCreateTableAddColumnsDifferentClient() throws Exception {
+        createTableAddColumns(false);
+    }
+
+    public void testCreateTableDropColumns() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+            String ddl =
+                    "create table IF NOT EXISTS TEST( id1 char(2) NOT NULL," + " col1 integer,"
+                            + " col2 integer," + " CONSTRAINT NAME_PK PRIMARY KEY (id1))"
+                            + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000";
+            conn.createStatement().execute(ddl);
+            conn.createStatement().execute("UPSERT INTO TEST VALUES('a', 11)");
+            conn.commit();
+
+            // execute ddl while dropping a column
+            ddl = "alter table TEST drop column col1";
+            try {
+                conn.createStatement().execute(ddl);
+                fail("Dropping a column from a table with APPEND_ONLY_SCHEMA=true should fail");
+            } catch (SQLException e) {
+                assertEquals(SQLExceptionCode.CANNOT_DROP_COL_APPEND_ONLY_SCHEMA.getErrorCode(),
+                    e.getErrorCode());
+            }
+        }
+    }
+
+    @Test
+    public void testValidateAttributes() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
+            try {
+                conn.createStatement().execute(
+                    "create table IF NOT EXISTS TEST1 ( id char(1) NOT NULL,"
+                            + " col1 integer NOT NULL,"
+                            + " CONSTRAINT NAME_PK PRIMARY KEY (id, col1))"
+                            + " APPEND_ONLY_SCHEMA = true");
+                fail("UPDATE_CACHE_FREQUENCY attribute must not be set to ALWAYS if APPEND_ONLY_SCHEMA is true");
+            } catch (SQLException e) {
+                assertEquals(SQLExceptionCode.UPDATE_CACHE_FREQUENCY_INVALID.getErrorCode(),
+                    e.getErrorCode());
+            }
+            
+            conn.createStatement().execute(
+                "create table IF NOT EXISTS TEST1 ( id char(1) NOT NULL,"
+                        + " col1 integer NOT NULL"
+                        + " CONSTRAINT NAME_PK PRIMARY KEY (id, col1))"
+                        + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=1000");
+            try {
+                conn.createStatement().execute(
+                    "create view IF NOT EXISTS MY_VIEW (val1 integer NOT NULL) AS SELECT * FROM TEST1"
+                            + " UPDATE_CACHE_FREQUENCY=1000");
+                fail("APPEND_ONLY_SCHEMA must be true for a view if it is true for the base table ");
+            }
+            catch (SQLException e) {
+                assertEquals(SQLExceptionCode.VIEW_APPEND_ONLY_SCHEMA.getErrorCode(),
+                    e.getErrorCode());
+            }
+        }
+    }
+    
+    @Test
+    public void testUpsertRowToDeletedTable() throws Exception {
+        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
+        try (Connection conn1 = DriverManager.getConnection(getUrl(), props);
+                Connection conn2 = DriverManager.getConnection(getUrl(), props)) {
+            // create sequence for auto partition
+            conn1.createStatement().execute("CREATE SEQUENCE metric_id_seq CACHE 1");
+            // create base table
+            conn1.createStatement().execute("CREATE TABLE metric_table (metricId INTEGER NOT NULL, metricVal DOUBLE, CONSTRAINT PK PRIMARY KEY(metricId))" 
+                    + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=1, AUTO_PARTITION_SEQ=metric_id_seq");
+            // create view
+            String ddl =
+                    "CREATE VIEW IF NOT EXISTS"
+                            + " view1( hostName varchar NOT NULL,"
+                            + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (hostName))"
+                            + " AS SELECT * FROM metric_table"
+                            + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000";
+            conn1.createStatement().execute(ddl);
+            
+            // drop the table using a different connection
+            conn2.createStatement().execute("DROP VIEW view1");
+            
+            // upsert one row
+            conn1.createStatement().execute("UPSERT INTO view1(hostName, metricVal) VALUES('host1', 1.0)");
+            // upsert doesn't fail since base table still exists
+            conn1.commit();
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/it/java/org/apache/phoenix/end2end/AutoPartitionViewsIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AutoPartitionViewsIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AutoPartitionViewsIT.java
index 2b3f932..b21b772 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AutoPartitionViewsIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AutoPartitionViewsIT.java
@@ -167,11 +167,11 @@ public class AutoPartitionViewsIT extends BaseHBaseManagedTimeIT {
             assertTrue("Partition column view referenced attribute should be true ",
                 partitionCol3.isViewReferenced());
             // verify viewConstant was set correctly
-            byte[] expectedPartition1 = new byte[Bytes.SIZEOF_LONG + 1];
+            byte[] expectedPartition1 = new byte[Bytes.SIZEOF_INT + 1];
             PInteger.INSTANCE.toBytes(Integer.MAX_VALUE - 2, expectedPartition1, 0);
-            byte[] expectedPartition2 = new byte[Bytes.SIZEOF_LONG + 1];
+            byte[] expectedPartition2 = new byte[Bytes.SIZEOF_INT + 1];
             PInteger.INSTANCE.toBytes(Integer.MAX_VALUE - 1, expectedPartition2, 0);
-            byte[] expectedPartition3 = new byte[Bytes.SIZEOF_LONG + 1];
+            byte[] expectedPartition3 = new byte[Bytes.SIZEOF_INT + 1];
             PInteger.INSTANCE.toBytes(Integer.MAX_VALUE, expectedPartition3, 0);
             assertArrayEquals("Unexpected Partition column view constant attribute",
                 expectedPartition1, partitionCol1.getViewConstant());

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
index 612adae..ca0a6c3 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/FromCompiler.java
@@ -776,7 +776,7 @@ public class FromCompiler {
                     MetaDataProtocol.MIN_TABLE_TIMESTAMP, PTable.INITIAL_SEQ_NUM, null, null, columns, null, null,
                     Collections.<PTable> emptyList(), false, Collections.<PName> emptyList(), null, null, false, false,
                     false, null, null, null, false, false, 0, 0L, SchemaUtil
-                            .isNamespaceMappingEnabled(PTableType.SUBQUERY, connection.getQueryServices().getProps()), null);
+                            .isNamespaceMappingEnabled(PTableType.SUBQUERY, connection.getQueryServices().getProps()), null, false);
 
             String alias = subselectNode.getAlias();
             TableRef tableRef = new TableRef(alias, t, MetaDataProtocol.MIN_TABLE_TIMESTAMP, false);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
index 5317b49..4c18bf8 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/JoinCompiler.java
@@ -1307,7 +1307,8 @@ public class JoinCompiler {
                 left.isImmutableRows(), Collections.<PName> emptyList(), null, null, PTable.DEFAULT_DISABLE_WAL,
                 left.isMultiTenant(), left.getStoreNulls(), left.getViewType(), left.getViewIndexId(),
                 left.getIndexType(), left.rowKeyOrderOptimizable(), left.isTransactional(),
-                left.getUpdateCacheFrequency(), left.getIndexDisableTimestamp(), left.isNamespaceMapped(), left.getAutoPartitionSeqName());
+                left.getUpdateCacheFrequency(), left.getIndexDisableTimestamp(), left.isNamespaceMapped(), 
+                left.getAutoPartitionSeqName(), left.isAppendOnlySchema());
     }
 
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/compile/TupleProjectionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/TupleProjectionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/TupleProjectionCompiler.java
index 8c3d399..4d3c0cf 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/TupleProjectionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/TupleProjectionCompiler.java
@@ -153,7 +153,8 @@ public class TupleProjectionCompiler {
                 table.getParentName(), table.getIndexes(), table.isImmutableRows(), Collections.<PName> emptyList(),
                 null, null, table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(),
                 table.getViewIndexId(),
-                table.getIndexType(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getIndexType(), table.rowKeyOrderOptimizable(), table.isTransactional(), table.getUpdateCacheFrequency(), 
+                table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     public static PTable createProjectedTable(TableRef tableRef, List<ColumnRef> sourceColumnRefs, boolean retainPKColumns) throws SQLException {
@@ -181,7 +182,7 @@ public class TupleProjectionCompiler {
                 Collections.<PTable> emptyList(), table.isImmutableRows(), Collections.<PName> emptyList(), null, null,
                 table.isWALDisabled(), table.isMultiTenant(), table.getStoreNulls(), table.getViewType(),
                 table.getViewIndexId(), null, table.rowKeyOrderOptimizable(), table.isTransactional(),
-                table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName());
+                table.getUpdateCacheFrequency(), table.getIndexDisableTimestamp(), table.isNamespaceMapped(), table.getAutoPartitionSeqName(), table.isAppendOnlySchema());
     }
 
     // For extracting column references from single select statement

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
index 71cd7fc..8dd350c 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/UnionCompiler.java
@@ -85,7 +85,7 @@ public class UnionCompiler {
                 scn == null ? HConstants.LATEST_TIMESTAMP : scn, null, null, projectedColumns, null, null, null, true,
                 null, null, null, true, true, true, null, null, null, false, false, 0, 0L,
                 SchemaUtil.isNamespaceMappingEnabled(PTableType.SUBQUERY,
-                        statement.getConnection().getQueryServices().getProps()), null);
+                        statement.getConnection().getQueryServices().getProps()), null, false);
         TableRef tableRef = new TableRef(null, tempTable, 0, false);
         return tableRef;
     }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
index 25483a3..7f222bb 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataEndpointImpl.java
@@ -20,6 +20,7 @@ package org.apache.phoenix.coprocessor;
 import static com.google.common.base.Preconditions.checkArgument;
 import static com.google.common.base.Preconditions.checkState;
 import static org.apache.hadoop.hbase.KeyValueUtil.createFirstOnRow;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARRAY_SIZE_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.CLASS_NAME_BYTES;
@@ -277,6 +278,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
     private static final KeyValue IS_NAMESPACE_MAPPED_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY,
             TABLE_FAMILY_BYTES, IS_NAMESPACE_MAPPED_BYTES);
     private static final KeyValue AUTO_PARTITION_SEQ_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, AUTO_PARTITION_SEQ_BYTES);
+    private static final KeyValue APPEND_ONLY_SCHEMA_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, APPEND_ONLY_SCHEMA_BYTES);
     
     private static final List<KeyValue> TABLE_KV_COLUMNS = Arrays.<KeyValue>asList(
             EMPTY_KEYVALUE_KV,
@@ -302,7 +304,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
             TRANSACTIONAL_KV,
             UPDATE_CACHE_FREQUENCY_KV,
             IS_NAMESPACE_MAPPED_KV,
-            AUTO_PARTITION_SEQ_KV
+            AUTO_PARTITION_SEQ_KV,
+            APPEND_ONLY_SCHEMA_KV
             );
     static {
         Collections.sort(TABLE_KV_COLUMNS, KeyValue.COMPARATOR);
@@ -331,6 +334,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
     private static final int INDEX_DISABLE_TIMESTAMP = TABLE_KV_COLUMNS.indexOf(INDEX_DISABLE_TIMESTAMP_KV);
     private static final int IS_NAMESPACE_MAPPED_INDEX = TABLE_KV_COLUMNS.indexOf(IS_NAMESPACE_MAPPED_KV);
     private static final int AUTO_PARTITION_SEQ_INDEX = TABLE_KV_COLUMNS.indexOf(AUTO_PARTITION_SEQ_KV);
+    private static final int APPEND_ONLY_SCHEMA_INDEX = TABLE_KV_COLUMNS.indexOf(APPEND_ONLY_SCHEMA_KV);
 
     // KeyValues for Column
     private static final KeyValue DECIMAL_DIGITS_KV = createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, DECIMAL_DIGITS_BYTES);
@@ -914,6 +918,11 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
         Cell autoPartitionSeqKv = tableKeyValues[AUTO_PARTITION_SEQ_INDEX];
         String autoPartitionSeq = autoPartitionSeqKv != null ? (String) PVarchar.INSTANCE.toObject(autoPartitionSeqKv.getValueArray(), autoPartitionSeqKv.getValueOffset(),
             autoPartitionSeqKv.getValueLength()) : null;
+        Cell isAppendOnlySchemaKv = tableKeyValues[APPEND_ONLY_SCHEMA_INDEX];
+        boolean isAppendOnlySchema = isAppendOnlySchemaKv == null ? false
+                : Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(isAppendOnlySchemaKv.getValueArray(),
+                    isAppendOnlySchemaKv.getValueOffset(), isAppendOnlySchemaKv.getValueLength()));
+        
         
         List<PColumn> columns = Lists.newArrayListWithExpectedSize(columnCount);
         List<PTable> indexes = new ArrayList<PTable>();
@@ -964,7 +973,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                 tableType == INDEX ? dataTableName : null, indexes, isImmutableRows, physicalTables, defaultFamilyName,
                 viewStatement, disableWAL, multiTenant, storeNulls, viewType, viewIndexId, indexType,
                 rowKeyOrderOptimizable, transactional, updateCacheFrequency, stats, baseColumnCount,
-                indexDisableTimestamp, isNamespaceMapped, autoPartitionSeq);
+                indexDisableTimestamp, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema);
     }
 
     private PSchema getSchema(RegionScanner scanner, long clientTimeStamp) throws IOException, SQLException {
@@ -1453,7 +1462,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                         done.run(builder.build());
                         return;
                     }
-                    PColumn autoPartitionCol = parentTable.getColumns().get(MetaDataUtil.getAutoPartitionColIndex(parentTable));
+                    PColumn autoPartitionCol = parentTable.getPKColumns().get(MetaDataUtil.getAutoPartitionColIndex(parentTable));
                     if (!PLong.INSTANCE.isCoercibleTo(autoPartitionCol.getDataType(), autoPartitionNum)) {
                         builder.setReturnCode(MetaDataProtos.MutationCode.CANNOT_COERCE_AUTO_PARTITION_ID);
                         builder.setMutationTime(EnvironmentEdgeManager.currentTimeMillis());
@@ -1490,9 +1499,9 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                     familyCellMap = autoPartitionPut.getFamilyCellMap();
                     cells = familyCellMap.get(TABLE_FAMILY_BYTES);
                     cell = cells.get(0);
-                    byte[] bytes = new byte [Bytes.SIZEOF_LONG + 1];
                     PDataType dataType = autoPartitionCol.getDataType();
                     Object val = dataType.toObject(autoPartitionNum, PLong.INSTANCE);
+                    byte[] bytes = new byte [dataType.getByteSize() + 1];
                     dataType.toBytes(val, bytes, 0);
                     Cell viewConstantCell = new KeyValue(cell.getRow(), cell.getFamily(), VIEW_CONSTANT_BYTES,
                         cell.getTimestamp(), Type.codeToType(cell.getTypeByte()), bytes);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/PTableProtos.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/PTableProtos.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/PTableProtos.java
index fca181d..4171680 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/PTableProtos.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/generated/PTableProtos.java
@@ -3363,6 +3363,16 @@ public final class PTableProtos {
      */
     com.google.protobuf.ByteString
         getAutoParititonSeqNameBytes();
+
+    // optional bool isAppendOnlySchema = 32;
+    /**
+     * <code>optional bool isAppendOnlySchema = 32;</code>
+     */
+    boolean hasIsAppendOnlySchema();
+    /**
+     * <code>optional bool isAppendOnlySchema = 32;</code>
+     */
+    boolean getIsAppendOnlySchema();
   }
   /**
    * Protobuf type {@code PTable}
@@ -3588,6 +3598,11 @@ public final class PTableProtos {
               autoParititonSeqName_ = input.readBytes();
               break;
             }
+            case 256: {
+              bitField0_ |= 0x08000000;
+              isAppendOnlySchema_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -4257,6 +4272,22 @@ public final class PTableProtos {
       }
     }
 
+    // optional bool isAppendOnlySchema = 32;
+    public static final int ISAPPENDONLYSCHEMA_FIELD_NUMBER = 32;
+    private boolean isAppendOnlySchema_;
+    /**
+     * <code>optional bool isAppendOnlySchema = 32;</code>
+     */
+    public boolean hasIsAppendOnlySchema() {
+      return ((bitField0_ & 0x08000000) == 0x08000000);
+    }
+    /**
+     * <code>optional bool isAppendOnlySchema = 32;</code>
+     */
+    public boolean getIsAppendOnlySchema() {
+      return isAppendOnlySchema_;
+    }
+
     private void initFields() {
       schemaNameBytes_ = com.google.protobuf.ByteString.EMPTY;
       tableNameBytes_ = com.google.protobuf.ByteString.EMPTY;
@@ -4289,6 +4320,7 @@ public final class PTableProtos {
       indexDisableTimestamp_ = 0L;
       isNamespaceMapped_ = false;
       autoParititonSeqName_ = "";
+      isAppendOnlySchema_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -4449,6 +4481,9 @@ public final class PTableProtos {
       if (((bitField0_ & 0x04000000) == 0x04000000)) {
         output.writeBytes(31, getAutoParititonSeqNameBytes());
       }
+      if (((bitField0_ & 0x08000000) == 0x08000000)) {
+        output.writeBool(32, isAppendOnlySchema_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -4587,6 +4622,10 @@ public final class PTableProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeBytesSize(31, getAutoParititonSeqNameBytes());
       }
+      if (((bitField0_ & 0x08000000) == 0x08000000)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(32, isAppendOnlySchema_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -4753,6 +4792,11 @@ public final class PTableProtos {
         result = result && getAutoParititonSeqName()
             .equals(other.getAutoParititonSeqName());
       }
+      result = result && (hasIsAppendOnlySchema() == other.hasIsAppendOnlySchema());
+      if (hasIsAppendOnlySchema()) {
+        result = result && (getIsAppendOnlySchema()
+            == other.getIsAppendOnlySchema());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -4890,6 +4934,10 @@ public final class PTableProtos {
         hash = (37 * hash) + AUTOPARITITONSEQNAME_FIELD_NUMBER;
         hash = (53 * hash) + getAutoParititonSeqName().hashCode();
       }
+      if (hasIsAppendOnlySchema()) {
+        hash = (37 * hash) + ISAPPENDONLYSCHEMA_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getIsAppendOnlySchema());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -5076,6 +5124,8 @@ public final class PTableProtos {
         bitField0_ = (bitField0_ & ~0x20000000);
         autoParititonSeqName_ = "";
         bitField0_ = (bitField0_ & ~0x40000000);
+        isAppendOnlySchema_ = false;
+        bitField0_ = (bitField0_ & ~0x80000000);
         return this;
       }
 
@@ -5244,6 +5294,10 @@ public final class PTableProtos {
           to_bitField0_ |= 0x04000000;
         }
         result.autoParititonSeqName_ = autoParititonSeqName_;
+        if (((from_bitField0_ & 0x80000000) == 0x80000000)) {
+          to_bitField0_ |= 0x08000000;
+        }
+        result.isAppendOnlySchema_ = isAppendOnlySchema_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -5433,6 +5487,9 @@ public final class PTableProtos {
           autoParititonSeqName_ = other.autoParititonSeqName_;
           onChanged();
         }
+        if (other.hasIsAppendOnlySchema()) {
+          setIsAppendOnlySchema(other.getIsAppendOnlySchema());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -7309,6 +7366,39 @@ public final class PTableProtos {
         return this;
       }
 
+      // optional bool isAppendOnlySchema = 32;
+      private boolean isAppendOnlySchema_ ;
+      /**
+       * <code>optional bool isAppendOnlySchema = 32;</code>
+       */
+      public boolean hasIsAppendOnlySchema() {
+        return ((bitField0_ & 0x80000000) == 0x80000000);
+      }
+      /**
+       * <code>optional bool isAppendOnlySchema = 32;</code>
+       */
+      public boolean getIsAppendOnlySchema() {
+        return isAppendOnlySchema_;
+      }
+      /**
+       * <code>optional bool isAppendOnlySchema = 32;</code>
+       */
+      public Builder setIsAppendOnlySchema(boolean value) {
+        bitField0_ |= 0x80000000;
+        isAppendOnlySchema_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool isAppendOnlySchema = 32;</code>
+       */
+      public Builder clearIsAppendOnlySchema() {
+        bitField0_ = (bitField0_ & ~0x80000000);
+        isAppendOnlySchema_ = false;
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:PTable)
     }
 
@@ -7356,7 +7446,7 @@ public final class PTableProtos {
       "\016\n\006values\030\002 \003(\014\022\033\n\023guidePostsByteCount\030\003",
       " \001(\003\022\025\n\rkeyBytesCount\030\004 \001(\003\022\027\n\017guidePost" +
       "sCount\030\005 \001(\005\022!\n\013pGuidePosts\030\006 \001(\0132\014.PGui" +
-      "dePosts\"\374\005\n\006PTable\022\027\n\017schemaNameBytes\030\001 " +
+      "dePosts\"\230\006\n\006PTable\022\027\n\017schemaNameBytes\030\001 " +
       "\002(\014\022\026\n\016tableNameBytes\030\002 \002(\014\022\036\n\ttableType" +
       "\030\003 \002(\0162\013.PTableType\022\022\n\nindexState\030\004 \001(\t\022" +
       "\026\n\016sequenceNumber\030\005 \002(\003\022\021\n\ttimeStamp\030\006 \002" +
@@ -7375,10 +7465,11 @@ public final class PTableProtos {
       "nsactional\030\033 \001(\010\022\034\n\024updateCacheFrequency" +
       "\030\034 \001(\003\022\035\n\025indexDisableTimestamp\030\035 \001(\003\022\031\n",
       "\021isNamespaceMapped\030\036 \001(\010\022\034\n\024autoParitito" +
-      "nSeqName\030\037 \001(\t*A\n\nPTableType\022\n\n\006SYSTEM\020\000" +
-      "\022\010\n\004USER\020\001\022\010\n\004VIEW\020\002\022\t\n\005INDEX\020\003\022\010\n\004JOIN\020" +
-      "\004B@\n(org.apache.phoenix.coprocessor.gene" +
-      "ratedB\014PTableProtosH\001\210\001\001\240\001\001"
+      "nSeqName\030\037 \001(\t\022\032\n\022isAppendOnlySchema\030  \001" +
+      "(\010*A\n\nPTableType\022\n\n\006SYSTEM\020\000\022\010\n\004USER\020\001\022\010" +
+      "\n\004VIEW\020\002\022\t\n\005INDEX\020\003\022\010\n\004JOIN\020\004B@\n(org.apa" +
+      "che.phoenix.coprocessor.generatedB\014PTabl" +
+      "eProtosH\001\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -7402,7 +7493,7 @@ public final class PTableProtos {
           internal_static_PTable_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_PTable_descriptor,
-              new java.lang.String[] { "SchemaNameBytes", "TableNameBytes", "TableType", "IndexState", "SequenceNumber", "TimeStamp", "PkNameBytes", "BucketNum", "Columns", "Indexes", "IsImmutableRows", "GuidePosts", "DataTableNameBytes", "DefaultFamilyName", "DisableWAL", "MultiTenant", "ViewType", "ViewStatement", "PhysicalNames", "TenantId", "ViewIndexId", "IndexType", "StatsTimeStamp", "StoreNulls", "BaseColumnCount", "RowKeyOrderOptimizable", "Transactional", "UpdateCacheFrequency", "IndexDisableTimestamp", "IsNamespaceMapped", "AutoParititonSeqName", });
+              new java.lang.String[] { "SchemaNameBytes", "TableNameBytes", "TableType", "IndexState", "SequenceNumber", "TimeStamp", "PkNameBytes", "BucketNum", "Columns", "Indexes", "IsImmutableRows", "GuidePosts", "DataTableNameBytes", "DefaultFamilyName", "DisableWAL", "MultiTenant", "ViewType", "ViewStatement", "PhysicalNames", "TenantId", "ViewIndexId", "IndexType", "StatsTimeStamp", "StoreNulls", "BaseColumnCount", "RowKeyOrderOptimizable", "Transactional", "UpdateCacheFrequency", "IndexDisableTimestamp", "IsNamespaceMapped", "AutoParititonSeqName", "IsAppendOnlySchema", });
           return null;
         }
       };

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
index 5661098..8064ce1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
@@ -351,6 +351,10 @@ public enum SQLExceptionCode {
     CANNOT_SALT_LOCAL_INDEX(1110,"XCL10", "Local index may not be salted."),
 
     INDEX_FAILURE_BLOCK_WRITE(1120, "XCL20", "Writes to table blocked until index can be updated."),
+    
+    UPDATE_CACHE_FREQUENCY_INVALID(1130, "XCL30", "UPDATE_CACHE_FREQUENCY cannot be set to ALWAYS if APPEND_ONLY_SCHEMA is true."),
+    CANNOT_DROP_COL_APPEND_ONLY_SCHEMA(1131, "XCL31", "Cannot drop column from table that with append only schema."),
+    VIEW_APPEND_ONLY_SCHEMA(1132, "XCL32", "APPEND_ONLY_SCHEMA property of view must match the base table"),
 
     /**
      * Implementation defined class. Phoenix internal error. (errorcode 20, sqlstate INT).

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
index c571625..344fc3e 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java
@@ -295,6 +295,9 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData {
     public static final String AUTO_PARTITION_SEQ = "AUTO_PARTITION_SEQ";
     public static final byte[] AUTO_PARTITION_SEQ_BYTES = Bytes.toBytes(AUTO_PARTITION_SEQ);
     
+    public static final String APPEND_ONLY_SCHEMA = "APPEND_ONLY_SCHEMA";
+    public static final byte[] APPEND_ONLY_SCHEMA_BYTES = Bytes.toBytes(APPEND_ONLY_SCHEMA);
+    
     public static final String ASYNC_CREATED_DATE = "ASYNC_CREATED_DATE";
 
     private final PhoenixConnection connection;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
index 278b4aa..401d57b 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ColumnDef.java
@@ -43,7 +43,7 @@ public class ColumnDef {
     private final Boolean isNull;
     private final Integer maxLength;
     private final Integer scale;
-    private final boolean isPK;
+    private boolean isPK;
     private final SortOrder sortOrder;
     private final boolean isArray;
     private final Integer arrSize;
@@ -185,6 +185,11 @@ public class ColumnDef {
     public boolean isRowTimestamp() {
         return isRowTimestamp;
     }
+    
+    public void setIsPK(boolean isPK) {
+        this.isPK = isPK;
+    }
+    
     @Override
     public String toString() {
         StringBuilder buf = new StringBuilder(columnDefName.getColumnNode().toString());

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
index 667d89c..931ecfc 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java
@@ -195,6 +195,12 @@ import org.apache.twill.zookeeper.ZKClients;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
+import co.cask.tephra.TransactionSystemClient;
+import co.cask.tephra.TxConstants;
+import co.cask.tephra.distributed.PooledClientProvider;
+import co.cask.tephra.distributed.TransactionServiceClient;
+import co.cask.tephra.zookeeper.TephraZKClientService;
+
 import com.google.common.annotations.VisibleForTesting;
 import com.google.common.base.Joiner;
 import com.google.common.base.Throwables;
@@ -208,12 +214,6 @@ import com.google.common.collect.Maps;
 import com.google.common.collect.Sets;
 import com.google.common.util.concurrent.ThreadFactoryBuilder;
 
-import co.cask.tephra.TransactionSystemClient;
-import co.cask.tephra.TxConstants;
-import co.cask.tephra.distributed.PooledClientProvider;
-import co.cask.tephra.distributed.TransactionServiceClient;
-import co.cask.tephra.zookeeper.TephraZKClientService;
-
 public class ConnectionQueryServicesImpl extends DelegateQueryServices implements ConnectionQueryServices {
     private static final Logger logger = LoggerFactory.getLogger(ConnectionQueryServicesImpl.class);
     private static final int INITIAL_CHILD_SERVICES_CAPACITY = 100;
@@ -1937,13 +1937,13 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
                 for (Pair<String, Object> prop : propsList) {
                     String propName = prop.getFirst();
                     Object propValue = prop.getSecond();
-                    if ((isHTableProperty(propName) ||  TableProperty.isPhoenixTableProperty(propName)) && addingColumns) {
+                    if ((MetaDataUtil.isHTableProperty(propName) ||  TableProperty.isPhoenixTableProperty(propName)) && addingColumns) {
                         // setting HTable and PhoenixTable properties while adding a column is not allowed.
                         throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_SET_TABLE_PROPERTY_ADD_COLUMN)
                         .setMessage("Property: " + propName).build()
                         .buildException();
                     }
-                    if (isHTableProperty(propName)) {
+                    if (MetaDataUtil.isHTableProperty(propName)) {
                         // Can't have a column family name for a property that's an HTableProperty
                         if (!family.equals(QueryConstants.ALL_FAMILY_PROPERTIES_KEY)) {
                             throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY)
@@ -1964,7 +1964,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
                                 tableProps.put(TxConstants.READ_NON_TX_DATA, propValue);
                             }
                         } else {
-                            if (isHColumnProperty(propName)) {
+                            if (MetaDataUtil.isHColumnProperty(propName)) {
                                 if (family.equals(QueryConstants.ALL_FAMILY_PROPERTIES_KEY)) {
                                     commonFamilyProps.put(propName, propValue);
                                 } else {
@@ -2170,14 +2170,6 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement
         }
     }
     
-    private boolean isHColumnProperty(String propName) {
-        return HColumnDescriptor.getDefaultValues().containsKey(propName);
-    }
-
-    private boolean isHTableProperty(String propName) {
-        return !isHColumnProperty(propName) && !TableProperty.isPhoenixTableProperty(propName);
-    } 
-    
     private HashSet<String> existingColumnFamiliesForBaseTable(PName baseTableName) throws TableNotFoundException {
         synchronized (latestMetaDataLock) {
             throwConnectionClosedIfNullMetaData();

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java
index 5c7ac1a..4efb708 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryConstants.java
@@ -18,6 +18,7 @@
 package org.apache.phoenix.query;
 
 
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARG_POSITION;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARRAY_SIZE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ;
@@ -269,6 +270,7 @@ public interface QueryConstants {
             UPDATE_CACHE_FREQUENCY + " BIGINT," +
             IS_NAMESPACE_MAPPED + " BOOLEAN," +
             AUTO_PARTITION_SEQ + " VARCHAR," +
+            APPEND_ONLY_SCHEMA + " BOOLEAN," +
             "CONSTRAINT " + SYSTEM_TABLE_PK_NAME + " PRIMARY KEY (" + TENANT_ID + ","
             + TABLE_SCHEM + "," + TABLE_NAME + "," + COLUMN_NAME + "," + COLUMN_FAMILY + "))\n" +
             HConstants.VERSIONS + "=" + MetaDataProtocol.DEFAULT_MAX_META_DATA_VERSIONS + ",\n" +

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java
index f1a7548..ddd2de0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateTable.java
@@ -277,7 +277,13 @@ public class DelegateTable implements PTable {
         return delegate.isNamespaceMapped();
     }
 
+    @Override
     public String getAutoPartitionSeqName() {
         return delegate.getAutoPartitionSeqName();
     }
+    
+    @Override
+    public boolean isAppendOnlySchema() {
+        return delegate.isAppendOnlySchema();
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
index 95fde4b..2658174 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java
@@ -24,6 +24,7 @@ import static org.apache.hadoop.hbase.HColumnDescriptor.TTL;
 import static org.apache.phoenix.coprocessor.BaseScannerRegionObserver.ANALYZE_TABLE;
 import static org.apache.phoenix.coprocessor.BaseScannerRegionObserver.RUN_UPDATE_STATS_ASYNC_ATTRIB;
 import static org.apache.phoenix.exception.SQLExceptionCode.INSUFFICIENT_MULTI_TENANT_COLUMNS;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARG_POSITION;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ARRAY_SIZE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.ASYNC_CREATED_DATE;
@@ -259,8 +260,9 @@ public class MetaDataClient {
             TRANSACTIONAL + "," +
             UPDATE_CACHE_FREQUENCY + "," +
             IS_NAMESPACE_MAPPED + "," +
-            AUTO_PARTITION_SEQ +
-            ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+            AUTO_PARTITION_SEQ +  "," +
+            APPEND_ONLY_SCHEMA +
+            ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
 
     private static final String CREATE_SCHEMA = "UPSERT INTO " + SYSTEM_CATALOG_SCHEMA + ".\"" + SYSTEM_CATALOG_TABLE
             + "\"( " + TABLE_SCHEM + "," + TABLE_NAME + ") VALUES (?,?)";
@@ -863,7 +865,87 @@ public class MetaDataClient {
     }
 
     public MutationState createTable(CreateTableStatement statement, byte[][] splits, PTable parent, String viewStatement, ViewType viewType, byte[][] viewColumnConstants, BitSet isViewColumnReferenced) throws SQLException {
-        PTable table = createTableInternal(statement, splits, parent, viewStatement, viewType, viewColumnConstants, isViewColumnReferenced, null, null, null);
+        TableName tableName = statement.getTableName();
+        Map<String,Object> tableProps = Maps.newHashMapWithExpectedSize(statement.getProps().size());
+        Map<String,Object> commonFamilyProps = Maps.newHashMapWithExpectedSize(statement.getProps().size() + 1);
+        populatePropertyMaps(statement.getProps(), tableProps, commonFamilyProps);
+        
+        boolean isAppendOnlySchema = false;
+        Boolean appendOnlySchemaProp = (Boolean) TableProperty.APPEND_ONLY_SCHEMA.getValue(tableProps);
+        if (appendOnlySchemaProp != null) {
+            isAppendOnlySchema = appendOnlySchemaProp;
+        }
+        long updateCacheFrequency = 0;
+        Long updateCacheFrequencyProp = (Long) TableProperty.UPDATE_CACHE_FREQUENCY.getValue(tableProps);
+        if (updateCacheFrequencyProp != null) {
+            updateCacheFrequency = updateCacheFrequencyProp;
+        }
+        // updateCacheFrequency cannot be set to ALWAYS if isAppendOnlySchema is true
+        if (isAppendOnlySchema && updateCacheFrequency==0) {
+            throw new SQLExceptionInfo.Builder(SQLExceptionCode.UPDATE_CACHE_FREQUENCY_INVALID)
+            .setSchemaName(tableName.getSchemaName()).setTableName(tableName.getTableName())
+            .build().buildException();
+        }
+        // view isAppendOnlySchema property must match the parent table 
+        if (parent!=null && isAppendOnlySchema!= parent.isAppendOnlySchema()) {
+            throw new SQLExceptionInfo.Builder(SQLExceptionCode.VIEW_APPEND_ONLY_SCHEMA)
+            .setSchemaName(tableName.getSchemaName()).setTableName(tableName.getTableName())
+            .build().buildException();
+        }
+        
+        PTable table = null;
+        // if the APPEND_ONLY_SCHEMA attribute is true first check if the table is present in the cache
+        // if it is add columns that are not already present
+        if (isAppendOnlySchema) {
+            // look up the table in the cache 
+            MetaDataMutationResult result = updateCache(tableName.getSchemaName(), tableName.getTableName());
+            if (result.getMutationCode()==MutationCode.TABLE_ALREADY_EXISTS) {
+                table = result.getTable();
+                if (!statement.ifNotExists()) {
+                    throw new NewerTableAlreadyExistsException(tableName.getSchemaName(), tableName.getTableName(), table);
+                }
+                
+                List<ColumnDef> columnDefs = statement.getColumnDefs();
+                PrimaryKeyConstraint pkConstraint = statement.getPrimaryKeyConstraint();
+                // get the list of columns to add
+                List<ColumnDef> newColumnDefs = Lists.newArrayList();
+                for (ColumnDef columnDef : columnDefs) {
+                    if (pkConstraint.contains(columnDef.getColumnDefName())) {
+                        columnDef.setIsPK(true);
+                    }
+                    String familyName = columnDef.getColumnDefName().getFamilyName();
+                    String columnName = columnDef.getColumnDefName().getColumnName();
+                    if (familyName!=null) {
+                        try {
+                            PColumnFamily columnFamily = table.getColumnFamily(familyName);
+                            columnFamily.getColumn(columnName);
+                        }
+                        catch (ColumnFamilyNotFoundException | ColumnNotFoundException e){
+                            newColumnDefs.add(columnDef);
+                        }
+                    }
+                    else {
+                        try {
+                            table.getColumn(columnName);
+                        }
+                        catch (ColumnNotFoundException e){
+                            newColumnDefs.add(columnDef);
+                        }
+                    }
+                }
+                // if there are new columns to add 
+                if (!newColumnDefs.isEmpty()) {
+                    return addColumn(table, newColumnDefs, statement.getProps(),
+                        statement.ifNotExists(), true,
+                        NamedTableNode.create(statement.getTableName()), statement.getTableType());
+                }
+                else {
+                    return new MutationState(0,connection);
+                }
+            }
+        }
+        table = createTableInternal(statement, splits, parent, viewStatement, viewType, viewColumnConstants, isViewColumnReferenced, null, null, null, tableProps, commonFamilyProps);
+            
         if (table == null || table.getType() == PTableType.VIEW || table.isTransactional()) {
             return new MutationState(0,connection);
         }
@@ -883,6 +965,22 @@ public class MetaDataClient {
         return connection.getQueryServices().updateData(plan);
     }
 
+    private void populatePropertyMaps(ListMultimap<String,Pair<String,Object>> props, Map<String, Object> tableProps,
+            Map<String, Object> commonFamilyProps) {
+        // Somewhat hacky way of determining if property is for HColumnDescriptor or HTableDescriptor
+        HColumnDescriptor defaultDescriptor = new HColumnDescriptor(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES);
+        if (!props.isEmpty()) {
+            Collection<Pair<String,Object>> propsList = props.get(QueryConstants.ALL_FAMILY_PROPERTIES_KEY);
+            for (Pair<String,Object> prop : propsList) {
+                if (defaultDescriptor.getValue(prop.getFirst()) == null) {
+                    tableProps.put(prop.getFirst(), prop.getSecond());
+                } else {
+                    commonFamilyProps.put(prop.getFirst(), prop.getSecond());
+                }
+            }
+        }
+    }
+
     public MutationState updateStatistics(UpdateStatisticsStatement updateStatisticsStmt)
             throws SQLException {
         // Don't mistakenly commit pending rows
@@ -1160,11 +1258,14 @@ public class MetaDataClient {
         IndexKeyConstraint ik = statement.getIndexConstraint();
         TableName indexTableName = statement.getIndexTableName();
         
+        Map<String,Object> tableProps = Maps.newHashMapWithExpectedSize(statement.getProps().size());
+        Map<String,Object> commonFamilyProps = Maps.newHashMapWithExpectedSize(statement.getProps().size() + 1);
+        populatePropertyMaps(statement.getProps(), tableProps, commonFamilyProps);
         List<Pair<ParseNode, SortOrder>> indexParseNodeAndSortOrderList = ik.getParseNodeAndSortOrderList();
         List<ColumnName> includedColumns = statement.getIncludeColumns();
         TableRef tableRef = null;
         PTable table = null;
-        boolean retry = true;
+        int numRetries = 0;
         Short indexId = null;
         boolean allocateIndexId = false;
         boolean isLocalIndex = statement.getIndexType() == IndexType.LOCAL;
@@ -1359,11 +1460,11 @@ public class MetaDataClient {
                 }
                 PrimaryKeyConstraint pk = FACTORY.primaryKey(null, allPkColumns);
                 CreateTableStatement tableStatement = FACTORY.createTable(indexTableName, statement.getProps(), columnDefs, pk, statement.getSplitNodes(), PTableType.INDEX, statement.ifNotExists(), null, null, statement.getBindCount());
-                table = createTableInternal(tableStatement, splits, dataTable, null, null, null, null, indexId, statement.getIndexType(), asyncCreatedDate);
+                table = createTableInternal(tableStatement, splits, dataTable, null, null, null, null, indexId, statement.getIndexType(), asyncCreatedDate, tableProps, commonFamilyProps);
                 break;
             } catch (ConcurrentTableMutationException e) { // Can happen if parent data table changes while above is in progress
-                if (retry) {
-                    retry = false;
+                if (numRetries<5) {
+                    numRetries++;
                     continue;
                 }
                 throw e;
@@ -1541,7 +1642,12 @@ public class MetaDataClient {
         return false;
     }
     
-    private PTable createTableInternal(CreateTableStatement statement, byte[][] splits, final PTable parent, String viewStatement, ViewType viewType, final byte[][] viewColumnConstants, final BitSet isViewColumnReferenced, Short indexId, IndexType indexType, Date asyncCreatedDate) throws SQLException {
+    private PTable createTableInternal(CreateTableStatement statement, byte[][] splits,
+            final PTable parent, String viewStatement, ViewType viewType,
+            final byte[][] viewColumnConstants, final BitSet isViewColumnReferenced, Short indexId,
+            IndexType indexType, Date asyncCreatedDate,
+            Map<String,Object> tableProps,
+            Map<String,Object> commonFamilyProps) throws SQLException {
         final PTableType tableType = statement.getTableType();
         boolean wasAutoCommit = connection.getAutoCommit();
         connection.rollback();
@@ -1563,6 +1669,7 @@ public class MetaDataClient {
             Integer saltBucketNum = null;
             String defaultFamilyName = null;
             boolean isImmutableRows = false;
+            boolean isAppendOnlySchema = false;
             List<PName> physicalNames = Collections.emptyList();
             boolean addSaltColumn = false;
             boolean rowKeyOrderOptimizable = true;
@@ -1574,6 +1681,7 @@ public class MetaDataClient {
                 timestamp = TransactionUtil.getTableTimestamp(connection, transactional);
                 storeNulls = parent.getStoreNulls();
                 isImmutableRows = parent.isImmutableRows();
+                isAppendOnlySchema = parent.isAppendOnlySchema();
                 // Index on view
                 // TODO: Can we support a multi-tenant index directly on a multi-tenant
                 // table instead of only a view? We don't have anywhere to put the link
@@ -1630,21 +1738,6 @@ public class MetaDataClient {
                 pkName = pkConstraint.getName();
             }
 
-            Map<String,Object> tableProps = Maps.newHashMapWithExpectedSize(statement.getProps().size());
-            Map<String,Object> commonFamilyProps = Maps.newHashMapWithExpectedSize(statement.getProps().size() + 1);
-            // Somewhat hacky way of determining if property is for HColumnDescriptor or HTableDescriptor
-            HColumnDescriptor defaultDescriptor = new HColumnDescriptor(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES);
-            if (!statement.getProps().isEmpty()) {
-                Collection<Pair<String,Object>> props = statement.getProps().get(QueryConstants.ALL_FAMILY_PROPERTIES_KEY);
-                for (Pair<String,Object> prop : props) {
-                    if (defaultDescriptor.getValue(prop.getFirst()) == null) {
-                        tableProps.put(prop.getFirst(), prop.getSecond());
-                    } else {
-                        commonFamilyProps.put(prop.getFirst(), prop.getSecond());
-                    }
-                }
-            }
-
             // Although unusual, it's possible to set a mapped VIEW as having immutable rows.
             // This tells Phoenix that you're managing the index maintenance yourself.
             if (tableType != PTableType.INDEX && (tableType != PTableType.VIEW || viewType == ViewType.MAPPED)) {
@@ -1655,6 +1748,11 @@ public class MetaDataClient {
                     isImmutableRows = isImmutableRowsProp;
                 }
             }
+            
+            if (tableType == PTableType.TABLE) { 
+                Boolean isAppendOnlySchemaProp = (Boolean) TableProperty.APPEND_ONLY_SCHEMA.getValue(tableProps);
+                isAppendOnlySchema = isAppendOnlySchemaProp!=null ? isAppendOnlySchemaProp : false;
+            }
 
             // Can't set any of these on views or shared indexes on views
             if (tableType != PTableType.VIEW && indexId == null) {
@@ -1831,6 +1929,7 @@ public class MetaDataClient {
                     }
                     multiTenant = parent.isMultiTenant();
                     saltBucketNum = parent.getBucketNum();
+                    isAppendOnlySchema = parent.isAppendOnlySchema();
                     isImmutableRows = parent.isImmutableRows();
                     disableWAL = (disableWALProp == null ? parent.isWALDisabled() : disableWALProp);
                     defaultFamilyName = parent.getDefaultFamilyName() == null ? null : parent.getDefaultFamilyName().getString();
@@ -2036,7 +2135,7 @@ public class MetaDataClient {
                         Collections.<PTable>emptyList(), isImmutableRows,
                         Collections.<PName>emptyList(), defaultFamilyName == null ? null :
                                 PNameFactory.newName(defaultFamilyName), null,
-                        Boolean.TRUE.equals(disableWAL), false, false, null, indexId, indexType, true, false, 0, 0L, isNamespaceMapped, autoPartitionSeq);
+                        Boolean.TRUE.equals(disableWAL), false, false, null, indexId, indexType, true, false, 0, 0L, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema);
                 connection.addTable(table, MetaDataProtocol.MIN_TABLE_TIMESTAMP);
             } else if (tableType == PTableType.INDEX && indexId == null) {
                 if (tableProps.get(HTableDescriptor.MAX_FILESIZE) == null) {
@@ -2072,7 +2171,7 @@ public class MetaDataClient {
                     // For client-side cache, we need to update the column
                     // set the autoPartition column attributes   
                     if (parent != null && parent.getAutoPartitionSeqName() != null
-                            && MetaDataUtil.getAutoPartitionColIndex(parent) == columnPosition) {
+                            && parent.getPKColumns().get(MetaDataUtil.getAutoPartitionColIndex(parent)).equals(column)) {
                         columns.set(i, column = new DelegateColumn(column) {
                             @Override
                             public byte[] getViewConstant() {
@@ -2176,6 +2275,7 @@ public class MetaDataClient {
             } else {
                 tableUpsert.setString(24, autoPartitionSeq);
             }
+            tableUpsert.setBoolean(25, isAppendOnlySchema);
             tableUpsert.execute();
 
             if (asyncCreatedDate != null) {
@@ -2243,15 +2343,21 @@ public class MetaDataClient {
                 // If the parent table of the view has the auto partition sequence name attribute,
                 // set the view statement and relevant partition column attributes correctly
                 if (parent!=null && parent.getAutoPartitionSeqName()!=null) {
-                    int autoPartitionColIndex = parent.isMultiTenant() ? 1 : 0;
+                    int autoPartitionColIndex = -1;
+                    PColumn autoPartitionCol = parent.getPKColumns().get(MetaDataUtil.getAutoPartitionColIndex(parent));
+                    for (int i=0; i<columns.size(); ++i) {
+                        if (autoPartitionCol.getName().equals(columns.get(i).getName())) {
+                            autoPartitionColIndex = i;
+                        }
+                    }
                     final Long autoPartitionNum = Long.valueOf(result.getAutoPartitionNum());
                     final PColumn column = columns.get(autoPartitionColIndex);
                     columns.set(autoPartitionColIndex, new DelegateColumn(column) {
                         @Override
                         public byte[] getViewConstant() {
-                            byte[] bytes = new byte [Bytes.SIZEOF_LONG + 1];
                             PDataType dataType = column.getDataType();
                             Object val = dataType.toObject(autoPartitionNum, PLong.INSTANCE);
+                            byte[] bytes = new byte [dataType.getByteSize() + 1];
                             dataType.toBytes(val, bytes, 0);
                             return bytes;
                         }
@@ -2274,7 +2380,7 @@ public class MetaDataClient {
                         PTable.INITIAL_SEQ_NUM, pkName == null ? null : PNameFactory.newName(pkName), saltBucketNum, columns,
                         dataTableName == null ? null : newSchemaName, dataTableName == null ? null : PNameFactory.newName(dataTableName), Collections.<PTable>emptyList(), isImmutableRows,
                         physicalNames, defaultFamilyName == null ? null : PNameFactory.newName(defaultFamilyName), viewStatement, Boolean.TRUE.equals(disableWAL), multiTenant, storeNulls, viewType,
-                        indexId, indexType, rowKeyOrderOptimizable, transactional, updateCacheFrequency, 0L, isNamespaceMapped, autoPartitionSeq);
+                        indexId, indexType, rowKeyOrderOptimizable, transactional, updateCacheFrequency, 0L, isNamespaceMapped, autoPartitionSeq, isAppendOnlySchema);
                 result = new MetaDataMutationResult(code, result.getMutationTime(), table, true);
                 addTableToCache(result);
                 return table;
@@ -2682,16 +2788,23 @@ public class MetaDataClient {
             tableBoolUpsert.execute();
         }
     }
-
+    
     public MutationState addColumn(AddColumnStatement statement) throws SQLException {
+        PTable table = FromCompiler.getResolver(statement, connection).getTables().get(0).getTable();
+        return addColumn(table, statement.getColumnDefs(), statement.getProps(), statement.ifNotExists(), false, statement.getTable(), statement.getTableType());
+    }
+
+    public MutationState addColumn(PTable table, List<ColumnDef> columnDefs,
+            ListMultimap<String, Pair<String, Object>> stmtProperties, boolean ifNotExists,
+            boolean removeTableProps, NamedTableNode namedTableNode, PTableType tableType)
+            throws SQLException {
         connection.rollback();
         boolean wasAutoCommit = connection.getAutoCommit();
         try {
             connection.setAutoCommit(false);
             PName tenantId = connection.getTenantId();
-            TableName tableNameNode = statement.getTable().getName();
-            String schemaName = tableNameNode.getSchemaName();
-            String tableName = tableNameNode.getTableName();
+            String schemaName = table.getSchemaName().getString();
+            String tableName = table.getTableName().getString();
 
             Boolean isImmutableRowsProp = null;
             Boolean multiTenantProp = null;
@@ -2700,17 +2813,14 @@ public class MetaDataClient {
             Boolean isTransactionalProp = null;
             Long updateCacheFrequencyProp = null;
 
-            ListMultimap<String,Pair<String,Object>> stmtProperties = statement.getProps();
             Map<String, List<Pair<String, Object>>> properties = new HashMap<>(stmtProperties.size());
-            TableRef tableRef = FromCompiler.getResolver(statement, connection).getTables().get(0);
-            PTable table = tableRef.getTable();
-            List<ColumnDef> columnDefs = statement.getColumnDefs();
             if (columnDefs == null) {
                 columnDefs = Collections.emptyList();
             }
             for (String family : stmtProperties.keySet()) {
-                List<Pair<String, Object>> propsList = stmtProperties.get(family);
-                for (Pair<String, Object> prop : propsList) {
+                List<Pair<String, Object>> origPropsList = stmtProperties.get(family);
+                List<Pair<String, Object>> propsList = Lists.newArrayListWithExpectedSize(origPropsList.size());
+                for (Pair<String, Object> prop : origPropsList) {
                     String propName = prop.getFirst();
                     if (TableProperty.isPhoenixTableProperty(propName)) {
                         TableProperty tableProp = TableProperty.valueOf(propName);
@@ -2729,7 +2839,11 @@ public class MetaDataClient {
                         } else if (propName.equals(UPDATE_CACHE_FREQUENCY)) {
                             updateCacheFrequencyProp = (Long)value;
                         }
-                    } 
+                    }
+                    // if removeTableProps is true only add the property if it is not a HTable or Phoenix Table property
+                    if (!removeTableProps || (!TableProperty.isPhoenixTableProperty(propName) && !MetaDataUtil.isHTableProperty(propName))) {
+                        propsList.add(prop);
+                    }
                 }
                 properties.put(family, propsList);
             }
@@ -2737,7 +2851,7 @@ public class MetaDataClient {
             boolean changingPhoenixTableProperty = false;
             boolean nonTxToTx = false;
             while (true) {
-                ColumnResolver resolver = FromCompiler.getResolver(statement, connection);
+                ColumnResolver resolver = FromCompiler.getResolver(namedTableNode, connection);
                 table = resolver.getTables().get(0).getTable();
                 int nIndexes = table.getIndexes().size();
                 int nNewColumns = columnDefs.size();
@@ -2929,7 +3043,7 @@ public class MetaDataClient {
                 }
                 long seqNum = table.getSequenceNumber();
                 if (changingPhoenixTableProperty || columnDefs.size() > 0) { 
-                    seqNum = incrementTableSeqNum(table, statement.getTableType(), columnDefs.size(), isTransactional, updateCacheFrequency, isImmutableRows, disableWAL, multiTenant, storeNulls);
+                    seqNum = incrementTableSeqNum(table, tableType, columnDefs.size(), isTransactional, updateCacheFrequency, isImmutableRows, disableWAL, multiTenant, storeNulls);
                     tableMetaData.addAll(connection.getMutationState().toMutations(timeStamp).next().getSecond());
                     connection.rollback();
                 }
@@ -2962,7 +3076,7 @@ public class MetaDataClient {
                     MutationCode code = processMutationResult(schemaName, tableName, result);
                     if (code == MutationCode.COLUMN_ALREADY_EXISTS) {
                         addTableToCache(result);
-                        if (!statement.ifNotExists()) {
+                        if (!ifNotExists) {
                             throw new ColumnAlreadyExistsException(schemaName, tableName, SchemaUtil.findExistingColumn(result.getTable(), columns));
                         }
                         return new MutationState(0,connection);
@@ -3124,6 +3238,7 @@ public class MetaDataClient {
                 final ColumnResolver resolver = FromCompiler.getResolver(statement, connection);
                 TableRef tableRef = resolver.getTables().get(0);
                 PTable table = tableRef.getTable();
+                
                 List<ColumnName> columnRefs = statement.getColumnRefs();
                 if(columnRefs == null) {
                     columnRefs = Lists.newArrayListWithCapacity(0);
@@ -3149,6 +3264,10 @@ public class MetaDataClient {
                         throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_DROP_PK)
                             .setColumnName(columnToDrop.getName().getString()).build().buildException();
                     }
+                    else if (table.isAppendOnlySchema()) {
+                        throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_DROP_COL_APPEND_ONLY_SCHEMA)
+                        .setColumnName(columnToDrop.getName().getString()).build().buildException();
+                    }
                     columnsToDrop.add(new ColumnRef(columnRef.getTableRef(), columnToDrop.getPosition()));
                 }
 

http://git-wip-us.apache.org/repos/asf/phoenix/blob/a0504fba/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java
index 5a3f18e..ca48fcb 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PTable.java
@@ -349,9 +349,14 @@ public interface PTable extends PMetaDataEntity {
     boolean isNamespaceMapped();
     
     /**
-     * 
      * @return The sequence name used to get the unique identifier for views
      * that are automatically partitioned.
      */
-    String getAutoPartitionSeqName(); 
+    String getAutoPartitionSeqName();
+    
+    /**
+     * @return true if the you can only add (and never delete) columns to the table,
+     * you are also not allowed to delete the table  
+     */
+    boolean isAppendOnlySchema();
 }