You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ya...@apache.org on 2020/10/30 17:49:42 UTC

[phoenix] branch 4.x updated: PHOENIX-6171 Child views should not be allowed to override the parent view PHOENIX_TTL attribute.

This is an automated email from the ASF dual-hosted git repository.

yanxinyi pushed a commit to branch 4.x
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/4.x by this push:
     new 7cbebb4  PHOENIX-6171 Child views should not be allowed to override the parent view PHOENIX_TTL attribute.
7cbebb4 is described below

commit 7cbebb443c66904e87ff3f64da375974a9209e11
Author: Jacob Isaac <ji...@salesforce.com>
AuthorDate: Sun Oct 25 12:46:49 2020 -0700

    PHOENIX-6171 Child views should not be allowed to override the parent view PHOENIX_TTL attribute.
    
    Signed-off-by: Xinyi Yan <ya...@apache.org>
---
 .../java/org/apache/phoenix/end2end/ViewTTLIT.java | 620 ++++++++++++++-------
 .../phoenix/coprocessor/MetaDataEndpointImpl.java  |  56 ++
 .../apache/phoenix/exception/SQLExceptionCode.java |   2 +
 .../org/apache/phoenix/schema/MetaDataClient.java  |  11 +
 4 files changed, 484 insertions(+), 205 deletions(-)

diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewTTLIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewTTLIT.java
index 3a69fcb..09fb765 100644
--- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewTTLIT.java
+++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ViewTTLIT.java
@@ -18,7 +18,6 @@
 
 package org.apache.phoenix.end2end;
 
-import com.google.common.collect.Lists;
 import org.apache.hadoop.hbase.HConstants;
 import org.apache.hadoop.hbase.client.Result;
 import org.apache.hadoop.hbase.client.ResultScanner;
@@ -33,12 +32,14 @@ import org.apache.hadoop.hbase.filter.SubstringComparator;
 import org.apache.hadoop.hbase.util.Bytes;
 import org.apache.phoenix.exception.SQLExceptionCode;
 import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
-import org.apache.phoenix.query.PhoenixTestBuilder;
+import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder;
+import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.GlobalViewOptions;
 import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TableOptions;
-import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TenantViewOptions;
 import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TenantViewIndexOptions;
+import org.apache.phoenix.query.PhoenixTestBuilder.SchemaBuilder.TenantViewOptions;
 import org.apache.phoenix.query.QueryConstants;
 import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.util.EnvironmentEdgeManager;
 import org.apache.phoenix.util.SchemaUtil;
 import org.apache.phoenix.util.TestUtil;
 import org.junit.Test;
@@ -61,21 +62,24 @@ public class ViewTTLIT extends ParallelStatsDisabledIT {
     private static final Logger LOGGER = LoggerFactory.getLogger(ViewTTLIT.class);
     private static final String ORG_ID_FMT = "00D0x000%s";
     private static final String ID_FMT = "00A0y000%07d";
-    private static final String PHOENIX_TTL_HEADER_SQL =  "SELECT PHOENIX_TTL FROM SYSTEM.CATALOG "
+    private static final String PHOENIX_TTL_HEADER_SQL = "SELECT PHOENIX_TTL FROM SYSTEM.CATALOG "
             + "WHERE %s AND TABLE_SCHEM = '%s' AND TABLE_NAME = '%s' AND TABLE_TYPE = '%s'";
 
-    private static final String ALTER_PHOENIX_TTL_SQL = "ALTER VIEW %s.%s set PHOENIX_TTL=%d";
+    private static final String ALTER_PHOENIX_TTL_SQL
+            = "ALTER VIEW \"%s\".\"%s\" set PHOENIX_TTL=%s";
+
+    private static final String ALTER_SQL_WITH_NO_TTL
+            = "ALTER VIEW \"%s\".\"%s\" ADD IF NOT EXISTS %s CHAR(10)";
 
     // Scans the HBase rows directly for the view ttl related header rows column and asserts
-    private void assertViewHeaderRowsHavePhoenixTTLRelatedCells(String schemaName, long minTimestamp,
-            boolean rawScan, int expectedRows) throws IOException, SQLException {
+    private void assertViewHeaderRowsHavePhoenixTTLRelatedCells(String schemaName,
+            long minTimestamp, boolean rawScan, int expectedRows) throws IOException, SQLException {
 
         FilterList filterList = new FilterList(FilterList.Operator.MUST_PASS_ALL);
-        RowFilter schemaNameFilter = new RowFilter(
+        RowFilter schemaNameFilter = new RowFilter(CompareFilter.CompareOp.EQUAL,
+                new SubstringComparator(schemaName));
+        QualifierFilter phoenixTTLQualifierFilter = new QualifierFilter(
                 CompareFilter.CompareOp.EQUAL,
-                new SubstringComparator(schemaName)
-        );
-        QualifierFilter phoenixTTLQualifierFilter = new QualifierFilter(CompareFilter.CompareOp.EQUAL,
                 new BinaryComparator(PhoenixDatabaseMetaData.PHOENIX_TTL_BYTES));
         filterList.addFilter(schemaNameFilter);
         filterList.addFilter(phoenixTTLQualifierFilter);
@@ -89,25 +93,28 @@ public class ViewTTLIT extends ParallelStatsDisabledIT {
             ResultScanner scanner = tbl.getScanner(allRows);
             int numMatchingRows = 0;
             for (Result result = scanner.next(); result != null; result = scanner.next()) {
-                numMatchingRows +=
-                        result.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES,
-                                PhoenixDatabaseMetaData.PHOENIX_TTL_BYTES) ? 1 : 0;
+                numMatchingRows += result.containsColumn(QueryConstants.DEFAULT_COLUMN_FAMILY_BYTES,
+                        PhoenixDatabaseMetaData.PHOENIX_TTL_BYTES) ? 1 : 0;
             }
             assertEquals(String.format("Expected rows do not match for table = %s at timestamp %d",
-                    Bytes.toString(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES), minTimestamp), expectedRows, numMatchingRows);
+                    Bytes.toString(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES),
+                    minTimestamp), expectedRows, numMatchingRows);
         }
 
     }
 
