phoenix-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From jamestay...@apache.org
Subject [2/2] git commit: PHOENIX-850 Optimize ORDER BY and GROUP BY for tenant specific indexes (JamesTaylor)
Date Sun, 16 Mar 2014 06:22:08 GMT
PHOENIX-850 Optimize ORDER BY and GROUP BY for tenant specific indexes (JamesTaylor)


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

Branch: refs/heads/4.0
Commit: 816e1358fee2a994b34ae64598fd7408e6a2baa4
Parents: 50f8fb2
Author: James Taylor <jamestaylor@apache.org>
Authored: Sat Mar 15 22:24:40 2014 -0700
Committer: James Taylor <jamestaylor@apache.org>
Committed: Sat Mar 15 23:21:53 2014 -0700

----------------------------------------------------------------------
 .../end2end/BaseTenantSpecificViewIndexIT.java  |  10 +-
 .../org/apache/phoenix/end2end/BaseViewIT.java  |   8 +-
 .../phoenix/compile/CreateTableCompiler.java    |  35 +++--
 .../phoenix/compile/ExpressionCompiler.java     |  28 +++-
 .../apache/phoenix/compile/FromCompiler.java    |   2 +-
 .../phoenix/compile/IndexStatementRewriter.java |  10 +-
 .../apache/phoenix/compile/JoinCompiler.java    |   6 +-
 .../apache/phoenix/compile/PostDDLCompiler.java |   2 +
 .../apache/phoenix/compile/QueryCompiler.java   |   7 +-
 .../TrackOrderPreservingExpressionCompiler.java |   8 +-
 .../apache/phoenix/compile/WhereCompiler.java   |  47 ++++++-
 .../coprocessor/MetaDataEndpointImpl.java       |  14 +-
 .../phoenix/coprocessor/MetaDataProtocol.java   |   7 +-
 .../coprocessor/generated/PTableProtos.java     | 131 ++++++++++++++---
 .../apache/phoenix/index/IndexMaintainer.java   |   5 +-
 .../apache/phoenix/iterate/ExplainTable.java    |   2 +-
 .../phoenix/jdbc/PhoenixDatabaseMetaData.java   |   2 +
 .../apache/phoenix/optimize/QueryOptimizer.java |   3 +-
 .../query/ConnectionlessQueryServicesImpl.java  |   2 +-
 .../apache/phoenix/query/QueryConstants.java    |   2 +
 .../apache/phoenix/schema/DelegateColumn.java   |   5 +
 .../apache/phoenix/schema/MetaDataClient.java   |  60 +++++---
 .../java/org/apache/phoenix/schema/PColumn.java |   2 +
 .../org/apache/phoenix/schema/PColumnImpl.java  | 139 ++++++++++---------
 .../apache/phoenix/schema/PMetaDataImpl.java    |   2 +-
 .../org/apache/phoenix/schema/SaltingUtil.java  |   2 +-
 .../java/org/apache/phoenix/util/IndexUtil.java |   9 ++
 .../TenantSpecificViewIndexCompileTest.java     |  84 +++++++++++
 .../expression/ColumnExpressionTest.java        |   8 +-
 .../iterate/AggregateResultScannerTest.java     |   5 +
 phoenix-protocol/src/main/PTable.proto          |   1 +
 31 files changed, 473 insertions(+), 175 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
