blob: ceaa1402bbc2561c693b9a1ec7077c14dcc1ae67 [file] [log] [blame]
/*
* 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.mapreduce.index.IndexUpgradeTool.ROLLBACK_OP;
import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
import static org.apache.phoenix.exception.SQLExceptionCode.MAX_LOOKBACK_AGE_SUPPORTED_FOR_TABLES_ONLY;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertThrows;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Properties;
import java.util.UUID;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.KeepDeletedCells;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Admin;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptor;
import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.Row;
import org.apache.hadoop.hbase.client.Table;
import org.apache.hadoop.hbase.client.TableDescriptor;
import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
import org.apache.hadoop.hbase.regionserver.BloomType;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.jdbc.PhoenixStatement;
import org.apache.phoenix.mapreduce.index.IndexUpgradeTool;
import org.apache.phoenix.query.BaseTest;
import org.apache.phoenix.query.ConnectionQueryServices;
import org.apache.phoenix.query.KeyRange;
import org.apache.phoenix.query.QueryConstants;
import org.apache.phoenix.query.QueryServices;
import org.apache.phoenix.query.QueryServicesOptions;
import org.apache.phoenix.schema.ColumnAlreadyExistsException;
import org.apache.phoenix.schema.PTable;
import org.apache.phoenix.schema.PTable.ImmutableStorageScheme;
import org.apache.phoenix.schema.PTable.QualifierEncodingScheme;
import org.apache.phoenix.schema.PTableKey;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.SchemaNotFoundException;
import org.apache.phoenix.schema.TableAlreadyExistsException;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.util.ByteUtil;
import org.apache.phoenix.util.EnvironmentEdgeManager;
import org.apache.phoenix.util.IndexUtil;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.QueryUtil;
import org.apache.phoenix.util.ReadOnlyProps;
import org.apache.phoenix.util.SchemaUtil;
import org.apache.phoenix.util.TestUtil;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(ParallelStatsDisabledTest.class)
public class CreateTableIT extends ParallelStatsDisabledIT {
@Test
public void testStartKeyStopKey() throws SQLException {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
conn.createStatement().execute("CREATE TABLE " + tableName
+ " (pk char(2) not null primary key) SPLIT ON ('EA','EZ')");
conn.close();
String query = "select count(*) from " + tableName + " where pk >= 'EA' and pk < 'EZ'";
conn = DriverManager.getConnection(getUrl(), props);
Statement statement = conn.createStatement();
statement.execute(query);
PhoenixStatement pstatement = statement.unwrap(PhoenixStatement.class);
List<KeyRange> splits = pstatement.getQueryPlan().getSplits();
assertTrue(splits.size() > 0);
}
@Test
public void testCreateAlterTableWithDuplicateColumn() throws Exception {
Properties props = new Properties();
int failureCount = 0;
int expectedExecCount = 0;
String tableName = generateUniqueName();
String viewName = generateUniqueName();
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
try {
// Case 1 - Adding a column as "Default_CF.Column" in
// CREATE TABLE query where "Column" is same as single PK Column
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL PRIMARY KEY, city VARCHAR,"
+ " name1 VARCHAR, name VARCHAR)", tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
try {
// Case 2 - Adding a column as "Default_CF.Column" in CREATE
// TABLE query where "Default_CF.Column" already exists as non-Pk column
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL PRIMARY KEY, city VARCHAR,"
+ " name1 VARCHAR, name1 VARCHAR)", tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
try {
// Case 3 - Adding a column as "Default_CF.Column" in CREATE
// TABLE query where "Column" is same as single PK Column.
// The only diff from Case 1 is that both PK Column and
// "Default_CF.Column" are of different DataType
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (key1 VARCHAR NOT NULL PRIMARY KEY, city VARCHAR,"
+ " name1 VARCHAR, key1 INTEGER)", tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
try {
// Case 4 - Adding a column as "Default_CF.Column" in
// CREATE TABLE query where "Column" is same as one of the
// PK Column from Composite PK Columns
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL, name1 VARCHAR NOT NULL,"
+ " name2 VARCHAR, name VARCHAR"
+ " CONSTRAINT PK PRIMARY KEY(name, name1))", tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
try {
// Case 5 - Adding a column as "Default_CF.Column" in
// CREATE VIEW query where "Column" is same as one of the
// PK Column from Composite PK Columns derived from parent table
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL, name1 VARCHAR NOT NULL,"
+ " name2 VARCHAR, name3 VARCHAR"
+ " CONSTRAINT PK PRIMARY KEY(name, name1))", tableName));
expectedExecCount++;
conn.createStatement().execute(String.format("CREATE VIEW %s"
+ " (name1 CHAR(5)) AS SELECT * FROM %s", viewName, tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
try {
// Case 6 - Adding a column as "Default_CF.Column" in
// ALTER TABLE query where "Column" is same as one of the
// PK Column from Composite PK Columns
conn.createStatement().execute(
String.format("DROP TABLE %s", tableName));
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL, name1 VARCHAR NOT NULL,"
+ " name2 VARCHAR, name3 VARCHAR"
+ " CONSTRAINT PK PRIMARY KEY(name, name1))", tableName));
expectedExecCount++;
conn.createStatement().execute(
String.format("ALTER TABLE %s ADD name1 INTEGER", tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
try {
// Case 7 - Adding a column as "Default_CF.Column" in
// ALTER TABLE query where "Column" is same as single PK Column
conn.createStatement().execute(
String.format("DROP TABLE %s", tableName));
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL PRIMARY KEY, city VARCHAR,"
+ " name1 VARCHAR, name2 VARCHAR)", tableName));
expectedExecCount++;
conn.createStatement().execute(
String.format("ALTER TABLE %s ADD name VARCHAR", tableName));
fail("Should have failed with ColumnAlreadyExistsException");
} catch (ColumnAlreadyExistsException e) {
// expected
failureCount++;
}
assertEquals(7, failureCount);
assertEquals(3, expectedExecCount);
conn.createStatement().execute(
String.format("DROP TABLE %s", tableName));
// Case 8 - Adding a column as "Non_Default_CF.Column" in
// CREATE TABLE query where "Column" is same as single PK Column
// Hence, we allow creating such column
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL PRIMARY KEY, city VARCHAR,"
+ " name1 VARCHAR, a.name VARCHAR)", tableName));
conn.createStatement().execute(
String.format("DROP TABLE %s", tableName));
// Case 9 - Adding a column as "Non_Default_CF.Column" in
// ALTER TABLE query where "Column" is same as single PK Column
// Hence, we allow creating such column
conn.createStatement().execute(String.format("CREATE TABLE %s"
+ " (name VARCHAR NOT NULL PRIMARY KEY, city VARCHAR,"
+ " name1 VARCHAR, name2 VARCHAR)", tableName));
conn.createStatement().execute(
String.format("ALTER TABLE %s ADD a.name VARCHAR", tableName));
}
}
@Test
public void testCreateTable() throws Exception {
String schemaName = "TEST";
String tableName = schemaName + generateUniqueName();
Properties props = new Properties();
String ddl =
"CREATE TABLE " + tableName + "( data.addtime VARCHAR ,\n"
+ " data.dir VARCHAR ,\n"
+ " data.end_time VARCHAR ,\n"
+ " data.file VARCHAR ,\n"
+ " data.fk_log VARCHAR ,\n"
+ " data.host VARCHAR ,\n"
+ " data.r VARCHAR ,\n"
+ " data.size VARCHAR ,\n"
+ " data.start_time VARCHAR ,\n"
+ " data.stat_date DATE ,\n"
+ " data.stat_hour VARCHAR ,\n"
+ " data.stat_minute VARCHAR ,\n"
+ " data.state VARCHAR ,\n"
+ " data.title VARCHAR ,\n"
+ " data.\"user\" VARCHAR ,\n"
+ " data.inrow VARCHAR ,\n"
+ " data.jobid VARCHAR ,\n"
+ " data.jobtype VARCHAR ,\n"
+ " data.level VARCHAR ,\n"
+ " data.msg VARCHAR ,\n"
+ " data.outrow VARCHAR ,\n"
+ " data.pass_time VARCHAR ,\n"
+ " data.type VARCHAR ,\n"
+ " id INTEGER not null primary key desc\n"
+ " ) ";
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute(ddl);
}
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
assertNotNull(admin.getDescriptor(TableName.valueOf(tableName)));
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(BloomType.ROW, columnFamilies[0].getBloomFilterType());
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute(ddl);
fail();
} catch (TableAlreadyExistsException e) {
// expected
}
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute("DROP TABLE " + tableName);
}
props.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, Boolean.TRUE.toString());
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute("CREATE SCHEMA " + schemaName);
}
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute(ddl);
assertNotEquals(null, admin.getDescriptor(TableName.valueOf(
SchemaUtil.getPhysicalTableName(tableName.getBytes(), true).getName())));
} finally {
admin.close();
}
props.setProperty(QueryServices.DROP_METADATA_ATTRIB, Boolean.TRUE.toString());
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute("DROP TABLE " + tableName);
}
}
@Test
public void testCreateMultiTenantTable() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl =
"CREATE TABLE " + tableName
+ " ( TenantId UNSIGNED_INT NOT NULL ,\n"
+ " Id UNSIGNED_INT NOT NULL ,\n"
+ " val VARCHAR ,\n"
+ " CONSTRAINT pk PRIMARY KEY(TenantId, Id) \n"
+ " ) MULTI_TENANT=true";
conn.createStatement().execute(ddl);
conn = DriverManager.getConnection(getUrl(), props);
try {
conn.createStatement().execute(ddl);
fail();
} catch (TableAlreadyExistsException e) {
// expected
}
conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute("DROP TABLE " + tableName);
}
/**
* Test that when the ddl only has PK cols, ttl is set.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs1() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)"
+ " ) TTL=86400, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(1, columnFamilies.length);
assertEquals(86400, columnFamilies[0].getTimeToLive());
}
@Test
public void testCreatingTooManyIndexesIsNotAllowed() throws Exception {
String tableName = generateUniqueName();
String ddl = "CREATE TABLE " + tableName + " (\n"
+ "ID VARCHAR(15) PRIMARY KEY,\n"
+ "COL1 BIGINT,"
+ "COL2 BIGINT,"
+ "COL3 BIGINT,"
+ "COL4 BIGINT) ";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
int maxIndexes = conn.unwrap(PhoenixConnection.class).getQueryServices().getProps().getInt(
QueryServices.MAX_INDEXES_PER_TABLE, QueryServicesOptions.DEFAULT_MAX_INDEXES_PER_TABLE);
// Use local indexes since there's only one physical table for all of them.
for (int i = 0; i < maxIndexes; i++) {
conn.createStatement().execute("CREATE LOCAL INDEX I_" + i + tableName + " ON " + tableName + "(COL1) INCLUDE (COL2,COL3,COL4)");
}
// here we ensure we get a too many indexes error
try {
conn.createStatement().execute("CREATE LOCAL INDEX I_" + maxIndexes + tableName + " ON " + tableName + "(COL1) INCLUDE (COL2,COL3,COL4)");
fail();
} catch (SQLException e) {
assertEquals(SQLExceptionCode.TOO_MANY_INDEXES.getErrorCode(), e.getErrorCode());
}
}
/**
* Tests that when: 1) DDL has both pk as well as key value columns 2) Key value columns have
* different column family names 3) TTL specifier doesn't have column family name. Then: 1)TTL
* is set. 2)All column families have the same TTL.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs2() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " b.col2 bigint," + " c.col3 bigint, "
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) TTL=86400, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(2, columnFamilies.length);
assertEquals(86400, columnFamilies[0].getTimeToLive());
assertEquals("B", columnFamilies[0].getNameAsString());
assertEquals(86400, columnFamilies[1].getTimeToLive());
assertEquals("C", columnFamilies[1].getNameAsString());
}
/**
* Tests that when: 1) DDL has both pk as well as key value columns 2) Key value columns have
* both default and explicit column family names 3) TTL specifier doesn't have column family
* name. Then: 1)TTL is set. 2)All column families have the same TTL.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs3() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " b.col2 bigint," + " col3 bigint, "
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) TTL=86400, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(2, columnFamilies.length);
assertEquals("0", columnFamilies[0].getNameAsString());
assertEquals(86400, columnFamilies[0].getTimeToLive());
assertEquals("B", columnFamilies[1].getNameAsString());
assertEquals(86400, columnFamilies[1].getTimeToLive());
}
/**
* Tests that when: 1) DDL has both pk as well as key value columns 2) Key value columns have
* both default and explicit column family names 3) Block size specifier has the explicit
* column family name. Then: 1)BLOCKSIZE is set. 2)The default column family has
* DEFAULT_BLOCKSIZE. 3)The explicit column family has the BLOCK_SIZE specified
* in DDL.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs4() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " b.col2 bigint," + " col3 bigint, "
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) b.BLOCKSIZE=50000, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(2, columnFamilies.length);
assertEquals("0", columnFamilies[0].getNameAsString());
assertEquals(ColumnFamilyDescriptorBuilder.DEFAULT_BLOCKSIZE, columnFamilies[0].getBlocksize());
assertEquals("B", columnFamilies[1].getNameAsString());
assertEquals(50000, columnFamilies[1].getBlocksize());
}
/**
* Tests that when: 1) DDL has both pk as well as key value columns 2) Key value columns have
* explicit column family names 3) Different BLOCKSIZE specifiers for different column
* family names. Then: 1)BLOCKSIZE is set. 2)Each explicit column family has the
* BLOCKSIZE as specified in DDL.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs5() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " b.col2 bigint," + " c.col3 bigint, "
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) b.BLOCKSIZE=50000, c.BLOCKSIZE=60000, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(2, columnFamilies.length);
assertEquals("B", columnFamilies[0].getNameAsString());
assertEquals(50000, columnFamilies[0].getBlocksize());
assertEquals("C", columnFamilies[1].getNameAsString());
assertEquals(60000, columnFamilies[1].getBlocksize());
}
/**
* Tests that when: 1) DDL has both pk as well as key value columns 2) There is a default column
* family specified. Then: 1)TTL is set for the specified default column family.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs6() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " col2 bigint," + " col3 bigint, "
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) DEFAULT_COLUMN_FAMILY='a', TTL=10000, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(1, columnFamilies.length);
assertEquals("a", columnFamilies[0].getNameAsString());
assertEquals(10000, columnFamilies[0].getTimeToLive());
}
/**
* Tests that when: 1) DDL has only pk columns 2) There is a default column family specified.
* Then: 1)TTL is set for the specified default column family.
*/
@Test
public void testCreateTableColumnFamilyHBaseAttribs7() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) DEFAULT_COLUMN_FAMILY='a', TTL=10000, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(1, columnFamilies.length);
assertEquals("a", columnFamilies[0].getNameAsString());
assertEquals(10000, columnFamilies[0].getTimeToLive());
}
@Test
public void testCreateTableColumnFamilyHBaseAttribs8() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)"
+ " ) BLOOMFILTER = 'NONE', SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
conn.createStatement().execute(ddl);
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
ColumnFamilyDescriptor[] columnFamilies =
admin.getDescriptor(TableName.valueOf(tableName)).getColumnFamilies();
assertEquals(BloomType.NONE, columnFamilies[0].getBloomFilterType());
}
/**
* Test to ensure that NOT NULL constraint isn't added to a non primary key column.
* @throws Exception
*/
@Test
public void testNotNullConstraintForNonPKColumn() throws Exception {
String tableName = generateUniqueName();
String ddl =
"CREATE TABLE IF NOT EXISTS " + tableName + " ( "
+ " ORGANIZATION_ID CHAR(15) NOT NULL, "
+ " EVENT_TIME DATE NOT NULL, USER_ID CHAR(15) NOT NULL, "
+ " ENTRY_POINT_ID CHAR(15) NOT NULL, ENTRY_POINT_TYPE CHAR(2) NOT NULL , "
+ " APEX_LIMIT_ID CHAR(15) NOT NULL, USERNAME CHAR(80), "
+ " NAMESPACE_PREFIX VARCHAR, ENTRY_POINT_NAME VARCHAR NOT NULL , "
+ " EXECUTION_UNIT_NO VARCHAR, LIMIT_TYPE VARCHAR, "
+ " LIMIT_VALUE DOUBLE " + " CONSTRAINT PK PRIMARY KEY ("
+ " ORGANIZATION_ID, EVENT_TIME,USER_ID,ENTRY_POINT_ID, ENTRY_POINT_TYPE, APEX_LIMIT_ID "
+ " ) ) VERSIONS=1";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
try {
conn.createStatement().execute(ddl);
fail(" Non pk column ENTRY_POINT_NAME has a NOT NULL constraint");
} catch (SQLException sqle) {
assertEquals(SQLExceptionCode.KEY_VALUE_NOT_NULL.getErrorCode(),
sqle.getErrorCode());
}
}
@Test
public void testNotNullConstraintForWithSinglePKCol() throws Exception {
String tableName = generateUniqueName();
String ddl = "create table " + tableName + " (k integer primary key, v bigint not null)";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
try {
conn.createStatement().execute(ddl);
fail(" Non pk column V has a NOT NULL constraint");
} catch (SQLException sqle) {
assertEquals(SQLExceptionCode.KEY_VALUE_NOT_NULL.getErrorCode(),
sqle.getErrorCode());
}
}
@Test
public void testSpecifyingColumnFamilyForTTLFails() throws Exception {
String tableName = generateUniqueName();
String ddl =
"create table IF NOT EXISTS " + tableName + " (" + " id char(1) NOT NULL,"
+ " col1 integer NOT NULL," + " CF.col2 integer,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1)"
+ " ) DEFAULT_COLUMN_FAMILY='a', CF.TTL=10000, SALT_BUCKETS = 4";
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
try {
conn.createStatement().execute(ddl);
} catch (SQLException sqle) {
assertEquals(SQLExceptionCode.COLUMN_FAMILY_NOT_ALLOWED_FOR_PROPERTY.getErrorCode(),
sqle.getErrorCode());
}
}
@Test
public void testCreateTableWithoutSchema() throws Exception {
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
props.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, Boolean.toString(true));
String schemaName = generateUniqueName();
String createSchemaDDL = "CREATE SCHEMA " + schemaName;
;
String tableName = generateUniqueName();
String createTableDDL =
"CREATE TABLE " + schemaName + "." + tableName + " (pk INTEGER PRIMARY KEY)";
String dropTableDDL = "DROP TABLE " + schemaName + "." + tableName;
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
try {
conn.createStatement().execute(createTableDDL);
fail();
} catch (SchemaNotFoundException snfe) {
// expected
}
conn.createStatement().execute(createSchemaDDL);
}
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createTableDDL);
}
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(dropTableDDL);
}
props.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, Boolean.toString(false));
try (Connection conn = DriverManager.getConnection(getUrl(), props);) {
conn.createStatement().execute(createTableDDL);
} catch (SchemaNotFoundException e) {
fail();
}
}
@Test
public void testCreateTableIfNotExistsForEncodedColumnNames() throws Exception {
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
String tableName = generateUniqueName();
String createTableDDL =
"CREATE TABLE IF NOT EXISTS " + tableName + " (pk INTEGER PRIMARY KEY)";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN, tableName, conn);
}
// Execute the ddl again
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createTableDDL);
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName);
assertFalse(rs.next());
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN, tableName, conn);
}
// Now execute the ddl with a different COLUMN_ENCODED_BYTES. This shouldn't change the
// original encoded bytes setting.
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createTableDDL + " COLUMN_ENCODED_BYTES = 1");
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName);
assertFalse(rs.next());
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN, tableName, conn);
}
// Now execute the ddl where COLUMN_ENCODED_BYTES=0. This shouldn't change the original
// encoded bytes setting.
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createTableDDL + " COLUMN_ENCODED_BYTES = 0");
ResultSet rs = conn.createStatement().executeQuery("SELECT * FROM " + tableName);
assertFalse(rs.next());
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN, tableName, conn);
}
}
private void assertColumnEncodingMetadata(QualifierEncodingScheme expectedEncodingScheme,
ImmutableStorageScheme expectedStorageScheme, String tableName, Connection conn)
throws Exception {
PhoenixConnection phxConn = conn.unwrap(PhoenixConnection.class);
PTable table = phxConn.getTable(new PTableKey(null, tableName));
assertEquals(expectedEncodingScheme, table.getEncodingScheme());
assertEquals(expectedStorageScheme, table.getImmutableStorageScheme());
}
@Test
public void testMultiTenantImmutableTableMetadata() throws Exception {
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
String nonEncodedOneCellPerColumnMultiTenantTable = generateUniqueName();
String twoByteQualifierEncodedOneCellPerColumnMultiTenantTable = generateUniqueName();
String oneByteQualifierEncodedOneCellPerColumnMultiTenantTable = generateUniqueName();
String twoByteQualifierSingleCellArrayWithOffsetsMultitenantTable = generateUniqueName();
String oneByteQualifierSingleCellArrayWithOffsetsMultitenantTable = generateUniqueName();
String createTableDDL;
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
createTableDDL =
"create IMMUTABLE TABLE " + nonEncodedOneCellPerColumnMultiTenantTable + " ("
+ " id char(1) NOT NULL," + " col1 integer NOT NULL,"
+ " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) MULTI_TENANT=true, COLUMN_ENCODED_BYTES=0";
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.NON_ENCODED_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN,
nonEncodedOneCellPerColumnMultiTenantTable, conn);
}
props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
createTableDDL =
"create IMMUTABLE table "
+ twoByteQualifierEncodedOneCellPerColumnMultiTenantTable + " ("
+ " id char(1) NOT NULL," + " col1 integer NOT NULL,"
+ " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) MULTI_TENANT=true";
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN,
twoByteQualifierEncodedOneCellPerColumnMultiTenantTable, conn);
}
props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
createTableDDL =
"create IMMUTABLE table "
+ oneByteQualifierEncodedOneCellPerColumnMultiTenantTable + " ("
+ " id char(1) NOT NULL," + " col1 integer NOT NULL,"
+ " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) MULTI_TENANT=true, COLUMN_ENCODED_BYTES = 1";
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.ONE_BYTE_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN,
oneByteQualifierEncodedOneCellPerColumnMultiTenantTable, conn);
}
props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
createTableDDL =
"create IMMUTABLE table "
+ twoByteQualifierSingleCellArrayWithOffsetsMultitenantTable + " ("
+ " id char(1) NOT NULL," + " col1 integer NOT NULL,"
+ " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) MULTI_TENANT=true, IMMUTABLE_STORAGE_SCHEME=SINGLE_CELL_ARRAY_WITH_OFFSETS";
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS,
twoByteQualifierSingleCellArrayWithOffsetsMultitenantTable, conn);
}
props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
createTableDDL =
"create IMMUTABLE table "
+ oneByteQualifierSingleCellArrayWithOffsetsMultitenantTable + " ("
+ " id char(1) NOT NULL," + " col1 integer NOT NULL,"
+ " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) MULTI_TENANT=true, IMMUTABLE_STORAGE_SCHEME=SINGLE_CELL_ARRAY_WITH_OFFSETS, COLUMN_ENCODED_BYTES=1";
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.ONE_BYTE_QUALIFIERS,
ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS,
oneByteQualifierSingleCellArrayWithOffsetsMultitenantTable, conn);
}
}
@Test
public void testCreateChangeDetectionEnabledTable() throws Exception {
//create a table with CHANGE_DETECTION_ENABLED and verify both that it's set properly
//on the PTable, and that it gets persisted to the external schema registry
String schemaName = generateUniqueName();
String tableName = generateUniqueName();
String fullTableName = SchemaUtil.getTableName(schemaName, tableName);
try (PhoenixConnection conn = (PhoenixConnection) DriverManager.getConnection(getUrl())) {
String ddl = "CREATE TABLE " + fullTableName +
" (id char(1) NOT NULL," + " col1 integer NOT NULL," + " col2 bigint NOT NULL," +
" CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) " +
"CHANGE_DETECTION_ENABLED=true";
conn.createStatement().execute(ddl);
PTable table = conn.getTableNoCache(fullTableName);
assertTrue(table.isChangeDetectionEnabled());
AlterTableIT.verifySchemaExport(table, getUtility().getConfiguration());
}
}
@Test
public void testCreateIndexWithDifferentStorageAndEncoding() throws Exception {
verifyIndexSchemeChange(false, false);
verifyIndexSchemeChange(false, true);
verifyIndexSchemeChange(true, false);
verifyIndexSchemeChange(true, true);
String tableName = generateUniqueName();
String indexName = generateUniqueName();
String createTableDDL = "create IMMUTABLE TABLE " + tableName + "(id char(1) NOT NULL, col1 char(1), col2 char(1) "
+ "CONSTRAINT NAME_PK PRIMARY KEY (id)) IMMUTABLE_STORAGE_SCHEME=SINGLE_CELL_ARRAY_WITH_OFFSETS";
String createIndexDDL = "create INDEX " + indexName + " ON " + tableName + " (col1) INCLUDE (col2) IMMUTABLE_STORAGE_SCHEME=ONE_CELL_PER_COLUMN";
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS, tableName, conn);
boolean failed = false;
try {
conn.createStatement().execute(createIndexDDL);
} catch (SQLException e) {
assertEquals(e.getErrorCode(), SQLExceptionCode.INVALID_IMMUTABLE_STORAGE_SCHEME_CHANGE.getErrorCode());
failed = true;
}
assertEquals(true, failed);
}
}
private void verifyIndexSchemeChange(boolean immutable, boolean multiTenant) throws Exception{
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
String nonEncodedOneCellPerColumnTable = generateUniqueName();
String createTableDDL;
String createIndexDDL;
String createTableBaseDDL = "create " + (immutable? " IMMUTABLE ":"") + " TABLE %s ("
+ " id char(1) NOT NULL," + " col1 integer NOT NULL,"
+ " col2 bigint NOT NULL,"
+ " CONSTRAINT NAME_PK PRIMARY KEY (id, col1, col2)) MULTI_TENANT=" + (multiTenant? "true,":"false,");
String createIndexBaseDDL = "create index %s ON %s (col1) INCLUDE (col2) ";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
createTableDDL = String.format(createTableBaseDDL, nonEncodedOneCellPerColumnTable);
createTableDDL += "IMMUTABLE_STORAGE_SCHEME=ONE_CELL_PER_COLUMN, COLUMN_ENCODED_BYTES=0";
conn.createStatement().execute(createTableDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.NON_ENCODED_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN,
nonEncodedOneCellPerColumnTable, conn);
String idxName = "IDX_" + generateUniqueName();
// Don't specify anything to see if it inherits from parent
createIndexDDL = String.format(createIndexBaseDDL, idxName, nonEncodedOneCellPerColumnTable);
conn.createStatement().execute(createIndexDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.NON_ENCODED_QUALIFIERS,
ImmutableStorageScheme.ONE_CELL_PER_COLUMN,
idxName, conn);
idxName = "IDX_" + generateUniqueName();
createIndexDDL = String.format(createIndexBaseDDL, idxName, nonEncodedOneCellPerColumnTable);
createIndexDDL += "IMMUTABLE_STORAGE_SCHEME=SINGLE_CELL_ARRAY_WITH_OFFSETS";
conn.createStatement().execute(createIndexDDL);
// Check if it sets the encoding to 2
assertColumnEncodingMetadata(QualifierEncodingScheme.TWO_BYTE_QUALIFIERS,
ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS,
idxName, conn);
idxName = "IDX_" + generateUniqueName();
createIndexDDL = String.format(createIndexBaseDDL, idxName, nonEncodedOneCellPerColumnTable);
createIndexDDL += "IMMUTABLE_STORAGE_SCHEME=SINGLE_CELL_ARRAY_WITH_OFFSETS, COLUMN_ENCODED_BYTES=3";
conn.createStatement().execute(createIndexDDL);
assertColumnEncodingMetadata(QualifierEncodingScheme.THREE_BYTE_QUALIFIERS,
ImmutableStorageScheme.SINGLE_CELL_ARRAY_WITH_OFFSETS,
idxName, conn);
createIndexDDL = String.format(createIndexBaseDDL, idxName, nonEncodedOneCellPerColumnTable);
createIndexDDL += "IMMUTABLE_STORAGE_SCHEME=SINGLE_CELL_ARRAY_WITH_OFFSETS, COLUMN_ENCODED_BYTES=0";
// should fail
boolean failed = false;
try {
conn.createStatement().execute(createIndexDDL);
} catch (SQLException e) {
failed = true;
assertEquals(SQLExceptionCode.INVALID_IMMUTABLE_STORAGE_SCHEME_AND_COLUMN_QUALIFIER_BYTES.getErrorCode(),e.getErrorCode());
}
assertEquals(true, failed);
}
}
private void verifyUCFValueInSysCat(String tableName, String createTableString,
Properties props, long expectedUCFInSysCat) throws SQLException {
String readSysCatQuery = "SELECT TABLE_NAME, UPDATE_CACHE_FREQUENCY FROM SYSTEM.CATALOG "
+ "WHERE TABLE_NAME = '" + tableName + "' AND TABLE_TYPE='u'";
try (Connection connection = DriverManager.getConnection(getUrl(), props);
Statement stmt = connection.createStatement()) {
stmt.execute(createTableString);
try (ResultSet rs = stmt.executeQuery(readSysCatQuery)) {
assertTrue(rs.next());
assertEquals(expectedUCFInSysCat, rs.getLong(2));
}
stmt.execute("drop table " + tableName);
}
}
@Test
public void testCreateTableNoUpdateCacheFreq() throws Exception {
String tableName = generateUniqueName();
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
String createTableString = "CREATE TABLE " + tableName + " (k VARCHAR PRIMARY KEY, "
+ "v1 VARCHAR, v2 VARCHAR)";
verifyUCFValueInSysCat(tableName, createTableString, props,
QueryServicesOptions.DEFAULT_UPDATE_CACHE_FREQUENCY);
}
@Test
public void testCreateTableWithTableLevelUpdateCacheFreq() throws Exception {
String tableName = generateUniqueName();
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
HashMap<String, Long> expectedUCF = new HashMap<>();
expectedUCF.put("10", new Long(10L));
expectedUCF.put("0", new Long(0L));
expectedUCF.put("10000", new Long(10000L));
expectedUCF.put("ALWAYS", new Long(0L));
expectedUCF.put("NEVER", new Long(Long.MAX_VALUE));
for (HashMap.Entry<String, Long> entry : expectedUCF.entrySet()) {
String tableLevelUCF = entry.getKey();
long expectedUCFInSysCat = entry.getValue();
String createTableString = "CREATE TABLE " + tableName + " (k VARCHAR PRIMARY KEY,"
+ "v1 VARCHAR, v2 VARCHAR) UPDATE_CACHE_FREQUENCY = " + tableLevelUCF;
verifyUCFValueInSysCat(tableName, createTableString, props, expectedUCFInSysCat);
}
}
@Test
public void testCreateTableWithInvalidTableUpdateCacheFreqShouldThrow() throws Exception {
String tableName = generateUniqueName();
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
ArrayList<String> invalidUCF = new ArrayList<>();
invalidUCF.add("GIBBERISH");
invalidUCF.add("10000.6");
for (String tableLevelUCF : invalidUCF) {
String createTableString = "CREATE TABLE " + tableName + " (k VARCHAR PRIMARY KEY,"
+ "v1 VARCHAR, v2 VARCHAR) UPDATE_CACHE_FREQUENCY = " + tableLevelUCF;
try {
verifyUCFValueInSysCat(tableName, createTableString, props, -1L);
fail();
} catch (IllegalArgumentException e) {
// expected
assertTrue(e.getMessage().contains("Table's " +
PhoenixDatabaseMetaData.UPDATE_CACHE_FREQUENCY));
}
}
}
@Test
public void testCreateTableWithConnLevelUpdateCacheFreq() throws Exception {
String tableName = generateUniqueName();
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
HashMap<String, Long> expectedUCF = new HashMap<>();
expectedUCF.put("10", new Long(10L));
expectedUCF.put("0", new Long(0L));
expectedUCF.put("10000", new Long(10000L));
expectedUCF.put("ALWAYS", new Long(0L));
expectedUCF.put("NEVER", new Long(Long.MAX_VALUE));
for (HashMap.Entry<String, Long> entry : expectedUCF.entrySet()) {
String connLevelUCF = entry.getKey();
long expectedUCFInSysCat = entry.getValue();
String createTableString = "CREATE TABLE " + tableName + " (k VARCHAR PRIMARY KEY,"
+ "v1 VARCHAR, v2 VARCHAR)";
props.put(QueryServices.DEFAULT_UPDATE_CACHE_FREQUENCY_ATRRIB, connLevelUCF);
verifyUCFValueInSysCat(tableName, createTableString, props, expectedUCFInSysCat);
}
}
@Test
public void testCreateTableWithNamespaceMappingEnabled() throws Exception {
final String NS = "NS_" + generateUniqueName();
final String TBL = "TBL_" + generateUniqueName();
final String CF = "CF";
Properties props = new Properties();
props.setProperty(QueryServices.IS_NAMESPACE_MAPPING_ENABLED, Boolean.TRUE.toString());
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute("CREATE SCHEMA " + NS);
// test for a table that is in non-default schema
{
String table = NS + "." + TBL;
conn.createStatement().execute(
"CREATE TABLE " + table + " (PK VARCHAR PRIMARY KEY, " + CF + ".COL VARCHAR)");
assertTrue(QueryUtil
.getExplainPlan(
conn.createStatement().executeQuery("explain select * from " + table))
.contains(NS + ":" + TBL));
conn.createStatement().execute("DROP TABLE " + table);
}
// test for a table whose name contains a dot (e.g. "AAA.BBB") in default schema
{
String table = "\"" + NS + "." + TBL + "\"";
conn.createStatement().execute(
"CREATE TABLE " + table + " (PK VARCHAR PRIMARY KEY, " + CF + ".COL VARCHAR)");
assertTrue(QueryUtil
.getExplainPlan(
conn.createStatement().executeQuery("explain select * from " + table))
.contains(NS + "." + TBL));
conn.createStatement().execute("DROP TABLE " + table);
}
// test for a view whose name contains a dot (e.g. "AAA.BBB") in non-default schema
{
String table = NS + ".\"" + NS + "." + TBL + "\"";
conn.createStatement().execute(
"CREATE TABLE " + table + " (PK VARCHAR PRIMARY KEY, " + CF + ".COL VARCHAR)");
assertTrue(QueryUtil
.getExplainPlan(
conn.createStatement().executeQuery("explain select * from " + table))
.contains(NS + ":" + NS + "." + TBL));
conn.createStatement().execute("DROP TABLE " + table);
}
conn.createStatement().execute("DROP SCHEMA " + NS);
}
}
@Test
public void testSetTableDescriptorPropertyOnView() throws Exception {
Properties props = new Properties();
final String dataTableFullName = generateUniqueName();
String ddl =
"CREATE TABLE " + dataTableFullName + " (\n" + "ID1 VARCHAR(15) NOT NULL,\n"
+ "ID2 VARCHAR(15) NOT NULL,\n" + "CREATED_DATE DATE,\n"
+ "CREATION_TIME BIGINT,\n" + "LAST_USED DATE,\n"
+ "CONSTRAINT PK PRIMARY KEY (ID1, ID2)) ";
Connection conn1 = DriverManager.getConnection(getUrl(), props);
conn1.createStatement().execute(ddl);
conn1.close();
final String viewFullName = generateUniqueName();
Connection conn2 = DriverManager.getConnection(getUrl(), props);
ddl =
"CREATE VIEW " + viewFullName + " AS SELECT * FROM " + dataTableFullName
+ " WHERE CREATION_TIME = 1 THROW_INDEX_WRITE_FAILURE = FALSE";
try {
conn2.createStatement().execute(ddl);
fail();
} catch (SQLException e) {
assertEquals(SQLExceptionCode.VIEW_WITH_PROPERTIES.getErrorCode(), e.getErrorCode());
}
conn2.close();
}
@Test
public void testCreateViewFromNonExistentTable() throws Exception {
try (Connection conn = DriverManager.getConnection(getUrl())) {
conn.createStatement().execute(
"CREATE TABLE IF NOT EXISTS S.T1 (A INTEGER PRIMARY KEY, B INTEGER)");
// 1. create view from non-existent table (without schema)
try {
conn.createStatement().execute(
"CREATE VIEW IF NOT EXISTS V1(C INTEGER) AS SELECT * FROM T2");
fail("Creating view on non-existent table should have failed");
} catch (TableNotFoundException e) {
assertEquals("T2", e.getTableName());
assertEquals("", e.getSchemaName());
assertEquals("ERROR 1012 (42M03): Table undefined. tableName=T2",
e.getMessage());
}
// 2. create view from existing table - successful
conn.createStatement().execute(
"CREATE VIEW IF NOT EXISTS V1(C INTEGER) AS SELECT * FROM S.T1");
// 3. create view from non-existent table (with schema)
try {
conn.createStatement().execute(
"CREATE VIEW IF NOT EXISTS V2(C INTEGER) AS SELECT * FROM S.T2");
fail("Creating view on non-existent table should have failed");
} catch (TableNotFoundException e) {
assertEquals("T2", e.getTableName());
assertEquals("S", e.getSchemaName());
assertEquals("ERROR 1012 (42M03): Table undefined. tableName=S.T2",
e.getMessage());
}
}
}
@Test
public void testSettingGuidePostWidth() throws Exception {
try (Connection conn = DriverManager.getConnection(getUrl())) {
String dataTable = generateUniqueName();
int guidePostWidth = 20;
String ddl =
"CREATE TABLE " + dataTable + " (k INTEGER PRIMARY KEY, a bigint, b bigint)"
+ " GUIDE_POSTS_WIDTH=" + guidePostWidth;
conn.createStatement().execute(ddl);
assertEquals(20, checkGuidePostWidth(dataTable));
String viewName = "V_" + generateUniqueName();
ddl =
"CREATE VIEW " + viewName + " AS SELECT * FROM " + dataTable
+ " GUIDE_POSTS_WIDTH=" + guidePostWidth;
try {
conn.createStatement().execute(ddl);
} catch (SQLException e) {
assertEquals(SQLExceptionCode.CANNOT_SET_GUIDE_POST_WIDTH.getErrorCode(),
e.getErrorCode());
}
// let the view creation go through
ddl = "CREATE VIEW " + viewName + " AS SELECT * FROM " + dataTable;
conn.createStatement().execute(ddl);
String globalIndex = "GI_" + generateUniqueName();
ddl =
"CREATE INDEX " + globalIndex + " ON " + dataTable
+ "(a) INCLUDE (b) GUIDE_POSTS_WIDTH = " + guidePostWidth;
try {
conn.createStatement().execute(ddl);
} catch (SQLException e) {
assertEquals(SQLExceptionCode.CANNOT_SET_GUIDE_POST_WIDTH.getErrorCode(),
e.getErrorCode());
}
String localIndex = "LI_" + generateUniqueName();
ddl =
"CREATE LOCAL INDEX " + localIndex + " ON " + dataTable
+ "(b) INCLUDE (a) GUIDE_POSTS_WIDTH = " + guidePostWidth;
try {
conn.createStatement().execute(ddl);
} catch (SQLException e) {
assertEquals(SQLExceptionCode.CANNOT_SET_GUIDE_POST_WIDTH.getErrorCode(),
e.getErrorCode());
}
String viewIndex = "VI_" + generateUniqueName();
ddl =
"CREATE LOCAL INDEX " + viewIndex + " ON " + dataTable
+ "(b) INCLUDE (a) GUIDE_POSTS_WIDTH = " + guidePostWidth;
try {
conn.createStatement().execute(ddl);
} catch (SQLException e) {
assertEquals(SQLExceptionCode.CANNOT_SET_GUIDE_POST_WIDTH.getErrorCode(),
e.getErrorCode());
}
}
}
/**
* Ensure that HTD contains table priorities correctly.
*/
@Test
public void testTableDescriptorPriority() throws SQLException, IOException {
String tableName = "TBL_" + generateUniqueName();
String indexName = "IND_" + generateUniqueName();
String fullTableName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, tableName);
String fullIndexeName = SchemaUtil.getTableName(TestUtil.DEFAULT_SCHEMA_NAME, indexName);
// Check system tables priorities.
try (Admin admin = driver.getConnectionQueryServices(getUrl(), new Properties()).getAdmin();
Connection c = DriverManager.getConnection(getUrl())) {
ResultSet rs = c.getMetaData().getTables("",
"\""+ PhoenixDatabaseMetaData.SYSTEM_CATALOG_SCHEMA + "\"",
null,
new String[] {PTableType.SYSTEM.toString()});
ReadOnlyProps p = c.unwrap(PhoenixConnection.class).getQueryServices().getProps();
while (rs.next()) {
String schemaName = rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM);
String tName = rs.getString(PhoenixDatabaseMetaData.TABLE_NAME);
org.apache.hadoop.hbase.TableName hbaseTableName = SchemaUtil.getPhysicalTableName(SchemaUtil.getTableName(schemaName, tName), p);
TableDescriptor htd = admin.getDescriptor(hbaseTableName);
String val = htd.getValue("PRIORITY");
assertNotNull("PRIORITY is not set for table:" + htd, val);
assertTrue(Integer.parseInt(val)
>= IndexUtil.getMetadataPriority(config));
}
Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
String ddl ="CREATE TABLE " + fullTableName + TestUtil.TEST_TABLE_SCHEMA;
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.execute(ddl);
BaseTest.populateTestTable(fullTableName);
ddl = "CREATE INDEX " + indexName
+ " ON " + fullTableName + " (long_col1, long_col2)"
+ " INCLUDE (decimal_col1, decimal_col2)";
stmt.execute(ddl);
}
TableDescriptor dataTable = admin.getDescriptor(
org.apache.hadoop.hbase.TableName.valueOf(fullTableName));
String val = dataTable.getValue("PRIORITY");
assertTrue(val == null || Integer.parseInt(val) < HConstants.HIGH_QOS);
TableDescriptor indexTable = admin.getDescriptor(
org.apache.hadoop.hbase.TableName.valueOf(fullIndexeName));
val = indexTable.getValue("PRIORITY");
assertNotNull("PRIORITY is not set for table:" + indexTable, val);
assertTrue(Integer.parseInt(val) >= IndexUtil.getIndexPriority(config));
}
}
@Test
public void testCreateTableSchemaVersionAndTopicName() throws Exception {
Properties props = new Properties();
final String schemaName = generateUniqueName();
final String tableName = generateUniqueName();
final String version = "V1.0";
final String topicName = "MyTopicName";
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
testCreateTableSchemaVersionAndTopicNameHelper(conn, schemaName, tableName, version, topicName);
}
}
public static void testCreateTableSchemaVersionAndTopicNameHelper(Connection conn, String schemaName, String tableName,
String dataTableVersion, String topicName)
throws Exception {
final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName);
String ddl =
"CREATE TABLE " + dataTableFullName + " (\n" + "ID1 VARCHAR(15) NOT NULL,\n"
+ "ID2 VARCHAR(15) NOT NULL,\n" + "CREATED_DATE DATE,\n"
+ "CREATION_TIME BIGINT,\n" + "LAST_USED DATE,\n"
+ "CONSTRAINT PK PRIMARY KEY (ID1, ID2)) SCHEMA_VERSION='" + dataTableVersion
+ "'";
if (topicName != null) {
ddl += ", STREAMING_TOPIC_NAME='" + topicName + "'";
}
conn.createStatement().execute(ddl);
PTable table = conn.unwrap(PhoenixConnection.class).getTableNoCache(dataTableFullName);
assertEquals(dataTableVersion, table.getSchemaVersion());
if (topicName != null) {
assertEquals(topicName, table.getStreamingTopicName());
} else {
assertNull(table.getStreamingTopicName());
}
}
@Test
public void testCreateTableDDLTimestamp() throws Exception {
Properties props = new Properties();
final String schemaName = generateUniqueName();
final String tableName = generateUniqueName();
final String dataTableFullName = SchemaUtil.getTableName(schemaName, tableName);
String ddl =
"CREATE TABLE " + dataTableFullName + " (\n" + "ID1 VARCHAR(15) NOT NULL,\n"
+ "ID2 VARCHAR(15) NOT NULL,\n" + "CREATED_DATE DATE,\n"
+ "CREATION_TIME BIGINT,\n" + "LAST_USED DATE,\n"
+ "CONSTRAINT PK PRIMARY KEY (ID1, ID2)) ";
long startTS = EnvironmentEdgeManager.currentTimeMillis();
try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
conn.createStatement().execute(ddl);
verifyLastDDLTimestamp(dataTableFullName, startTS, conn);
}
}
@Test
public void testCreateTableWithColumnQualifiers() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 11, INT2 INTEGER ENCODED_QUALIFIER 12, " +
"INT3 INTEGER ENCODED_QUALIFIER 14) COLUMN_QUALIFIER_COUNTER ('"
+ QueryConstants.DEFAULT_COLUMN_FAMILY + "'=15)";
conn.createStatement().execute(ddl);
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable table = pconn.getTable(new PTableKey(null, tableName));
QualifierEncodingScheme encodingScheme = table.getEncodingScheme();
assertNotEquals(PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, encodingScheme);
PTable.EncodedCQCounter cqCounter = table.getEncodedCQCounter();
assertEquals(15, cqCounter.values().get(QueryConstants.DEFAULT_COLUMN_FAMILY).intValue());
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT2")
.getColumnQualifierBytes()));
assertEquals(14, encodingScheme.decode(table.getColumnForColumnName("INT3")
.getColumnQualifierBytes()));
assertNull(table.getMaxLookbackAge());
}
@Test
public void testCreateTableWithNotOrderedColumnQualifiers() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT3 INTEGER ENCODED_QUALIFIER 14, INT INTEGER ENCODED_QUALIFIER 11, " +
"INT2 INTEGER ENCODED_QUALIFIER 12) COLUMN_QUALIFIER_COUNTER ('"
+ QueryConstants.DEFAULT_COLUMN_FAMILY + "'=15)";
conn.createStatement().execute(ddl);
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable table = pconn.getTable(new PTableKey(null, tableName));
QualifierEncodingScheme encodingScheme = table.getEncodingScheme();
assertNotEquals(PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, encodingScheme);
PTable.EncodedCQCounter cqCounter = table.getEncodedCQCounter();
assertEquals(15, cqCounter.values().get(QueryConstants.DEFAULT_COLUMN_FAMILY).intValue());
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT2")
.getColumnQualifierBytes()));
assertEquals(14, encodingScheme.decode(table.getColumnForColumnName("INT3")
.getColumnQualifierBytes()));
}
@Test
public void testCreateTableWithColumnQualifiersWithoutCounter() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 11, INT2 INTEGER ENCODED_QUALIFIER 12, " +
"INT3 INTEGER ENCODED_QUALIFIER 14)";
conn.createStatement().execute(ddl);
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable table = pconn.getTable(new PTableKey(null, tableName));
QualifierEncodingScheme encodingScheme = table.getEncodingScheme();
assertNotEquals(PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, encodingScheme);
PTable.EncodedCQCounter cqCounter = table.getEncodedCQCounter();
assertEquals(15, cqCounter.values().get(QueryConstants.DEFAULT_COLUMN_FAMILY).intValue());
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT2")
.getColumnQualifierBytes()));
assertEquals(14, encodingScheme.decode(table.getColumnForColumnName("INT3")
.getColumnQualifierBytes()));
}
@Test
public void testCreateTableWithColumnQualifiersMultipleFamilies() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE IMMUTABLE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"A.INT INTEGER ENCODED_QUALIFIER 11, A.INT2 INTEGER ENCODED_QUALIFIER 13, " +
"B.INT3 INTEGER ENCODED_QUALIFIER 12) " +
"COLUMN_QUALIFIER_COUNTER ('A'=14, 'B'=13)";
conn.createStatement().execute(ddl);
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable table = pconn.getTable(new PTableKey(null, tableName));
QualifierEncodingScheme encodingScheme = table.getEncodingScheme();
assertNotEquals(PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, encodingScheme);
PTable.EncodedCQCounter cqCounter = table.getEncodedCQCounter();
assertEquals(14, cqCounter.values().get("A").intValue());
assertEquals(13, cqCounter.values().get("B").intValue());
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT")
.getColumnQualifierBytes()));
assertEquals(13, encodingScheme.decode(table.getColumnForColumnName("INT2")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT3")
.getColumnQualifierBytes()));
}
@Test
public void testCreateTableWithColumnQualifiersMultipleFamiliesWithoutCounter() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE IMMUTABLE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"A.INT INTEGER ENCODED_QUALIFIER 11, A.INT2 INTEGER ENCODED_QUALIFIER 13, " +
"B.INT3 INTEGER ENCODED_QUALIFIER 12)";
conn.createStatement().execute(ddl);
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable table = pconn.getTable(new PTableKey(null, tableName));
QualifierEncodingScheme encodingScheme = table.getEncodingScheme();
assertNotEquals(PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, encodingScheme);
PTable.EncodedCQCounter cqCounter = table.getEncodedCQCounter();
assertEquals(14, cqCounter.values().get("A").intValue());
assertEquals(13, cqCounter.values().get("B").intValue());
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT")
.getColumnQualifierBytes()));
assertEquals(13, encodingScheme.decode(table.getColumnForColumnName("INT2")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT3")
.getColumnQualifierBytes()));
}
@Test
public void testCreateTableWithColumnQualifiersDuplicateCQ() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 11, INT2 INTEGER ENCODED_QUALIFIER 11, " +
"INT3 INTEGER ENCODED_QUALIFIER 14) COLUMN_QUALIFIER_COUNTER ('0'=15)";
try {
conn.createStatement().execute(ddl);
fail("Duplicate Column Qualifiers");
} catch (SQLException e) {
// expected DUPLICATE_CQ
if (e.getErrorCode() != SQLExceptionCode.DUPLICATE_CQ.getErrorCode()) {
fail("Duplicate Column Qualifiers");
}
}
}
@Test
public void testCreateTableInvalidColumnQualifier() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 11, INT2 INTEGER ENCODED_QUALIFIER 9, " +
"INT3 INTEGER ENCODED_QUALIFIER 14) COLUMN_QUALIFIER_COUNTER ('0'=15)";
try {
conn.createStatement().execute(ddl);
fail("Invalid Column Qualifier");
} catch (SQLException e) {
// expected INVALID_CQ
if (e.getErrorCode() != SQLExceptionCode.INVALID_CQ.getErrorCode()) {
fail("Invalid Column Qualifier");
}
}
ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 11) COLUMN_QUALIFIER_COUNTER ('0'=8)";
try {
conn.createStatement().execute(ddl);
fail("Invalid Column Qualifier");
} catch (SQLException e) {
// expected INVALID_CQ
if (e.getErrorCode() != SQLExceptionCode.INVALID_CQ.getErrorCode()) {
fail("Invalid Column Qualifier");
}
}
ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 15) COLUMN_QUALIFIER_COUNTER ('0'=13)";
try {
conn.createStatement().execute(ddl);
fail("Invalid Column Qualifier");
} catch (SQLException e) {
// expected INVALID_CQ
if (e.getErrorCode() != SQLExceptionCode.INVALID_CQ.getErrorCode()) {
fail("Invalid Column Qualifier");
}
}
ddl = "CREATE IMMUTABLE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT1 INTEGER, " +
"INT2 INTEGER " +
"DEFAULT_COLUMN_FAMILY=dF" +
"COLUMN_QUALIFIER_COUNTER (\"0\"=13)";
try {
conn.createStatement().execute(ddl);
} catch (SQLException e) {
//expected
}
}
@Test
public void testCreateTableMissingColumnQualifier() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER, INT2 INTEGER ENCODED_QUALIFIER 12)";
try {
conn.createStatement().execute(ddl);
fail("Invalid Column Qualifier");
} catch (SQLException e) {
// expected MISSING_CQ
if (e.getErrorCode() != SQLExceptionCode.MISSING_CQ.getErrorCode()) {
fail("Missing Column Qualifier");
}
}
ddl = "CREATE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT INTEGER ENCODED_QUALIFIER 11, INT2 INTEGER) COLUMN_QUALIFIER_COUNTER ('0'=13)";
try {
conn.createStatement().execute(ddl);
fail("Invalid Column Qualifier");
} catch (SQLException e) {
// expected MISSING_CQ
if (e.getErrorCode() != SQLExceptionCode.MISSING_CQ.getErrorCode()) {
fail("Missing Column Qualifier");
}
}
}
@Test
public void testCreateTableDefaultColumnQualifier() throws Exception {
Properties props = new Properties();
Connection conn = DriverManager.getConnection(getUrl(), props);
String tableName = generateUniqueName();
String ddl = "CREATE IMMUTABLE TABLE \"" + tableName + "\"(K VARCHAR NOT NULL PRIMARY KEY, " +
"INT1 INTEGER, " +
"INT2 INTEGER, " +
"a.INT3 INTEGER, " +
"\"A\".INT4 INTEGER, " +
"\"b\".INT5 INTEGER, " +
"\"B\".INT6 INTEGER) " +
"DEFAULT_COLUMN_FAMILY=dF";
conn.createStatement().execute(ddl);
PhoenixConnection pconn = conn.unwrap(PhoenixConnection.class);
PTable table = pconn.getTable(new PTableKey(null, tableName));
QualifierEncodingScheme encodingScheme = table.getEncodingScheme();
assertNotEquals(PTable.QualifierEncodingScheme.NON_ENCODED_QUALIFIERS, encodingScheme);
PTable.EncodedCQCounter cqCounter = table.getEncodedCQCounter();
assertEquals(13, cqCounter.values().get("dF").intValue());
assertEquals(13, cqCounter.values().get("A").intValue());
assertEquals(12, cqCounter.values().get("b").intValue());
assertEquals(12, cqCounter.values().get("B").intValue());
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT1")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT2")
.getColumnQualifierBytes()));
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT3")
.getColumnQualifierBytes()));
assertEquals(12, encodingScheme.decode(table.getColumnForColumnName("INT4")
.getColumnQualifierBytes()));
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT5")
.getColumnQualifierBytes()));
assertEquals(11, encodingScheme.decode(table.getColumnForColumnName("INT6")
.getColumnQualifierBytes()));
}
// Test for PHOENIX-6953
@Test
public void testCoprocessorsForCreateIndexOnOldImplementation() throws Exception {
String tableName = generateUniqueName();
String index1Name = generateUniqueName();
String index2Name = generateUniqueName();
String ddl =
"create table " + tableName + " ( k integer PRIMARY KEY," + " v1 integer,"
+ " v2 integer)";
String index1Ddl = "create index " + index1Name + " on " + tableName + " (v1)";
String index2Ddl = "create index " + index2Name + " on " + tableName + " (v2)";
Properties props = new Properties();
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
try (Connection conn = DriverManager.getConnection(getUrl());
Statement stmt = conn.createStatement();) {
stmt.execute(ddl);
stmt.execute(index1Ddl);
TableDescriptor index1DescriptorBefore =
admin.getDescriptor(TableName.valueOf(index1Name));
assertTrue(index1DescriptorBefore
.hasCoprocessor(org.apache.phoenix.index.GlobalIndexChecker.class.getName()));
// Now roll back to the old indexing
IndexUpgradeTool iut =
new IndexUpgradeTool(ROLLBACK_OP, tableName, null,
"/tmp/index_upgrade_" + UUID.randomUUID().toString(), false, null,
false);
iut.setConf(getUtility().getConfiguration());
iut.prepareToolSetup();
assertEquals(0, iut.executeTool());
TableDescriptor index1DescriptorAfter =
admin.getDescriptor(TableName.valueOf(index1Name));
assertFalse(index1DescriptorAfter
.hasCoprocessor(org.apache.phoenix.index.GlobalIndexChecker.class.getName()));
// New index must not have GlobalIndexChecker
stmt.execute(index2Ddl);
TableDescriptor index2Descriptor = admin.getDescriptor(TableName.valueOf(index2Name));
assertFalse(index2Descriptor
.hasCoprocessor(org.apache.phoenix.index.GlobalIndexChecker.class.getName()));
}
}
// Test for PHOENIX-6953
@Test
public void testCoprocessorsForTransactionalCreateIndexOnOldImplementation() throws Exception {
String tableName = generateUniqueName();
String index1Name = generateUniqueName();
String ddl =
"create table " + tableName + " ( k integer PRIMARY KEY," + " v1 integer,"
+ " v2 integer) TRANSACTIONAL=TRUE";
String index1Ddl = "create index " + index1Name + " on " + tableName + " (v1)";
Properties props = new Properties();
Admin admin = driver.getConnectionQueryServices(getUrl(), props).getAdmin();
try (Connection conn = DriverManager.getConnection(getUrl());
Statement stmt = conn.createStatement();) {
stmt.execute(ddl);
stmt.execute(index1Ddl);
// Transactional indexes don't have GlobalIndexChecker
TableDescriptor index1DescriptorBefore =
admin.getDescriptor(TableName.valueOf(index1Name));
assertFalse(index1DescriptorBefore
.hasCoprocessor(org.apache.phoenix.index.GlobalIndexChecker.class.getName()));
// Now roll back to the old indexing
IndexUpgradeTool iut =
new IndexUpgradeTool(ROLLBACK_OP, tableName, null,
"/tmp/index_upgrade_" + UUID.randomUUID().toString(), false, null,
false);
iut.setConf(getUtility().getConfiguration());
iut.prepareToolSetup();
assertEquals(0, iut.executeTool());
// Make sure we don't add GlobalIndexChecker
TableDescriptor index1DescriptorAfter =
admin.getDescriptor(TableName.valueOf(index1Name));
assertFalse(index1DescriptorAfter
.hasCoprocessor(org.apache.phoenix.index.GlobalIndexChecker.class.getName()));
// We should also test for setting / unsetting the transactional status, but both are
// forbidden at the time of writing.
}
}
@Test
public void testCreateTableWithNoVerify() throws SQLException, IOException, InterruptedException {
final String tableName = SchemaUtil.getTableName(generateUniqueName(), generateUniqueName());
final byte[] tableBytes = tableName.getBytes();
final byte[] familyName = Bytes.toBytes(SchemaUtil.normalizeIdentifier("0"));
final byte[][] splits = new byte[][] {Bytes.toBytes(20), Bytes.toBytes(30)};
try (Admin admin = driver.getConnectionQueryServices(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES)).getAdmin()) {
admin.createTable(TableDescriptorBuilder.newBuilder(TableName.valueOf(tableBytes))
.addColumnFamily(ColumnFamilyDescriptorBuilder.newBuilder(familyName)
.setKeepDeletedCells(KeepDeletedCells.TRUE).build())
.build(), splits);
}
final byte[] uintCol = Bytes.toBytes("UINT_COL");
final byte[] ulongCol = Bytes.toBytes("ULONG_COL");
final byte[] key_1 = ByteUtil.concat(Bytes.toBytes(20), Bytes.toBytes(200L), Bytes.toBytes("b"));
final byte[] key_2 = ByteUtil.concat(Bytes.toBytes(40), Bytes.toBytes(400L), Bytes.toBytes("d"));
final byte[] emptyColumnQualifier = Bytes.toBytes("_0");
ConnectionQueryServices services = driver.getConnectionQueryServices(getUrl(), PropertiesUtil.deepCopy(TEST_PROPERTIES));
try (Table hTable = services.getTable(tableBytes)) {
// Insert rows using standard HBase mechanism with standard HBase "types"
List<Row> mutations = new ArrayList<>();
Put put = new Put(key_1);
put.addColumn(familyName, uintCol, HConstants.LATEST_TIMESTAMP, Bytes.toBytes(5000));
put.addColumn(familyName, ulongCol, HConstants.LATEST_TIMESTAMP, Bytes.toBytes(50000L));
mutations.add(put);
put = new Put(key_2);
put.addColumn(familyName, uintCol, HConstants.LATEST_TIMESTAMP, Bytes.toBytes(4000));
put.addColumn(familyName, ulongCol, HConstants.LATEST_TIMESTAMP, Bytes.toBytes(40000L));
mutations.add(put);
hTable.batch(mutations, null);
Result result = hTable.get(new Get(key_1));
assertFalse(result.isEmpty());
result = hTable.get(new Get(key_2));
assertFalse(result.isEmpty());
}
String ddl = "create table " + tableName +
" (uint_key unsigned_int not null," +
" ulong_key unsigned_long not null," +
" string_key varchar not null,\n" +
" uint_col unsigned_int," +
" ulong_col unsigned_long" +
" CONSTRAINT pk PRIMARY KEY (uint_key, ulong_key, string_key)) noverify COLUMN_ENCODED_BYTES=NONE";
try (Connection conn = DriverManager.getConnection(url)) {
conn.createStatement().execute(ddl);
}
try (Table hTable = services.getTable(tableBytes)) {
Result result = hTable.get(new Get(key_1));
byte[] value = result.getValue(familyName, uintCol);
assertEquals(5000, Bytes.toInt(value));
value = result.getValue(familyName, ulongCol);
assertEquals(50000L, Bytes.toLong(value));
value = result.getValue(familyName, emptyColumnQualifier);
assertNull(value);
result = hTable.get(new Get(key_2));
value = result.getValue(familyName, uintCol);
assertEquals(4000, Bytes.toInt(value));
value = result.getValue(familyName, ulongCol);
assertEquals(40000L, Bytes.toLong(value));
value = result.getValue(familyName, emptyColumnQualifier);
assertNull(value);
}
}
@Test
public void testCreateTableWithTableLevelMaxLookbackAge() throws Exception {
String schemaName = generateUniqueName();
String dataTableName = generateUniqueName();
String fullTableName = SchemaUtil.getTableName(schemaName, dataTableName);
Long maxLookbackAge = 259200L;
createTableWithTableLevelMaxLookbackAge(fullTableName, maxLookbackAge.toString());
assertEquals(maxLookbackAge, queryTableLevelMaxLookbackAge(fullTableName));
schemaName = generateUniqueName();
dataTableName = generateUniqueName();
fullTableName = SchemaUtil.getTableName(schemaName, dataTableName);
maxLookbackAge = 25920000000L;
createTableWithTableLevelMaxLookbackAge(fullTableName, maxLookbackAge.toString());
assertEquals(maxLookbackAge, queryTableLevelMaxLookbackAge(fullTableName));
String indexTableName = generateUniqueName();
createIndexOnTableWithMaxLookbackAge(indexTableName, fullTableName);
assertEquals(maxLookbackAge, queryTableLevelMaxLookbackAge(SchemaUtil.getTableName(schemaName, indexTableName)));
}
@Test
public void testCreateTableWithTableLevelMaxLookbackAgeAsNull() throws Exception {
String schemaName = generateUniqueName();
String dataTableName = generateUniqueName();
String fullTableName = SchemaUtil.getTableName(schemaName, dataTableName);
createTableWithTableLevelMaxLookbackAge(fullTableName, "NULL");
assertNull(queryTableLevelMaxLookbackAge(fullTableName));
String indexTableName = generateUniqueName();
createIndexOnTableWithMaxLookbackAge(indexTableName, fullTableName);
assertNull(queryTableLevelMaxLookbackAge(SchemaUtil.getTableName(schemaName, indexTableName)));
}
@Test
public void testCreateTableWithInvalidTableLevelMaxLookbackAge() {
String errMsg = "Table level MAX_LOOKBACK_AGE should be a BIGINT value in milli-seconds";
IllegalArgumentException err = assertThrows(IllegalArgumentException.class,
() -> createTableWithTableLevelMaxLookbackAge(
SchemaUtil.getTableName(generateUniqueName(), generateUniqueName()), "2.3"));
assertEquals(errMsg, err.getMessage());
err = assertThrows(IllegalArgumentException.class, () -> createTableWithTableLevelMaxLookbackAge(
SchemaUtil.getTableName(generateUniqueName(), generateUniqueName()), "three"));
assertEquals(errMsg, err.getMessage());
}
@Test
public void testCreateIndexWithTableLevelMaxLookbackAge() throws Exception {
String schemaName = generateUniqueName();
String dataTableName = generateUniqueName();
String fullTableName = SchemaUtil.getTableName(schemaName, dataTableName);
String indexTableName = generateUniqueName();
createTableWithTableLevelMaxLookbackAge(fullTableName, "NULL");
String indexOptions = "MAX_LOOKBACK_AGE=300";
SQLException err = assertThrows(SQLException.class,
() -> createIndexOnTableWithMaxLookbackAge(indexTableName, fullTableName, indexOptions));
assertEquals(MAX_LOOKBACK_AGE_SUPPORTED_FOR_TABLES_ONLY.getErrorCode(), err.getErrorCode());
}
public static long verifyLastDDLTimestamp(String tableFullName, long startTS, Connection conn) throws SQLException {
long endTS = EnvironmentEdgeManager.currentTimeMillis();
//Now try the PTable API
long ddlTimestamp = getLastDDLTimestamp(conn, tableFullName);
assertTrue("PTable DDL Timestamp not in the right range!",
ddlTimestamp >= startTS && ddlTimestamp <= endTS);
return ddlTimestamp;
}
public static long getLastDDLTimestamp(Connection conn, String tableFullName) throws SQLException {
PTable table = conn.unwrap(PhoenixConnection.class).getTableNoCache(tableFullName);
assertNotNull("PTable is null!", table);
assertNotNull("DDL timestamp is null!", table.getLastDDLTimestamp());
return table.getLastDDLTimestamp();
}
private int checkGuidePostWidth(String tableName) throws Exception {
try (Connection conn = DriverManager.getConnection(getUrl())) {
String query =
"SELECT GUIDE_POSTS_WIDTH FROM SYSTEM.CATALOG WHERE TABLE_NAME = ? AND COLUMN_FAMILY IS NULL AND COLUMN_NAME IS NULL";
PreparedStatement stmt = conn.prepareStatement(query);
stmt.setString(1, tableName);
ResultSet rs = stmt.executeQuery();
assertTrue(rs.next());
return rs.getInt(1);
}
}
private void createTableWithTableLevelMaxLookbackAge(String fullTableName, String maxLookbackAge) throws Exception {
try(Connection conn = DriverManager.getConnection(getUrl())) {
String createDdl = "CREATE TABLE " + fullTableName +
" (id char(1) NOT NULL PRIMARY KEY, col1 integer) MAX_LOOKBACK_AGE="+maxLookbackAge;
conn.createStatement().execute(createDdl);
}
}
private void createIndexOnTableWithMaxLookbackAge(String indexTableName, String fullTableName, String indexOptions) throws Exception {
try(Connection conn = DriverManager.getConnection(getUrl())) {
String createIndexDdl = "CREATE INDEX " + indexTableName + " ON " + fullTableName + " (COL1) " +
(indexOptions == null ? "" : indexOptions);
conn.createStatement().execute(createIndexDdl);
}
}
private void createIndexOnTableWithMaxLookbackAge(String indexTableName, String fullTableName) throws Exception {
createIndexOnTableWithMaxLookbackAge(indexTableName, fullTableName, null);
}
}