-    private void assertSyscatHavePhoenixTTLRelatedColumns(String tenantId, String schemaName, String tableName, String tableType, long ttlValueExpected)
-            throws SQLException {
+    private void assertSyscatHavePhoenixTTLRelatedColumns(String tenantId, String schemaName,
+            String tableName, String tableType, long ttlValueExpected) throws SQLException {
 
         try (Connection connection = DriverManager.getConnection(getUrl())) {
             Statement stmt = connection.createStatement();
-            String tenantClause = tenantId == null || tenantId.isEmpty() ? "TENANT_ID IS NULL" : String.format("TENANT_ID = '%s'", tenantId);
-            String sql = String.format(PHOENIX_TTL_HEADER_SQL, tenantClause, schemaName, tableName, tableType);
+            String tenantClause = tenantId == null || tenantId.isEmpty() ?
+                    "TENANT_ID IS NULL" :
+                    String.format("TENANT_ID = '%s'", tenantId);
+            String sql = String
+                    .format(PHOENIX_TTL_HEADER_SQL, tenantClause, schemaName, tableName, tableType);
             stmt.execute(sql);
-            ResultSet rs = stmt.getResultSet() ;
+            ResultSet rs = stmt.getResultSet();
             long actualTTLValueReturned = rs.next() ? rs.getLong(1) : 0;
 
             assertEquals(String.format("Expected rows do not match for schema = %s, table = %s",
@@ -119,6 +126,100 @@ public class ViewTTLIT extends ParallelStatsDisabledIT {
         return name.replace("\"", "");
     }
 
+    private SchemaBuilder createLevel2TenantViewWithGlobalLevelTTL(
+            TenantViewOptions tenantViewOptions, TenantViewIndexOptions tenantViewIndexOptions)
+            throws Exception {
+        // Define the test schema.
+        // 1. Table with columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
+        // 2. GlobalView with columns => (ID, COL4, COL5, COL6), PK => (ID)
+        // 3. Tenant with columns => (ZID, COL7, COL8, COL9), PK => (ZID)
+        final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
+
+        TableOptions tableOptions = TableOptions.withDefaults();
+        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+
+        GlobalViewOptions globalViewOptions = GlobalViewOptions.withDefaults();
+        // Phoenix TTL is set to 300s => 300000 ms
+        globalViewOptions.setTableProps("PHOENIX_TTL=300");
+
+        SchemaBuilder.GlobalViewIndexOptions globalViewIndexOptions
+                = SchemaBuilder.GlobalViewIndexOptions.withDefaults();
+        globalViewIndexOptions.setLocal(false);
+
+        TenantViewOptions tenantViewWithOverrideOptions = TenantViewOptions.withDefaults();
+        if (tenantViewOptions != null) {
+            tenantViewWithOverrideOptions = tenantViewOptions;
+        }
+        TenantViewIndexOptions tenantViewIndexOverrideOptions = TenantViewIndexOptions.withDefaults();
+        if (tenantViewIndexOptions != null) {
+            tenantViewIndexOverrideOptions = tenantViewIndexOptions;
+        }
+        schemaBuilder.withTableOptions(tableOptions).withGlobalViewOptions(globalViewOptions)
+                .withGlobalViewIndexOptions(globalViewIndexOptions)
+                .withTenantViewOptions(tenantViewWithOverrideOptions)
+                .withTenantViewIndexOptions(tenantViewIndexOverrideOptions).buildWithNewTenant();
+        return schemaBuilder;
+    }
+
+    private SchemaBuilder createLevel2TenantViewWithTenantLevelTTL(
+            TenantViewOptions tenantViewOptions, TenantViewIndexOptions tenantViewIndexOptions)
+            throws Exception {
+        // Define the test schema.
+        // 1. Table with columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
+        // 2. GlobalView with columns => (ID, COL4, COL5, COL6), PK => (ID)
+        // 3. Tenant with columns => (ZID, COL7, COL8, COL9), PK => (ZID)
+        final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
+
+        TableOptions tableOptions = TableOptions.withDefaults();
+        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+
+        GlobalViewOptions globalViewOptions = GlobalViewOptions.withDefaults();
+
+        SchemaBuilder.GlobalViewIndexOptions globalViewIndexOptions
+                = SchemaBuilder.GlobalViewIndexOptions.withDefaults();
+        globalViewIndexOptions.setLocal(false);
+
+        TenantViewOptions tenantViewWithOverrideOptions = TenantViewOptions.withDefaults();
+        // Phoenix TTL is set to 300s => 300000 ms
+        tenantViewWithOverrideOptions.setTableProps("PHOENIX_TTL=300");
+        if (tenantViewOptions != null) {
+            tenantViewWithOverrideOptions = tenantViewOptions;
+        }
+        TenantViewIndexOptions tenantViewIndexOverrideOptions = TenantViewIndexOptions.withDefaults();
+        if (tenantViewIndexOptions != null) {
+            tenantViewIndexOverrideOptions = tenantViewIndexOptions;
+        }
+        schemaBuilder.withTableOptions(tableOptions).withGlobalViewOptions(globalViewOptions)
+                .withGlobalViewIndexOptions(globalViewIndexOptions)
+                .withTenantViewOptions(tenantViewWithOverrideOptions)
+                .withTenantViewIndexOptions(tenantViewIndexOverrideOptions).buildWithNewTenant();
+        return schemaBuilder;
+    }
+
+    private SchemaBuilder createLevel1TenantView(TenantViewOptions tenantViewOptions,
+            TenantViewIndexOptions tenantViewIndexOptions) throws Exception {
+        // Define the test schema.
+        // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
+        // 2. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
+        final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
+
+        TableOptions tableOptions = TableOptions.withDefaults();
+        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+
+        TenantViewOptions tenantViewOverrideOptions = TenantViewOptions.withDefaults();
+        if (tenantViewOptions != null) {
+            tenantViewOverrideOptions = tenantViewOptions;
+        }
+        TenantViewIndexOptions tenantViewIndexOverrideOptions = TenantViewIndexOptions.withDefaults();
+        if (tenantViewIndexOptions != null) {
+            tenantViewIndexOverrideOptions = tenantViewIndexOptions;
+        }
+
+        schemaBuilder.withTableOptions(tableOptions)
+                .withTenantViewOptions(tenantViewOverrideOptions)
+                .withTenantViewIndexOptions(tenantViewIndexOverrideOptions).buildNewView();
+        return schemaBuilder;
+    }
 
     /**
      * -----------------
@@ -126,34 +227,29 @@ public class ViewTTLIT extends ParallelStatsDisabledIT {
      * -----------------
      */
 
-    @Test
-    public void testWithBasicGlobalViewWithNoPhoenixTTLDefined() throws Exception {
+    @Test public void testWithBasicGlobalViewWithNoPhoenixTTLDefined() throws Exception {
 
-        long startTime = System.currentTimeMillis();
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
 
         // Define the test schema.
         // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
         // 2. GlobalView with default columns => (ID, COL4, COL5, COL6), PK => (ID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
-        schemaBuilder
-                .withTableDefaults()
-                .withGlobalViewDefaults()
-                .build();
+        final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
+        schemaBuilder.withTableDefaults().withGlobalViewDefaults().build();
 
         // Expected 2 rows - one for Table and GlobalView each.
-        // Since the PHOENIX_TTL property values are not being set, we expect the view header columns to show up in raw scans only.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, true, 2);
+        // Since the PHOENIX_TTL property values are not being set,
+        // we expect the view header columns to show up in raw scans only.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, true, 2);
     }
 
-
-
-    @Test
-    public void testPhoenixTTLWithTableLevelTTLFails() throws Exception {
+    @Test public void testPhoenixTTLWithTableLevelTTLFails() throws Exception {
 
         // Define the test schema.
         // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
         // 2. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
+        final SchemaBuilder schemaBuilder = new SchemaBuilder(getUrl());
 
         TableOptions tableOptions = TableOptions.withDefaults();
         tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true,TTL=100");
@@ -161,241 +257,355 @@ public class ViewTTLIT extends ParallelStatsDisabledIT {
         TenantViewOptions tenantViewOptions = TenantViewOptions.withDefaults();
         tenantViewOptions.setTableProps("PHOENIX_TTL=1000");
         try {
-            schemaBuilder
-                    .withTableOptions(tableOptions)
-                    .withTenantViewOptions(tenantViewOptions)
+            schemaBuilder.withTableOptions(tableOptions).withTenantViewOptions(tenantViewOptions)
                     .buildNewView();
             fail();
         } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL_FOR_TABLE_WITH_TTL.getErrorCode(), e.getErrorCode());
+            assertEquals(SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL_FOR_TABLE_WITH_TTL
+                    .getErrorCode(), e.getErrorCode());
         }
     }
 
-    @Test
-    public void testPhoenixTTLWithViewIndexFails() throws Exception {
-
-        // Define the test schema.
-        // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
-        // 2. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
-
-        TableOptions tableOptions = TableOptions.withDefaults();
-        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+    @Test public void testPhoenixTTLWithViewIndexFails() throws Exception {
 
         TenantViewIndexOptions tenantViewIndexOptions = TenantViewIndexOptions.withDefaults();
         tenantViewIndexOptions.setIndexProps("PHOENIX_TTL=1000");
         try {
-            schemaBuilder
-                    .withTableOptions(tableOptions)
-                    .withTenantViewDefaults()
-                    .withTenantViewIndexOptions(tenantViewIndexOptions)
-                    .buildNewView();
+            final SchemaBuilder schemaBuilder = createLevel1TenantView(null,
+                    tenantViewIndexOptions);
             fail();
         } catch (SQLException e) {
-            assertEquals(SQLExceptionCode.PHOENIX_TTL_SUPPORTED_FOR_VIEWS_ONLY.getErrorCode(), e.getErrorCode());
+            assertEquals(SQLExceptionCode.PHOENIX_TTL_SUPPORTED_FOR_VIEWS_ONLY.getErrorCode(),
+                    e.getErrorCode());
         }
     }
 
-    @Test
-    public void testPhoenixTTLForLevelOneView() throws Exception {
-        long startTime = System.currentTimeMillis();
-
-        // Define the test schema.
-        // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
-        // 2. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
-
-        TableOptions tableOptions = TableOptions.withDefaults();
-        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+    @Test public void testPhoenixTTLForLevelOneView() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
 
         TenantViewOptions tenantViewOptions = TenantViewOptions.withDefaults();
         // Phoenix TTL is set to 120s => 120000 ms
         tenantViewOptions.setTableProps("PHOENIX_TTL=120");
-        schemaBuilder
-                .withTableOptions(tableOptions)
-                .withTenantViewOptions(tenantViewOptions)
-                .withTenantViewIndexDefaults()
-                .buildNewView();
 
+        final SchemaBuilder schemaBuilder = createLevel1TenantView(tenantViewOptions, null);
         String tenantId = schemaBuilder.getDataOptions().getTenantId();
-        String schemaName = stripQuotes(SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String tenantViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String indexOnTenantViewName = String.format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
 
         // Expected 2 rows - one for TenantView and ViewIndex each.
-        // Since the PHOENIX_TTL property values are being set, we expect the view header columns to show up in regular scans too.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
-        // Since the PHOENIX_TTL property values are not being overriden, we expect the TTL value to be different from the global view.
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName, PTableType.VIEW.getSerializedValue(), 120000);
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName, PTableType.INDEX.getSerializedValue(), 120000);
+        // Since the PHOENIX_TTL property values are being set,
+        // we expect the view header columns to show up in regular scans too.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 120000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 120000);
 
     }
 
-    @Test
-    public void testPhoenixTTLForLevelTwoView() throws Exception {
-        long startTime = System.currentTimeMillis();
-
-        // Define the test schema.
-        // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
-        // 2. GlobalView with default columns => (ID, COL4, COL5, COL6), PK => (ID)
-        // 3. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
-
-        TableOptions tableOptions = TableOptions.withDefaults();
-        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
-
-        PhoenixTestBuilder.SchemaBuilder.GlobalViewOptions
-                globalViewOptions = PhoenixTestBuilder.SchemaBuilder.GlobalViewOptions.withDefaults();
-        // Phoenix TTL is set to 300s => 300000 ms
-        globalViewOptions.setTableProps("PHOENIX_TTL=300");
-
-        PhoenixTestBuilder.SchemaBuilder.GlobalViewIndexOptions
-                globalViewIndexOptions =
-                PhoenixTestBuilder.SchemaBuilder.GlobalViewIndexOptions.withDefaults();
-        globalViewIndexOptions.setLocal(false);
+    @Test public void testPhoenixTTLForLevelTwoView() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
 
-        TenantViewOptions tenantViewWithOverrideOptions = TenantViewOptions.withDefaults();
-        // Phoenix TTL is set to 120s => 120000 ms
-        tenantViewWithOverrideOptions.setTableProps("PHOENIX_TTL=120");
-        schemaBuilder
-                .withTableOptions(tableOptions)
-                .withGlobalViewOptions(globalViewOptions)
-                .withGlobalViewIndexOptions(globalViewIndexOptions)
-                .withTenantViewOptions(tenantViewWithOverrideOptions)
-                .withTenantViewIndexDefaults()
-                .buildWithNewTenant();
+        final SchemaBuilder schemaBuilder = createLevel2TenantViewWithGlobalLevelTTL(null, null);
 
         String tenantId = schemaBuilder.getDataOptions().getTenantId();
-        String schemaName = stripQuotes(SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String globalViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
-        String tenantViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String globalViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
         String indexOnGlobalViewName = String.format("IDX_%s", globalViewName);
-        String indexOnTenantViewName = String.format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
 
         // Expected 4 rows - one for GlobalView, one for TenantView and ViewIndex each.
-        // Since the PHOENIX_TTL property values are being set, we expect the view header columns to show up in regular scans too.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 4);
-        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, globalViewName, PTableType.VIEW.getSerializedValue(), 300000);
-        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, indexOnGlobalViewName, PTableType.INDEX.getSerializedValue(), 300000);
-        // Since the PHOENIX_TTL property values are not being overriden, we expect the TTL value to be different from the global view.
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName, PTableType.VIEW.getSerializedValue(), 120000);
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName, PTableType.INDEX.getSerializedValue(), 120000);
-
-        // Without override
-        startTime = System.currentTimeMillis();
-
-        TenantViewOptions tenantViewWithoutOverrideOptions = TenantViewOptions.withDefaults();
-        schemaBuilder
-                .withTableOptions(tableOptions)
-                .withGlobalViewOptions(globalViewOptions)
-                .withGlobalViewIndexOptions(globalViewIndexOptions)
-                .withTenantViewOptions(tenantViewWithoutOverrideOptions)
-                .withTenantViewIndexDefaults()
-                .buildWithNewTenant();
-
-        tenantId = schemaBuilder.getDataOptions().getTenantId();
-        schemaName = stripQuotes(SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        globalViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
-        tenantViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        indexOnGlobalViewName = String.format("IDX_%s", globalViewName);
-        indexOnTenantViewName = String.format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
-
-
-        // Expected 2 rows - one for TenantView and ViewIndex each.
-        // Since the PHOENIX_TTL property values are being set, we expect the view header columns to show up in regular scans too.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
-        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, globalViewName, PTableType.VIEW.getSerializedValue(), 300000);
-        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, indexOnGlobalViewName, PTableType.INDEX.getSerializedValue(), 300000);
-        // Since the PHOENIX_TTL property values are not being overriden, we expect the TTL value to be same as the global view.
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName, PTableType.VIEW.getSerializedValue(), 300000);
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName, PTableType.INDEX.getSerializedValue(), 300000);
+        // Since the PHOENIX_TTL property values are being set,
+        // we expect the view header columns to show up in regular scans too.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 4);
+        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, globalViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, indexOnGlobalViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
+        // Since the PHOENIX_TTL property values are not being overridden,
+        // we expect the TTL value to be same as the global view.
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
     }
 
