blob: 91e93707d778a53da499ad2268a08ddee521fa67 [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.jdbc.PhoenixDatabaseMetaData.TABLE_FAMILY_BYTES;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.sql.Connection;
import java.sql.DriverManager;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import org.apache.hadoop.hbase.client.HTableInterface;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.filter.CompareFilter.CompareOp;
import org.apache.hadoop.hbase.filter.Filter;
import org.apache.hadoop.hbase.filter.FilterList;
import org.apache.hadoop.hbase.filter.FirstKeyOnlyFilter;
import org.apache.hadoop.hbase.filter.SingleColumnValueFilter;
import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.expression.Expression;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.tuple.ResultTuple;
import org.apache.phoenix.schema.types.PVarchar;
import org.apache.phoenix.util.MetaDataUtil;
import org.apache.phoenix.util.PhoenixRuntime;
import org.apache.phoenix.util.PropertiesUtil;
import org.apache.phoenix.util.TestUtil;
import org.junit.Test;
import com.google.common.collect.Sets;
public class PhoenixRuntimeIT extends ParallelStatsDisabledIT {
private static void assertTenantIds(Expression e, HTableInterface htable, Filter filter, String[] tenantIds) throws IOException {
ImmutableBytesWritable ptr = new ImmutableBytesWritable();
Scan scan = new Scan();
scan.setFilter(filter);
ResultScanner scanner = htable.getScanner(scan);
Result result = null;
ResultTuple tuple;
Set<String> actualTenantIds = Sets.newHashSetWithExpectedSize(tenantIds.length);
Set<String> expectedTenantIds = new HashSet<>(Arrays.asList(tenantIds));
while ((result = scanner.next()) != null) {
tuple = new ResultTuple(result);
e.evaluate(tuple, ptr);
String tenantId = (String)PVarchar.INSTANCE.toObject(ptr);
actualTenantIds.add(tenantId == null ? "" : tenantId);
}
assertTrue(actualTenantIds.containsAll(expectedTenantIds));
}
@Test
public void testGetTenantIdExpressionForSaltedTable() throws Exception {
testGetTenantIdExpression(true);
}
@Test
public void testGetTenantIdExpressionForUnsaltedTable() throws Exception {
testGetTenantIdExpression(false);
}
private static Filter getUserTableAndViewsFilter() {
SingleColumnValueFilter tableFilter = new SingleColumnValueFilter(TABLE_FAMILY_BYTES, PhoenixDatabaseMetaData.TABLE_TYPE_BYTES, CompareOp.EQUAL, Bytes.toBytes(PTableType.TABLE.getSerializedValue()));
tableFilter.setFilterIfMissing(true);
SingleColumnValueFilter viewFilter = new SingleColumnValueFilter(TABLE_FAMILY_BYTES, PhoenixDatabaseMetaData.TABLE_TYPE_BYTES, CompareOp.EQUAL, Bytes.toBytes(PTableType.VIEW.getSerializedValue()));
viewFilter.setFilterIfMissing(true);
FilterList filter = new FilterList(FilterList.Operator.MUST_PASS_ONE, Arrays.asList(new Filter[] {tableFilter, viewFilter}));
return filter;
}
private void testGetTenantIdExpression(boolean isSalted) throws Exception {
Connection conn = DriverManager.getConnection(getUrl());
conn.setAutoCommit(true);
String tableName = generateUniqueName() ;
String sequenceName = generateUniqueName();
String t1 = generateUniqueName();
String t2 = t1 + generateUniqueName(); // ensure bigger
conn.createStatement().execute("CREATE TABLE " + tableName + " (k1 VARCHAR NOT NULL, k2 VARCHAR, CONSTRAINT PK PRIMARY KEY(K1,K2)) MULTI_TENANT=true" + (isSalted ? ",SALT_BUCKETS=3" : ""));
conn.createStatement().execute("CREATE SEQUENCE " + sequenceName);
conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('" + t1 + "','x')");
conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('" + t2 + "','y')");
Properties props = PropertiesUtil.deepCopy(TestUtil.TEST_PROPERTIES);
props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, t1);
Connection tsconn = DriverManager.getConnection(getUrl(), props);
tsconn.createStatement().execute("CREATE SEQUENCE " + sequenceName);
Expression e1 = PhoenixRuntime.getTenantIdExpression(tsconn, PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_NAME);
HTableInterface htable1 = tsconn.unwrap(PhoenixConnection.class).getQueryServices().getTable(PhoenixDatabaseMetaData.SYSTEM_SEQUENCE_NAME_BYTES);
assertTenantIds(e1, htable1, new FirstKeyOnlyFilter(), new String[] {"", t1} );
String viewName = generateUniqueName();
tsconn.createStatement().execute("CREATE VIEW " + viewName + "(V1 VARCHAR) AS SELECT * FROM " + tableName);
Expression e2 = PhoenixRuntime.getTenantIdExpression(tsconn, PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME);
HTableInterface htable2 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(PhoenixDatabaseMetaData.SYSTEM_CATALOG_NAME_BYTES);
assertTenantIds(e2, htable2, getUserTableAndViewsFilter(), new String[] {"", t1} );
Expression e3 = PhoenixRuntime.getTenantIdExpression(conn, tableName);
HTableInterface htable3 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(tableName));
assertTenantIds(e3, htable3, new FirstKeyOnlyFilter(), new String[] {t1, t2} );
String basTableName = generateUniqueName();
conn.createStatement().execute("CREATE TABLE " + basTableName + " (k1 VARCHAR PRIMARY KEY)");
Expression e4 = PhoenixRuntime.getTenantIdExpression(conn, basTableName);
assertNull(e4);
String indexName1 = generateUniqueName();
tsconn.createStatement().execute("CREATE INDEX " + indexName1 + " ON " + viewName + "(V1)");
Expression e5 = PhoenixRuntime.getTenantIdExpression(tsconn, indexName1);
HTableInterface htable5 = tsconn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(MetaDataUtil.VIEW_INDEX_TABLE_PREFIX + tableName));
assertTenantIds(e5, htable5, new FirstKeyOnlyFilter(), new String[] {t1} );
String indexName2 = generateUniqueName();
conn.createStatement().execute("CREATE INDEX " + indexName2 + " ON " + tableName + "(k2)");
Expression e6 = PhoenixRuntime.getTenantIdExpression(conn, indexName2);
HTableInterface htable6 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(indexName2));
assertTenantIds(e6, htable6, new FirstKeyOnlyFilter(), new String[] {t1, t2} );
tableName = generateUniqueName() + "BAR_" + (isSalted ? "SALTED" : "UNSALTED");
conn.createStatement().execute("CREATE TABLE " + tableName + " (k1 VARCHAR NOT NULL, k2 VARCHAR, CONSTRAINT PK PRIMARY KEY(K1,K2)) " + (isSalted ? "SALT_BUCKETS=3" : ""));
conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('" + t1 + "','x')");
conn.createStatement().execute("UPSERT INTO " + tableName + " VALUES('" + t2 + "','y')");
Expression e7 = PhoenixRuntime.getFirstPKColumnExpression(conn, tableName);
HTableInterface htable7 = conn.unwrap(PhoenixConnection.class).getQueryServices().getTable(Bytes.toBytes(tableName));
assertTenantIds(e7, htable7, new FirstKeyOnlyFilter(), new String[] {t1, t2} );
}
}