PHOENIX-3445 Add a CREATE IMMUTABLE TABLE construct to make immutable tables more explicit
Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/d2a22418 Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/d2a22418 Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/d2a22418 Branch: refs/heads/encodecolumns2 Commit: d2a224186ffbd605a028ac99d14bf3ac9436a5c5 Parents: e966e26 Author: Thomas D'Silva <tdsi...@salesforce.com> Authored: Mon Nov 28 17:08:27 2016 -0800 Committer: Thomas D'Silva <tdsi...@salesforce.com> Committed: Fri Dec 16 11:27:26 2016 -0800 ---------------------------------------------------------------------- .../apache/phoenix/end2end/AlterTableIT.java | 16 ++-- .../phoenix/end2end/AlterTableWithViewsIT.java | 41 +++++++++ .../phoenix/end2end/AppendOnlySchemaIT.java | 21 ++--- .../phoenix/end2end/ImmutableTablePropIT.java | 92 ++++++++++++++++++++ .../end2end/QueryDatabaseMetaDataIT.java | 3 +- phoenix-core/src/main/antlr3/PhoenixSQL.g | 7 +- .../phoenix/exception/SQLExceptionCode.java | 4 +- .../apache/phoenix/jdbc/PhoenixStatement.java | 8 +- .../phoenix/parse/CreateTableStatement.java | 14 ++- .../apache/phoenix/parse/ParseNodeFactory.java | 4 +- .../org/apache/phoenix/query/QueryServices.java | 1 + .../apache/phoenix/schema/MetaDataClient.java | 23 ++--- .../apache/phoenix/schema/TableProperty.java | 50 ++++++----- 13 files changed, 219 insertions(+), 65 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java index 5da0ee7..155b6c2 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableIT.java @@ -1168,9 +1168,8 @@ public class AlterTableIT extends ParallelStatsDisabledIT { assertImmutableRows(conn, dataTableFullName, true); ddl = "ALTER TABLE " + dataTableFullName + " SET COMPACTION_ENABLED = FALSE, VERSIONS = 10"; conn.createStatement().execute(ddl); - ddl = "ALTER TABLE " + dataTableFullName + " SET COMPACTION_ENABLED = FALSE, CF1.MIN_VERSIONS = 1, CF2.MIN_VERSIONS = 3, MIN_VERSIONS = 8, IMMUTABLE_ROWS=false, CF1.KEEP_DELETED_CELLS = true, KEEP_DELETED_CELLS = false"; + ddl = "ALTER TABLE " + dataTableFullName + " SET COMPACTION_ENABLED = FALSE, CF1.MIN_VERSIONS = 1, CF2.MIN_VERSIONS = 3, MIN_VERSIONS = 8, CF1.KEEP_DELETED_CELLS = true, KEEP_DELETED_CELLS = false"; conn.createStatement().execute(ddl); - assertImmutableRows(conn, dataTableFullName, false); try (HBaseAdmin admin = conn.unwrap(PhoenixConnection.class).getQueryServices().getAdmin()) { HTableDescriptor tableDesc = admin.getTableDescriptor(Bytes.toBytes(dataTableFullName)); @@ -1346,11 +1345,16 @@ public class AlterTableIT extends ParallelStatsDisabledIT { String viewFullName = SchemaUtil.getTableName(schemaName, generateUniqueName()); ddl = "CREATE VIEW " + viewFullName + " AS SELECT * FROM " + dataTableFullName + " WHERE CREATION_TIME = 1"; conn1.createStatement().execute(ddl); - ddl = "ALTER VIEW " + viewFullName + " SET IMMUTABLE_ROWS = TRUE"; + ddl = "ALTER VIEW " + viewFullName + " SET UPDATE_CACHE_FREQUENCY = 10"; conn1.createStatement().execute(ddl); - assertImmutableRows(conn1, viewFullName, true); - ddl = "ALTER VIEW " + viewFullName + " SET IMMUTABLE_ROWS = FALSE"; + conn1.createStatement().execute("SELECT * FROM " + viewFullName); + PhoenixConnection pconn = conn1.unwrap(PhoenixConnection.class); + assertEquals(10, pconn.getTable(new PTableKey(pconn.getTenantId(), viewFullName)).getUpdateCacheFrequency()); + ddl = "ALTER VIEW " + viewFullName + " SET UPDATE_CACHE_FREQUENCY = 20"; conn1.createStatement().execute(ddl); + conn1.createStatement().execute("SELECT * FROM " + viewFullName); + pconn = conn1.unwrap(PhoenixConnection.class); + assertEquals(20, pconn.getTable(new PTableKey(pconn.getTenantId(), viewFullName)).getUpdateCacheFrequency()); assertImmutableRows(conn1, viewFullName, false); ddl = "ALTER VIEW " + viewFullName + " SET DISABLE_WAL = TRUE"; try { @@ -2230,6 +2234,6 @@ public class AlterTableIT extends ParallelStatsDisabledIT { } } } - + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java index 6e4f5c0..91aca4e 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AlterTableWithViewsIT.java @@ -19,6 +19,7 @@ package org.apache.phoenix.end2end; import static org.apache.phoenix.exception.SQLExceptionCode.CANNOT_MUTATE_TABLE; import static org.apache.phoenix.util.PhoenixRuntime.TENANT_ID_ATTRIB; +import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -32,6 +33,7 @@ import java.sql.ResultSetMetaData; import java.sql.SQLException; import java.util.Arrays; import java.util.Collection; +import java.util.Properties; import org.apache.commons.lang.ArrayUtils; import org.apache.hadoop.hbase.client.HTableInterface; @@ -45,6 +47,8 @@ import org.apache.phoenix.schema.PNameFactory; import org.apache.phoenix.schema.PTable; import org.apache.phoenix.schema.PTableKey; import org.apache.phoenix.schema.PTableType; +import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.SchemaUtil; import org.junit.Test; import org.junit.runner.RunWith; import org.junit.runners.Parameterized; @@ -719,4 +723,41 @@ public class AlterTableWithViewsIT extends ParallelStatsDisabledIT { } } + @Test + public void testAlterTablePropertyOnView() throws Exception { + try (Connection conn = DriverManager.getConnection(getUrl()); + Connection viewConn = isMultiTenant ? DriverManager.getConnection(TENANT_SPECIFIC_URL1) : conn ) { + String baseTableName = "NONTXNTBL_" + generateUniqueName() + (isMultiTenant ? "0":"1"); + String viewOfTable = baseTableName + "_VIEW"; + + String ddl = "CREATE TABLE " + baseTableName + " (\n" + +"ID VARCHAR(15) NOT NULL,\n" + +"CREATED_DATE DATE,\n" + +"CONSTRAINT PK PRIMARY KEY (ID))"; + conn.createStatement().execute(ddl); + ddl = "CREATE VIEW " + viewOfTable + " AS SELECT * FROM " + baseTableName; + viewConn.createStatement().execute(ddl); + + try { + viewConn.createStatement().execute("ALTER VIEW " + viewOfTable + " SET IMMUTABLE_ROWS = true"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.CANNOT_ALTER_TABLE_PROPERTY_ON_VIEW.getErrorCode(), e.getErrorCode()); + } + + viewConn.createStatement().execute("ALTER VIEW " + viewOfTable + " SET UPDATE_CACHE_FREQUENCY = 100"); + viewConn.createStatement().execute("SELECT * FROM "+ viewOfTable); + PName tenantId = isMultiTenant ? PNameFactory.newName("tenant1") : null; + assertEquals(100, viewConn.unwrap(PhoenixConnection.class).getTable(new PTableKey(tenantId, viewOfTable)).getUpdateCacheFrequency()); + + try { + viewConn.createStatement().execute("ALTER VIEW " + viewOfTable + " SET APPEND_ONLY_SCHEMA = true"); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.CANNOT_ALTER_TABLE_PROPERTY_ON_VIEW.getErrorCode(), e.getErrorCode()); + } + } + + } + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java index 93341b7..8d40094 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/AppendOnlySchemaIT.java @@ -89,7 +89,7 @@ public class AppendOnlySchemaIT extends ParallelStatsDisabledIT { + viewName + " ( hostName varchar NOT NULL, tagName varChar" + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (hostName))" + " AS SELECT * FROM " + metricTableName - + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000"; + + " UPDATE_CACHE_FREQUENCY=300000"; conn1.createStatement().execute(ddl); conn1.createStatement().execute("UPSERT INTO " + viewName + "(hostName, metricVal) VALUES('host1', 1.0)"); conn1.commit(); @@ -201,7 +201,7 @@ public class AppendOnlySchemaIT extends ParallelStatsDisabledIT { + viewName + "( hostName varchar NOT NULL," + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (hostName))" + " AS SELECT * FROM " + metricTableName - + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000"; + + " UPDATE_CACHE_FREQUENCY=300000"; conn1.createStatement().execute(ddl); conn1.createStatement().execute("UPSERT INTO " + viewName + "(hostName, metricVal1) VALUES('host1', 1.0)"); @@ -215,7 +215,7 @@ public class AppendOnlySchemaIT extends ParallelStatsDisabledIT { + viewName + "( instanceName varchar, hostName varchar, metricVal2 double, metricVal1 double" + " CONSTRAINT HOSTNAME_PK PRIMARY KEY (instancename, hostName))" + " AS SELECT * FROM " + metricTableName - + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=300000"; + + " UPDATE_CACHE_FREQUENCY=300000"; conn2.createStatement().execute(ddl); conn2.createStatement().execute( @@ -308,16 +308,11 @@ public class AppendOnlySchemaIT extends ParallelStatsDisabledIT { + " col1 integer NOT NULL" + " CONSTRAINT NAME_PK PRIMARY KEY (id, col1))" + " APPEND_ONLY_SCHEMA = true, UPDATE_CACHE_FREQUENCY=1000"); - try { - conn.createStatement().execute( - "create view IF NOT EXISTS " + viewName + " (val1 integer NOT NULL) AS SELECT * FROM " + tableName - + " UPDATE_CACHE_FREQUENCY=1000"); - fail("APPEND_ONLY_SCHEMA must be true for a view if it is true for the base table "); - } - catch (SQLException e) { - assertEquals(SQLExceptionCode.VIEW_APPEND_ONLY_SCHEMA.getErrorCode(), - e.getErrorCode()); - } + conn.createStatement().execute( + "create view IF NOT EXISTS " + viewName + " (val1 integer) AS SELECT * FROM " + tableName + + " UPDATE_CACHE_FREQUENCY=1000"); + PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class); + assertEquals(true, pconn.getTable(new PTableKey(pconn.getTenantId(), viewName)).isAppendOnlySchema()); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTablePropIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTablePropIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTablePropIT.java new file mode 100644 index 0000000..693fb81 --- /dev/null +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/ImmutableTablePropIT.java @@ -0,0 +1,92 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.phoenix.end2end; + +import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.Statement; +import java.util.Properties; + +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.schema.PTable; +import org.apache.phoenix.schema.PTableKey; +import org.apache.phoenix.util.PropertiesUtil; +import org.apache.phoenix.util.SchemaUtil; +import org.junit.Test; + +public class ImmutableTablePropIT extends ParallelStatsDisabledIT { + + @Test + public void testImmutableKeyword() throws Exception { + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + String immutableDataTableFullName = SchemaUtil.getTableName("", generateUniqueName()); + String mutableDataTableFullName = SchemaUtil.getTableName("", generateUniqueName()); + try (Connection conn = DriverManager.getConnection(getUrl(), props);) { + Statement stmt = conn.createStatement(); + // create table with immutable keyword + String ddl = "CREATE IMMUTABLE TABLE " + immutableDataTableFullName + + " (a_string varchar not null, col1 integer" + + " CONSTRAINT pk PRIMARY KEY (a_string)) STORE_NULLS=true"; + stmt.execute(ddl); + + // create table without immutable keyword + ddl = "CREATE TABLE " + mutableDataTableFullName + + " (a_string varchar not null, col1 integer" + + " CONSTRAINT pk PRIMARY KEY (a_string)) STORE_NULLS=true"; + stmt.execute(ddl); + + PhoenixConnection phxConn = conn.unwrap(PhoenixConnection.class); + PTable immutableTable = phxConn.getTable(new PTableKey(null, immutableDataTableFullName)); + assertTrue("IMMUTABLE_ROWS should be set to true", immutableTable.isImmutableRows()); + PTable mutableTable = phxConn.getTable(new PTableKey(null, mutableDataTableFullName)); + assertFalse("IMMUTABLE_ROWS should be set to false", mutableTable.isImmutableRows()); + } + } + + @Test + public void testImmutableProperty() throws Exception { + Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES); + String immutableDataTableFullName = SchemaUtil.getTableName("", generateUniqueName()); + String mutableDataTableFullName = SchemaUtil.getTableName("", generateUniqueName()); + try (Connection conn = DriverManager.getConnection(getUrl(), props);) { + Statement stmt = conn.createStatement(); + // create table with immutable_table property set to true + String ddl = "CREATE TABLE " + immutableDataTableFullName + + " (a_string varchar not null, col1 integer" + + " CONSTRAINT pk PRIMARY KEY (a_string)) IMMUTABLE_ROWS=true"; + stmt.execute(ddl); + + // create table with immutable_table property set to false + ddl = "CREATE TABLE " + mutableDataTableFullName + + " (a_string varchar not null, col1 integer" + + " CONSTRAINT pk PRIMARY KEY (a_string)) IMMUTABLE_ROWS=false"; + stmt.execute(ddl); + + PhoenixConnection phxConn = conn.unwrap(PhoenixConnection.class); + PTable immutableTable = phxConn.getTable(new PTableKey(null, immutableDataTableFullName)); + assertTrue("IMMUTABLE_ROWS should be set to true", immutableTable.isImmutableRows()); + PTable mutableTable = phxConn.getTable(new PTableKey(null, mutableDataTableFullName)); + assertFalse("IMMUTABLE_ROWS should be set to false", mutableTable.isImmutableRows()); + } + } + +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java index 805691d..ec9f32f 100644 --- a/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java +++ b/phoenix-core/src/it/java/org/apache/phoenix/end2end/QueryDatabaseMetaDataIT.java @@ -842,7 +842,7 @@ public class QueryDatabaseMetaDataIT extends BaseClientManagedTimeIT { createStmt = "create view " + MDTEST_NAME + " (id char(1) not null primary key,\n" + " b.col1 integer,\n" + - " \"c\".col2 bigint) \n"; + " \"c\".col2 bigint) IMMUTABLE_ROWS=true \n"; // should be ok now conn1.createStatement().execute(createStmt); conn1.close(); @@ -875,7 +875,6 @@ public class QueryDatabaseMetaDataIT extends BaseClientManagedTimeIT { } catch (ReadOnlyTableException e) { // expected to fail b/c table is read-only } - conn2.createStatement().execute("ALTER VIEW " + MDTEST_NAME + " SET IMMUTABLE_ROWS=TRUE"); HTableInterface htable = conn2.getQueryServices().getTable(SchemaUtil.getTableNameAsBytes(MDTEST_SCHEMA_NAME,MDTEST_NAME)); Put put = new Put(Bytes.toBytes("0")); http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/antlr3/PhoenixSQL.g ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/antlr3/PhoenixSQL.g b/phoenix-core/src/main/antlr3/PhoenixSQL.g index 1d1a873..a5e46dc 100644 --- a/phoenix-core/src/main/antlr3/PhoenixSQL.g +++ b/phoenix-core/src/main/antlr3/PhoenixSQL.g @@ -137,6 +137,7 @@ tokens DEFAULT = 'default'; DUPLICATE = 'duplicate'; IGNORE = 'ignore'; + IMMUTABLE = 'immutable'; } @@ -433,11 +434,11 @@ explain_node returns [BindableStatement ret] // Parse a create table statement. create_table_node returns [CreateTableStatement ret] - : CREATE TABLE (IF NOT ex=EXISTS)? t=from_table_name + : CREATE (im=IMMUTABLE)? TABLE (IF NOT ex=EXISTS)? t=from_table_name (LPAREN c=column_defs (pk=pk_constraint)? RPAREN) (p=fam_properties)? (SPLIT ON s=value_expression_list)? - {ret = factory.createTable(t, p, c, pk, s, PTableType.TABLE, ex!=null, null, null, getBindCount()); } + {ret = factory.createTable(t, p, c, pk, s, PTableType.TABLE, ex!=null, null, null, getBindCount(), im!=null ? true : null); } ; // Parse a create schema statement. @@ -454,7 +455,7 @@ create_view_node returns [CreateTableStatement ret] FROM bt=from_table_name (WHERE w=expression)? )? (p=fam_properties)? - { ret = factory.createTable(t, p, c, pk, null, PTableType.VIEW, ex!=null, bt==null ? t : bt, w, getBindCount()); } + { ret = factory.createTable(t, p, c, pk, null, PTableType.VIEW, ex!=null, bt==null ? t : bt, w, getBindCount(), null); } ; // Parse a create index statement. http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java b/phoenix-core/src/main/java/org/apache/phoenix/exception/SQLExceptionCode.java index ac5619f..20f3974 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 @@ -363,7 +363,9 @@ public enum SQLExceptionCode { UPDATE_CACHE_FREQUENCY_INVALID(1130, "XCL30", "UPDATE_CACHE_FREQUENCY cannot be set to ALWAYS if APPEND_ONLY_SCHEMA is true."), CANNOT_DROP_COL_APPEND_ONLY_SCHEMA(1131, "XCL31", "Cannot drop column from table that with append only schema."), - VIEW_APPEND_ONLY_SCHEMA(1132, "XCL32", "APPEND_ONLY_SCHEMA property of view must match the base table"), + + CANNOT_ALTER_IMMUTABLE_ROWS_PROPERTY(1133, "XCL33", "IMMUTABLE_ROWS property can be changed only if the table storage scheme is ONE_CELL_PER_KEYVALUE_COLUMN"), + CANNOT_ALTER_TABLE_PROPERTY_ON_VIEW(1134, "XCL34", "Altering this table property on a view is not allowed"), /** * Implementation defined class. Phoenix internal error. (errorcode 20, sqlstate INT). http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java index 2a7cd0e..54bef29 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixStatement.java @@ -632,8 +632,8 @@ public class PhoenixStatement implements Statement, SQLCloseable { private static class ExecutableCreateTableStatement extends CreateTableStatement implements CompilableStatement { ExecutableCreateTableStatement(TableName tableName, ListMultimap<String,Pair<String,Object>> props, List<ColumnDef> columnDefs, PrimaryKeyConstraint pkConstraint, List<ParseNode> splitNodes, PTableType tableType, boolean ifNotExists, - TableName baseTableName, ParseNode tableTypeIdNode, int bindCount) { - super(tableName, props, columnDefs, pkConstraint, splitNodes, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount); + TableName baseTableName, ParseNode tableTypeIdNode, int bindCount, Boolean immutableRows) { + super(tableName, props, columnDefs, pkConstraint, splitNodes, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount, immutableRows); } @SuppressWarnings("unchecked") @@ -1170,8 +1170,8 @@ public class PhoenixStatement implements Statement, SQLCloseable { @Override public CreateTableStatement createTable(TableName tableName, ListMultimap<String,Pair<String,Object>> props, List<ColumnDef> columns, PrimaryKeyConstraint pkConstraint, - List<ParseNode> splits, PTableType tableType, boolean ifNotExists, TableName baseTableName, ParseNode tableTypeIdNode, int bindCount) { - return new ExecutableCreateTableStatement(tableName, props, columns, pkConstraint, splits, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount); + List<ParseNode> splits, PTableType tableType, boolean ifNotExists, TableName baseTableName, ParseNode tableTypeIdNode, int bindCount, Boolean immutableRows) { + return new ExecutableCreateTableStatement(tableName, props, columns, pkConstraint, splits, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount, immutableRows); } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateTableStatement.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateTableStatement.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateTableStatement.java index 3c84cd0..73b7a11 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateTableStatement.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/CreateTableStatement.java @@ -17,12 +17,16 @@ */ package org.apache.phoenix.parse; +import java.util.Collection; import java.util.Collections; import java.util.List; +import org.apache.hadoop.hbase.HColumnDescriptor; import org.apache.hadoop.hbase.util.Pair; import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.query.QueryConstants; import org.apache.phoenix.schema.PTableType; +import org.apache.phoenix.schema.TableProperty; import com.google.common.collect.ImmutableList; import com.google.common.collect.ImmutableListMultimap; @@ -39,6 +43,8 @@ public class CreateTableStatement extends MutableStatement { private final boolean ifNotExists; private final TableName baseTableName; private final ParseNode whereClause; + // TODO change this to boolean at the next major release and remove TableProperty.IMMUTABLE_ROWS and QueryServiceOptions.IMMUTABLE_ROWS_ATTRIB + private final Boolean immutableRows; public CreateTableStatement(CreateTableStatement createTable, List<ColumnDef> columns) { this.tableName = createTable.tableName; @@ -51,11 +57,12 @@ public class CreateTableStatement extends MutableStatement { this.ifNotExists = createTable.ifNotExists; this.baseTableName = createTable.baseTableName; this.whereClause = createTable.whereClause; + this.immutableRows = createTable.immutableRows; } protected CreateTableStatement(TableName tableName, ListMultimap<String,Pair<String,Object>> props, List<ColumnDef> columns, PrimaryKeyConstraint pkConstraint, List<ParseNode> splitNodes, PTableType tableType, boolean ifNotExists, - TableName baseTableName, ParseNode whereClause, int bindCount) { + TableName baseTableName, ParseNode whereClause, int bindCount, Boolean immutableRows) { this.tableName = tableName; this.props = props == null ? ImmutableListMultimap.<String,Pair<String,Object>>of() : props; this.tableType = PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA.equals(tableName.getSchemaName()) ? PTableType.SYSTEM : tableType; @@ -66,6 +73,7 @@ public class CreateTableStatement extends MutableStatement { this.ifNotExists = ifNotExists; this.baseTableName = baseTableName; this.whereClause = whereClause; + this.immutableRows = immutableRows; } public ParseNode getWhereClause() { @@ -108,4 +116,8 @@ public class CreateTableStatement extends MutableStatement { public PrimaryKeyConstraint getPrimaryKeyConstraint() { return pkConstraint; } + + public Boolean immutableRows() { + return immutableRows; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java index 232a91e..0376877 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/parse/ParseNodeFactory.java @@ -293,8 +293,8 @@ public class ParseNodeFactory { return new IndexKeyConstraint(parseNodeAndSortOrder); } - public CreateTableStatement createTable(TableName tableName, ListMultimap<String,Pair<String,Object>> props, List<ColumnDef> columns, PrimaryKeyConstraint pkConstraint, List<ParseNode> splits, PTableType tableType, boolean ifNotExists, TableName baseTableName, ParseNode tableTypeIdNode, int bindCount) { - return new CreateTableStatement(tableName, props, columns, pkConstraint, splits, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount); + public CreateTableStatement createTable(TableName tableName, ListMultimap<String,Pair<String,Object>> props, List<ColumnDef> columns, PrimaryKeyConstraint pkConstraint, List<ParseNode> splits, PTableType tableType, boolean ifNotExists, TableName baseTableName, ParseNode tableTypeIdNode, int bindCount, Boolean immutableRows) { + return new CreateTableStatement(tableName, props, columns, pkConstraint, splits, tableType, ifNotExists, baseTableName, tableTypeIdNode, bindCount, immutableRows); } public CreateSchemaStatement createSchema(String schemaName, boolean ifNotExists) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java index f5ee612..65d385e 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServices.java @@ -92,6 +92,7 @@ public interface QueryServices extends SQLCloseable { public static final String ROW_KEY_ORDER_SALTED_TABLE_ATTRIB = "phoenix.query.rowKeyOrderSaltedTable"; public static final String USE_INDEXES_ATTRIB = "phoenix.query.useIndexes"; + @Deprecated // use the IMMUTABLE keyword while creating the table public static final String IMMUTABLE_ROWS_ATTRIB = "phoenix.mutate.immutableRows"; public static final String INDEX_MUTATE_BATCH_SIZE_THRESHOLD_ATTRIB = "phoenix.index.mutableBatchSizeThreshold"; public static final String DROP_METADATA_ATTRIB = "phoenix.schema.dropMetaData"; http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/MetaDataClient.java index ecd5f7a..0803e89 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 @@ -889,9 +889,14 @@ public class MetaDataClient { populatePropertyMaps(statement.getProps(), tableProps, commonFamilyProps); boolean isAppendOnlySchema = false; - Boolean appendOnlySchemaProp = (Boolean) TableProperty.APPEND_ONLY_SCHEMA.getValue(tableProps); - if (appendOnlySchemaProp != null) { - isAppendOnlySchema = appendOnlySchemaProp; + if (parent==null) { + Boolean appendOnlySchemaProp = (Boolean) TableProperty.APPEND_ONLY_SCHEMA.getValue(tableProps); + if (appendOnlySchemaProp != null) { + isAppendOnlySchema = appendOnlySchemaProp; + } + } + else { + isAppendOnlySchema = parent.isAppendOnlySchema(); } long updateCacheFrequency = 0; Long updateCacheFrequencyProp = (Long) TableProperty.UPDATE_CACHE_FREQUENCY.getValue(tableProps); @@ -904,12 +909,6 @@ public class MetaDataClient { .setSchemaName(tableName.getSchemaName()).setTableName(tableName.getTableName()) .build().buildException(); } - // view isAppendOnlySchema property must match the parent table - if (parent!=null && isAppendOnlySchema!= parent.isAppendOnlySchema()) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.VIEW_APPEND_ONLY_SCHEMA) - .setSchemaName(tableName.getSchemaName()).setTableName(tableName.getTableName()) - .build().buildException(); - } PTable table = null; // if the APPEND_ONLY_SCHEMA attribute is true first check if the table is present in the cache @@ -1424,7 +1423,7 @@ public class MetaDataClient { statement.getProps().put("", new Pair<String,Object>(DEFAULT_COLUMN_FAMILY_NAME,dataTable.getDefaultFamilyName().getString())); } PrimaryKeyConstraint pk = FACTORY.primaryKey(null, allPkColumns); - CreateTableStatement tableStatement = FACTORY.createTable(indexTableName, statement.getProps(), columnDefs, pk, statement.getSplitNodes(), PTableType.INDEX, statement.ifNotExists(), null, null, statement.getBindCount()); + CreateTableStatement tableStatement = FACTORY.createTable(indexTableName, statement.getProps(), columnDefs, pk, statement.getSplitNodes(), PTableType.INDEX, statement.ifNotExists(), null, null, statement.getBindCount(), null); table = createTableInternal(tableStatement, splits, dataTable, null, null, null, null, allocateIndexId, statement.getIndexType(), asyncCreatedDate, tableProps, commonFamilyProps); break; } catch (ConcurrentTableMutationException e) { // Can happen if parent data table changes while above is in progress @@ -1725,7 +1724,9 @@ public class MetaDataClient { // Although unusual, it's possible to set a mapped VIEW as having immutable rows. // This tells Phoenix that you're managing the index maintenance yourself. if (tableType != PTableType.INDEX && (tableType != PTableType.VIEW || viewType == ViewType.MAPPED)) { - Boolean isImmutableRowsProp = (Boolean) TableProperty.IMMUTABLE_ROWS.getValue(tableProps); + // TODO remove TableProperty.IMMUTABLE_ROWS at the next major release + Boolean isImmutableRowsProp = statement.immutableRows()!=null? statement.immutableRows() : + (Boolean) TableProperty.IMMUTABLE_ROWS.getValue(tableProps); if (isImmutableRowsProp == null) { isImmutableRows = connection.getQueryServices().getProps().getBoolean(QueryServices.IMMUTABLE_ROWS_ATTRIB, QueryServicesOptions.DEFAULT_IMMUTABLE_ROWS); } else { http://git-wip-us.apache.org/repos/asf/phoenix/blob/d2a22418/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java index 4f24c92..69cc7ff 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/schema/TableProperty.java @@ -36,23 +36,24 @@ import org.apache.phoenix.util.SchemaUtil; public enum TableProperty { - IMMUTABLE_ROWS(PhoenixDatabaseMetaData.IMMUTABLE_ROWS, true, true), + @Deprecated // use the IMMUTABLE keyword while creating the table + IMMUTABLE_ROWS(PhoenixDatabaseMetaData.IMMUTABLE_ROWS, true, true, false), - MULTI_TENANT(PhoenixDatabaseMetaData.MULTI_TENANT, true, false), + MULTI_TENANT(PhoenixDatabaseMetaData.MULTI_TENANT, true, false, false), - DISABLE_WAL(PhoenixDatabaseMetaData.DISABLE_WAL, true, false), + DISABLE_WAL(PhoenixDatabaseMetaData.DISABLE_WAL, true, false, false), - SALT_BUCKETS(PhoenixDatabaseMetaData.SALT_BUCKETS, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, SALT_ONLY_ON_CREATE_TABLE, false), + SALT_BUCKETS(PhoenixDatabaseMetaData.SALT_BUCKETS, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, SALT_ONLY_ON_CREATE_TABLE, false, false), - DEFAULT_COLUMN_FAMILY(DEFAULT_COLUMN_FAMILY_NAME, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, DEFAULT_COLUMN_FAMILY_ONLY_ON_CREATE_TABLE, false), + DEFAULT_COLUMN_FAMILY(DEFAULT_COLUMN_FAMILY_NAME, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, DEFAULT_COLUMN_FAMILY_ONLY_ON_CREATE_TABLE, false, false), - TTL(HColumnDescriptor.TTL, COLUMN_FAMILY_NOT_ALLOWED_FOR_TTL, true, CANNOT_ALTER_PROPERTY, false), + TTL(HColumnDescriptor.TTL, COLUMN_FAMILY_NOT_ALLOWED_FOR_TTL, true, CANNOT_ALTER_PROPERTY, false, false), - STORE_NULLS(PhoenixDatabaseMetaData.STORE_NULLS, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, false), + STORE_NULLS(PhoenixDatabaseMetaData.STORE_NULLS, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, false, false), - TRANSACTIONAL(PhoenixDatabaseMetaData.TRANSACTIONAL, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, false), - - UPDATE_CACHE_FREQUENCY(PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY, true, true) { + TRANSACTIONAL(PhoenixDatabaseMetaData.TRANSACTIONAL, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, false, false), + + UPDATE_CACHE_FREQUENCY(PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY, true, true, true) { @Override public Object getValue(Object value) { if (value instanceof String) { @@ -69,15 +70,15 @@ public enum TableProperty { } }, - AUTO_PARTITION_SEQ(PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, false) { + AUTO_PARTITION_SEQ(PhoenixDatabaseMetaData.AUTO_PARTITION_SEQ, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, false, false, false) { @Override public Object getValue(Object value) { return value == null ? null : SchemaUtil.normalizeIdentifier(value.toString()); } }, - APPEND_ONLY_SCHEMA(PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, true), - GUIDE_POSTS_WIDTH(PhoenixDatabaseMetaData.GUIDE_POSTS_WIDTH, true, false) { + APPEND_ONLY_SCHEMA(PhoenixDatabaseMetaData.APPEND_ONLY_SCHEMA, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, true, true, false), + GUIDE_POSTS_WIDTH(PhoenixDatabaseMetaData.GUIDE_POSTS_WIDTH, true, false, false) { @Override public Object getValue(Object value) { return value == null ? null : ((Number) value).longValue(); @@ -91,25 +92,27 @@ public enum TableProperty { private final boolean isMutable; // whether or not a property can be changed through statements like ALTER TABLE. private final SQLExceptionCode mutatingImmutablePropException; private final boolean isValidOnView; + private final boolean isMutableOnView; - private TableProperty(String propertyName, boolean isMutable, boolean isValidOnView) { - this(propertyName, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, isMutable, CANNOT_ALTER_PROPERTY, isValidOnView); + private TableProperty(String propertyName, boolean isMutable, boolean isValidOnView, boolean isMutableOnView) { + this(propertyName, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, isMutable, CANNOT_ALTER_PROPERTY, isValidOnView, isMutableOnView); } - private TableProperty(String propertyName, SQLExceptionCode colFamilySpecifiedException, boolean isMutable, boolean isValidOnView) { - this(propertyName, colFamilySpecifiedException, isMutable, CANNOT_ALTER_PROPERTY, isValidOnView); + private TableProperty(String propertyName, SQLExceptionCode colFamilySpecifiedException, boolean isMutable, boolean isValidOnView, boolean isMutableOnView) { + this(propertyName, colFamilySpecifiedException, isMutable, CANNOT_ALTER_PROPERTY, isValidOnView, isMutableOnView); } - private TableProperty(String propertyName, boolean isMutable, boolean isValidOnView, SQLExceptionCode isMutatingException) { - this(propertyName, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, isMutable, isMutatingException, isValidOnView); + private TableProperty(String propertyName, boolean isMutable, boolean isValidOnView, boolean isMutableOnView, SQLExceptionCode isMutatingException) { + this(propertyName, COLUMN_FAMILY_NOT_ALLOWED_TABLE_PROPERTY, isMutable, isMutatingException, isValidOnView, isMutableOnView); } - private TableProperty(String propertyName, SQLExceptionCode colFamSpecifiedException, boolean isMutable, SQLExceptionCode mutatingException, boolean isValidOnView) { + private TableProperty(String propertyName, SQLExceptionCode colFamSpecifiedException, boolean isMutable, SQLExceptionCode mutatingException, boolean isValidOnView, boolean isMutableOnView) { this.propertyName = propertyName; this.colFamSpecifiedException = colFamSpecifiedException; this.isMutable = isMutable; this.mutatingImmutablePropException = mutatingException; this.isValidOnView = isValidOnView; + this.isMutableOnView = isMutableOnView; } public static boolean isPhoenixTableProperty(String property) { @@ -132,8 +135,8 @@ public enum TableProperty { // isQualified is true if column family name is specified in property name public void validate(boolean isMutating, boolean isQualified, PTableType tableType) throws SQLException { checkForColumnFamily(isQualified); - checkForMutability(isMutating); checkIfApplicableForView(tableType); + checkForMutability(isMutating,tableType); } private void checkForColumnFamily(boolean isQualified) throws SQLException { @@ -142,10 +145,13 @@ public enum TableProperty { } } - private void checkForMutability(boolean isMutating) throws SQLException { + private void checkForMutability(boolean isMutating, PTableType tableType) throws SQLException { if (isMutating && !isMutable) { throw new SQLExceptionInfo.Builder(mutatingImmutablePropException).setMessage(". Property: " + propertyName).build().buildException(); } + if (isMutating && tableType == PTableType.VIEW && !isMutableOnView) { + throw new SQLExceptionInfo.Builder(SQLExceptionCode.CANNOT_ALTER_TABLE_PROPERTY_ON_VIEW).setMessage(". Property: " + propertyName).build().buildException(); + } } private void checkIfApplicableForView(PTableType tableType)