-    @Test
-    public void testPhoenixTTLForWhenTTLIsZero() throws Exception {
-        long startTime = System.currentTimeMillis();
-
-        // Define the test schema.
-        // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
-        // 2. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
-
-        TableOptions tableOptions = TableOptions.withDefaults();
-        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+    @Test public void testPhoenixTTLForWhenTTLIsZero() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
 
         TenantViewOptions tenantViewOptions = TenantViewOptions.withDefaults();
         // Client can also specify PHOENIX_TTL=NONE
         tenantViewOptions.setTableProps("PHOENIX_TTL=0");
-        schemaBuilder
-                .withTableOptions(tableOptions)
-                .withTenantViewOptions(tenantViewOptions)
-                .withTenantViewIndexDefaults()
-                .buildNewView();
+        final SchemaBuilder schemaBuilder = createLevel1TenantView(tenantViewOptions, null);
 
         String tenantId = schemaBuilder.getDataOptions().getTenantId();
-        String schemaName = stripQuotes(SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String tenantViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String indexOnTenantViewName = String.format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
 
         // Expected 3 deleted rows - one for Table, one for TenantView and ViewIndex each.
         // Since the PHOENIX_TTL property values are not being set or being set to zero,
         // we expect the view header columns to show up in raw scans only.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, true, 3);
-        // Since the PHOENIX_TTL property values are not being overriden, we expect the TTL value to be different from the global view.
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName, PTableType.VIEW.getSerializedValue(), 0);
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName, PTableType.INDEX.getSerializedValue(), 0);
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, true, 3);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 0);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 0);
 
     }
 
