http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cd7e86b/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 ecc66dd..445edd8 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
@@ -102,20 +102,20 @@ import com.google.common.collect.Sets;
 
 
 public class JoinCompiler {
-    
+
     public enum ColumnRefType {
         PREFILTER,
         JOINLOCAL,
         GENERAL,
     }
-    
+
     private final PhoenixStatement statement;
     private final SelectStatement select;
     private final ColumnResolver origResolver;
     private final boolean useStarJoin;
     private final Map<ColumnRef, ColumnRefType> columnRefs;
-    
-    
+
+
     private JoinCompiler(PhoenixStatement statement, SelectStatement select, 
ColumnResolver resolver) {
         this.statement = statement;
         this.select = select;
@@ -123,20 +123,20 @@ public class JoinCompiler {
         this.useStarJoin = !select.getHint().hasHint(Hint.NO_STAR_JOIN);
         this.columnRefs = new HashMap<ColumnRef, ColumnRefType>();
     }
-    
+
     public static JoinTable compile(PhoenixStatement statement, 
SelectStatement select, ColumnResolver resolver) throws SQLException {
-        JoinCompiler compiler = new JoinCompiler(statement, select, resolver); 
       
+        JoinCompiler compiler = new JoinCompiler(statement, select, resolver);
         JoinTableConstructor constructor = compiler.new JoinTableConstructor();
         Pair<Table, List<JoinSpec>> res = select.getFrom().accept(constructor);
         JoinTable joinTable = res.getSecond() == null ? compiler.new 
JoinTable(res.getFirst()) : compiler.new JoinTable(res.getFirst(), 
res.getSecond());
         if (select.getWhere() != null) {
             joinTable.addFilter(select.getWhere());
         }
-        
+
         ColumnRefParseNodeVisitor generalRefVisitor = new 
ColumnRefParseNodeVisitor(resolver, statement.getConnection());
         ColumnRefParseNodeVisitor joinLocalRefVisitor = new 
ColumnRefParseNodeVisitor(resolver, statement.getConnection());
         ColumnRefParseNodeVisitor prefilterRefVisitor = new 
ColumnRefParseNodeVisitor(resolver, statement.getConnection());
-        
+
         joinTable.pushDownColumnRefVisitors(generalRefVisitor, 
joinLocalRefVisitor, prefilterRefVisitor);
 
         for (AliasedNode node : select.getSelect()) {
@@ -155,7 +155,7 @@ public class JoinCompiler {
                 node.getNode().accept(generalRefVisitor);
             }
         }
-        
+
         for (ColumnRef ref : generalRefVisitor.getColumnRefMap().keySet()) {
             compiler.columnRefs.put(ref, ColumnRefType.GENERAL);
         }
@@ -167,16 +167,16 @@ public class JoinCompiler {
             if (!compiler.columnRefs.containsKey(ref))
                 compiler.columnRefs.put(ref, ColumnRefType.PREFILTER);
         }
-        
+
         return joinTable;
     }
 
     private class JoinTableConstructor implements TableNodeVisitor<Pair<Table, 
List<JoinSpec>>> {
-        
+
         private TableRef resolveTable(String alias, TableName name) throws 
SQLException {
             if (alias != null)
                 return origResolver.resolveTable(null, alias);
-            
+
             return origResolver.resolveTable(name.getSchemaName(), 
name.getTableName());
         }
 
@@ -198,7 +198,7 @@ public class JoinCompiler {
                 joinSpecs = new ArrayList<JoinSpec>();
             }
             joinSpecs.add(new JoinSpec(joinNode.getType(), 
joinNode.getOnNode(), joinTable, joinNode.isSingleValueOnly(), origResolver));
-            
+
             return new Pair<Table, List<JoinSpec>>(lhs.getFirst(), joinSpecs);
         }
 
@@ -220,7 +220,7 @@ public class JoinCompiler {
             return new Pair<Table, List<JoinSpec>>(table, null);
         }
     }
-    
+
     public class JoinTable {
         private final Table table;
         private final List<JoinSpec> joinSpecs;
@@ -230,7 +230,7 @@ public class JoinCompiler {
         private final boolean allLeftJoin;
         private final boolean isPrefilterAccepted;
         private final List<JoinSpec> prefilterAcceptedTables;
-        
+
         private JoinTable(Table table) {
             this.table = table;
             this.joinSpecs = Collections.<JoinSpec>emptyList();
@@ -241,7 +241,7 @@ public class JoinCompiler {
             this.isPrefilterAccepted = true;
             this.prefilterAcceptedTables = Collections.<JoinSpec>emptyList();
         }
-        
+
         private JoinTable(Table table, List<JoinSpec> joinSpecs) {
             this.table = table;
             this.joinSpecs = joinSpecs;
@@ -274,57 +274,57 @@ public class JoinCompiler {
                 }
             }
         }
-        
+
         public Table getTable() {
             return table;
         }
-        
+
         public List<JoinSpec> getJoinSpecs() {
             return joinSpecs;
         }
-        
+
         public List<Table> getTables() {
             return tables;
         }
-        
+
         public List<TableRef> getTableRefs() {
             return tableRefs;
         }
-        
+
         public boolean isAllLeftJoin() {
             return allLeftJoin;
         }
-        
+
         public SelectStatement getStatement() {
             return select;
         }
-        
+
         public ColumnResolver getOriginalResolver() {
             return origResolver;
         }
-        
+
         public Map<ColumnRef, ColumnRefType> getColumnRefs() {
             return columnRefs;
         }
-        
+
         public ParseNode getPostFiltersCombined() {
             return combine(postFilters);
         }
-        
+
         public void addFilter(ParseNode filter) throws SQLException {
             if (joinSpecs.isEmpty()) {
                 table.addFilter(filter);
                 return;
             }
-            
+
             WhereNodeVisitor visitor = new WhereNodeVisitor(origResolver, 
table,
-                    postFilters, 
Collections.<TableRef>singletonList(table.getTableRef()), 
+                    postFilters, 
Collections.<TableRef>singletonList(table.getTableRef()),
                     isPrefilterAccepted, prefilterAcceptedTables, 
statement.getConnection());
             filter.accept(visitor);
         }
-        
-        public void pushDownColumnRefVisitors(ColumnRefParseNodeVisitor 
generalRefVisitor, 
-                ColumnRefParseNodeVisitor joinLocalRefVisitor, 
+
+        public void pushDownColumnRefVisitors(ColumnRefParseNodeVisitor 
generalRefVisitor,
+                ColumnRefParseNodeVisitor joinLocalRefVisitor,
                 ColumnRefParseNodeVisitor prefilterRefVisitor) throws 
SQLException {
             for (ParseNode node : table.getPreFilters()) {
                 node.accept(prefilterRefVisitor);
@@ -349,7 +349,7 @@ public class JoinCompiler {
                 joinTable.pushDownColumnRefVisitors(generalRefVisitor, 
joinLocalRefVisitor, prefilterRefVisitor);
             }
         }
-        
+
         public Expression compilePostFilterExpression(StatementContext 
context, Table table) throws SQLException {
             List<ParseNode> filtersCombined = Lists.<ParseNode> 
newArrayList(postFilters);
             if (table != null) {
@@ -357,18 +357,18 @@ public class JoinCompiler {
             }
             return JoinCompiler.compilePostFilterExpression(context, 
filtersCombined);
         }
-        
+
         /**
          * Returns a boolean vector indicating whether the evaluation of join 
expressions
          * can be evaluated at an early stage if the input JoinSpec can be 
taken as a
-         * star join. Otherwise returns null.  
+         * star join. Otherwise returns null.
          * @return a boolean vector for a star join; or null for non star join.
          */
         public boolean[] getStarJoinVector() {
             int count = joinSpecs.size();
             if (!table.isFlat() ||
-                    (!useStarJoin 
-                            && count > 1 
+                    (!useStarJoin
+                            && count > 1
                             && joinSpecs.get(count - 1).getType() != 
JoinType.Left
                             && joinSpecs.get(count - 1).getType() != 
JoinType.Semi
                             && joinSpecs.get(count - 1).getType() != 
JoinType.Anti
@@ -378,7 +378,7 @@ public class JoinCompiler {
             boolean[] vector = new boolean[count];
             for (int i = 0; i < count; i++) {
                 JoinSpec joinSpec = joinSpecs.get(i);
-                if (joinSpec.getType() != JoinType.Left 
+                if (joinSpec.getType() != JoinType.Left
                         && joinSpec.getType() != JoinType.Inner
                         && joinSpec.getType() != JoinType.Semi
                         && joinSpec.getType() != JoinType.Anti)
@@ -392,56 +392,56 @@ public class JoinCompiler {
                     }
                 }
             }
-            
+
             return vector;
         }
-        
+
         public JoinTable getSubJoinTableWithoutPostFilters() {
             return joinSpecs.size() > 1 ? new JoinTable(table, 
joinSpecs.subList(0, joinSpecs.size() - 1)) :
                 new JoinTable(table);
         }
-        
+
         public SelectStatement getAsSingleSubquery(SelectStatement query, 
boolean asSubquery) throws SQLException {
             assert (isFlat(query));
-            
+
             if (asSubquery)
                 return query;
-            
-            return NODE_FACTORY.select(select, query.getFrom(), 
query.getWhere());            
+
+            return NODE_FACTORY.select(select, query.getFrom(), 
query.getWhere());
         }
-        
+
         public boolean hasPostReference() {
             for (Table table : tables) {
                 if (table.isWildCardSelect()) {
                     return true;
                 }
             }
-            
+
             for (Map.Entry<ColumnRef, ColumnRefType> e : 
columnRefs.entrySet()) {
                 if (e.getValue() == ColumnRefType.GENERAL && 
tableRefs.contains(e.getKey().getTableRef())) {
                     return true;
                 }
             }
-            
+
             return false;
         }
-        
+
         public boolean hasFilters() {
            if (!postFilters.isEmpty())
                return true;
-           
+
            if (isPrefilterAccepted && table.hasFilters())
                return true;
-           
+
            for (JoinSpec joinSpec : prefilterAcceptedTables) {
                if (joinSpec.getJoinTable().hasFilters())
                    return true;
            }
-           
+
            return false;
         }
     }
-    
+
     public class JoinSpec {
         private final JoinType type;
         private final List<EqualParseNode> onConditions;
@@ -449,8 +449,8 @@ public class JoinCompiler {
         private final boolean singleValueOnly;
         private Set<TableRef> dependencies;
         private OnNodeVisitor onNodeVisitor;
-        
-        private JoinSpec(JoinType type, ParseNode onNode, JoinTable joinTable, 
+
+        private JoinSpec(JoinType type, ParseNode onNode, JoinTable joinTable,
                 boolean singleValueOnly, ColumnResolver resolver) throws 
SQLException {
             this.type = type;
             this.onConditions = new ArrayList<EqualParseNode>();
@@ -462,38 +462,38 @@ public class JoinCompiler {
                 onNode.accept(this.onNodeVisitor);
             }
         }
-        
+
         public void addOnCondition(ParseNode node) throws SQLException {
             node.accept(onNodeVisitor);
         }
-        
+
         public JoinType getType() {
             return type;
         }
-        
+
         public List<EqualParseNode> getOnConditions() {
             return onConditions;
         }
-        
+
         public JoinTable getJoinTable() {
             return joinTable;
         }
-        
+
         public boolean isSingleValueOnly() {
             return singleValueOnly;
         }
-        
+
         public Set<TableRef> getDependencies() {
             return dependencies;
         }
-        
+
         public Pair<List<Expression>, List<Expression>> 
compileJoinConditions(StatementContext lhsCtx, StatementContext rhsCtx, boolean 
sortExpressions) throws SQLException {
             if (onConditions.isEmpty()) {
                 return new Pair<List<Expression>, List<Expression>>(
-                        Collections.<Expression> 
singletonList(LiteralExpression.newConstant(1)), 
+                        Collections.<Expression> 
singletonList(LiteralExpression.newConstant(1)),
                         Collections.<Expression> 
singletonList(LiteralExpression.newConstant(1)));
             }
-            
+
             List<Pair<Expression, Expression>> compiled = 
Lists.<Pair<Expression, Expression>> 
newArrayListWithExpectedSize(onConditions.size());
             ExpressionCompiler lhsCompiler = new ExpressionCompiler(lhsCtx);
             ExpressionCompiler rhsCompiler = new ExpressionCompiler(rhsCtx);
@@ -546,11 +546,11 @@ public class JoinCompiler {
 
             return new Pair<List<Expression>, List<Expression>>(lConditions, 
rConditions);
         }
-        
+
         private PDataType getCommonType(PDataType lType, PDataType rType) 
throws SQLException {
             if (lType == rType)
                 return lType;
-            
+
             if (!lType.isComparableTo(rType))
                 throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.TYPE_MISMATCH)
                     .setMessage("On-clause LHS expression and RHS expression 
must be comparable. LHS type: " + lType + ", RHS type: " + rType)
@@ -609,7 +609,7 @@ public class JoinCompiler {
             return PVarbinary.INSTANCE;
         }
     }
-    
+
     public class Table {
         private final TableNode tableNode;
         private final List<ColumnDef> dynamicColumns;
@@ -619,8 +619,8 @@ public class JoinCompiler {
         private final List<ParseNode> preFilters;
         private final List<ParseNode> postFilters;
         private final boolean isPostFilterConvertible;
-        
-        private Table(TableNode tableNode, List<ColumnDef> dynamicColumns, 
+
+        private Table(TableNode tableNode, List<ColumnDef> dynamicColumns,
                 List<AliasedNode> selectNodes, TableRef tableRef) {
             this.tableNode = tableNode;
             this.dynamicColumns = dynamicColumns;
@@ -631,8 +631,8 @@ public class JoinCompiler {
             this.postFilters = Collections.<ParseNode>emptyList();
             this.isPostFilterConvertible = false;
         }
-        
-        private Table(DerivedTableNode tableNode, 
+
+        private Table(DerivedTableNode tableNode,
                 List<AliasedNode> selectNodes, TableRef tableRef) throws 
SQLException {
             this.tableNode = tableNode;
             this.dynamicColumns = Collections.<ColumnDef>emptyList();
@@ -643,35 +643,35 @@ public class JoinCompiler {
             this.postFilters = new ArrayList<ParseNode>();
             this.isPostFilterConvertible = 
SubselectRewriter.isPostFilterConvertible(subselect);
         }
-        
+
         public TableNode getTableNode() {
             return tableNode;
         }
-        
+
         public List<ColumnDef> getDynamicColumns() {
             return dynamicColumns;
         }
-        
+
         public boolean isSubselect() {
             return subselect != null;
         }
-        
+
         public List<AliasedNode> getSelectNodes() {
             return selectNodes;
         }
-        
+
         public List<ParseNode> getPreFilters() {
             return preFilters;
         }
-        
+
         public List<ParseNode> getPostFilters() {
             return postFilters;
         }
-        
+
         public TableRef getTableRef() {
             return tableRef;
         }
-        
+
         public void addFilter(ParseNode filter) {
             if (!isSubselect() || isPostFilterConvertible) {
                 preFilters.add(filter);
@@ -679,30 +679,30 @@ public class JoinCompiler {
                 postFilters.add(filter);
             }
         }
-        
+
         public ParseNode getPreFiltersCombined() {
             return combine(preFilters);
         }
-        
+
         public Expression compilePostFilterExpression(StatementContext 
context) throws SQLException {
             return JoinCompiler.compilePostFilterExpression(context, 
postFilters);
         }
-        
+
         public SelectStatement getAsSubquery(List<OrderByNode> orderBy) throws 
SQLException {
             if (isSubselect())
                 return 
SubselectRewriter.applyOrderBy(SubselectRewriter.applyPostFilters(subselect, 
preFilters, tableNode.getAlias()), orderBy, tableNode.getAlias());
-            
+
             return NODE_FACTORY.select(tableNode, select.getHint(), false, 
selectNodes, getPreFiltersCombined(), null, null, orderBy, null, 0, false, 
select.hasSequence());
         }
-        
+
         public boolean hasFilters() {
             return isSubselect() ? (!postFilters.isEmpty() || 
subselect.getWhere() != null || subselect.getHaving() != null) : 
!preFilters.isEmpty();
         }
-        
+
         public boolean isFlat() {
             return subselect == null || JoinCompiler.isFlat(subselect);
         }
-        
+
         protected boolean isWildCardSelect() {
             return (selectNodes.size() == 1 && selectNodes.get(0).getNode() 
instanceof TableWildcardParseNode);
         }
@@ -721,7 +721,7 @@ public class JoinCompiler {
                 }
             }
         }
-        
+
         public ProjectedPTableWrapper createProjectedTable(boolean 
retainPKColumns, StatementContext context) throws SQLException {
             assert(!isSubselect());
             List<PColumn> projectedColumns = new ArrayList<PColumn>();
@@ -745,31 +745,33 @@ public class JoinCompiler {
             } else {
                 for (Map.Entry<ColumnRef, ColumnRefType> e : 
columnRefs.entrySet()) {
                     ColumnRef columnRef = e.getKey();
-                    if (e.getValue() != ColumnRefType.PREFILTER 
+                    if (e.getValue() != ColumnRefType.PREFILTER
                             && columnRef.getTableRef().equals(tableRef)
                             && (!retainPKColumns || 
!SchemaUtil.isPKColumn(columnRef.getColumn()))) {
                         PColumn column = columnRef.getColumn();
                         addProjectedColumn(projectedColumns, 
sourceExpressions, columnNameMap,
-                                column, 
PNameFactory.newName(TupleProjector.VALUE_COLUMN_FAMILY), hasSaltingColumn, 
+                                column, 
PNameFactory.newName(TupleProjector.VALUE_COLUMN_FAMILY), hasSaltingColumn,
                                 columnRef instanceof LocalIndexColumnRef, 
context);
                     }
-                }               
+                }
             }
-            
+
             PTable t = PTableImpl.makePTable(table.getTenantId(), 
PNameFactory.newName(PROJECTED_TABLE_SCHEMA), table.getName(), PTableType.JOIN,
                         table.getIndexState(), table.getTimeStamp(), 
table.getSequenceNumber(), table.getPKName(),
                         retainPKColumns ? table.getBucketNum() : null, 
projectedColumns, table.getParentSchemaName(),
-                        table.getParentTableName(), table.getIndexes(), 
table.isImmutableRows(), Collections.<PName>emptyList(), null, null, 
table.isWALDisabled(), table.isMultiTenant(), table.getViewType(), 
table.getViewIndexId(), table.getIndexType());
+                        table.getParentTableName(), table.getIndexes(), 
table.isImmutableRows(), Collections.<PName>emptyList(), null, null,
+                        table.isWALDisabled(), table.isMultiTenant(), 
table.getStoreNulls(), table.getViewType(), table.getViewIndexId(),
+                        table.getIndexType());
             return new ProjectedPTableWrapper(t, columnNameMap, 
sourceExpressions);
         }
-        
+
         private void addProjectedColumn(List<PColumn> projectedColumns, 
List<Expression> sourceExpressions,
-                ListMultimap<String, String> columnNameMap, PColumn 
sourceColumn, PName familyName, boolean hasSaltingColumn, 
-                boolean isLocalIndexColumnRef, StatementContext context) 
+                ListMultimap<String, String> columnNameMap, PColumn 
sourceColumn, PName familyName, boolean hasSaltingColumn,
+                boolean isLocalIndexColumnRef, StatementContext context)
         throws SQLException {
             if (sourceColumn == SALTING_COLUMN)
                 return;
-            
+
             int position = projectedColumns.size() + (hasSaltingColumn ? 1 : 
0);
             PTable table = tableRef.getTable();
             String schemaName = table.getSchemaName().getString();
@@ -777,23 +779,23 @@ public class JoinCompiler {
             String colName = isLocalIndexColumnRef ? 
IndexUtil.getIndexColumnName(sourceColumn) : sourceColumn.getName().getString();
             String fullName = getProjectedColumnName(schemaName, tableName, 
colName);
             String aliasedName = tableRef.getTableAlias() == null ? fullName : 
getProjectedColumnName(null, tableRef.getTableAlias(), colName);
-            
+
             columnNameMap.put(colName, aliasedName);
             if (!fullName.equals(aliasedName)) {
                 columnNameMap.put(fullName, aliasedName);
             }
-            
+
             PName name = PNameFactory.newName(aliasedName);
-            PColumnImpl column = new PColumnImpl(name, familyName, 
sourceColumn.getDataType(), 
-                    sourceColumn.getMaxLength(), sourceColumn.getScale(), 
sourceColumn.isNullable(), 
+            PColumnImpl column = new PColumnImpl(name, familyName, 
sourceColumn.getDataType(),
+                    sourceColumn.getMaxLength(), sourceColumn.getScale(), 
sourceColumn.isNullable(),
                     position, sourceColumn.getSortOrder(), 
sourceColumn.getArraySize(), sourceColumn.getViewConstant(), 
sourceColumn.isViewReferenced());
-            Expression sourceExpression = isLocalIndexColumnRef ? 
-                      NODE_FACTORY.column(TableName.create(schemaName, 
tableName), "\"" + colName + "\"", null).accept(new 
ExpressionCompiler(context)) 
+            Expression sourceExpression = isLocalIndexColumnRef ?
+                      NODE_FACTORY.column(TableName.create(schemaName, 
tableName), "\"" + colName + "\"", null).accept(new ExpressionCompiler(context))
                     : new ColumnRef(tableRef, 
sourceColumn.getPosition()).newColumnExpression();
             projectedColumns.add(column);
             sourceExpressions.add(sourceExpression);
         }
-        
+
         public ProjectedPTableWrapper createProjectedTable(RowProjector 
rowProjector) throws SQLException {
             assert(isSubselect());
             List<PColumn> projectedColumns = new ArrayList<PColumn>();
@@ -803,20 +805,22 @@ public class JoinCompiler {
             for (PColumn column : table.getColumns()) {
                 String colName = getProjectedColumnName(null, 
tableRef.getTableAlias(), column.getName().getString());
                 Expression sourceExpression = 
rowProjector.getColumnProjector(column.getPosition()).getExpression();
-                PColumnImpl projectedColumn = new 
PColumnImpl(PNameFactory.newName(colName), 
PNameFactory.newName(TupleProjector.VALUE_COLUMN_FAMILY), 
-                        sourceExpression.getDataType(), 
sourceExpression.getMaxLength(), sourceExpression.getScale(), 
sourceExpression.isNullable(), 
-                        column.getPosition(), sourceExpression.getSortOrder(), 
column.getArraySize(), column.getViewConstant(), column.isViewReferenced());    
            
+                PColumnImpl projectedColumn = new 
PColumnImpl(PNameFactory.newName(colName), 
PNameFactory.newName(TupleProjector.VALUE_COLUMN_FAMILY),
+                        sourceExpression.getDataType(), 
sourceExpression.getMaxLength(), sourceExpression.getScale(), 
sourceExpression.isNullable(),
+                        column.getPosition(), sourceExpression.getSortOrder(), 
column.getArraySize(), column.getViewConstant(), column.isViewReferenced());
                 projectedColumns.add(projectedColumn);
                 sourceExpressions.add(sourceExpression);
             }
             PTable t = PTableImpl.makePTable(table.getTenantId(), 
PNameFactory.newName(PROJECTED_TABLE_SCHEMA), table.getName(), PTableType.JOIN,
                         table.getIndexState(), table.getTimeStamp(), 
table.getSequenceNumber(), table.getPKName(),
                         null, projectedColumns, table.getParentSchemaName(),
-                        table.getParentTableName(), table.getIndexes(), 
table.isImmutableRows(), Collections.<PName>emptyList(), null, null, 
table.isWALDisabled(), table.isMultiTenant(), table.getViewType(), 
table.getViewIndexId(), table.getIndexType());
+                        table.getParentTableName(), table.getIndexes(), 
table.isImmutableRows(), Collections.<PName>emptyList(), null, null,
+                        table.isWALDisabled(), table.isMultiTenant(), 
table.getStoreNulls(), table.getViewType(),
+                        table.getViewIndexId(), table.getIndexType());
             return new ProjectedPTableWrapper(t, columnNameMap, 
sourceExpressions);
         }
     }
-    
+
     private static class WhereNodeVisitor extends 
BooleanParseNodeVisitor<Void> {
         private Table table;
         private List<ParseNode> postFilters;
@@ -824,9 +828,9 @@ public class JoinCompiler {
         private boolean isPrefilterAccepted;
         private List<JoinSpec> prefilterAcceptedTables;
         ColumnRefParseNodeVisitor columnRefVisitor;
-        
+
         public WhereNodeVisitor(ColumnResolver resolver, Table table,
-                List<ParseNode> postFilters, List<TableRef> selfTableRefs, 
boolean isPrefilterAccepted, 
+                List<ParseNode> postFilters, List<TableRef> selfTableRefs, 
boolean isPrefilterAccepted,
                 List<JoinSpec> prefilterAcceptedTables, PhoenixConnection 
connection) {
             this.table = table;
             this.postFilters = postFilters;
@@ -835,12 +839,12 @@ public class JoinCompiler {
             this.prefilterAcceptedTables = prefilterAcceptedTables;
             this.columnRefVisitor = new ColumnRefParseNodeVisitor(resolver, 
connection);
         }
-        
+
         @Override
         protected boolean enterBooleanNode(ParseNode node) throws SQLException 
{
             return false;
         }
-        
+
         @Override
         protected Void leaveBooleanNode(ParseNode node,
                 List<Void> l) throws SQLException {
@@ -876,17 +880,17 @@ public class JoinCompiler {
             }
             return null;
         }
-        
+
         @Override
         protected boolean enterNonBooleanNode(ParseNode node) throws 
SQLException {
             return false;
         }
-        
+
         @Override
         protected Void leaveNonBooleanNode(ParseNode node, List<Void> l) 
throws SQLException {
             return null;
         }
-        
+
         @Override
         public boolean visitEnter(AndParseNode node) throws SQLException {
             return true;
@@ -896,38 +900,38 @@ public class JoinCompiler {
         public Void visitLeave(AndParseNode node, List<Void> l) throws 
SQLException {
             return null;
         }
-        
+
         @Override
-        public Void visitLeave(ComparisonParseNode node, List<Void> l) 
+        public Void visitLeave(ComparisonParseNode node, List<Void> l)
                 throws SQLException {
             if (!(node instanceof EqualParseNode))
                 return leaveBooleanNode(node, l);
-            
+
             ListIterator<JoinSpec> iter = 
prefilterAcceptedTables.listIterator(prefilterAcceptedTables.size());
             while (iter.hasPrevious()) {
                 JoinSpec joinSpec = iter.previous();
                 if (joinSpec.getType() != JoinType.Inner || 
joinSpec.isSingleValueOnly()) {
                     continue;
                 }
-                
+
                 try {
                     joinSpec.addOnCondition(node);
                     return null;
                 } catch (SQLException e) {
                 }
             }
-            
+
             return leaveBooleanNode(node, l);
         }
     }
-    
+
     private static class OnNodeVisitor extends BooleanParseNodeVisitor<Void> {
         private List<EqualParseNode> onConditions;
         private Set<TableRef> dependencies;
         private JoinTable joinTable;
         private ColumnRefParseNodeVisitor columnRefVisitor;
-        
-        public OnNodeVisitor(ColumnResolver resolver, List<EqualParseNode> 
onConditions, 
+
+        public OnNodeVisitor(ColumnResolver resolver, List<EqualParseNode> 
onConditions,
                 Set<TableRef> dependencies, JoinTable joinTable, 
PhoenixConnection connection) {
             this.onConditions = onConditions;
             this.dependencies = dependencies;
@@ -1005,7 +1009,7 @@ public class JoinCompiler {
 
         /*
          * Conditions in the ON clause can only be:
-         * 1) an equal test between a self table expression and a foreign 
+         * 1) an equal test between a self table expression and a foreign
          *    table expression.
          * 2) a boolean condition referencing to the self table only.
          * Otherwise, it can be ambiguous.
@@ -1014,16 +1018,16 @@ public class JoinCompiler {
             throw new 
SQLExceptionInfo.Builder(SQLExceptionCode.AMBIGUOUS_JOIN_CONDITION).build().buildException();
         }
     }
-    
+
     private static class LocalIndexColumnRef extends ColumnRef {
         private final TableRef indexTableRef;
-        
+
         public LocalIndexColumnRef(TableRef tableRef, String familyName,
                 String columnName, TableRef indexTableRef) throws 
MetaDataEntityNotFoundException {
             super(tableRef, familyName, columnName);
             this.indexTableRef = indexTableRef;
         }
-        
+
         @Override
         public TableRef getTableRef() {
             return indexTableRef;
@@ -1056,7 +1060,7 @@ public class JoinCompiler {
             try {
                 columnRef = resolver.resolveColumn(node.getSchemaName(), 
node.getTableName(), node.getName());
             } catch (ColumnNotFoundException e) {
-                // This could be a LocalIndexDataColumnRef. If so, the table 
name must have 
+                // This could be a LocalIndexDataColumnRef. If so, the table 
name must have
                 // been appended by the IndexStatementRewriter, and we can 
convert it into.
                 TableRef tableRef = 
resolver.resolveTable(node.getSchemaName(), node.getTableName());
                 if (tableRef.getTable().getIndexType() == IndexType.LOCAL) {
@@ -1066,8 +1070,8 @@ public class JoinCompiler {
                                     .getParentTableName().getString())), 
connection).resolveTable(
                             tableRef.getTable().getSchemaName().getString(),
                             
tableRef.getTable().getParentTableName().getString());
-                    columnRef = new LocalIndexColumnRef(parentTableRef, 
-                            IndexUtil.getDataColumnFamilyName(node.getName()), 
+                    columnRef = new LocalIndexColumnRef(parentTableRef,
+                            IndexUtil.getDataColumnFamilyName(node.getName()),
                             IndexUtil.getDataColumnName(node.getName()), 
tableRef);
                 } else {
                     throw e;
@@ -1075,7 +1079,7 @@ public class JoinCompiler {
             }
             columnRefMap.put(columnRef, node);
             tableRefSet.add(columnRef.getTableRef());
-            return null;                
+            return null;
         }
 
         public Set<TableRef> getTableRefSet() {
@@ -1104,7 +1108,7 @@ public class JoinCompiler {
                     ret = isSelf ? ColumnRefType.COMPLEX : 
ColumnRefType.FOREIGN_ONLY;
                     break;
                 default: // COMPLEX do nothing
-                    break;    
+                    break;
                 }
 
                 if (ret == ColumnRefType.COMPLEX) {
@@ -1115,29 +1119,29 @@ public class JoinCompiler {
             return ret;
         }
     }
-    
+
     private static final String PROJECTED_TABLE_SCHEMA = ".";
     // for creation of new statements
     private static final ParseNodeFactory NODE_FACTORY = new 
ParseNodeFactory();
-    
+
     private static boolean isFlat(SelectStatement select) {
-        return !select.isJoin() 
-                && !select.isAggregate() 
-                && !select.isDistinct() 
+        return !select.isJoin()
+                && !select.isAggregate()
+                && !select.isDistinct()
                 && !(select.getFrom() instanceof DerivedTableNode)
                 && select.getLimit() == null;
     }
-    
+
     private static ParseNode combine(List<ParseNode> nodes) {
         if (nodes.isEmpty())
             return null;
-        
+
         if (nodes.size() == 1)
             return nodes.get(0);
-        
+
         return NODE_FACTORY.and(nodes);
     }
-    
+
     private List<AliasedNode> extractFromSelect(List<AliasedNode> select, 
TableRef tableRef, ColumnResolver resolver) throws SQLException {
         List<AliasedNode> ret = new ArrayList<AliasedNode>();
         ColumnRefParseNodeVisitor visitor = new 
ColumnRefParseNodeVisitor(resolver, statement.getConnection());
@@ -1152,7 +1156,7 @@ public class JoinCompiler {
                 }
                 continue;
             }
-            
+
             node.accept(visitor);
             ColumnRefParseNodeVisitor.ColumnRefType type = 
visitor.getContentType(Collections.singletonList(tableRef));
             if (type == ColumnRefParseNodeVisitor.ColumnRefType.SELF_ONLY) {
@@ -1168,11 +1172,11 @@ public class JoinCompiler {
         }
         return ret;
     }
-    
+
     private static Expression compilePostFilterExpression(StatementContext 
context, List<ParseNode> postFilters) throws SQLException {
         if (postFilters.isEmpty())
             return null;
-        
+
         ExpressionCompiler expressionCompiler = new 
ExpressionCompiler(context);
         List<Expression> expressions = new 
ArrayList<Expression>(postFilters.size());
         for (ParseNode postFilter : postFilters) {
@@ -1180,13 +1184,13 @@ public class JoinCompiler {
             Expression expression = postFilter.accept(expressionCompiler);
             expressions.add(expression);
         }
-        
+
         if (expressions.size() == 1)
             return expressions.get(0);
-        
+
         return AndExpression.create(expressions);
     }
-    
+
     public static SelectStatement optimize(PhoenixStatement statement, 
SelectStatement select, final ColumnResolver resolver) throws SQLException {
         TableRef groupByTableRef = null;
         TableRef orderByTableRef = null;
@@ -1221,11 +1225,11 @@ public class JoinCompiler {
             }
             if (orderByTableRef != null && !orderByTableRef.equals(table)) {
                 orderByTableRef = null;
-            }            
+            }
         }
-        
+
         final Map<TableRef, TableRef> replacement = new HashMap<TableRef, 
TableRef>();
-        
+
         for (Table table : join.getTables()) {
             if (table.isSubselect())
                 continue;
@@ -1236,12 +1240,12 @@ public class JoinCompiler {
             QueryPlan plan = 
statement.getConnection().getQueryServices().getOptimizer().optimize(statement, 
stmt);
             if (!plan.getTableRef().equals(tableRef)) {
                 replacement.put(tableRef, plan.getTableRef());
-            }            
+            }
         }
-        
-        if (replacement.isEmpty()) 
+
+        if (replacement.isEmpty())
             return select;
-        
+
         TableNode from = select.getFrom();
         TableNode newFrom = from.accept(new TableNodeVisitor<TableNode>() {
             private TableRef resolveTable(String alias, TableName name) throws 
SQLException {
@@ -1297,10 +1301,10 @@ public class JoinCompiler {
                 return subselectNode;
             }
         });
-        
-        return IndexStatementRewriter.translate(NODE_FACTORY.select(select, 
newFrom), resolver, replacement);        
+
+        return IndexStatementRewriter.translate(NODE_FACTORY.select(select, 
newFrom), resolver, replacement);
     }
-    
+
     private static SelectStatement getSubqueryForOptimizedPlan(HintNode 
hintNode, List<ColumnDef> dynamicCols, TableRef tableRef, Map<ColumnRef, 
ColumnRefType> columnRefs, ParseNode where, List<ParseNode> groupBy,
             List<OrderByNode> orderBy, boolean isWildCardSelect, boolean 
hasSequence) {
         String schemaName = tableRef.getTable().getSchemaName().getString();
@@ -1324,20 +1328,20 @@ public class JoinCompiler {
 
         return NODE_FACTORY.select(from, hintNode, false, selectList, where, 
groupBy, null, orderBy, null, 0, groupBy != null, hasSequence);
     }
-    
+
     public class PTableWrapper {
        protected PTable table;
        protected ListMultimap<String, String> columnNameMap;
-       
+
        protected PTableWrapper(PTable table, ListMultimap<String, String> 
columnNameMap) {
                this.table = table;
                this.columnNameMap = columnNameMap;
        }
-       
+
        public PTable getTable() {
                return table;
        }
-       
+
        public ListMultimap<String, String> getColumnNameMap() {
                return columnNameMap;
        }
@@ -1345,11 +1349,11 @@ public class JoinCompiler {
        public List<String> getMappedColumnName(String name) {
                return columnNameMap.get(name);
        }
-        
+
         public ColumnResolver createColumnResolver() {
             return new JoinedTableColumnResolver(this, origResolver);
         }
-        
+
         public PTableWrapper mergeProjectedTables(PTableWrapper rWrapper, 
JoinType type) throws SQLException {
             PTable left = this.getTable();
             PTable right = rWrapper.getTable();
@@ -1361,8 +1365,8 @@ public class JoinCompiler {
                     if (SchemaUtil.isPKColumn(c)) {
                         merged.add(c);
                     } else {
-                        PColumnImpl column = new PColumnImpl(c.getName(), 
c.getFamilyName(), c.getDataType(), 
-                                c.getMaxLength(), c.getScale(), true, 
c.getPosition(), 
+                        PColumnImpl column = new PColumnImpl(c.getName(), 
c.getFamilyName(), c.getDataType(),
+                                c.getMaxLength(), c.getScale(), true, 
c.getPosition(),
                                 c.getSortOrder(), c.getArraySize(), 
c.getViewConstant(), c.isViewReferenced());
                         merged.add(column);
                     }
@@ -1371,9 +1375,9 @@ public class JoinCompiler {
             int position = merged.size();
             for (PColumn c : right.getColumns()) {
                 if (!SchemaUtil.isPKColumn(c)) {
-                    PColumnImpl column = new PColumnImpl(c.getName(), 
-                            
PNameFactory.newName(TupleProjector.VALUE_COLUMN_FAMILY), c.getDataType(), 
-                            c.getMaxLength(), c.getScale(), type == 
JoinType.Inner ? c.isNullable() : true, position++, 
+                    PColumnImpl column = new PColumnImpl(c.getName(),
+                            
PNameFactory.newName(TupleProjector.VALUE_COLUMN_FAMILY), c.getDataType(),
+                            c.getMaxLength(), c.getScale(), type == 
JoinType.Inner ? c.isNullable() : true, position++,
                             c.getSortOrder(), c.getArraySize(), 
c.getViewConstant(), c.isViewReferenced());
                     merged.add(column);
                 }
@@ -1383,48 +1387,48 @@ public class JoinCompiler {
             }
             PTable t = PTableImpl.makePTable(left.getTenantId(), 
left.getSchemaName(),
                     
PNameFactory.newName(SchemaUtil.getTableName(left.getName().getString(), 
right.getName().getString())), left.getType(), left.getIndexState(), 
left.getTimeStamp(), left.getSequenceNumber(), left.getPKName(), 
left.getBucketNum(), merged,
-                    left.getParentSchemaName(), left.getParentTableName(), 
left.getIndexes(), left.isImmutableRows(), Collections.<PName>emptyList(), 
null, null, PTable.DEFAULT_DISABLE_WAL, left.isMultiTenant(), 
left.getViewType(), left.getViewIndexId(), left.getIndexType());
+                    left.getParentSchemaName(), left.getParentTableName(), 
left.getIndexes(), left.isImmutableRows(), Collections.<PName>emptyList(), 
null, null, PTable.DEFAULT_DISABLE_WAL, left.isMultiTenant(), 
left.getStoreNulls(), left.getViewType(), left.getViewIndexId(), 
left.getIndexType());
 
             ListMultimap<String, String> mergedMap = 
ArrayListMultimap.<String, String>create();
             mergedMap.putAll(this.getColumnNameMap());
             mergedMap.putAll(rWrapper.getColumnNameMap());
-            
+
             return new PTableWrapper(t, mergedMap);
         }
     }
-    
+
     public class ProjectedPTableWrapper extends PTableWrapper {
        private List<Expression> sourceExpressions;
-       
+
        protected ProjectedPTableWrapper(PTable table, ListMultimap<String, 
String> columnNameMap, List<Expression> sourceExpressions) {
                super(table, columnNameMap);
                this.sourceExpressions = sourceExpressions;
        }
-       
+
        public Expression getSourceExpression(PColumn column) {
                return sourceExpressions.get(column.getPosition() - 
(table.getBucketNum() == null ? 0 : 1));
        }
-        
+
         public TupleProjector createTupleProjector() {
             return new TupleProjector(this);
         }
     }
-    
+
     public static class JoinedTableColumnResolver implements ColumnResolver {
        private PTableWrapper table;
        private ColumnResolver tableResolver;
        private TableRef tableRef;
-       
+
        private JoinedTableColumnResolver(PTableWrapper table, ColumnResolver 
tableResolver) {
                this.table = table;
                this.tableResolver = tableResolver;
             this.tableRef = new TableRef(ParseNodeFactory.createTempAlias(), 
table.getTable(), 0, false);
        }
-        
+
         public PTableWrapper getPTableWrapper() {
             return table;
         }
-        
+
         public TableRef getTableRef() {
             return tableRef;
         }
@@ -1451,18 +1455,18 @@ public class JoinCompiler {
                                List<String> names = 
table.getMappedColumnName(name);
                                if (names.size() == 1) {
                                        PColumn column = 
tableRef.getTable().getColumn(names.get(0));
-                                       return new ColumnRef(tableRef, 
column.getPosition());                                   
+                                       return new ColumnRef(tableRef, 
column.getPosition());
                                }
-                               
+
                                if (names.size() > 1) {
                                        throw new 
AmbiguousColumnException(name);
                                }
-                               
+
                                throw e;
                        }
                }
     }
-    
+
     private static String getProjectedColumnName(String schemaName, String 
tableName,
                        String colName) {
        return SchemaUtil.getColumnName(SchemaUtil.getTableName(schemaName, 
tableName), colName);

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cd7e86b/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 f2bc355..8145e67 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
@@ -40,6 +40,7 @@ import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.PK_NAME_BYTES;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SALT_BUCKETS_BYTES;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SCHEMA_NAME_INDEX;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.SORT_ORDER_BYTES;
+import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.STORE_NULLS_BYTES;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES;
 import static org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_NAME_INDEX;
 import static 
org.apache.phoenix.jdbc.PhoenixDatabaseMetaData.TABLE_SEQ_NUM_BYTES;
@@ -155,7 +156,7 @@ import com.google.protobuf.RpcController;
 import com.google.protobuf.Service;
 
 /**
- * 
+ *
  * Endpoint co-processor through which all Phoenix metadata mutations flow.
  * We only allow mutations to the latest version of a Phoenix table (i.e. the
  * timeStamp must be increasing).
@@ -166,7 +167,7 @@ import com.google.protobuf.Service;
  * any in use on the data table, b/c otherwise we can end up with data rows 
that
  * are not valid against a schema row.
  *
- * 
+ *
  * @since 0.1
  */
 @SuppressWarnings("deprecation")
@@ -190,9 +191,10 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
     private static final KeyValue VIEW_INDEX_ID_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
VIEW_INDEX_ID_BYTES);
     private static final KeyValue INDEX_TYPE_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
INDEX_TYPE_BYTES);
     private static final KeyValue INDEX_DISABLE_TIMESTAMP_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
INDEX_DISABLE_TIMESTAMP_BYTES);
+    private static final KeyValue STORE_NULLS_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
STORE_NULLS_BYTES);
     private static final KeyValue EMPTY_KEYVALUE_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
QueryConstants.EMPTY_COLUMN_BYTES);
     private static final List<KeyValue> TABLE_KV_COLUMNS = 
Arrays.<KeyValue>asList(
-            EMPTY_KEYVALUE_KV, 
+            EMPTY_KEYVALUE_KV,
             TABLE_TYPE_KV,
             TABLE_SEQ_NUM_KV,
             COLUMN_COUNT_KV,
@@ -208,7 +210,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
             VIEW_TYPE_KV,
             VIEW_INDEX_ID_KV,
             INDEX_TYPE_KV,
-            INDEX_DISABLE_TIMESTAMP_KV
+            INDEX_DISABLE_TIMESTAMP_KV,
+            STORE_NULLS_KV
             );
     static {
         Collections.sort(TABLE_KV_COLUMNS, KeyValue.COMPARATOR);
@@ -228,7 +231,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
     private static final int VIEW_TYPE_INDEX = 
TABLE_KV_COLUMNS.indexOf(VIEW_TYPE_KV);
     private static final int VIEW_INDEX_ID_INDEX = 
TABLE_KV_COLUMNS.indexOf(VIEW_INDEX_ID_KV);
     private static final int INDEX_TYPE_INDEX = 
TABLE_KV_COLUMNS.indexOf(INDEX_TYPE_KV);
-    
+    private static final int STORE_NULLS_INDEX = 
TABLE_KV_COLUMNS.indexOf(STORE_NULLS_KV);
+
     // KeyValues for Column
     private static final KeyValue DECIMAL_DIGITS_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
DECIMAL_DIGITS_BYTES);
     private static final KeyValue COLUMN_SIZE_KV = 
KeyValue.createFirstOnRow(ByteUtil.EMPTY_BYTE_ARRAY, TABLE_FAMILY_BYTES, 
COLUMN_SIZE_BYTES);
@@ -263,7 +267,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
     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;
 
     private static PName newPName(byte[] keyBuffer, int keyOffset, int 
keyLength) {
@@ -339,7 +343,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
             }
             
builder.setReturnCode(MetaDataProtos.MutationCode.TABLE_ALREADY_EXISTS);
             builder.setMutationTime(currentTime);
-            
+
             if (table.getTimeStamp() != tableTimeStamp) {
                 builder.setTable(PTableImpl.toProto(table));
             }
@@ -447,11 +451,11 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                        sortOrderKv == null ? SortOrder.getDefault() : 
SortOrder.fromSystemValue(PInteger.INSTANCE
                         .getCodec().decodeInt(sortOrderKv.getValueArray(),
                                        sortOrderKv.getValueOffset(), 
SortOrder.getDefault()));
-        
+
         Cell arraySizeKv = colKeyValues[ARRAY_SIZE_INDEX];
         Integer arraySize = arraySizeKv == null ? null :
             
PInteger.INSTANCE.getCodec().decodeInt(arraySizeKv.getValueArray(), 
arraySizeKv.getValueOffset(), SortOrder.getDefault());
- 
+
         Cell viewConstantKv = colKeyValues[VIEW_CONSTANT_INDEX];
         byte[] viewConstant = viewConstantKv == null ? null : 
viewConstantKv.getValue();
         Cell isViewReferencedKv = colKeyValues[IS_VIEW_REFERENCED_INDEX];
@@ -459,7 +463,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         PColumn column = new PColumnImpl(colName, famName, dataType, 
maxLength, scale, isNullable, position-1, sortOrder, arraySize, viewConstant, 
isViewReferenced);
         columns.add(column);
     }
-    
+
     private PTable getTable(RegionScanner scanner, long clientTimeStamp, long 
tableTimeStamp)
         throws IOException, SQLException {
         List<Cell> results = Lists.newArrayList();
@@ -469,7 +473,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         }
         Cell[] tableKeyValues = new Cell[TABLE_KV_COLUMNS.size()];
         Cell[] colKeyValues = new Cell[COLUMN_KV_COLUMNS.size()];
-    
+
         // Create PTable based on KeyValues from scan
         Cell keyValue = results.get(0);
         byte[] keyBuffer = keyValue.getRowArray();
@@ -487,7 +491,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         System.arraycopy(keyBuffer, keyOffset + schemaNameLength + 1 + 
tenantIdLength + 1,
             tableNameBytes, 0, tableNameLength);
         PName tableName = PNameFactory.newName(tableNameBytes);
-    
+
         int offset = tenantIdLength + schemaNameLength + tableNameLength + 3;
         // This will prevent the client from continually looking for the 
current
         // table when we know that there will never be one since we disallow 
updates
@@ -501,7 +505,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         // clientTimeStamp < tableTimeStamp
         // ? clientTimeStamp-1
         // : keyValue.getTimestamp();
-    
+
         int i = 0;
         int j = 0;
         while (i < results.size() && j < TABLE_KV_COLUMNS.size()) {
@@ -517,7 +521,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
                 tableKeyValues[j++] = kv;
                 i++;
             } else if (cmp > 0) {
-                timeStamp = Math.max(timeStamp, kv.getTimestamp()); 
+                timeStamp = Math.max(timeStamp, kv.getTimestamp());
                 tableKeyValues[j++] = null;
             } else {
                 i++; // shouldn't happen - means unexpected KV in system table 
header row
@@ -576,13 +580,16 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
             PBoolean.INSTANCE.toObject(disableWALKv.getValueArray(), 
disableWALKv.getValueOffset(), disableWALKv.getValueLength()));
         Cell multiTenantKv = tableKeyValues[MULTI_TENANT_INDEX];
         boolean multiTenant = multiTenantKv == null ? false : 
Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(multiTenantKv.getValueArray(), 
multiTenantKv.getValueOffset(), multiTenantKv.getValueLength()));
+        Cell storeNullsKv = tableKeyValues[STORE_NULLS_INDEX];
+        boolean storeNulls = storeNullsKv == null ? false : 
Boolean.TRUE.equals(PBoolean.INSTANCE.toObject(storeNullsKv.getValueArray(), 
storeNullsKv.getValueOffset(), storeNullsKv.getValueLength()));
         Cell viewTypeKv = tableKeyValues[VIEW_TYPE_INDEX];
         ViewType viewType = viewTypeKv == null ? null : 
ViewType.fromSerializedValue(viewTypeKv.getValueArray()[viewTypeKv.getValueOffset()]);
         Cell viewIndexIdKv = tableKeyValues[VIEW_INDEX_ID_INDEX];
         Short viewIndexId = viewIndexIdKv == null ? null : 
(Short)MetaDataUtil.getViewIndexIdDataType().getCodec().decodeShort(viewIndexIdKv.getValueArray(),
 viewIndexIdKv.getValueOffset(), SortOrder.getDefault());
         Cell indexTypeKv = tableKeyValues[INDEX_TYPE_INDEX];
         IndexType indexType = indexTypeKv == null ? null : 
IndexType.fromSerializedValue(indexTypeKv.getValueArray()[indexTypeKv.getValueOffset()]);
-        
+
+
         List<PColumn> columns = 
Lists.newArrayListWithExpectedSize(columnCount);
         List<PTable> indexes = new ArrayList<PTable>();
         List<PName> physicalTables = new ArrayList<PName>();
@@ -616,17 +623,17 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
             try {
                 statsHTable = ServerUtil.getHTableForCoprocessorScan(env, 
PhoenixDatabaseMetaData.SYSTEM_STATS_NAME_BYTES);
                 stats = StatisticsUtil.readStatistics(statsHTable, 
physicalTableName.getBytes(), clientTimeStamp);
-                timeStamp = Math.max(timeStamp, stats.getTimestamp()); 
+                timeStamp = Math.max(timeStamp, stats.getTimestamp());
             } catch (org.apache.hadoop.hbase.TableNotFoundException e) {
                 logger.warn(PhoenixDatabaseMetaData.SYSTEM_STATS_NAME + " not 
online yet?");
             } finally {
                 if (statsHTable != null) statsHTable.close();
             }
         }
-        return PTableImpl.makePTable(tenantId, schemaName, tableName, 
tableType, indexState, timeStamp, 
-            tableSeqNum, pkName, saltBucketNum, columns, tableType == INDEX ? 
schemaName : null, 
-            tableType == INDEX ? dataTableName : null, indexes, 
isImmutableRows, physicalTables, defaultFamilyName, viewStatement, 
-            disableWAL, multiTenant, viewType, viewIndexId, indexType, stats);
+        return PTableImpl.makePTable(tenantId, schemaName, tableName, 
tableType, indexState, timeStamp,
+            tableSeqNum, pkName, saltBucketNum, columns, tableType == INDEX ? 
schemaName : null,
+            tableType == INDEX ? dataTableName : null, indexes, 
isImmutableRows, physicalTables, defaultFamilyName, viewStatement,
+            disableWAL, multiTenant, storeNulls, viewType, viewIndexId, 
indexType, stats);
     }
 
     private PTable buildDeletedTable(byte[] key, ImmutableBytesPtr cacheKey, 
HRegion region,
@@ -634,7 +641,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         if (clientTimeStamp == HConstants.LATEST_TIMESTAMP) {
             return null;
         }
-    
+
         Scan scan = MetaDataUtil.newTableRowsScan(key, clientTimeStamp, 
HConstants.LATEST_TIMESTAMP);
         scan.setFilter(new FirstKeyOnlyFilter());
         scan.setRaw(true);
@@ -681,8 +688,8 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         }
         return null;
     }
-    
-    
+
+
     @Override
     public void createTable(RpcController controller, CreateTableRequest 
request,
             RpcCallback<MetaDataResponse> done) {
@@ -813,7 +820,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
         }
         locks.add(rowLock);
     }
-    
+
     protected static final byte[] PHYSICAL_TABLE_BYTES = new byte[] 
{PTable.LinkType.PHYSICAL_TABLE.getSerializedValue()};
     /**
      * @param tableName parent table's name
@@ -877,7 +884,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
             hTable.close();
         }
     }
-    
+
     @Override
     public void dropTable(RpcController controller, DropTableRequest request,
             RpcCallback<MetaDataResponse> done) {
@@ -916,7 +923,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol 
implements Coprocesso
                 return;
             }
             List<RowLock> locks = Lists.newArrayList();
-            
+
             try {
                 acquireLock(region, lockKey, locks);
                 if (key != lockKey) {
@@ -958,16 +965,16 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
         byte[] tableName, byte[] parentTableName, PTableType tableType, 
List<Mutation> rowsToDelete,
         List<ImmutableBytesPtr> invalidateList, List<RowLock> locks,
         List<byte[]> tableNamesToDelete, boolean isCascade) throws 
IOException, SQLException {
-       
-       
+
+
         long clientTimeStamp = MetaDataUtil.getClientTimeStamp(rowsToDelete);
-    
+
         HRegion region = env.getRegion();
         ImmutableBytesPtr cacheKey = new ImmutableBytesPtr(key);
-        
+
         Cache<ImmutableBytesPtr,PTable> metaDataCache = 
GlobalCache.getInstance(this.env).getMetaDataCache();
         PTable table = metaDataCache.getIfPresent(cacheKey);
-       
+
         // We always cache the latest version - fault in if not in cache
         if (table != null
                 || (table = buildTable(key, cacheKey, region, 
HConstants.LATEST_TIMESTAMP)) != null) {
@@ -1008,7 +1015,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
         if (tableViewFinderResult.hasViews()) {
                if (isCascade) {
                        if (tableViewFinderResult.allViewsInMultipleRegions()) {
-                           // We don't yet support deleting a table with views 
where SYSTEM.CATALOG has split and the 
+                           // We don't yet support deleting a table with views 
where SYSTEM.CATALOG has split and the
                                // view metadata spans multiple regions
                                return new 
MetaDataMutationResult(MutationCode.UNALLOWED_TABLE_MUTATION, 
EnvironmentEdgeManager.currentTimeMillis(), null);
                        } else if 
(tableViewFinderResult.allViewsInSingleRegion()) {
@@ -1030,13 +1037,13 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                                    return result;
                                }
                                        }
-                       }       
+                       }
                } else {
                // DROP without CASCADE on tables with child views is not 
permitted
                return new 
MetaDataMutationResult(MutationCode.UNALLOWED_TABLE_MUTATION, 
EnvironmentEdgeManager.currentTimeMillis(), null);
             }
-        } 
-        
+        }
+
         if (tableType != PTableType.VIEW) { // Add to list of HTables to 
delete, unless it's a view
             tableNamesToDelete.add(table.getName().getBytes());
         }
@@ -1062,7 +1069,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
             results.clear();
             scanner.next(results);
         } while (!results.isEmpty());
-    
+
         // Recursively delete indexes
         for (byte[] indexName : indexNames) {
             byte[] indexKey = SchemaUtil.getTableKey(tenantId, schemaName, 
indexName);
@@ -1080,7 +1087,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                 return result;
             }
         }
-    
+
         return new MetaDataMutationResult(MutationCode.TABLE_ALREADY_EXISTS,
                 EnvironmentEdgeManager.currentTimeMillis(), table, 
tableNamesToDelete);
     }
@@ -1144,7 +1151,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                     return new 
MetaDataMutationResult(MutationCode.TABLE_NOT_FOUND,
                             EnvironmentEdgeManager.currentTimeMillis(), null);
                 }
-        
+
                 long expectedSeqNum = 
MetaDataUtil.getSequenceNumber(tableMetadata) - 1; // lookup
                                                                                
          // TABLE_SEQ_NUM
                                                                                
          // in
@@ -1163,7 +1170,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                     return new 
MetaDataMutationResult(MutationCode.CONCURRENT_TABLE_MUTATION,
                             EnvironmentEdgeManager.currentTimeMillis(), table);
                 }
-        
+
                 PTableType type = table.getType();
                 if (type == PTableType.INDEX) {
                     // Disallow mutation of an index table
@@ -1186,7 +1193,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                 if (result != null) {
                     return result;
                 }
-        
+
                 region.mutateRowsWithLocks(tableMetadata, Collections.<byte[]> 
emptySet());
                 // Invalidate from cache
                 for (ImmutableBytesPtr invalidateKey : invalidateList) {
@@ -1272,11 +1279,11 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
             ProtobufUtil.setControllerException(controller, ioe);
         }
     }
-    
+
     private PTable doGetTable(byte[] key, long clientTimeStamp) throws 
IOException, SQLException {
         return doGetTable(key, clientTimeStamp, null);
     }
-    
+
     private PTable doGetTable(byte[] key, long clientTimeStamp, RowLock 
rowLock) throws IOException, SQLException {
         ImmutableBytesPtr cacheKey = new ImmutableBytesPtr(key);
         Cache<ImmutableBytesPtr, PTable> metaDataCache =
@@ -1507,10 +1514,10 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
             int disableTimeStampKVIndex = -1;
             int index = 0;
             for(Cell cell : newKVs){
-                if(Bytes.compareTo(cell.getQualifierArray(), 
cell.getQualifierOffset(), cell.getQualifierLength(), 
+                if(Bytes.compareTo(cell.getQualifierArray(), 
cell.getQualifierOffset(), cell.getQualifierLength(),
                       INDEX_STATE_BYTES, 0, INDEX_STATE_BYTES.length) == 0){
                   newKV = cell;
-                } else if (Bytes.compareTo(cell.getQualifierArray(), 
cell.getQualifierOffset(), cell.getQualifierLength(), 
+                } else if (Bytes.compareTo(cell.getQualifierArray(), 
cell.getQualifierOffset(), cell.getQualifierLength(),
                   INDEX_DISABLE_TIMESTAMP_BYTES, 0, 
INDEX_DISABLE_TIMESTAMP_BYTES.length) == 0){
                   disableTimeStampKVIndex = index;
                 }
@@ -1538,14 +1545,14 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                 Cell dataTableKV = 
currentResult.getColumnLatestCell(TABLE_FAMILY_BYTES, DATA_TABLE_NAME_BYTES);
                 Cell currentStateKV = 
currentResult.getColumnLatestCell(TABLE_FAMILY_BYTES, INDEX_STATE_BYTES);
                 Cell currentDisableTimeStamp = 
currentResult.getColumnLatestCell(TABLE_FAMILY_BYTES, 
INDEX_DISABLE_TIMESTAMP_BYTES);
-               
+
                 PIndexState currentState =
                         
PIndexState.fromSerializedValue(currentStateKV.getValueArray()[currentStateKV
                                 .getValueOffset()]);
-                
+
                 // check if we need reset disable time stamp
-                if( (newState == PIndexState.DISABLE) && 
-                    (currentState == PIndexState.DISABLE || currentState == 
PIndexState.INACTIVE) && 
+                if( (newState == PIndexState.DISABLE) &&
+                    (currentState == PIndexState.DISABLE || currentState == 
PIndexState.INACTIVE) &&
                     (currentDisableTimeStamp != null && 
currentDisableTimeStamp.getValueLength() > 0) &&
                     (disableTimeStampKVIndex >= 0)) {
                     Long curTimeStampVal = (Long) 
PLong.INSTANCE.toObject(currentDisableTimeStamp.getValueArray(),
@@ -1559,7 +1566,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                         newKVs.remove(disableTimeStampKVIndex);
                     }
                 }
-                
+
                 // Detect invalid transitions
                 if (currentState == PIndexState.BUILDING) {
                     if (newState == PIndexState.USABLE) {
@@ -1595,7 +1602,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                     newKVs.set(0, KeyValueUtil.newKeyValue(key, 
TABLE_FAMILY_BYTES,
                         INDEX_STATE_BYTES, timeStamp, 
Bytes.toBytes(newState.getSerializedValue())));
                 }
-                
+
                 if (currentState != newState) {
                     byte[] dataTableKey = null;
                     if(dataTableKV != null) {
@@ -1633,7 +1640,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
                 
ServerUtil.createIOException(SchemaUtil.getTableName(schemaName, tableName), 
t));
         }
     }
-    
+
     private static MetaDataMutationResult checkTableKeyInRegion(byte[] key, 
HRegion region) {
         byte[] startKey = region.getStartKey();
         byte[] endKey = region.getEndKey();
@@ -1645,7 +1652,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
         return new MetaDataMutationResult(MutationCode.TABLE_NOT_IN_REGION,
                 EnvironmentEdgeManager.currentTimeMillis(), null);
     }
- 
+
     /**
      * Certain operations, such as DROP TABLE are not allowed if there a table 
has child views.
      * This class wraps the Results of a scanning the Phoenix Metadata for 
child views for a specific table
@@ -1686,7 +1693,7 @@ public class MetaDataEndpointImpl extends 
MetaDataProtocol implements Coprocesso
             return results.size() > 0 && allViewsNotInSingleRegion;
         }
     }
-    
+
     @Override
     public void clearTableFromCache(RpcController controller, 
ClearTableFromCacheRequest request,
             RpcCallback<ClearTableFromCacheResponse> done) {

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cd7e86b/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 1e34bc9..8df3748 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
@@ -2933,6 +2933,16 @@ public final class PTableProtos {
      * <code>optional int64 statsTimeStamp = 23;</code>
      */
     long getStatsTimeStamp();
+
+    // required bool storeNulls = 24;
+    /**
+     * <code>required bool storeNulls = 24;</code>
+     */
+    boolean hasStoreNulls();
+    /**
+     * <code>required bool storeNulls = 24;</code>
+     */
+    boolean getStoreNulls();
   }
   /**
    * Protobuf type {@code PTable}
@@ -3118,6 +3128,11 @@ public final class PTableProtos {
               statsTimeStamp_ = input.readInt64();
               break;
             }
+            case 192: {
+              bitField0_ |= 0x00080000;
+              storeNulls_ = input.readBool();
+              break;
+            }
           }
         }
       } catch (com.google.protobuf.InvalidProtocolBufferException e) {
@@ -3632,6 +3647,22 @@ public final class PTableProtos {
       return statsTimeStamp_;
     }
 
+    // required bool storeNulls = 24;
+    public static final int STORENULLS_FIELD_NUMBER = 24;
+    private boolean storeNulls_;
+    /**
+     * <code>required bool storeNulls = 24;</code>
+     */
+    public boolean hasStoreNulls() {
+      return ((bitField0_ & 0x00080000) == 0x00080000);
+    }
+    /**
+     * <code>required bool storeNulls = 24;</code>
+     */
+    public boolean getStoreNulls() {
+      return storeNulls_;
+    }
+
     private void initFields() {
       schemaNameBytes_ = com.google.protobuf.ByteString.EMPTY;
       tableNameBytes_ = com.google.protobuf.ByteString.EMPTY;
@@ -3656,6 +3687,7 @@ public final class PTableProtos {
       viewIndexId_ = 0;
       indexType_ = com.google.protobuf.ByteString.EMPTY;
       statsTimeStamp_ = 0L;
+      storeNulls_ = false;
     }
     private byte memoizedIsInitialized = -1;
     public final boolean isInitialized() {
@@ -3698,6 +3730,10 @@ public final class PTableProtos {
         memoizedIsInitialized = 0;
         return false;
       }
+      if (!hasStoreNulls()) {
+        memoizedIsInitialized = 0;
+        return false;
+      }
       for (int i = 0; i < getColumnsCount(); i++) {
         if (!getColumns(i).isInitialized()) {
           memoizedIsInitialized = 0;
@@ -3792,6 +3828,9 @@ public final class PTableProtos {
       if (((bitField0_ & 0x00040000) == 0x00040000)) {
         output.writeInt64(23, statsTimeStamp_);
       }
+      if (((bitField0_ & 0x00080000) == 0x00080000)) {
+        output.writeBool(24, storeNulls_);
+      }
       getUnknownFields().writeTo(output);
     }
 
@@ -3898,6 +3937,10 @@ public final class PTableProtos {
         size += com.google.protobuf.CodedOutputStream
           .computeInt64Size(23, statsTimeStamp_);
       }
+      if (((bitField0_ & 0x00080000) == 0x00080000)) {
+        size += com.google.protobuf.CodedOutputStream
+          .computeBoolSize(24, storeNulls_);
+      }
       size += getUnknownFields().getSerializedSize();
       memoizedSerializedSize = size;
       return size;
@@ -4024,6 +4067,11 @@ public final class PTableProtos {
         result = result && (getStatsTimeStamp()
             == other.getStatsTimeStamp());
       }
+      result = result && (hasStoreNulls() == other.hasStoreNulls());
+      if (hasStoreNulls()) {
+        result = result && (getStoreNulls()
+            == other.getStoreNulls());
+      }
       result = result &&
           getUnknownFields().equals(other.getUnknownFields());
       return result;
@@ -4129,6 +4177,10 @@ public final class PTableProtos {
         hash = (37 * hash) + STATSTIMESTAMP_FIELD_NUMBER;
         hash = (53 * hash) + hashLong(getStatsTimeStamp());
       }
+      if (hasStoreNulls()) {
+        hash = (37 * hash) + STORENULLS_FIELD_NUMBER;
+        hash = (53 * hash) + hashBoolean(getStoreNulls());
+      }
       hash = (29 * hash) + getUnknownFields().hashCode();
       memoizedHashCode = hash;
       return hash;
@@ -4299,6 +4351,8 @@ public final class PTableProtos {
         bitField0_ = (bitField0_ & ~0x00200000);
         statsTimeStamp_ = 0L;
         bitField0_ = (bitField0_ & ~0x00400000);
+        storeNulls_ = false;
+        bitField0_ = (bitField0_ & ~0x00800000);
         return this;
       }
 
@@ -4435,6 +4489,10 @@ public final class PTableProtos {
           to_bitField0_ |= 0x00040000;
         }
         result.statsTimeStamp_ = statsTimeStamp_;
+        if (((from_bitField0_ & 0x00800000) == 0x00800000)) {
+          to_bitField0_ |= 0x00080000;
+        }
+        result.storeNulls_ = storeNulls_;
         result.bitField0_ = to_bitField0_;
         onBuilt();
         return result;
@@ -4598,6 +4656,9 @@ public final class PTableProtos {
         if (other.hasStatsTimeStamp()) {
           setStatsTimeStamp(other.getStatsTimeStamp());
         }
+        if (other.hasStoreNulls()) {
+          setStoreNulls(other.getStoreNulls());
+        }
         this.mergeUnknownFields(other.getUnknownFields());
         return this;
       }
@@ -4639,6 +4700,10 @@ public final class PTableProtos {
           
           return false;
         }
+        if (!hasStoreNulls()) {
+          
+          return false;
+        }
         for (int i = 0; i < getColumnsCount(); i++) {
           if (!getColumns(i).isInitialized()) {
             
@@ -6169,6 +6234,39 @@ public final class PTableProtos {
         return this;
       }
 
+      // required bool storeNulls = 24;
+      private boolean storeNulls_ ;
+      /**
+       * <code>required bool storeNulls = 24;</code>
+       */
+      public boolean hasStoreNulls() {
+        return ((bitField0_ & 0x00800000) == 0x00800000);
+      }
+      /**
+       * <code>required bool storeNulls = 24;</code>
+       */
+      public boolean getStoreNulls() {
+        return storeNulls_;
+      }
+      /**
+       * <code>required bool storeNulls = 24;</code>
+       */
+      public Builder setStoreNulls(boolean value) {
+        bitField0_ |= 0x00800000;
+        storeNulls_ = value;
+        onChanged();
+        return this;
+      }
+      /**
+       * <code>required bool storeNulls = 24;</code>
+       */
+      public Builder clearStoreNulls() {
+        bitField0_ = (bitField0_ & ~0x00800000);
+        storeNulls_ = false;
+        onChanged();
+        return this;
+      }
+
       // @@protoc_insertion_point(builder_scope:PTable)
     }
 
@@ -6214,7 +6312,7 @@ public final class PTableProtos {
       "ats\022\013\n\003key\030\001 \002(\014\022\016\n\006values\030\002 
\003(\014\022\033\n\023guid" +
       "ePostsByteCount\030\003 \001(\003\022\025\n\rkeyBytesCount\030\004" +
       " \001(\003\022\027\n\017guidePostsCount\030\005 
\001(\005\022!\n\013pGuideP",
-      "osts\030\006 
\001(\0132\014.PGuidePosts\"\242\004\n\006PTable\022\027\n\017s" +
+      "osts\030\006 
\001(\0132\014.PGuidePosts\"\266\004\n\006PTable\022\027\n\017s" +
       "chemaNameBytes\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\n" +
       "indexState\030\004 \001(\t\022\026\n\016sequenceNumber\030\005 
\002(\003" +
@@ -6228,10 +6326,11 @@ public final class PTableProtos {
       "\021 \001(\014\022\025\n\rviewStatement\030\022 
\001(\014\022\025\n\rphysical" +
       "Names\030\023 \003(\014\022\020\n\010tenantId\030\024 
\001(\014\022\023\n\013viewInd" +
       "exId\030\025 \001(\005\022\021\n\tindexType\030\026 
\001(\014\022\026\n\016statsTi" +
-      "meStamp\030\027 
\001(\003*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\004"
 +
-      "B@\n(org.apache.phoenix.coprocessor.gener" +
-      "atedB\014PTableProtosH\001\210\001\001\240\001\001"
+      "meStamp\030\027 \001(\003\022\022\n\nstoreNulls\030\030 
\002(\010*A\n\nPTa" +
+      
"bleType\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.phoen" +
+      "ix.coprocessor.generatedB\014PTableProtosH\001" +
+      "\210\001\001\240\001\001"
     };
     com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner 
assigner =
       new 
com.google.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner() {
@@ -6255,7 +6354,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", });
+              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", });
           return null;
         }
       };

http://git-wip-us.apache.org/repos/asf/phoenix/blob/9cd7e86b/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 aa6fdf0..76a1ad1 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
@@ -72,7 +72,7 @@ import com.google.common.collect.Lists;
 
 
 /**
- * 
+ *
  * JDBC DatabaseMetaData implementation of Phoenix reflecting read-only nature 
of driver.
  * Supported metadata methods include:
  * {@link #getTables(String, String, String, String[])}
@@ -94,8 +94,8 @@ import com.google.common.collect.Lists;
  * {@link #getSuperTables(String, String, String)}
  * {@link #getCatalogs()}
  * Other ResultSet methods return an empty result set.
- * 
- * 
+ *
+ *
  * @since 0.1
  */
 public class PhoenixDatabaseMetaData implements DatabaseMetaData, 
org.apache.phoenix.jdbc.Jdbc7Shim.DatabaseMetaData {
@@ -116,7 +116,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
     public static final String SYSTEM_STATS_TABLE = "STATS";
     public static final String SYSTEM_STATS_NAME = 
SchemaUtil.getTableName(SYSTEM_CATALOG_SCHEMA, SYSTEM_STATS_TABLE);
     public static final byte[] SYSTEM_STATS_NAME_BYTES = 
Bytes.toBytes(SYSTEM_STATS_NAME);
-    
+
     public static final String SYSTEM_CATALOG_ALIAS = "\"SYSTEM.TABLE\"";
 
     public static final String TABLE_NAME = "TABLE_NAME";
@@ -125,7 +125,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
     public static final byte[] TABLE_TYPE_BYTES = Bytes.toBytes(TABLE_TYPE);
     public static final String PHYSICAL_NAME = "PHYSICAL_NAME";
     public static final byte[] PHYSICAL_NAME_BYTES = 
Bytes.toBytes(PHYSICAL_NAME);
-    
+
     public static final String COLUMN_FAMILY = "COLUMN_FAMILY";
     public static final String TABLE_CAT = "TABLE_CAT";
     public static final String TABLE_CATALOG = "TABLE_CATALOG";
@@ -142,7 +142,9 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
     public static final byte[] COLUMN_COUNT_BYTES = 
Bytes.toBytes(COLUMN_COUNT);
     public static final String SALT_BUCKETS = "SALT_BUCKETS";
     public static final byte[] SALT_BUCKETS_BYTES = 
Bytes.toBytes(SALT_BUCKETS);
- 
+    public static final String STORE_NULLS = "STORE_NULLS";
+    public static final byte[] STORE_NULLS_BYTES = Bytes.toBytes(STORE_NULLS);
+
     public static final String DATA_TABLE_NAME = "DATA_TABLE_NAME";
     public static final byte[] DATA_TABLE_NAME_BYTES = 
Bytes.toBytes(DATA_TABLE_NAME);
     public static final String INDEX_STATE = "INDEX_STATE";
@@ -150,7 +152,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
 
     public static final String TENANT_ID = "TENANT_ID";
     public static final byte[] TENANT_ID_BYTES = Bytes.toBytes(TENANT_ID);
-    
+
     public static final String COLUMN_NAME = "COLUMN_NAME";
     public static final String DATA_TYPE = "DATA_TYPE";
     public static final byte[] DATA_TYPE_BYTES = Bytes.toBytes(DATA_TYPE);
@@ -204,7 +206,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
 
     public static final String TABLE_FAMILY = 
QueryConstants.DEFAULT_COLUMN_FAMILY;
     public static final byte[] TABLE_FAMILY_BYTES = 
QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES;
-    
+
     public static final String TYPE_SEQUENCE = "SEQUENCE";
     public static final byte[] SEQUENCE_FAMILY_BYTES = 
QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES;
     public static final String SEQUENCE_SCHEMA_NAME = SYSTEM_CATALOG_SCHEMA;
@@ -236,11 +238,11 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
     public static final String KEY_SEQ = "KEY_SEQ";
     public static final byte[] KEY_SEQ_BYTES = Bytes.toBytes(KEY_SEQ);
     public static final String SUPERTABLE_NAME = "SUPERTABLE_NAME";
-    
+
     public static final String TYPE_ID = "TYPE_ID";
     public static final String INDEX_DISABLE_TIMESTAMP = 
"INDEX_DISABLE_TIMESTAMP";
     public static final byte[] INDEX_DISABLE_TIMESTAMP_BYTES = 
Bytes.toBytes(INDEX_DISABLE_TIMESTAMP);
-    
+
     public static final String REGION_NAME = "REGION_NAME";
     public static final byte[] REGION_NAME_BYTES = Bytes.toBytes(REGION_NAME);
     public static final String GUIDE_POSTS = "GUIDE_POSTS";
@@ -260,10 +262,10 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
 
     public static final String PARENT_TENANT_ID = "PARENT_TENANT_ID";
     public static final byte[] PARENT_TENANT_ID_BYTES = 
Bytes.toBytes(PARENT_TENANT_ID);
-        
+
     private static final String TENANT_POS_SHIFT = "TENANT_POS_SHIFT";
     private static final byte[] TENANT_POS_SHIFT_BYTES = 
Bytes.toBytes(TENANT_POS_SHIFT);
-    
+
     private final PhoenixConnection connection;
     private final ResultSet emptyResultSet;
 
@@ -360,19 +362,19 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
             throws SQLException {
         return emptyResultSet;
     }
-    
+
     private static String escapePattern(String pattern) {
         return StringEscapeUtils.escapeSql(pattern); // Need to escape double 
quotes
     }
-    
+
     public static final String GLOBAL_TENANANTS_ONLY = "null";
-    
+
     private void addTenantIdFilter(StringBuilder buf, String tenantIdPattern) {
         PName tenantId = connection.getTenantId();
         if (tenantIdPattern == null) {
             if (tenantId != null) {
                 appendConjunction(buf);
-                buf.append(" (" + TENANT_ID + " IS NULL " + 
+                buf.append(" (" + TENANT_ID + " IS NULL " +
                         " OR " + TENANT_ID + " = '" + 
escapePattern(tenantId.getString()) + "') ");
             }
         } else if (tenantIdPattern.length() == 0) {
@@ -390,7 +392,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
     private static void appendConjunction(StringBuilder buf) {
         buf.append(buf.length() == 0 ? "" : " and ");
     }
-    
+
     @Override
     public ResultSet getColumns(String catalog, String schemaPattern, String 
tableNamePattern, String columnNamePattern)
             throws SQLException {
@@ -416,7 +418,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
                 SCOPE_SCHEMA + "," +
                 SCOPE_TABLE + "," +
                 SOURCE_DATA_TYPE + "," +
-                IS_AUTOINCREMENT + "," + 
+                IS_AUTOINCREMENT + "," +
                 ARRAY_SIZE + "," +
                 COLUMN_FAMILY + "," +
                 DATA_TYPE + " " + TYPE_ID + "," +// raw type id for potential 
internal consumption
@@ -659,7 +661,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
                 "true NON_UNIQUE,\n" +
                 "null INDEX_QUALIFIER,\n" +
                 TABLE_NAME + " INDEX_NAME,\n" +
-                DatabaseMetaData.tableIndexOther + " TYPE,\n" + 
+                DatabaseMetaData.tableIndexOther + " TYPE,\n" +
                 ORDINAL_POSITION + ",\n" +
                 COLUMN_NAME + ",\n" +
                 "CASE WHEN " + COLUMN_FAMILY + " IS NOT NULL THEN null WHEN " 
+ SORT_ORDER + " = " + (SortOrder.DESC.getSystemValue()) + " THEN 'D' ELSE 'A' 
END ASC_OR_DESC,\n" +
@@ -669,11 +671,11 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
                 // Include data type info, though not in spec
                 ExternalSqlTypeIdFunction.NAME + "(" + DATA_TYPE + ") AS " + 
DATA_TYPE + ",\n" +
                 SqlTypeNameFunction.NAME + "(" + DATA_TYPE + ") AS " + 
TYPE_NAME + ",\n" +
-                DATA_TYPE + " " + TYPE_ID + ",\n" + 
+                DATA_TYPE + " " + TYPE_ID + ",\n" +
                 COLUMN_FAMILY + ",\n" +
                 COLUMN_SIZE + ",\n" +
                 ARRAY_SIZE +
-                "\nfrom " + SYSTEM_CATALOG + 
+                "\nfrom " + SYSTEM_CATALOG +
                 "\nwhere ");
         buf.append(TABLE_SCHEM + (schema == null || schema.length() == 0 ? " 
is null" : " = '" + escapePattern(schema) + "'" ));
         buf.append("\nand " + DATA_TABLE_NAME + " = '" + escapePattern(table) 
+ "'" );
@@ -817,7 +819,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
                 SqlTypeNameFunction.NAME + "(" + DATA_TYPE + ") AS " + 
TYPE_NAME + "," +
                 COLUMN_SIZE + "," +
                 DATA_TYPE + " " + TYPE_ID + "," + // raw type id
-                VIEW_CONSTANT + 
+                VIEW_CONSTANT +
                 " from " + SYSTEM_CATALOG + " " + SYSTEM_CATALOG_ALIAS +
                 " where ");
         buf.append(TABLE_SCHEM + (schema == null || schema.length() == 0 ? " 
is null" : " = '" + escapePattern(schema) + "'" ));
@@ -908,7 +910,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
                 TENANT_ID + " " + TABLE_CAT + "," + // Use tenantId for catalog
                 TABLE_SCHEM + "," +
                 TABLE_NAME + "," +
-                COLUMN_FAMILY + " " + SUPERTABLE_NAME + 
+                COLUMN_FAMILY + " " + SUPERTABLE_NAME +
                 " from " + SYSTEM_CATALOG + " " + SYSTEM_CATALOG_ALIAS +
                 " where " + COLUMN_NAME + " is null" +
                 " and " + LINK_TYPE + " = " + 
LinkType.PHYSICAL_TABLE.getSerializedValue());
@@ -923,7 +925,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
         Statement stmt = connection.createStatement();
         return stmt.executeQuery(buf.toString());
     }
-    
+
     @Override
     public ResultSet getSuperTypes(String catalog, String schemaPattern, 
String typeNamePattern) throws SQLException {
         return emptyResultSet;
@@ -963,7 +965,7 @@ public class PhoenixDatabaseMetaData implements 
DatabaseMetaData, org.apache.pho
                }
     };
     private static final RowProjector TABLE_TYPE_ROW_PROJECTOR = new 
RowProjector(Arrays.<ColumnProjector>asList(
-            new ExpressionProjector(TABLE_TYPE, SYSTEM_CATALOG, 
+            new ExpressionProjector(TABLE_TYPE, SYSTEM_CATALOG,
                     new RowKeyColumnExpression(TABLE_TYPE_DATUM,
                             new 
RowKeyValueAccessor(Collections.<PDatum>singletonList(TABLE_TYPE_DATUM), 0)), 
false)
             ), 0, true);

Reply via email to