index 071c270..040aad2 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseTenantSpecificViewIndexIT.java
@@ -54,7 +54,7 @@ public class BaseTenantSpecificViewIndexIT extends BaseHBaseManagedTimeIT {
     }
     
     protected void testUpdatableViewsWithSameNameDifferentTenants(Integer saltBuckets) throws Exception {
-        createBaseTable("t2", saltBuckets);
+        createBaseTable("t", saltBuckets);
         Connection conn1 = createTenantConnection(TENANT1_ID);
         Connection conn2 = createTenantConnection(TENANT2_ID);
         try {
@@ -62,8 +62,8 @@ public class BaseTenantSpecificViewIndexIT extends BaseHBaseManagedTimeIT {
             String prefixForTenant2Data = "TII";
             
             // tenant views with same name for two different tables
-            createAndPopulateTenantView(conn1, TENANT1_ID, "t2", prefixForTenant1Data);
-            createAndPopulateTenantView(conn2, TENANT2_ID, "t2", prefixForTenant2Data);
+            createAndPopulateTenantView(conn1, TENANT1_ID, "t", prefixForTenant1Data);
+            createAndPopulateTenantView(conn2, TENANT2_ID, "t", prefixForTenant2Data);
             
             createAndVerifyIndex(conn1, saltBuckets, TENANT1_ID, prefixForTenant1Data);
             createAndVerifyIndex(conn2, saltBuckets, TENANT2_ID, prefixForTenant2Data);
@@ -104,8 +104,8 @@ public class BaseTenantSpecificViewIndexIT extends BaseHBaseManagedTimeIT {
         conn.commit();
         ResultSet rs = conn.createStatement().executeQuery("EXPLAIN SELECT k1, k2, v2 FROM v WHERE v2='" + valuePrefix + "v2-1'");
         assertEquals(saltBuckets == null ? 
-                "CLIENT PARALLEL 1-WAY RANGE SCAN OVER I ['" + tenantId + "',-32768,'" + valuePrefix + "v2-1']" :
-                "CLIENT PARALLEL 4-WAY SKIP SCAN ON 3 KEYS OVER I [0,'" + tenantId + "',-32768,'" + valuePrefix + "v2-1'] - [2,'" + tenantId + "',-32768,'" + valuePrefix + "v2-1']\n" + 
+                "CLIENT PARALLEL 1-WAY RANGE SCAN OVER _IDX_T ['" + tenantId + "',-32768,'" + valuePrefix + "v2-1']" :
+                "CLIENT PARALLEL 4-WAY SKIP SCAN ON 3 KEYS OVER _IDX_T [0,'" + tenantId + "',-32768,'" + valuePrefix + "v2-1'] - [2,'" + tenantId + "',-32768,'" + valuePrefix + "v2-1']\n" + 
                 "CLIENT MERGE SORT", QueryUtil.getExplainPlan(rs));
     }
     

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
index 6c80ac6..03e8a43 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/BaseViewIT.java
@@ -110,8 +110,8 @@ public class BaseViewIT extends BaseHBaseManagedTimeIT {
         assertFalse(rs.next());
         rs = conn.createStatement().executeQuery("EXPLAIN " + query);
         assertEquals(saltBuckets == null
-                ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER I1 [" + Short.MIN_VALUE + ",51]"
-                : "CLIENT PARALLEL " + saltBuckets + "-WAY SKIP SCAN ON 3 KEYS OVER I1 [0," + Short.MIN_VALUE + ",51] - [2," + Short.MIN_VALUE + ",51]\nCLIENT MERGE SORT",
+                ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER _IDX_T [" + Short.MIN_VALUE + ",51]"
+                : "CLIENT PARALLEL " + saltBuckets + "-WAY SKIP SCAN ON 3 KEYS OVER _IDX_T [0," + Short.MIN_VALUE + ",51] - [2," + Short.MIN_VALUE + ",51]\nCLIENT MERGE SORT",
             QueryUtil.getExplainPlan(rs));
 
         conn.createStatement().execute("CREATE INDEX i2 on v(s)");
@@ -124,8 +124,8 @@ public class BaseViewIT extends BaseHBaseManagedTimeIT {
         assertFalse(rs.next());
         rs = conn.createStatement().executeQuery("EXPLAIN " + query);
         assertEquals(saltBuckets == null
-                ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER I2 [" + (Short.MIN_VALUE+1) + ",'foo']"
-                : "CLIENT PARALLEL " + saltBuckets + "-WAY SKIP SCAN ON 3 KEYS OVER I2 [0," + (Short.MIN_VALUE+1) + ",'foo'] - [2," + (Short.MIN_VALUE+1) + ",'foo']\nCLIENT MERGE SORT",
+                ? "CLIENT PARALLEL 1-WAY RANGE SCAN OVER _IDX_T [" + (Short.MIN_VALUE+1) + ",'foo']"
+                : "CLIENT PARALLEL " + saltBuckets + "-WAY SKIP SCAN ON 3 KEYS OVER _IDX_T [0," + (Short.MIN_VALUE+1) + ",'foo'] - [2," + (Short.MIN_VALUE+1) + ",'foo']\nCLIENT MERGE SORT",
             QueryUtil.getExplainPlan(rs));
     }
 

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java
index 51af286..693d3d6 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/CreateTableCompiler.java
@@ -19,6 +19,7 @@ package org.apache.phoenix.compile;
 
 import java.sql.ParameterMetaData;
 import java.sql.SQLException;
+import java.util.BitSet;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
@@ -47,7 +48,6 @@ import org.apache.phoenix.parse.SelectStatement;
 import org.apache.phoenix.parse.TableName;
 import org.apache.phoenix.parse.WildcardParseNode;
 import org.apache.phoenix.query.DelegateConnectionQueryServices;
-import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.schema.ColumnRef;
 import org.apache.phoenix.schema.MetaDataClient;
 import org.apache.phoenix.schema.PMetaData;
@@ -83,12 +83,14 @@ public class CreateTableCompiler {
         // TODO: support any statement for a VIEW instead of just a WHERE clause
         ParseNode whereNode = create.getWhereClause();
         String viewStatementToBe = null;
-        byte[][] viewColumnConstantsToBe = MetaDataClient.EMPTY_VIEW_CONSTANTS;
+        byte[][] viewColumnConstantsToBe = null;
+        BitSet isViewColumnReferencedToBe = null;
         if (type == PTableType.VIEW) {
             TableRef tableRef = resolver.getTables().get(0);
-            viewColumnConstantsToBe = new byte[tableRef.getTable().getColumns().size()][];
-            // Used to track column references and their
-            ExpressionCompiler expressionCompiler = new ColumnTrackingExpressionCompiler(context, viewColumnConstantsToBe);
+            int nColumns = tableRef.getTable().getColumns().size();
+            isViewColumnReferencedToBe = new BitSet(nColumns);
+            // Used to track column references in a view
+            ExpressionCompiler expressionCompiler = new ColumnTrackingExpressionCompiler(context, isViewColumnReferencedToBe);
             parentToBe = tableRef.getTable();
             viewTypeToBe = parentToBe.getViewType() == ViewType.MAPPED ? ViewType.MAPPED : ViewType.UPDATABLE;
             if (whereNode == null) {
@@ -133,15 +135,22 @@ public class CreateTableCompiler {
                                 }
                             },
                             connection, tableRef.getTimeStamp());
+                    viewColumnConstantsToBe = new byte[nColumns][];
                     ViewWhereExpressionVisitor visitor = new ViewWhereExpressionVisitor(parentToBe, viewColumnConstantsToBe);
                     where.accept(visitor);
+                    // If view is not updatable, viewColumnConstants should be empty. We will still
+                    // inherit our parent viewConstants, but we have no additional ones.
                     viewTypeToBe = visitor.isUpdatable() ? ViewType.UPDATABLE : ViewType.READ_ONLY;
+                    if (viewTypeToBe != ViewType.UPDATABLE) {
+                        viewColumnConstantsToBe = null;
+                    }
                 }
             }
         }
         final ViewType viewType = viewTypeToBe;
         final String viewStatement = viewStatementToBe;
         final byte[][] viewColumnConstants = viewColumnConstantsToBe;
+        final BitSet isViewColumnReferenced = isViewColumnReferencedToBe;
         List<ParseNode> splitNodes = create.getSplitNodes();
         final byte[][] splits = new byte[splitNodes.size()][];
         ImmutableBytesWritable ptr = context.getTempPtr();
@@ -171,7 +180,7 @@ public class CreateTableCompiler {
             @Override
             public MutationState execute() throws SQLException {
                 try {
-                    return client.createTable(create, splits, parent, viewStatement, viewType, viewColumnConstants);
+                    return client.createTable(create, splits, parent, viewStatement, viewType, viewColumnConstants, isViewColumnReferenced);
                 } finally {
                     if (client.getConnection() != connection) {
                         client.getConnection().close();
@@ -197,21 +206,17 @@ public class CreateTableCompiler {
     }
     
     private static class ColumnTrackingExpressionCompiler extends ExpressionCompiler {
-        private final byte[][] columnValues;
+        private final BitSet isColumnReferenced;
         
-        public ColumnTrackingExpressionCompiler(StatementContext context, byte[][] columnValues) {
-            super(context);
-            this.columnValues = columnValues;
+        public ColumnTrackingExpressionCompiler(StatementContext context, BitSet isColumnReferenced) {
+            super(context, true);
+            this.isColumnReferenced = isColumnReferenced;
         }
         
         @Override
         protected ColumnRef resolveColumn(ColumnParseNode node) throws SQLException {
             ColumnRef ref = super.resolveColumn(node);
-            // Set columnValue at position to any non null value.
-            // We always strip the last byte so that we can recognize null
-            // as a value with a single byte.
-            // Will be overridden during ViewWhereExpressionVisitor 
-            columnValues[ref.getColumn().getPosition()] = QueryConstants.SEPARATOR_BYTE_ARRAY;
+            isColumnReferenced.set(ref.getColumn().getPosition());
             return ref;
         }
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
index 5506eb5..4a05c0f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/ExpressionCompiler.java
@@ -90,6 +90,7 @@ import org.apache.phoenix.schema.ColumnNotFoundException;
 import org.apache.phoenix.schema.ColumnRef;
 import org.apache.phoenix.schema.DelegateDatum;
 import org.apache.phoenix.schema.PArrayDataType;
+import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PDataType;
 import org.apache.phoenix.schema.PDatum;
 import org.apache.phoenix.schema.PTable;
@@ -98,6 +99,7 @@ import org.apache.phoenix.schema.RowKeyValueAccessor;
 import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.schema.TableRef;
 import org.apache.phoenix.schema.TypeMismatchException;
+import org.apache.phoenix.util.IndexUtil;
 import org.apache.phoenix.util.SchemaUtil;
 
 
@@ -107,14 +109,24 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio
     protected final StatementContext context;
     protected final GroupBy groupBy;
     private int nodeCount;
+    private final boolean resolveViewConstants;
     
     ExpressionCompiler(StatementContext context) {
-        this(context,GroupBy.EMPTY_GROUP_BY);
+        this(context,GroupBy.EMPTY_GROUP_BY, false);
+    }
+
+    ExpressionCompiler(StatementContext context, boolean resolveViewConstants) {
+        this(context,GroupBy.EMPTY_GROUP_BY, resolveViewConstants);
     }
 
     ExpressionCompiler(StatementContext context, GroupBy groupBy) {
+        this(context, groupBy, false);
+    }
+
+    ExpressionCompiler(StatementContext context, GroupBy groupBy, boolean resolveViewConstants) {
         this.context = context;
         this.groupBy = groupBy;
+        this.resolveViewConstants = resolveViewConstants;
     }
 
     public boolean isAggregate() {
@@ -328,9 +340,17 @@ public class ExpressionCompiler extends UnsupportedAllParseNodeVisitor<Expressio
     public Expression visit(ColumnParseNode node) throws SQLException {
         ColumnRef ref = resolveColumn(node);
         TableRef tableRef = ref.getTableRef();
-        if (tableRef.equals(context.getCurrentTable()) 
-                && !SchemaUtil.isPKColumn(ref.getColumn())) { // project only kv columns
-            context.getScan().addColumn(ref.getColumn().getFamilyName().getBytes(), ref.getColumn().getName().getBytes());
+        ImmutableBytesWritable ptr = context.getTempPtr();
+        PColumn column = ref.getColumn();
+        // If we have an UPDATABLE view, then we compile those view constants (i.e. columns in equality constraints
+        // in the view) to constants. This allows the optimize to optimize out reference to them in various scenarios.
+        // If the column is matched in a WHERE clause against a constant not equal to it's constant, then the entire
+        // query would become degenerate.
+        if (!resolveViewConstants && IndexUtil.getViewConstantValue(column, ptr)) {
+            return LiteralExpression.newConstant(column.getDataType().toObject(ptr), column.getDataType());
+        }
+        if (tableRef.equals(context.getCurrentTable()) && !SchemaUtil.isPKColumn(column)) { // project only kv columns
+            context.getScan().addColumn(column.getFamilyName().getBytes(), column.getName().getBytes());
         }
         Expression expression = ref.newColumnExpression();
         Expression wrappedExpression = wrapGroupByExpression(expression);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 a987798..f43ff4f 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
@@ -327,7 +327,7 @@ public class FromCompiler {
                         familyName = PNameFactory.newName(family);
                     }
                     allcolumns.add(new PColumnImpl(name, familyName, dynColumn.getDataType(), dynColumn.getMaxLength(),
-                            dynColumn.getScale(), dynColumn.isNull(), position, dynColumn.getSortOrder(), dynColumn.getArraySize(), null));
+                            dynColumn.getScale(), dynColumn.isNull(), position, dynColumn.getSortOrder(), dynColumn.getArraySize(), null, false));
                     position++;
                 }
                 theTable = PTableImpl.makePTable(theTable, allcolumns);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
index 8d4b7db..7a5ebe1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/IndexStatementRewriter.java
@@ -35,8 +35,6 @@ import org.apache.phoenix.parse.WildcardParseNode;
 import org.apache.phoenix.schema.ColumnRef;
 import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PDataType;
-import org.apache.phoenix.schema.PTable;
-import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.schema.TableRef;
 import org.apache.phoenix.util.IndexUtil;
 
@@ -81,10 +79,10 @@ public class IndexStatementRewriter extends ParseNodeRewriter {
         ColumnRef dataColRef = getResolver().resolveColumn(node.getSchemaName(), node.getTableName(), node.getName());
         PColumn dataCol = dataColRef.getColumn();
         TableRef dataTableRef = dataColRef.getTableRef();
-        PTable dataTable = dataTableRef.getTable();
-        // Rewrite view constants in updatable views as literals, as they won't be in the schema for
-        // an index on the view.
-        if (dataTable.getViewType() == ViewType.UPDATABLE && dataCol.getViewConstant() != null) {
+        // Rewrite view constants as literals, as they won't be in the schema for
+        // an index on the view. Our view may be READ_ONLY yet still have inherited
+        // view constants if based on an UPDATABLE view
+        if (dataCol.getViewConstant() != null) {
             byte[] viewConstant = dataCol.getViewConstant();
             // Ignore last byte, as it's only there so we can have a way to differentiate null
             // from the absence of a value.

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 bc57ac7..fd5174b 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
@@ -47,6 +47,7 @@ import org.apache.phoenix.parse.BetweenParseNode;
 import org.apache.phoenix.parse.BindTableNode;
 import org.apache.phoenix.parse.CaseParseNode;
 import org.apache.phoenix.parse.CastParseNode;
+import org.apache.phoenix.parse.ColumnDef;
 import org.apache.phoenix.parse.ColumnParseNode;
 import org.apache.phoenix.parse.ComparisonParseNode;
 import org.apache.phoenix.parse.ConcreteTableNode;
@@ -59,7 +60,6 @@ import org.apache.phoenix.parse.InListParseNode;
 import org.apache.phoenix.parse.IsNullParseNode;
 import org.apache.phoenix.parse.JoinTableNode;
 import org.apache.phoenix.parse.JoinTableNode.JoinType;
-import org.apache.phoenix.parse.ColumnDef;
 import org.apache.phoenix.parse.LikeParseNode;
 import org.apache.phoenix.parse.NamedTableNode;
 import org.apache.phoenix.parse.NotParseNode;
@@ -403,7 +403,7 @@ public class JoinCompiler {
         	PName name = PNameFactory.newName(aliasedName);
     		PColumnImpl column = new PColumnImpl(name, familyName, sourceColumn.getDataType(), 
     				sourceColumn.getMaxLength(), sourceColumn.getScale(), sourceColumn.isNullable(), 
-    				position, sourceColumn.getSortOrder(), sourceColumn.getArraySize(), sourceColumn.getViewConstant());
+    				position, sourceColumn.getSortOrder(), sourceColumn.getArraySize(), sourceColumn.getViewConstant(), sourceColumn.isViewReferenced());
         	Expression sourceExpression = new ColumnRef(sourceTable, sourceColumn.getPosition()).newColumnExpression();
         	projectedColumns.add(column);
         	sourceExpressions.add(sourceExpression);
@@ -1163,7 +1163,7 @@ public class JoinCompiler {
     			PColumnImpl column = new PColumnImpl(c.getName(), 
     					PNameFactory.newName(ScanProjector.VALUE_COLUMN_FAMILY), c.getDataType(), 
     					c.getMaxLength(), c.getScale(), innerJoin ? c.isNullable() : true, position++, 
-    					c.getSortOrder(), c.getArraySize(), c.getViewConstant());
+    					c.getSortOrder(), c.getArraySize(), c.getViewConstant(), c.isViewReferenced());
     			merged.add(column);
     		}
     	}

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/PostDDLCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/PostDDLCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/PostDDLCompiler.java
index ab9b889..ccf805f 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/PostDDLCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/PostDDLCompiler.java
@@ -191,6 +191,8 @@ public class PostDDLCompiler {
                             // as this just means the view is invalid. Continue on and try to perform
                             // any other Post DDL operations.
                             try {
+                                // Since dropping a VIEW does not affect the underlying data, we do
+                                // not need to pass through the view statement here.
                                 WhereCompiler.compile(context, select); // Push where clause into scan
                             } catch (ColumnFamilyNotFoundException e) {
                                 continue;

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
index 111d532..a354ed1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/QueryCompiler.java
@@ -243,10 +243,9 @@ public class QueryCompiler {
         ColumnResolver resolver = context.getResolver();
         TableRef tableRef = context.getCurrentTable();
         PTable table = tableRef.getTable();
+        ParseNode viewWhere = null;
         if (table.getViewStatement() != null) {
-            ParseNode viewNode = new SQLParser(table.getViewStatement()).parseQuery().getWhere();
-            // Push VIEW expression into select
-            select = select.combine(viewNode);
+            viewWhere = new SQLParser(table.getViewStatement()).parseQuery().getWhere();
         }
         Integer limit = LimitCompiler.compile(context, select);
 
@@ -258,7 +257,7 @@ public class QueryCompiler {
         // Don't pass groupBy when building where clause expression, because we do not want to wrap these
         // expressions as group by key expressions since they're pre, not post filtered.
         context.setResolver(FromCompiler.getResolverForQuery(select, connection));
-        WhereCompiler.compile(context, select);
+        WhereCompiler.compile(context, select, viewWhere);
         context.setResolver(resolver); // recover resolver
         OrderBy orderBy = OrderByCompiler.compile(context, select, groupBy, limit); 
         RowProjector projector = ProjectionCompiler.compile(context, select, groupBy, targetColumns);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
index 0572cd0..ebf117d 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/TrackOrderPreservingExpressionCompiler.java
@@ -34,6 +34,7 @@ import org.apache.phoenix.parse.DivideParseNode;
 import org.apache.phoenix.parse.MultiplyParseNode;
 import org.apache.phoenix.parse.SubtractParseNode;
 import org.apache.phoenix.schema.ColumnRef;
+import org.apache.phoenix.schema.PTable;
 import org.apache.phoenix.schema.SortOrder;
 import org.apache.phoenix.util.SchemaUtil;
 
@@ -62,7 +63,12 @@ public class TrackOrderPreservingExpressionCompiler extends ExpressionCompiler {
     
     TrackOrderPreservingExpressionCompiler(StatementContext context, GroupBy groupBy, int expectedEntrySize, Ordering ordering) {
         super(context, groupBy);
-        positionOffset =  context.getResolver().getTables().get(0).getTable().getBucketNum() == null ? 0 : 1;
+        PTable table = context.getResolver().getTables().get(0).getTable();
+        boolean isSalted = table.getBucketNum() != null;
+        boolean isMultiTenant = context.getConnection().getTenantId() != null && table.isMultiTenant();
+        boolean isSharedViewIndex = table.getViewIndexId() != null;
+        // TODO: util for this offset, as it's computed in numerous places
+        positionOffset = (isSalted ? 1 : 0) + (isMultiTenant ? 1 : 0) + (isSharedViewIndex ? 1 : 0);
         entries = Lists.newArrayListWithExpectedSize(expectedEntrySize);
         this.ordering = ordering;
     }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
index 126f402..98e4517 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/compile/WhereCompiler.java
@@ -26,15 +26,35 @@ import org.apache.hadoop.hbase.client.Scan;
 import org.apache.hadoop.hbase.filter.Filter;
 import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.exception.SQLExceptionInfo;
-import org.apache.phoenix.expression.*;
+import org.apache.phoenix.expression.AndExpression;
+import org.apache.phoenix.expression.Expression;
+import org.apache.phoenix.expression.KeyValueColumnExpression;
+import org.apache.phoenix.expression.LiteralExpression;
 import org.apache.phoenix.expression.visitor.KeyValueExpressionVisitor;
-import org.apache.phoenix.filter.*;
-import org.apache.phoenix.parse.*;
+import org.apache.phoenix.filter.MultiCFCQKeyValueComparisonFilter;
+import org.apache.phoenix.filter.MultiCQKeyValueComparisonFilter;
+import org.apache.phoenix.filter.RowKeyComparisonFilter;
+import org.apache.phoenix.filter.SingleCFCQKeyValueComparisonFilter;
+import org.apache.phoenix.filter.SingleCQKeyValueComparisonFilter;
+import org.apache.phoenix.parse.ColumnParseNode;
+import org.apache.phoenix.parse.FilterableStatement;
 import org.apache.phoenix.parse.HintNode.Hint;
-import org.apache.phoenix.schema.*;
-import org.apache.phoenix.util.*;
+import org.apache.phoenix.parse.ParseNode;
+import org.apache.phoenix.parse.ParseNodeFactory;
+import org.apache.phoenix.schema.AmbiguousColumnException;
+import org.apache.phoenix.schema.ColumnNotFoundException;
+import org.apache.phoenix.schema.ColumnRef;
+import org.apache.phoenix.schema.PDataType;
+import org.apache.phoenix.schema.PTable;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.schema.TableRef;
+import org.apache.phoenix.schema.TypeMismatchException;
+import org.apache.phoenix.util.ByteUtil;
+import org.apache.phoenix.util.ScanUtil;
+import org.apache.phoenix.util.SchemaUtil;
 
 import com.google.common.collect.Iterators;
+import com.google.common.collect.Lists;
 import com.google.common.collect.Sets;
 
 
@@ -51,6 +71,10 @@ public class WhereCompiler {
     private WhereCompiler() {
     }
 
+    public static Expression compile(StatementContext context, FilterableStatement statement) throws SQLException {
+        return compile(context, statement, null);
+    }
+    
     /**
      * Pushes where clause filter expressions into scan by building and setting a filter.
      * @param context the shared context during query compilation
@@ -61,7 +85,7 @@ public class WhereCompiler {
      * @throws ColumnNotFoundException if column name could not be resolved
      * @throws AmbiguousColumnException if an unaliased column name is ambiguous across multiple tables
      */
-    public static Expression compile(StatementContext context, FilterableStatement statement) throws SQLException {
+    public static Expression compile(StatementContext context, FilterableStatement statement, ParseNode viewWhere) throws SQLException {
         Set<Expression> extractedNodes = Sets.<Expression>newHashSet();
         WhereExpressionCompiler whereCompiler = new WhereExpressionCompiler(context);
         ParseNode where = statement.getWhere();
@@ -72,6 +96,11 @@ public class WhereCompiler {
         if (expression.getDataType() != PDataType.BOOLEAN) {
             throw TypeMismatchException.newException(PDataType.BOOLEAN, expression.getDataType(), expression.toString());
         }
+        if (viewWhere != null) {
+            WhereExpressionCompiler viewWhereCompiler = new WhereExpressionCompiler(context, true);
+            Expression viewExpression = viewWhere.accept(viewWhereCompiler);
+            expression = AndExpression.create(Lists.newArrayList(expression, viewExpression));
+        }
         
         expression = WhereOptimizer.pushKeyExpressionsToScan(context, statement, expression, extractedNodes);
         setScanFilter(context, statement, expression, whereCompiler.disambiguateWithFamily);
@@ -83,7 +112,11 @@ public class WhereCompiler {
         private boolean disambiguateWithFamily;
 
         WhereExpressionCompiler(StatementContext context) {
-            super(context);
+            super(context, true);
+        }
+
+        WhereExpressionCompiler(StatementContext context, boolean resolveViewConstants) {
+            super(context, resolveViewConstants);
         }
 
         @Override

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 62ced4b..09df3fb 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
@@ -31,6 +31,7 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.DISABLE_WAL_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.FAMILY_NAME_INDEX;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IMMUTABLE_ROWS_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_STATE_BYTES;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_VIEW_REFERENCED_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.NULLABLE_BYTES;
@@ -211,6 +212,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
     private static final KeyValue SORT_ORDER_KV = KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, SORT_ORDER_BYTES);
     private static final KeyValue ARRAY_SIZE_KV = KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, ARRAY_SIZE_BYTES);
     private static final KeyValue VIEW_CONSTANT_KV = KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, VIEW_CONSTANT_BYTES);
+    private static final KeyValue IS_VIEW_REFERENCED_KV = KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, IS_VIEW_REFERENCED_BYTES);
     private static final List<KeyValue> COLUMN_KV_COLUMNS = Arrays.<KeyValue>asList(
             DECIMAL_DIGITS_KV,
             COLUMN_SIZE_KV,
@@ -220,7 +222,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
             SORT_ORDER_KV,
             DATA_TABLE_NAME_KV, // included in both column and table row for metadata APIs
             ARRAY_SIZE_KV,
-            VIEW_CONSTANT_KV
+            VIEW_CONSTANT_KV,
+            IS_VIEW_REFERENCED_KV
             );
     static {
         Collections.sort(COLUMN_KV_COLUMNS, KeyValue.COMPARATOR);
@@ -233,6 +236,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
     private static final int SORT_ORDER_INDEX = COLUMN_KV_COLUMNS.indexOf(SORT_ORDER_KV);
     private static final int ARRAY_SIZE_INDEX = COLUMN_KV_COLUMNS.indexOf(ARRAY_SIZE_KV);
     private static final int VIEW_CONSTANT_INDEX = COLUMN_KV_COLUMNS.indexOf(VIEW_CONSTANT_KV);
+    private static final int IS_VIEW_REFERENCED_INDEX = COLUMN_KV_COLUMNS.indexOf(IS_VIEW_REFERENCED_KV);
     
     private static final int LINK_TYPE_INDEX = 0;
 
@@ -501,8 +505,9 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
  
         Cell viewConstantKv = colKeyValues[VIEW_CONSTANT_INDEX];
         byte[] viewConstant = viewConstantKv == null ? null : viewConstantKv.getValue();
-        PColumn column = new PColumnImpl(colName, famName, dataType, maxLength, scale, isNullable,
-                        position - 1, sortOrder, arraySize, viewConstant);
+        Cell isViewReferencedKv = colKeyValues[IS_VIEW_REFERENCED_INDEX];
+        boolean isViewReferenced = isViewReferencedKv != null && Boolean.TRUE.equals(PDataType.BOOLEAN.toObject(isViewReferencedKv.getValueArray(), isViewReferencedKv.getValueOffset(), isViewReferencedKv.getValueLength()));
+        PColumn column = new PColumnImpl(colName, famName, dataType, maxLength, scale, isNullable, position-1, sortOrder, arraySize, viewConstant, isViewReferenced);
         columns.add(column);
     }
     
@@ -1219,7 +1224,6 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                                 } else {
                                     continue;
                                 }
-
                                 return new MetaDataMutationResult(
                                         MutationCode.COLUMN_ALREADY_EXISTS, EnvironmentEdgeManager
                                                 .currentTimeMillis(), table);
@@ -1299,7 +1303,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                                     } else {
                                         continue;
                                     }
-                                    if (columnToDelete.getViewConstant() != null) { // Disallow deletion of column referenced in WHERE clause of view
+                                    if (columnToDelete.isViewReferenced()) { // Disallow deletion of column referenced in WHERE clause of view
                                         return new MetaDataMutationResult(MutationCode.UNALLOWED_TABLE_MUTATION, EnvironmentEdgeManager.currentTimeMillis(), table, columnToDelete);
                                     }
                                     // Look for columnToDelete in any indexes. If found as PK

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
index de6cf5b..4acf299 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/coprocessor/MetaDataProtocol.java
@@ -97,13 +97,18 @@ public abstract class MetaDataProtocol extends MetaDataService {
                 this.columnName = column.getName().getBytes();
                 this.familyName = column.getFamilyName().getBytes();    
             }
-            
         }
         
         public MetaDataMutationResult(MutationCode returnCode, long currentTime, PTable table) {
            this(returnCode, currentTime, table, Collections.<byte[]> emptyList());
         }
         
+        // For testing, so that connectionless can set wasUpdated so ColumnResolver doesn't complain
+        public MetaDataMutationResult(MutationCode returnCode, long currentTime, PTable table, boolean wasUpdated) {
+            this(returnCode, currentTime, table, Collections.<byte[]> emptyList());
+            this.wasUpdated = wasUpdated;
+         }
+         
         public MetaDataMutationResult(MutationCode returnCode, long currentTime, PTable table, List<byte[]> tableNamesToDelete) {
             this.returnCode = returnCode;
             this.mutationTime = currentTime;

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 ff946f3..ea4d135 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
@@ -224,6 +224,16 @@ public final class PTableProtos {
      * <code>optional bytes viewConstant = 10;</code>
      */
     com.google.protobuf.ByteString getViewConstant();
+
+    // optional bool viewReferenced = 11;
+    /**
+     * <code>optional bool viewReferenced = 11;</code>
+     */
+    boolean hasViewReferenced();
+    /**
+     * <code>optional bool viewReferenced = 11;</code>
+     */
+    boolean getViewReferenced();
   }
   /**
    * Protobuf type {@code PColumn}
@@ -326,6 +336,11 @@ public final class PTableProtos {
               viewConstant_ = input.readBytes();
               break;
             }
+            case 88: {
+              bitField0_ |= 0x00000400;
+              viewReferenced_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -553,6 +568,22 @@ public final class PTableProtos {
       return viewConstant_;
     }
 
+    // optional bool viewReferenced = 11;
+    public static final int VIEWREFERENCED_FIELD_NUMBER = 11;
+    private boolean viewReferenced_;
+    /**
+     * <code>optional bool viewReferenced = 11;</code>
+     */
+    public boolean hasViewReferenced() {
+      return ((bitField0_ & 0x00000400) == 0x00000400);
+    }
+    /**
+     * <code>optional bool viewReferenced = 11;</code>
+     */
+    public boolean getViewReferenced() {
+      return viewReferenced_;
+    }
+
     private void initFields() {
       columnNameBytes_ = com.google.protobuf.ByteString.EMPTY;
       familyNameBytes_ = com.google.protobuf.ByteString.EMPTY;
@@ -564,6 +595,7 @@ public final class PTableProtos {
       sortOrder_ = 0;
       arraySize_ = 0;
       viewConstant_ = com.google.protobuf.ByteString.EMPTY;
+      viewReferenced_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -627,6 +659,9 @@ public final class PTableProtos {
       if (((bitField0_ & 0x00000200) == 0x00000200)) {
         output.writeBytes(10, viewConstant_);
       }
+      if (((bitField0_ & 0x00000400) == 0x00000400)) {
+        output.writeBool(11, viewReferenced_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -676,6 +711,10 @@ public final class PTableProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeBytesSize(10, viewConstant_);
       }
+      if (((bitField0_ & 0x00000400) == 0x00000400)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(11, viewReferenced_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -749,6 +788,11 @@ public final class PTableProtos {
         result = result && getViewConstant()
             .equals(other.getViewConstant());
       }
+      result = result && (hasViewReferenced() == other.hasViewReferenced());
+      if (hasViewReferenced()) {
+        result = result && (getViewReferenced()
+            == other.getViewReferenced());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -802,6 +846,10 @@ public final class PTableProtos {
         hash = (37 * hash) + VIEWCONSTANT_FIELD_NUMBER;
         hash = (53 * hash) + getViewConstant().hashCode();
       }
+      if (hasViewReferenced()) {
+        hash = (37 * hash) + VIEWREFERENCED_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getViewReferenced());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -931,6 +979,8 @@ public final class PTableProtos {
         bitField0_ = (bitField0_ & ~0x00000100);
         viewConstant_ = com.google.protobuf.ByteString.EMPTY;
         bitField0_ = (bitField0_ & ~0x00000200);
+        viewReferenced_ = false;
+        bitField0_ = (bitField0_ & ~0x00000400);
         return this;
       }
 
@@ -999,6 +1049,10 @@ public final class PTableProtos {
           to_bitField0_ |= 0x00000200;
         }
         result.viewConstant_ = viewConstant_;
+        if (((from_bitField0_ & 0x00000400) == 0x00000400)) {
+          to_bitField0_ |= 0x00000400;
+        }
+        result.viewReferenced_ = viewReferenced_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -1047,6 +1101,9 @@ public final class PTableProtos {
         if (other.hasViewConstant()) {
           setViewConstant(other.getViewConstant());
         }
+        if (other.hasViewReferenced()) {
+          setViewReferenced(other.getViewReferenced());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -1474,6 +1531,39 @@ public final class PTableProtos {
         return this;
       }
 
+      // optional bool viewReferenced = 11;
+      private boolean viewReferenced_ ;
+      /**
+       * <code>optional bool viewReferenced = 11;</code>
+       */
+      public boolean hasViewReferenced() {
+        return ((bitField0_ & 0x00000400) == 0x00000400);
+      }
+      /**
+       * <code>optional bool viewReferenced = 11;</code>
+       */
+      public boolean getViewReferenced() {
+        return viewReferenced_;
+      }
+      /**
+       * <code>optional bool viewReferenced = 11;</code>
+       */
+      public Builder setViewReferenced(boolean value) {
+        bitField0_ |= 0x00000400;
+        viewReferenced_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>optional bool viewReferenced = 11;</code>
+       */
+      public Builder clearViewReferenced() {
+        bitField0_ = (bitField0_ & ~0x00000400);
+        viewReferenced_ = false;
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:PColumn)
     }
 
@@ -5532,29 +5622,30 @@ public final class PTableProtos {
       descriptor;
   static {
     java.lang.String[] descriptorData = {
-      "\n\014PTable.proto\"\317\001\n\007PColumn\022\027\n\017columnName" +
+      "\n\014PTable.proto\"\347\001\n\007PColumn\022\027\n\017columnName" +
       "Bytes\030\001 \002(\014\022\027\n\017familyNameBytes\030\002 \001(\014\022\020\n\010" +
       "dataType\030\003 \002(\t\022\021\n\tmaxLength\030\004 \001(\005\022\r\n\005sca" +
       "le\030\005 \001(\005\022\020\n\010nullable\030\006 \002(\010\022\020\n\010position\030\007" +
       " \002(\005\022\021\n\tsortOrder\030\010 \002(\005\022\021\n\tarraySize\030\t \001" +
-      "(\005\022\024\n\014viewConstant\030\n \001(\014\"*\n\013PTableStats\022" +
-      "\013\n\003key\030\001 \002(\t\022\016\n\006values\030\002 \003(\014\"\367\003\n\006PTable\022" +
-      "\027\n\017schemaNameBytes\030\001 \002(\014\022\026\n\016tableNameByt" +
-      "es\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(\003\022\023\n\013pkNameBytes\030\007" +
-      " \001(\014\022\021\n\tbucketNum\030\010 \002(\005\022\031\n\007columns\030\t \003(\013" +
-      "2\010.PColumn\022\030\n\007indexes\030\n \003(\0132\007.PTable\022\027\n\017" +
-      "isImmutableRows\030\013 \002(\010\022 \n\nguidePosts\030\014 \003(" +
-      "\0132\014.PTableStats\022\032\n\022dataTableNameBytes\030\r " +
-      "\001(\014\022\031\n\021defaultFamilyName\030\016 \001(\014\022\022\n\ndisabl" +
-      "eWAL\030\017 \002(\010\022\023\n\013multiTenant\030\020 \002(\010\022\020\n\010viewT" +
-      "ype\030\021 \001(\014\022\025\n\rviewStatement\030\022 \001(\014\022\025\n\rphys" +
-      "icalNames\030\023 \003(\014\022\020\n\010tenantId\030\024 \001(\014\022\023\n\013vie" +
-      "wIndexId\030\025 \001(\005*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"
+      "(\005\022\024\n\014viewConstant\030\n \001(\014\022\026\n\016viewReferenc" +
+      "ed\030\013 \001(\010\"*\n\013PTableStats\022\013\n\003key\030\001 \002(\t\022\016\n\006" +
+      "values\030\002 \003(\014\"\367\003\n\006PTable\022\027\n\017schemaNameByt" +
+      "es\030\001 \002(\014\022\026\n\016tableNameBytes\030\002 \002(\014\022\036\n\ttabl" +
+      "eType\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\ttimeStam" +
+      "p\030\006 \002(\003\022\023\n\013pkNameBytes\030\007 \001(\014\022\021\n\tbucketNu" +
+      "m\030\010 \002(\005\022\031\n\007columns\030\t \003(\0132\010.PColumn\022\030\n\007in" +
+      "dexes\030\n \003(\0132\007.PTable\022\027\n\017isImmutableRows\030" +
+      "\013 \002(\010\022 \n\nguidePosts\030\014 \003(\0132\014.PTableStats\022" +
+      "\032\n\022dataTableNameBytes\030\r \001(\014\022\031\n\021defaultFa" +
+      "milyName\030\016 \001(\014\022\022\n\ndisableWAL\030\017 \002(\010\022\023\n\013mu" +
+      "ltiTenant\030\020 \002(\010\022\020\n\010viewType\030\021 \001(\014\022\025\n\rvie" +
+      "wStatement\030\022 \001(\014\022\025\n\rphysicalNames\030\023 \003(\014\022" +
+      "\020\n\010tenantId\030\024 \001(\014\022\023\n\013viewIndexId\030\025 \001(\005*A",
+      "\n\nPTableType\022\n\n\006SYSTEM\020\000\022\010\n\004USER\020\001\022\010\n\004VI" +
+      "EW\020\002\022\t\n\005INDEX\020\003\022\010\n\004JOIN\020\004B@\n(org.apache." +
+      "phoenix.coprocessor.generatedB\014PTablePro" +
+      "tosH\001\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
       new com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -5566,7 +5657,7 @@ public final class PTableProtos {
           internal_static_PColumn_fieldAccessorTable = new
             com.google.protobuf.GeneratedMessage.FieldAccessorTable(
               internal_static_PColumn_descriptor,
-              new java.lang.String[] { "ColumnNameBytes", "FamilyNameBytes", "DataType", "MaxLength", "Scale", "Nullable", "Position", "SortOrder", "ArraySize", "ViewConstant", });
+              new java.lang.String[] { "ColumnNameBytes", "FamilyNameBytes", "DataType", "MaxLength", "Scale", "Nullable", "Position", "SortOrder", "ArraySize", "ViewConstant", "ViewReferenced", });
           internal_static_PTableStats_descriptor =
             getDescriptor().getMessageTypes().get(1);
           internal_static_PTableStats_fieldAccessorTable = new

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java b/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
index b569a3c..c1d6c25 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/index/IndexMaintainer.java
@@ -51,7 +51,6 @@ import org.apache.phoenix.schema.PColumnFamily;
 import org.apache.phoenix.schema.PDataType;
 import org.apache.phoenix.schema.PIndexState;
 import org.apache.phoenix.schema.PTable;
-import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.schema.PTableType;
 import org.apache.phoenix.schema.RowKeySchema;
 import org.apache.phoenix.schema.SaltingUtil;
@@ -245,10 +244,10 @@ public class IndexMaintainer implements Writable, Iterable<ColumnReference> {
 
         int dataPosOffset = (isDataTableSalted ? 1 : 0) + (this.isMultiTenant ? 1 : 0);
         int nDataPKColumns = dataRowKeySchema.getFieldCount() - dataPosOffset;
-        // For indexes on updatable views, we need to remember which data columns are "constants"
+        // For indexes on views, we need to remember which data columns are "constants"
         // These are the values in a VIEW where clause. For these, we don't put them in the
         // index, as they're the same for every row in the index.
-        if (dataTable.getViewType() == ViewType.UPDATABLE) {
+        if (dataTable.getType() == PTableType.VIEW) {
             List<PColumn>dataPKColumns = dataTable.getPKColumns();
             for (int i = dataPosOffset; i < dataPKColumns.size(); i++) {
                 PColumn dataPKColumn = dataPKColumns.get(i);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
index a0376b6..af13df4 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/iterate/ExplainTable.java
@@ -94,7 +94,7 @@ public abstract class ExplainTable {
         } else {
             hasSkipScanFilter = explainSkipScan(buf);
         }
-        buf.append("OVER " + tableRef.getTable().getName().getString());
+        buf.append("OVER " + tableRef.getTable().getPhysicalName().getString());
         if (!scanRanges.isPointLookup()) {
             appendKeyRanges(buf);
         }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 fce65e7..7b2f6da 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
@@ -180,6 +180,8 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData, org.apache.pho
     public static final byte[] ARRAY_SIZE_BYTES = Bytes.toBytes(ARRAY_SIZE);
     public static final String VIEW_CONSTANT = "VIEW_CONSTANT";
     public static final byte[] VIEW_CONSTANT_BYTES = Bytes.toBytes(VIEW_CONSTANT);
+    public static final String IS_VIEW_REFERENCED = "IS_VIEW_REFERENCED";
+    public static final byte[] IS_VIEW_REFERENCED_BYTES = Bytes.toBytes(IS_VIEW_REFERENCED);
     public static final String VIEW_INDEX_ID = "VIEW_INDEX_ID";
     public static final byte[] VIEW_INDEX_ID_BYTES = Bytes.toBytes(VIEW_INDEX_ID);
 

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
index ff87278..220ef89 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/optimize/QueryOptimizer.java
@@ -43,7 +43,6 @@ import org.apache.phoenix.schema.PColumn;
 import org.apache.phoenix.schema.PDatum;
 import org.apache.phoenix.schema.PIndexState;
 import org.apache.phoenix.schema.PTable;
-import org.apache.phoenix.schema.PTable.ViewType;
 import org.apache.phoenix.schema.PTableType;
 
 import com.google.common.collect.Lists;
@@ -266,7 +265,7 @@ public class QueryOptimizer {
         
         int nViewConstants = 0;
         PTable dataTable = dataPlan.getTableRef().getTable();
-        if (dataTable.getViewType() == ViewType.UPDATABLE) {
+        if (dataTable.getType() == PTableType.VIEW) {
             for (PColumn column : dataTable.getColumns()) {
                 if (column.getViewConstant() != null) {
                     nViewConstants++;

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
index 8b95ff1..7a190e1 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java
@@ -177,7 +177,7 @@ public class ConnectionlessQueryServicesImpl extends DelegateQueryServices imple
         try {
             String fullTableName = SchemaUtil.getTableName(schemaBytes, tableBytes);
             PTable table = metaData.getTable(new PTableKey(tenantId, fullTableName));
-            return new MetaDataMutationResult(MutationCode.TABLE_ALREADY_EXISTS, 0, table);
+            return new MetaDataMutationResult(MutationCode.TABLE_ALREADY_EXISTS, 0, table, true);
         } catch (TableNotFoundException e) {
             return new MetaDataMutationResult(MutationCode.TABLE_NOT_FOUND, 0, null);
         }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 6224fb0..06bccce 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
@@ -70,6 +70,7 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TYPE_NAME;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TYPE_SEQUENCE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_CONSTANT;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_INDEX_ID;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_VIEW_REFERENCED;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_STATEMENT;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.VIEW_TYPE;
 
@@ -184,6 +185,7 @@ public interface QueryConstants {
             SORT_ORDER + " INTEGER," +
             ARRAY_SIZE + " INTEGER,\n" +
             VIEW_CONSTANT + " VARBINARY,\n" +
+            IS_VIEW_REFERENCED + " BOOLEAN,\n" +
             KEY_SEQ + " SMALLINT,\n" +
             // Link metadata (only set on rows linking table to index or view)
             LINK_TYPE + " UNSIGNED_TINYINT,\n" +

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java
index 2356b2a..a4901cf 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/DelegateColumn.java
@@ -64,4 +64,9 @@ public class DelegateColumn extends DelegateDatum implements PColumn {
     public int getEstimatedSize() {
         return SizedUtil.OBJECT_SIZE + getDelegate().getEstimatedSize();
     }
+
+    @Override
+    public boolean isViewReferenced() {
+        return getDelegate().isViewReferenced();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/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 32c979a..cb891eb 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
@@ -33,6 +33,7 @@ import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.DEFAULT_COLUMN_FAM
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.DISABLE_WAL;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IMMUTABLE_ROWS;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.INDEX_STATE;
+import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.IS_VIEW_REFERENCED;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.KEY_SEQ;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.LINK_TYPE;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.MULTI_TENANT;
@@ -62,6 +63,7 @@ import java.sql.ResultSetMetaData;
 import java.sql.SQLException;
 import java.sql.SQLFeatureNotSupportedException;
 import java.sql.Types;
+import java.util.BitSet;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.Comparator;
@@ -129,7 +131,6 @@ import com.google.common.primitives.Ints;
 
 public class MetaDataClient {
     private static final Logger logger = LoggerFactory.getLogger(MetaDataClient.class);
-    public static final byte[][] EMPTY_VIEW_CONSTANTS = new byte[0][];
 
     private static final ParseNodeFactory FACTORY = new ParseNodeFactory();
     private static final String CREATE_TABLE =
@@ -220,9 +221,10 @@ public class MetaDataClient {
         DATA_TABLE_NAME + "," + // write this both in the column and table rows for access by metadata APIs
         ARRAY_SIZE + "," +
         VIEW_CONSTANT + "," + 
+        IS_VIEW_REFERENCED + "," + 
         PK_NAME + "," +  // write this both in the column and table rows for access by metadata APIs
         KEY_SEQ +
-        ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
+        ") VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
     private static final String UPDATE_COLUMN_POSITION =
         "UPSERT INTO " + SYSTEM_CATALOG_SCHEMA + ".\"" + SYSTEM_CATALOG_TABLE + "\" ( " + 
         TENANT_ID + "," +
@@ -356,11 +358,12 @@ public class MetaDataClient {
             colUpsert.setInt(13, column.getArraySize());
         }
         colUpsert.setBytes(14, column.getViewConstant());
-        colUpsert.setString(15, pkName);
+        colUpsert.setBoolean(15, column.isViewReferenced());
+        colUpsert.setString(16, pkName);
         if (keySeq == null) {
-            colUpsert.setNull(16, Types.SMALLINT);
+            colUpsert.setNull(17, Types.SMALLINT);
         } else {
-            colUpsert.setShort(16, keySeq);
+            colUpsert.setShort(17, keySeq);
         }
         colUpsert.execute();
     }
@@ -399,15 +402,15 @@ public class MetaDataClient {
             }
             
             PColumn column = new PColumnImpl(PNameFactory.newName(columnName), familyName, def.getDataType(),
-                    def.getMaxLength(), def.getScale(), def.isNull(), position, sortOrder, def.getArraySize(), null);
+                    def.getMaxLength(), def.getScale(), def.isNull(), position, sortOrder, def.getArraySize(), null, false);
             return column;
         } catch (IllegalArgumentException e) { // Based on precondition check in constructor
             throw new SQLException(e);
         }
     }
 
-    public MutationState createTable(CreateTableStatement statement, byte[][] splits, PTable parent, String viewStatement, ViewType viewType, byte[][] viewColumnConstants) throws SQLException {
-        PTable table = createTableInternal(statement, splits, parent, viewStatement, viewType, viewColumnConstants, null);
+    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);
         if (table == null || table.getType() == PTableType.VIEW) {
             return new MutationState(0,connection);
         }
@@ -564,14 +567,13 @@ public class MetaDataClient {
                     allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, SortOrder.getDefault()));
                     columnDefs.add(FACTORY.columnDef(colName, dataType.getSqlTypeName(), false, null, null, false, SortOrder.getDefault()));
                 }
-                boolean isUpdatableView = dataTable.getViewType() == ViewType.UPDATABLE;
                 // First columns are the indexed ones
                 for (Pair<ColumnName, SortOrder> pair : indexedPkColumns) {
                     ColumnName colName = pair.getFirst();
                     PColumn col = resolver.resolveColumn(null, colName.getFamilyName(), colName.getColumnName()).getColumn();
                     unusedPkColumns.remove(col);
                     // Ignore view constants for updatable views as we don't need these in the index
-                    if (!isUpdatableView || col.getViewConstant() == null) {
+                    if (col.getViewConstant() == null) {
                         PDataType dataType = IndexUtil.getIndexColumnDataType(col);
                         colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col));
                         allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, pair.getSecond()));
@@ -584,7 +586,7 @@ public class MetaDataClient {
                     for (PColumn col : unusedPkColumns) {
                         // Don't add columns with constant values from updatable views, as
                         // we don't need these in the index
-                        if (!isUpdatableView || col.getViewConstant() == null) {
+                        if (col.getViewConstant() == null) {
                             ColumnName colName = ColumnName.caseSensitiveColumnName(IndexUtil.getIndexColumnName(col));
                             allPkColumns.add(new Pair<ColumnName, SortOrder>(colName, col.getSortOrder()));
                             PDataType dataType = IndexUtil.getIndexColumnDataType(col);
@@ -607,7 +609,7 @@ public class MetaDataClient {
                         if (pk.contains(colName)) {
                             throw new SQLExceptionInfo.Builder(SQLExceptionCode.COLUMN_EXIST_IN_DEF).build().buildException();
                         }
-                        if (!SchemaUtil.isPKColumn(col) && (!isUpdatableView || col.getViewConstant() == null)) {
+                        if (!SchemaUtil.isPKColumn(col) && col.getViewConstant() == null) {
                             // Need to re-create ColumnName, since the above one won't have the column family name
                             colName = ColumnName.caseSensitiveColumnName(col.getFamilyName().getString(), IndexUtil.getIndexColumnName(col));
                             columnDefs.add(FACTORY.columnDef(colName, col.getDataType().getSqlTypeName(), col.isNullable(), col.getMaxLength(), col.getScale(), false, col.getSortOrder()));
@@ -646,7 +648,7 @@ public class MetaDataClient {
                     statement.getProps().put("", new Pair<String,Object>(DEFAULT_COLUMN_FAMILY_NAME,dataTable.getDefaultFamilyName().getString()));
                 }
                 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, EMPTY_VIEW_CONSTANTS, viewIndexId);
+                table = createTableInternal(tableStatement, splits, dataTable, null, null, null, null, viewIndexId);
                 break;
             } catch (ConcurrentTableMutationException e) { // Can happen if parent data table changes while above is in progress
                 if (retry) {
@@ -714,7 +716,7 @@ public class MetaDataClient {
         return null;
     }
     
-    private PTable createTableInternal(CreateTableStatement statement, byte[][] splits, final PTable parent, String viewStatement, ViewType viewType, byte[][] viewColumnConstants, Short viewIndexId) throws SQLException {
+    private PTable createTableInternal(CreateTableStatement statement, byte[][] splits, final PTable parent, String viewStatement, ViewType viewType, final byte[][] viewColumnConstants, final BitSet isViewColumnReferenced, Short viewIndexId) throws SQLException {
         final PTableType tableType = statement.getTableType();
         boolean wasAutoCommit = connection.getAutoCommit();
         connection.rollback();
@@ -1065,16 +1067,28 @@ public class MetaDataClient {
             short nextKeySeq = 0;
             for (int i = 0; i < columns.size(); i++) {
                 PColumn column = columns.get(i);
-                int columnPosition = column.getPosition();
-                final byte[] viewConstant = columnPosition < viewColumnConstants.length ? viewColumnConstants[columnPosition] : null;
+                final int columnPosition = column.getPosition();
                 // For client-side cache, we need to update the column
-                if (viewConstant != null) {
-                    columns.set(i, column = new DelegateColumn(column) {
-                        @Override
-                        public byte[] getViewConstant() {
-                            return viewConstant;
-                        }
-                    });
+                if (isViewColumnReferenced != null) {
+                    if (viewColumnConstants != null && columnPosition < viewColumnConstants.length) {
+                        columns.set(i, column = new DelegateColumn(column) {
+                            @Override
+                            public byte[] getViewConstant() {
+                                return viewColumnConstants[columnPosition];
+                            }
+                            @Override
+                            public boolean isViewReferenced() {
+                                return isViewColumnReferenced.get(columnPosition);
+                            }
+                        });
+                    } else {
+                        columns.set(i, column = new DelegateColumn(column) {
+                            @Override
+                            public boolean isViewReferenced() {
+                                return isViewColumnReferenced.get(columnPosition);
+                            }
+                        });
+                    }
                 }
                 Short keySeq = SchemaUtil.isPKColumn(column) ? ++nextKeySeq : null;
                 addColumnMutation(schemaName, tableName, column, colUpsert, parentTableName, pkName, keySeq);

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java
index 9270d55..54eeaf0 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumn.java
@@ -47,5 +47,7 @@ public interface PColumn extends PDatum {
     
     byte[] getViewConstant();
     
+    boolean isViewReferenced();
+    
     int getEstimatedSize();
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java
index 5999be6..c2e2ed2 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PColumnImpl.java
@@ -35,6 +35,7 @@ public class PColumnImpl implements PColumn {
     private SortOrder sortOrder;
     private Integer arraySize;
     private byte[] viewConstant;
+    private boolean isViewReferenced;
 
     public PColumnImpl() {
     }
@@ -46,13 +47,13 @@ public class PColumnImpl implements PColumn {
                        Integer scale,
                        boolean nullable,
                        int position,
-                       SortOrder sortOrder, Integer arrSize, byte[] viewConstant) {
-        init(name, familyName, dataType, maxLength, scale, nullable, position, sortOrder, arrSize, viewConstant);
+                       SortOrder sortOrder, Integer arrSize, byte[] viewConstant, boolean isViewReferenced) {
+        init(name, familyName, dataType, maxLength, scale, nullable, position, sortOrder, arrSize, viewConstant, isViewReferenced);
     }
 
     public PColumnImpl(PColumn column, int position) {
         this(column.getName(), column.getFamilyName(), column.getDataType(), column.getMaxLength(),
-                column.getScale(), column.isNullable(), position, column.getSortOrder(), column.getArraySize(), column.getViewConstant());
+                column.getScale(), column.isNullable(), position, column.getSortOrder(), column.getArraySize(), column.getViewConstant(), column.isViewReferenced());
     }
 
     private void init(PName name,
@@ -64,7 +65,7 @@ public class PColumnImpl implements PColumn {
             int position,
             SortOrder sortOrder,
             Integer arrSize,
-            byte[] viewConstant) {
+            byte[] viewConstant, boolean isViewReferenced) {
     	Preconditions.checkNotNull(sortOrder);
         this.dataType = dataType;
         if (familyName == null) {
@@ -85,6 +86,7 @@ public class PColumnImpl implements PColumn {
         this.sortOrder = sortOrder;
         this.arraySize = arrSize;
         this.viewConstant = viewConstant;
+        this.isViewReferenced = isViewReferenced;
     }
 
     @Override
@@ -173,63 +175,74 @@ public class PColumnImpl implements PColumn {
         return viewConstant;
     }
 
-  /**
-   * Create a PColumn instance from PBed PColumn instance
-   * @param column
-   */
-  public static PColumn createFromProto(PTableProtos.PColumn column) {
-    byte[] columnNameBytes = column.getColumnNameBytes().toByteArray();
-    PName columnName = PNameFactory.newName(columnNameBytes);
-    PName familyName = null;
-    if (column.hasFamilyNameBytes()) {
-      familyName = PNameFactory.newName(column.getFamilyNameBytes().toByteArray());
-    }
-    PDataType dataType = PDataType.fromSqlTypeName(column.getDataType());
-    Integer maxLength = null;
-    if (column.hasMaxLength()) {
-      maxLength = column.getMaxLength();
-    }
-    Integer scale = null;
-    if (column.hasScale()) {
-      scale = column.getScale();
-    }
-    boolean nullable = column.getNullable();
-    int position = column.getPosition();
-    SortOrder sortOrder = SortOrder.fromSystemValue(column.getSortOrder());
-    Integer arraySize = null;
-    if(column.hasArraySize()){
-      arraySize = column.getArraySize();
-    }
-    byte[] viewConstant = null;
-    if (column.hasViewConstant()) {
-        viewConstant = column.getViewConstant().toByteArray(); 
-    }
-    return new PColumnImpl(columnName, familyName, dataType, maxLength, scale, nullable, position,
-    		sortOrder, arraySize, viewConstant);
-  }
-
-  public static PTableProtos.PColumn toProto(PColumn column) {
-    PTableProtos.PColumn.Builder builder = PTableProtos.PColumn.newBuilder();
-    builder.setColumnNameBytes(HBaseZeroCopyByteString.wrap(column.getName().getBytes()));
-    if (column.getFamilyName() != null) {
-      builder.setFamilyNameBytes(HBaseZeroCopyByteString.wrap(column.getFamilyName().getBytes()));
-    }
-    builder.setDataType(column.getDataType().getSqlTypeName());
-    if (column.getMaxLength() != null) {
-      builder.setMaxLength(column.getMaxLength());
-    }
-    if (column.getScale() != null) {
-      builder.setScale(column.getScale());
-    }
-    builder.setNullable(column.isNullable());
-    builder.setPosition(column.getPosition());
-    builder.setSortOrder(column.getSortOrder().getSystemValue());
-    if(column.getArraySize() != null){
-      builder.setArraySize(column.getArraySize());
-    }
-    if(column.getViewConstant() != null){
-      builder.setViewConstant(HBaseZeroCopyByteString.wrap(column.getViewConstant()));
-    }
-    return builder.build();
-  }
+    @Override
+    public boolean isViewReferenced() {
+        return isViewReferenced;
+    }
+
+    /**
+     * Create a PColumn instance from PBed PColumn instance
+     * 
+     * @param column
+     */
+    public static PColumn createFromProto(PTableProtos.PColumn column) {
+        byte[] columnNameBytes = column.getColumnNameBytes().toByteArray();
+        PName columnName = PNameFactory.newName(columnNameBytes);
+        PName familyName = null;
+        if (column.hasFamilyNameBytes()) {
+            familyName = PNameFactory.newName(column.getFamilyNameBytes().toByteArray());
+        }
+        PDataType dataType = PDataType.fromSqlTypeName(column.getDataType());
+        Integer maxLength = null;
+        if (column.hasMaxLength()) {
+            maxLength = column.getMaxLength();
+        }
+        Integer scale = null;
+        if (column.hasScale()) {
+            scale = column.getScale();
+        }
+        boolean nullable = column.getNullable();
+        int position = column.getPosition();
+        SortOrder sortOrder = SortOrder.fromSystemValue(column.getSortOrder());
+        Integer arraySize = null;
+        if (column.hasArraySize()) {
+            arraySize = column.getArraySize();
+        }
+        byte[] viewConstant = null;
+        if (column.hasViewConstant()) {
+            viewConstant = column.getViewConstant().toByteArray();
+        }
+        boolean isViewReferenced = false;
+        if (column.hasViewReferenced()) {
+            isViewReferenced = column.getViewReferenced();
+        }
+
+        return new PColumnImpl(columnName, familyName, dataType, maxLength, scale, nullable, position, sortOrder,
+                arraySize, viewConstant, isViewReferenced);
+    }
+
+    public static PTableProtos.PColumn toProto(PColumn column) {
+        PTableProtos.PColumn.Builder builder = PTableProtos.PColumn.newBuilder();
+        builder.setColumnNameBytes(HBaseZeroCopyByteString.wrap(column.getName().getBytes()));
+        if (column.getFamilyName() != null) {
+            builder.setFamilyNameBytes(HBaseZeroCopyByteString.wrap(column.getFamilyName().getBytes()));
+        }
+        builder.setDataType(column.getDataType().getSqlTypeName());
+        if (column.getMaxLength() != null) {
+            builder.setMaxLength(column.getMaxLength());
+        }
+        if (column.getScale() != null) {
+            builder.setScale(column.getScale());
+        }
+        builder.setNullable(column.isNullable());
+        builder.setPosition(column.getPosition());
+        builder.setSortOrder(column.getSortOrder().getSystemValue());
+        if (column.getArraySize() != null) {
+            builder.setArraySize(column.getArraySize());
+        }
+        if (column.getViewConstant() != null) {
+            builder.setViewConstant(HBaseZeroCopyByteString.wrap(column.getViewConstant()));
+        }
+        return builder.build();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java
index ef48bbd..a1f7431 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/PMetaDataImpl.java
@@ -220,7 +220,7 @@ public class PMetaDataImpl implements PMetaData {
         // Update position of columns that follow removed column
         for (int i = position+1; i < oldColumns.size(); i++) {
             PColumn oldColumn = oldColumns.get(i);
-            PColumn newColumn = new PColumnImpl(oldColumn.getName(), oldColumn.getFamilyName(), oldColumn.getDataType(), oldColumn.getMaxLength(), oldColumn.getScale(), oldColumn.isNullable(), i-1+positionOffset, oldColumn.getSortOrder(), oldColumn.getArraySize(), oldColumn.getViewConstant());
+            PColumn newColumn = new PColumnImpl(oldColumn.getName(), oldColumn.getFamilyName(), oldColumn.getDataType(), oldColumn.getMaxLength(), oldColumn.getScale(), oldColumn.isNullable(), i-1+positionOffset, oldColumn.getSortOrder(), oldColumn.getArraySize(), oldColumn.getViewConstant(), oldColumn.isViewReferenced());
             columns.add(newColumn);
         }
         

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
index 4cf9ff1..8ae43e3 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/SaltingUtil.java
@@ -36,7 +36,7 @@ public class SaltingUtil {
     public static final String SALTING_COLUMN_NAME = "_SALT";
     public static final String SALTED_ROW_KEY_NAME = "_SALTED_KEY";
     public static final PColumnImpl SALTING_COLUMN = new PColumnImpl(
-            PNameFactory.newName(SALTING_COLUMN_NAME), null, PDataType.BINARY, 1, 0, false, 0, SortOrder.getDefault(), 0, null);
+            PNameFactory.newName(SALTING_COLUMN_NAME), null, PDataType.BINARY, 1, 0, false, 0, SortOrder.getDefault(), 0, null, false);
     public static final RowKeySchema VAR_BINARY_SALTED_SCHEMA = new RowKeySchemaBuilder(1)
         .addField(SALTING_COLUMN, false, SortOrder.getDefault())
         .addField(SchemaUtil.VAR_BINARY_DATUM, false, SortOrder.getDefault()).build();

http://git-wip-us.apache.org/repos/asf/incubator-phoenix/blob/816e1358/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
index 41fb6e5..2057752 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/util/IndexUtil.java
@@ -200,4 +200,13 @@ public class IndexUtil {
     public static boolean isDataPKColumn(PColumn column) {
         return column.getName().getString().startsWith(INDEX_COLUMN_NAME_SEP);
     }
+    
+    public static boolean getViewConstantValue(PColumn column, ImmutableBytesWritable ptr) {
+        byte[] value = column.getViewConstant();
+        if (value != null) {
+            ptr.set(value, 0, value.length-1);
+            return true;
+        }
+        return false;
+    }
 }


Mime
View raw message