-    @Test
-    public void testPhoenixTTLWithAlterView() throws Exception {
-        long startTime = System.currentTimeMillis();
-
-        // Define the test schema.
-        // 1. Table with default columns => (ORG_ID, KP, COL1, COL2, COL3), PK => (ORG_ID, KP)
-        // 2. Tenant with default columns => (ZID, COL7, COL8, COL9), PK => (ZID)
-        final PhoenixTestBuilder.SchemaBuilder schemaBuilder = new PhoenixTestBuilder.SchemaBuilder(getUrl());
-
-        TableOptions tableOptions = TableOptions.withDefaults();
-        tableOptions.setTableProps("COLUMN_ENCODED_BYTES=0,MULTI_TENANT=true");
+    @Test public void testPhoenixTTLWithAlterView() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
 
         TenantViewOptions tenantViewOptions = TenantViewOptions.withDefaults();
         // Client can also specify PHOENIX_TTL=0
         tenantViewOptions.setTableProps("PHOENIX_TTL=NONE");
-        schemaBuilder
-                .withTableOptions(tableOptions)
-                .withTenantViewOptions(tenantViewOptions)
-                .withTenantViewIndexDefaults()
-                .buildNewView();
+        final SchemaBuilder schemaBuilder = createLevel1TenantView(tenantViewOptions, null);
 
         String tenantId = schemaBuilder.getDataOptions().getTenantId();
-        String schemaName = stripQuotes(SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String tenantViewName = stripQuotes(SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
-        String indexOnTenantViewName = String.format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
 
         // Expected 3 deleted rows - one for Table, one for TenantView and ViewIndex each.
         // Since the PHOENIX_TTL property values are not being set or being set to zero,
         // we expect the view header columns to show up in raw scans only.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, true, 3);
-        // Since the PHOENIX_TTL property values are not being overriden, we expect the TTL value to be different from the global view.
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName, PTableType.VIEW.getSerializedValue(), 0);
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName, PTableType.INDEX.getSerializedValue(), 0);
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, true, 3);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 0);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 0);
 
         String tenantURL = getUrl() + ';' + TENANT_ID_ATTRIB + '=' + tenantId;
         try (Connection connection = DriverManager.getConnection(tenantURL)) {
-            Statement stmt = connection.createStatement();
+            try (Statement stmt = connection.createStatement()) {
+                // Phoenix TTL is set to 120s => 120000 ms
+                String sql = String
+                        .format(ALTER_PHOENIX_TTL_SQL, schemaName, tenantViewName, "120");
+                stmt.execute(sql);
+            }
+        }
+
+        // Expected 2 rows - one for TenantView and ViewIndex each.
+        // Since the PHOENIX_TTL property values are being set,
+        // we expect the view header columns to show up in regular scans too.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 120000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 120000);
+
+    }
+
+    @Test public void testCreateViewWithParentPhoenixTTLFails() throws Exception {
+        try {
+            TenantViewOptions tenantViewWithOverrideOptions = TenantViewOptions.withDefaults();
             // Phoenix TTL is set to 120s => 120000 ms
-            String sql = String.format(ALTER_PHOENIX_TTL_SQL, schemaName, tenantViewName, 120);
-            stmt.execute(sql);
+            tenantViewWithOverrideOptions.setTableProps("PHOENIX_TTL=120");
+            final SchemaBuilder schemaBuilder = createLevel2TenantViewWithGlobalLevelTTL(
+                    tenantViewWithOverrideOptions, null);
+            fail();
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL.getErrorCode(),
+                    e.getErrorCode());
         }
+    }
+
+    @Test public void testAlterViewWithParentPhoenixTTLFails() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
+
+        // Phoenix TTL is set to 300s
+        final SchemaBuilder schemaBuilder = createLevel2TenantViewWithGlobalLevelTTL(null, null);
+
+        String tenantId = schemaBuilder.getDataOptions().getTenantId();
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String globalViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnGlobalViewName = String.format("IDX_%s", globalViewName);
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+
+        // Expected 4 rows - one for GlobalView, one for TenantView and ViewIndex each.
+        // Since the PHOENIX_TTL property values are being set,
+        // we expect the view header columns to show up in regular scans too.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 4);
+        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, globalViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, indexOnGlobalViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
+        // Since the PHOENIX_TTL property values are not being overridden,
+        // we expect the TTL value to be same as the global view.
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
+
+        String tenantURL = getUrl() + ';' + TENANT_ID_ATTRIB + '=' + tenantId;
+        try (Connection connection = DriverManager.getConnection(tenantURL)) {
+            try (Statement stmt = connection.createStatement()) {
+                // Phoenix TTL is set to 120s => 120000 ms
+                String sql = String
+                        .format(ALTER_PHOENIX_TTL_SQL, schemaName, tenantViewName, "120");
+                stmt.execute(sql);
+                fail();
+            }
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL.getErrorCode(),
+                    e.getErrorCode());
+        }
+    }
+
+    @Test public void testAlterViewWithChildLevelPhoenixTTLFails() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
+
+        // Phoenix TTL is set to 300s
+        final SchemaBuilder schemaBuilder = createLevel2TenantViewWithTenantLevelTTL(null, null);
+
+        String tenantId = schemaBuilder.getDataOptions().getTenantId();
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String globalViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnGlobalViewName = String.format("IDX_%s", globalViewName);
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+
+        // Expected 2 rows - one for TenantView and ViewIndex each.
+        // Since the PHOENIX_TTL property values are being set,
+        // we expect the view header columns to show up in regular scans too.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
+
+        try (Connection connection = DriverManager.getConnection(getUrl())) {
+            try (Statement stmt = connection.createStatement()) {
+                // Phoenix TTL is set to 120s => 120000 ms
+                String sql = String
+                        .format(ALTER_PHOENIX_TTL_SQL, schemaName, globalViewName, "120");
+                stmt.execute(sql);
+                fail();
+            }
+        } catch (SQLException e) {
+            assertEquals(SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL.getErrorCode(),
+                    e.getErrorCode());
+        }
+    }
+
+    @Test public void testAlterViewWithNoPhoenixTTLSucceed() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
+
+        // Phoenix TTL is set to 300s
+        final SchemaBuilder schemaBuilder = createLevel2TenantViewWithTenantLevelTTL(null, null);
+
+        String tenantId = schemaBuilder.getDataOptions().getTenantId();
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String globalViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnGlobalViewName = String.format("IDX_%s", globalViewName);
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
 
         // Expected 2 rows - one for TenantView and ViewIndex each.
-        // Since the PHOENIX_TTL property values are being set, we expect the view header columns to show up in regular scans too.
-        assertViewHeaderRowsHavePhoenixTTLRelatedCells(schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
-        // Since the PHOENIX_TTL property values are not being overriden, we expect the TTL value to be different from the global view.
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName, PTableType.VIEW.getSerializedValue(), 120000);
-        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName, PTableType.INDEX.getSerializedValue(), 120000);
+        // Since the PHOENIX_TTL property values are being set,
+        // we expect the view header columns to show up in regular scans too.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 2);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
+
+        // ALTER global view
+        try (Connection connection = DriverManager.getConnection(getUrl())) {
+            try (Statement stmt = connection.createStatement()) {
+                String sql = String
+                        .format(ALTER_SQL_WITH_NO_TTL, schemaName, globalViewName, "COL_30");
+                stmt.execute(sql);
+            }
+        }
+
+        // ALTER tenant view
+        String tenantURL = getUrl() + ';' + TENANT_ID_ATTRIB + '=' + tenantId;
+        try (Connection connection = DriverManager.getConnection(tenantURL)) {
+            try (Statement stmt = connection.createStatement()) {
+                String sql = String
+                        .format(ALTER_SQL_WITH_NO_TTL, schemaName, tenantViewName, "COL_100");
+                stmt.execute(sql);
+            }
+        }
 
     }
 
+    @Test public void testResetPhoenixTTL() throws Exception {
+        long startTime = EnvironmentEdgeManager.currentTimeMillis();
+
+        final SchemaBuilder schemaBuilder = createLevel2TenantViewWithGlobalLevelTTL(null, null);
+        String tenantId = schemaBuilder.getDataOptions().getTenantId();
+        String schemaName = stripQuotes(
+                SchemaUtil.getSchemaNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String globalViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityGlobalViewName()));
+        String tenantViewName = stripQuotes(
+                SchemaUtil.getTableNameFromFullName(schemaBuilder.getEntityTenantViewName()));
+        String indexOnGlobalViewName = String.format("IDX_%s", globalViewName);
+        String indexOnTenantViewName = String
+                .format("IDX_%s", stripQuotes(schemaBuilder.getEntityKeyPrefix()));
+
+        try (Connection connection = DriverManager.getConnection(getUrl())) {
+            try (Statement stmt = connection.createStatement()) {
+                // Phoenix TTL is set to 'NONE'
+                String sql = String
+                        .format(ALTER_PHOENIX_TTL_SQL, schemaName, globalViewName, "'NONE'");
+                stmt.execute(sql);
+            }
+        }
+
+        // Expected 4 rows - one for GlobalView, one for TenantView and ViewIndex each.
+        // Since the PHOENIX_TTL property values for global view are being reset,
+        // we expect the view header columns value to be set to zero.
+        assertViewHeaderRowsHavePhoenixTTLRelatedCells(
+                schemaBuilder.getTableOptions().getSchemaName(), startTime, false, 4);
+        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, globalViewName,
+                PTableType.VIEW.getSerializedValue(), 0);
+        assertSyscatHavePhoenixTTLRelatedColumns("", schemaName, indexOnGlobalViewName,
+                PTableType.INDEX.getSerializedValue(), 0);
+        // Since the PHOENIX_TTL property values for the tenant view are not being reset,
+        // we expect the TTL value to be same as before.
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, tenantViewName,
+                PTableType.VIEW.getSerializedValue(), 300000);
+        assertSyscatHavePhoenixTTLRelatedColumns(tenantId, schemaName, indexOnTenantViewName,
+                PTableType.INDEX.getSerializedValue(), 300000);
+    }
 }
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 61cb297..659bf91 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
@@ -2605,11 +2605,14 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
      *     long, boolean)}
      */
     private MetaDataMutationResult validateIfMutationAllowedOnParent(
+            final PTable parentTable,
+            final List<Mutation> tableMetadata,
             final PTableType expectedType, final long clientTimeStamp,
             final byte[] tenantId, final byte[] schemaName,
             final byte[] tableOrViewName, final List<PTable> childViews,
             final int clientVersion) throws IOException, SQLException {
         boolean isMutationAllowed = true;
+        boolean isSchemaMutationAllowed = true;
         if (expectedType == PTableType.TABLE || expectedType == PTableType.VIEW) {
             try (Table hTable = env.getTable(getSystemTableForChildLinks(clientVersion,
                     env.getConfiguration()))) {
@@ -2638,6 +2641,11 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                         QueryServices.ALLOW_SPLITTABLE_SYSTEM_CATALOG_ROLLBACK);
                 }
             }
+            // Validate PHOENIX_TTL property settings for views only.
+            if (expectedType == PTableType.VIEW) {
+                isSchemaMutationAllowed = validatePhoenixTTLAttributeSettingForView(
+                        parentTable, childViews, tableMetadata, PHOENIX_TTL_BYTES);
+            }
         }
         if (!isMutationAllowed) {
             MetaDataMutationResult metaDataMutationResult =
@@ -2646,6 +2654,13 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
                     EnvironmentEdgeManager.currentTimeMillis(), null);
             return metaDataMutationResult;
         }
+        if (!isSchemaMutationAllowed) {
+            MetaDataMutationResult metaDataMutationResult =
+                    new MetaDataMutationResult(
+                            MetaDataProtocol.MutationCode.UNALLOWED_SCHEMA_MUTATION,
+                            EnvironmentEdgeManager.currentTimeMillis(), null);
+            return metaDataMutationResult;
+        }
         return null;
     }
 
@@ -2677,6 +2692,7 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
             try {
                 List<PTable> childViews = Lists.newArrayList();
                 MetaDataMutationResult mutationResult = validateIfMutationAllowedOnParent(
+                        parentTable, tableMetadata,
                         expectedType, clientTimeStamp, tenantId, schemaName, tableOrViewName,
                         childViews, clientVersion);
                 // only if mutation is allowed, we should get Optional.empty() here
@@ -2924,6 +2940,46 @@ public class MetaDataEndpointImpl extends MetaDataProtocol implements Coprocesso
         }
     }
 
+    // Checks whether a non-zero PHOENIX_TTL value is being set.
+    private boolean validatePhoenixTTLAttributeSettingForView(
+            final PTable parentTable,
+            final List<PTable> childViews,
+            final List<Mutation> tableMetadata,
+            final byte[] phoenixTtlBytes) {
+        boolean hasNewPhoenixTTLAttribute = false;
+        boolean isSchemaMutationAllowed = true;
+        for (Mutation m : tableMetadata) {
+            if (m instanceof Put) {
+                Put p = (Put)m;
+                List<Cell> cells = p.get(TABLE_FAMILY_BYTES, phoenixTtlBytes);
+                if (cells != null && cells.size() > 0) {
+                    Cell cell = cells.get(0);
+                    long newPhoenixTTL = (long) PLong.INSTANCE.toObject(cell.getValueArray(),
+                            cell.getValueOffset(), cell.getValueLength());
+                    hasNewPhoenixTTLAttribute =  newPhoenixTTL != PHOENIX_TTL_NOT_DEFINED ;
+                }
+            }
+        }
+
+        if (hasNewPhoenixTTLAttribute) {
+            // Disallow if the parent has PHOENIX_TTL set.
+            if (parentTable != null &&  parentTable.getPhoenixTTL() != PHOENIX_TTL_NOT_DEFINED) {
+                isSchemaMutationAllowed = false;
+            }
+
+            // Since we do not allow propagation of PHOENIX_TTL values during ALTER for now.
+            // If a child view exists and this view previously had a PHOENIX_TTL value set
+            // then that implies that the child view too has a valid PHOENIX_TTL (non zero).
+            // In this case we do not allow for ALTER of the view's PHOENIX_TTL value.
+            if (!childViews.isEmpty()) {
+                isSchemaMutationAllowed = false;
+            }
+        }
+        return isSchemaMutationAllowed;
+
+
+    }
+
     public static class ColumnFinder extends StatelessTraverseAllExpressionVisitor<Void> {
         private boolean columnFound;
         private final Expression columnExpression;
diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
index 015519f..9f4c139 100644
--- a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
+++ b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java
@@ -335,6 +335,8 @@ public enum SQLExceptionCode {
     ABOVE_INDEX_NON_ASYNC_THRESHOLD(1097, "44A34", "The estimated read size for index creation "
             + "is higher than " + QueryServices.CLIENT_INDEX_ASYNC_THRESHOLD+ ". You can edit the"
             + " limit or create ASYNC index."),
+    CANNOT_SET_OR_ALTER_PHOENIX_TTL(10953, "44A35", "Cannot set or alter "
+            + PhoenixDatabaseMetaData.PHOENIX_TTL + " property on an view when parent/child view has PHOENIX_TTL set,"),
 
     /** Sequence related */
     SEQUENCE_ALREADY_EXIST(1200, "42Z00", "Sequence already exists.", new Factory() {
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 f18c9f3..8e5de13 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
@@ -2077,6 +2077,13 @@ public class MetaDataClient {
                     }
                 }
 
+                // Cannot set PHOENIX_TTL if parent has already defined it.
+                if (tableType == VIEW  && parent != null && parent.getPhoenixTTL() != PHOENIX_TTL_NOT_DEFINED) {
+                    throw new SQLExceptionInfo.Builder(
+                            SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL)
+                            .setSchemaName(schemaName).setTableName(tableName).build().buildException();
+                }
+
                 if (tableType != VIEW) {
                     throw new SQLExceptionInfo.Builder(SQLExceptionCode.PHOENIX_TTL_SUPPORTED_FOR_VIEWS_ONLY)
                             .setSchemaName(schemaName)
@@ -3443,6 +3450,10 @@ public class MetaDataClient {
             }
             throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_MUTATE_TABLE)
             .setSchemaName(schemaName).setTableName(tableName).setFamilyName(familyName).setColumnName(columnName).setMessage(msg).build().buildException();
+        case UNALLOWED_SCHEMA_MUTATION:
+            throw new SQLExceptionInfo.Builder(
+                    SQLExceptionCode.CANNOT_SET_OR_ALTER_PHOENIX_TTL)
+                    .setSchemaName(schemaName).setTableName(tableName).build().buildException();
         case NO_OP:
         case COLUMN_ALREADY_EXISTS:
         case COLUMN_NOT_FOUND: