You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@phoenix.apache.org by ja...@apache.org on 2014/10/18 03:18:21 UTC

[2/4] PHOENIX-1297 Adding utility methods to get primary key information from the optimized query plan (Samarth Jain)

http://git-wip-us.apache.org/repos/asf/phoenix/blob/17eb70d8/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
index 45a61a7..81f4a45 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/compile/QueryOptimizerTest.java
@@ -20,15 +20,31 @@ package org.apache.phoenix.compile;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 
+import java.sql.Array;
 import java.sql.Connection;
+import java.sql.Date;
 import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
 
+import org.apache.hadoop.hbase.util.Pair;
 import org.apache.phoenix.compile.OrderByCompiler.OrderBy;
+import org.apache.phoenix.jdbc.PhoenixPreparedStatement;
 import org.apache.phoenix.jdbc.PhoenixStatement;
 import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.query.QueryConstants;
+import org.apache.phoenix.schema.PTableType;
+import org.apache.phoenix.util.PhoenixRuntime;
 import org.apache.phoenix.util.SchemaUtil;
+import org.junit.Ignore;
 import org.junit.Test;
 
+import com.google.common.base.Joiner;
+import com.google.common.base.Splitter;
+
 public class QueryOptimizerTest extends BaseConnectionlessQueryTest {
     
     public static final String SCHEMA_NAME = "";
@@ -306,4 +322,252 @@ public class QueryOptimizerTest extends BaseConnectionlessQueryTest {
         QueryPlan plan = stmt.optimizeQuery(query);
         assertEquals("T", plan.getTableRef().getTable().getTableName().getString());
     }
+    
+    @Test
+    // Multi-tenant = false; Query uses index = false; Salted = true
+    public void testAssertQueryPlanDetails1() throws Exception {
+        testAssertQueryPlanDetails(false, false, true);
+    }
+    
+    @Test
+    // Multi-tenant = true; Query uses index = false; Salted = true
+    public void testAssertQueryPlanDetails2() throws Exception {
+        testAssertQueryPlanDetails(true, false, true);
+    }
+    
+    @Test
+    @Ignore // FIXME : https://issues.apache.org/jira/browse/PHOENIX-1302
+    // Multi-tenant = true; Query uses index = true; Salted = false
+    public void testAssertQueryPlanDetails3() throws Exception {
+        testAssertQueryPlanDetails(true, true, true);
+    }
+    
+    @Test
+    // Multi-tenant = false; Query uses index = true; Salted = true
+    public void testAssertQueryPlanDetails4() throws Exception {
+        testAssertQueryPlanDetails(false, true, true);
+    }
+    
+    @Test
+    // Multi-tenant = false; Query uses index = false; Salted = false
+    public void testAssertQueryPlanDetails5() throws Exception {
+        testAssertQueryPlanDetails(false, false, false);
+    }
+    
+    @Test
+    // Multi-tenant = true; Query uses index = false; Salted = false
+    public void testAssertQueryPlanDetails6() throws Exception {
+        testAssertQueryPlanDetails(true, false, false);
+    }
+    
+    @Test
+    @Ignore // FIXME : https://issues.apache.org/jira/browse/PHOENIX-1302
+    // Multi-tenant = true; Query uses index = true; Salted = false
+    public void testAssertQueryPlanDetails7() throws Exception {
+        testAssertQueryPlanDetails(true, true, false);
+    }
+    
+    @Test
+    // Multi-tenant = false; Query uses index = true; Salted = false
+    public void testAssertQueryPlanDetails8() throws Exception {
+        testAssertQueryPlanDetails(false, true, false);
+    }
+
+    private void testAssertQueryPlanDetails(boolean multitenant, boolean useIndex, boolean salted) throws Exception {
+        String sql;
+        PreparedStatement stmt;
+        Connection conn = DriverManager.getConnection(getUrl(), new Properties());
+        try {
+            // create table
+            conn.createStatement().execute("create table "
+                    + "XYZ.ABC"
+                    + "   (organization_id char(15) not null, \n"
+                    + "    dec DECIMAL(10,2) not null,\n"
+                    + "    a_string_array varchar(100) array[] not null,\n"
+                    + "    b_string varchar(100),\n"
+                    + "    CF.a_integer integer,\n"
+                    + "    a_date date,\n"
+                    + "    CONSTRAINT pk PRIMARY KEY (organization_id, dec, a_string_array)\n"
+                    + ")" + (salted ? "SALT_BUCKETS=4" : "") + (multitenant == true ? (salted ? ",MULTI_TENANT=true" : "MULTI_TENANT=true") : ""));
+
+            
+            if (useIndex) {
+                // create index
+                conn.createStatement().execute("CREATE INDEX ABC_IDX ON XYZ.ABC (CF.a_integer) INCLUDE (a_date)");
+            }
+            
+            // switch to a tenant specific connection if multi-tenant.
+            conn = multitenant ? DriverManager.getConnection(getUrl("tenantId")) : conn;
+            
+            // create a tenant specific view if multi-tenant
+            if (multitenant) {
+                conn.createStatement().execute("CREATE VIEW ABC_VIEW (ORGANIZATION_ID VARCHAR) AS SELECT * FROM XYZ.ABC");
+            }
+            
+            String expectedColNames = multitenant ? addQuotes(null, "DEC,A_STRING_ARRAY") : addQuotes(null,"ORGANIZATION_ID,DEC,A_STRING_ARRAY");
+            String expectedColumnNameDataTypes = multitenant ? "\"DEC\" DECIMAL(10,2),\"A_STRING_ARRAY\" VARCHAR(100) ARRAY" : "\"ORGANIZATION_ID\" CHAR(15),\"DEC\" DECIMAL(10,2),\"A_STRING_ARRAY\" VARCHAR(100) ARRAY";
+            String tableName = multitenant ? "ABC_VIEW" : "XYZ.ABC";
+            String tenantFilter = multitenant ? "" : "organization_id = ? AND ";
+            String orderByRowKeyClause = multitenant ? "dec" : "organization_id";
+            
+            // Filter on row key columns of data table. No order by. No limit.
+            sql = "SELECT CF.a_integer FROM " + tableName + " where " + tenantFilter + " dec = ? and a_string_array = ?";
+            stmt = conn.prepareStatement(sql);
+            int counter = 1;
+            if (!multitenant) {
+                stmt.setString(counter++, "ORGID");
+            }
+            stmt.setDouble(counter++, 1.23);
+            String[] strArray = new String[2];
+            strArray[0] = "AB";
+            strArray[1] = "CD";
+            Array array = conn.createArrayOf("VARCHAR", strArray);
+            stmt.setArray(counter++, array);
+            assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 0);
+            
+            counter = 1;
+            // Filter on row key columns of data table. Order by row key columns. Limit specified.
+            sql = "SELECT CF.a_integer FROM " + tableName + " where " + tenantFilter + " dec = ? and a_string_array = ? ORDER BY " + orderByRowKeyClause + " LIMIT 100";
+            stmt = conn.prepareStatement(sql);
+            if (!multitenant) {
+                stmt.setString(counter++, "ORGID");
+            }
+            stmt.setDouble(counter++, 1.23);
+            array = conn.createArrayOf("VARCHAR", strArray);
+            stmt.setArray(counter++, array);
+            assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 100);
+            
+            counter = 1;
+            // Filter on row key columns of data table. Order by non-row key columns. Limit specified.
+            sql = "SELECT CF.a_integer FROM " + tableName + " where " + tenantFilter + " dec = ? and a_string_array = ? ORDER BY a_date LIMIT 100";
+            stmt = conn.prepareStatement(sql);
+            if (!multitenant) {
+                stmt.setString(counter++, "ORGID");
+            }
+            stmt.setDouble(counter++, 1.23);
+            array = conn.createArrayOf("VARCHAR", strArray);
+            stmt.setArray(counter++, array);
+            assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, true, 100);
+            
+            if (useIndex) {
+                
+                expectedColNames = multitenant ? ("\"CF\".\"A_INTEGER\"" + ",\"DEC\"" + ",\"A_STRING_ARRAY\"") : ("\"CF\".\"A_INTEGER\"" + ",\"ORGANIZATION_ID\"" + ",\"DEC\"" + ",\"A_STRING_ARRAY\"");
+                expectedColumnNameDataTypes = multitenant ? ("\"CF\".\"A_INTEGER\"" + " " + "INTEGER" + ",\"DEC\"" + " " + "DECIMAL(10,2)" + ",\"A_STRING_ARRAY\""+ " " + "VARCHAR(100) ARRAY") : ("\"CF\".\"A_INTEGER\"" + " " + "INTEGER" + ",\"ORGANIZATION_ID\"" + " " + "CHAR(15)" + ",\"DEC\"" + " " + "DECIMAL(10,2)" + ",\"A_STRING_ARRAY\""+ " " + "VARCHAR(100) ARRAY");
+                
+                // Filter on columns that the secondary index is on. No order by. No limit.
+                sql = "SELECT a_date FROM " + tableName + " where CF.a_integer = ?";
+                stmt = conn.prepareStatement(sql);
+                stmt.setInt(1, 1000);
+                assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 0);
+
+                // Filter on columns that the secondary index is on. Order by on the indexed column. Limit specified.
+                sql = "SELECT a_date FROM " + tableName + " where CF.a_integer = ? ORDER BY CF.a_integer LIMIT 100";
+                stmt = conn.prepareStatement(sql);
+                stmt.setInt(1, 1000);
+                assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, false, 100);
+
+                // Filter on columns that the secondary index is on. Order by on the non-indexed column. Limit specified.
+                sql = "SELECT a_integer FROM " + tableName + " where CF.a_integer = ? and a_date = ? ORDER BY a_date LIMIT 100";
+                stmt = conn.prepareStatement(sql);
+                stmt.setInt(1, 1000);
+                stmt.setDate(2, new Date(909000));
+                assertPlanDetails(stmt, expectedColNames, expectedColumnNameDataTypes, true, 100);
+            }
+        } finally {
+            conn.close();
+        }
+    }
+    
+    @Test
+    @Ignore // FIXME : https://issues.apache.org/jira/browse/PHOENIX-1302
+    public void testAssertQueryAgainstTenantSpecificViewGoesThroughIndex() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl(), new Properties());
+        
+        // create table
+        conn.createStatement().execute("create table "
+                + "XYZ.ABC"
+                + "   (organization_id char(15) not null, \n"
+                + "    entity_id char(15) not null,\n"
+                + "    a_string_array varchar(100) array[] not null,\n"
+                + "    b_string varchar(100),\n"
+                + "    a_string varchar,\n"
+                + "    a_date date,\n"
+                + "    CONSTRAINT pk PRIMARY KEY (organization_id, entity_id, a_string_array)\n"
+                + ")" + "MULTI_TENANT=true");
+
+        
+        // create index
+        conn.createStatement().execute("CREATE INDEX ABC_IDX ON XYZ.ABC (a_string) INCLUDE (a_date)");
+        
+        conn.close();
+        
+        // switch to a tenant specific connection
+        conn = DriverManager.getConnection(getUrl("tenantId"));
+        
+        // create a tenant specific view
+        conn.createStatement().execute("CREATE VIEW ABC_VIEW AS SELECT * FROM XYZ.ABC");
+        
+        // query against the tenant specific view
+        String sql = "SELECT a_date FROM ABC_VIEW where a_string = ?";
+        PreparedStatement stmt = conn.prepareStatement(sql);
+        stmt.setString(1, "1000");
+        QueryPlan plan = stmt.unwrap(PhoenixPreparedStatement.class).optimizeQuery();
+        assertEquals("Query should use index", PTableType.INDEX, plan.getTableRef().getTable().getType());
+        
+    }
+    
+    private void assertPlanDetails(PreparedStatement stmt, String expectedPkCols, String expectedPkColsDataTypes, boolean expectedHasOrderBy, int expectedLimit) throws SQLException {
+        Connection conn = stmt.getConnection();
+        QueryPlan plan = PhoenixRuntime.getOptimizedQueryPlan(stmt);
+        
+        List<Pair<String, String>> columns = new ArrayList<Pair<String, String>>();
+        PhoenixRuntime.getPkColsForSql(columns, plan, conn, true);
+        assertEquals(expectedPkCols, Joiner.on(",").join(getColumnNames(columns)));
+        List<String> dataTypes = new ArrayList<String>();
+        columns = new ArrayList<Pair<String,String>>();
+        PhoenixRuntime.getPkColsDataTypesForSql(columns, dataTypes, plan, conn, true);
+        
+        assertEquals(expectedPkColsDataTypes, appendColNamesDataTypes(columns, dataTypes));
+        assertEquals(expectedHasOrderBy, PhoenixRuntime.hasOrderBy(plan));
+        assertEquals(expectedLimit, PhoenixRuntime.getLimit(plan));
+    }
+    
+    private static List<String> getColumnNames(List<Pair<String, String>> columns) {
+        List<String> columnNames = new ArrayList<String>(columns.size());
+        for (Pair<String, String> col : columns) {
+            String familyName = col.getFirst();
+            String columnName = col.getSecond();
+            if (familyName != null) {
+                columnName = familyName + QueryConstants.NAME_SEPARATOR + columnName;
+            }
+            columnNames.add(columnName);
+        }
+        return columnNames;
+    }
+    
+    private String addQuotes(String familyName, String columnNames) {
+        Iterable<String> columnNamesList = Splitter.on(",").split(columnNames);
+        List<String> quotedColumnNames = new ArrayList<String>();
+        for (String columnName : columnNamesList) {
+            String quotedColumnName = SchemaUtil.getQuotedFullColumnName(familyName, columnName);
+            quotedColumnNames.add(quotedColumnName);
+        }
+        return Joiner.on(",").join(quotedColumnNames);
+    }
+    
+    private String appendColNamesDataTypes(List<Pair<String, String>> columns, List<String> dataTypes) {
+        int size = columns.size();
+        assertEquals(size, dataTypes.size()); // they will be equal, but what the heck?
+        List<String> pkColsDataTypes = new ArrayList<String>(size);
+        for (int i = 0; i < size; i++) {
+            String familyName = columns.get(i).getFirst();
+            String columnName = columns.get(i).getSecond();
+            if (familyName != null) {
+                columnName = familyName + QueryConstants.NAME_SEPARATOR + columnName;
+            }
+            pkColsDataTypes.add(columnName + " " + dataTypes.get(i));
+        }
+        return Joiner.on(",").join(pkColsDataTypes);
+    }
+    
 }
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/phoenix/blob/17eb70d8/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java b/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
index 9b0ebff..766917c 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/schema/ValueBitSetTest.java
@@ -18,6 +18,7 @@
 package org.apache.phoenix.schema;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import org.apache.hadoop.hbase.io.ImmutableBytesWritable;
@@ -70,6 +71,48 @@ public class ValueBitSetTest {
     }
     
     @Test
+    public void testMinNullableIndex() {
+        final int minNullableIndex = 4; // first 4 fields are not nullable.
+        int numFields = 6;
+        KeyValueSchemaBuilder builder = new KeyValueSchemaBuilder(minNullableIndex);
+        for (int i = 0; i < numFields; i++) {
+            final int fieldIndex = i;
+            builder.addField(new PDatum() {
+                @Override
+                public boolean isNullable() {
+                    // not nullable till index reaches minNullableIndex
+                    return fieldIndex < minNullableIndex;
+                }
+
+                @Override
+                public SortOrder getSortOrder() {
+                    return SortOrder.getDefault();
+                }
+
+                @Override
+                public Integer getScale() {
+                    return null;
+                }
+
+                @Override
+                public Integer getMaxLength() {
+                    return null;
+                }
+
+                @Override
+                public PDataType getDataType() {
+                    return PDataType.values()[fieldIndex % PDataType.values().length];
+                }
+            });
+        }
+        KeyValueSchema kvSchema = builder.build();
+        assertFalse(kvSchema.getFields().get(0).isNullable());
+        assertFalse(kvSchema.getFields().get(minNullableIndex - 1).isNullable());
+        assertTrue(kvSchema.getFields().get(minNullableIndex).isNullable());
+        assertTrue(kvSchema.getFields().get(minNullableIndex + 1).isNullable());
+    }
+    
+    @Test
     public void testNullCount() {
         int nFields = 32;
         int nRepeating = 5;

http://git-wip-us.apache.org/repos/asf/phoenix/blob/17eb70d8/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java
new file mode 100644
index 0000000..7ddb235
--- /dev/null
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixEncodeDecodeTest.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010 The Apache Software Foundation
+ *
+ * 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 maynot 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 applicablelaw 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.util;
+
+import static org.junit.Assert.assertEquals;
+
+import java.sql.Connection;
+import java.sql.Date;
+import java.sql.DriverManager;
+import java.util.Arrays;
+
+import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.junit.Test;
+
+import com.google.common.collect.Lists;
+
+public class PhoenixEncodeDecodeTest extends BaseConnectionlessQueryTest {
+    
+    @Test
+    public void testDecodeValues1() throws Exception {
+        testDecodeValues(false, false);
+    }
+    
+    @Test
+    public void testDecodeValues2() throws Exception {
+        testDecodeValues(true, false);
+    }
+    
+    @Test
+    public void testDecodeValues3() throws Exception {
+        testDecodeValues(true, true);
+    }
+    
+    @Test
+    public void testDecodeValues4() throws Exception {
+        testDecodeValues(false, true);
+    }
+    
+    @SuppressWarnings("unchecked")
+    private void testDecodeValues(boolean nullFixedWidth, boolean nullVariableWidth) throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl());
+        conn.createStatement().execute(
+                "CREATE TABLE T(pk1 CHAR(15) not null, pk2 VARCHAR not null, CF1.v1 DATE, CF2.v2 VARCHAR, CF2.v1 VARCHAR " +
+                "CONSTRAINT pk PRIMARY KEY (pk1, pk2)) ");
+        
+        Date d = nullFixedWidth ? null : new Date(100);
+        String s = nullVariableWidth ? null : "foo";
+        Object[] values = new Object[] {"def", "eid", d, s, s};
+        byte[] bytes = PhoenixRuntime.encodeValues(conn, "T", values, Lists.newArrayList(new Pair<String, String>(null, "pk1"), new Pair<String, String>(null, "pk2"), new Pair<String, String>("cf1", "v1"), new Pair<String, String>("cf2", "v2"), new Pair<String, String>("cf2", "v1")));
+        Object[] decodedValues = PhoenixRuntime.decodeValues(conn, "T", bytes, Lists.newArrayList(new Pair<String, String>(null, "pk1"), new Pair<String, String>(null, "pk2"), new Pair<String, String>("cf1", "v1"), new Pair<String, String>("cf2", "v2"), new Pair<String, String>("cf2", "v1")));
+        assertEquals(Lists.newArrayList("def", "eid", d, s, s), Arrays.asList(decodedValues));
+    }
+    
+}

http://git-wip-us.apache.org/repos/asf/phoenix/blob/17eb70d8/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
----------------------------------------------------------------------
diff --git a/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
index 9a277ad..847aed9 100644
--- a/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
+++ b/phoenix-core/src/test/java/org/apache/phoenix/util/PhoenixRuntimeTest.java
@@ -22,8 +22,20 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
-
+import static org.junit.Assert.fail;
+
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Properties;
+
+import org.apache.commons.lang.exception.ExceptionUtils;
+import org.apache.hadoop.hbase.util.Pair;
+import org.apache.phoenix.compile.QueryPlan;
 import org.apache.phoenix.query.BaseConnectionlessQueryTest;
+import org.apache.phoenix.schema.PDataType;
 import org.junit.Test;
 
 import com.google.common.collect.ImmutableList;
@@ -80,4 +92,67 @@ public class PhoenixRuntimeTest extends BaseConnectionlessQueryTest {
         assertTrue(execCmd.isStrict());
         assertEquals("!", execCmd.getArrayElementSeparator());
     }
+    
+    @Test
+    public void testGetPkColsDataTypes() throws Exception {
+        Connection conn = DriverManager.getConnection(getUrl(), new Properties());
+        int i = 0;
+        PDataType[] pTypes = PDataType.values();
+        int size = pTypes.length;
+        StringBuilder sb = null;
+        try {
+            for (i = 0 ; i < size; i++) {
+                PDataType pType = pTypes[i];
+                String sqlTypeName = pType.getSqlTypeName();
+                if (sqlTypeName.equalsIgnoreCase("VARBINARY ARRAY")) {
+                    // we don't support VARBINARY ARRAYS yet
+                    // JIRA - https://issues.apache.org/jira/browse/PHOENIX-1329
+                    continue;
+                }
+                if (pType.isArrayType() && PDataType.arrayBaseType(pType).isFixedWidth() && PDataType.arrayBaseType(pType).getByteSize() == null) {
+                    // Need to treat array type whose base type is of fixed width whose byte size is not known as a special case. 
+                    // Cannot just use the sql type name returned by PDataType.getSqlTypeName().
+                    String baseTypeName = PDataType.arrayBaseType(pType).getSqlTypeName();
+                    sqlTypeName = baseTypeName + "(15)" + " " + PDataType.ARRAY_TYPE_SUFFIX;
+                } else if (pType.isFixedWidth() && pType.getByteSize() == null) {
+                    sqlTypeName = sqlTypeName + "(15)";
+                }
+                String columnName = "col" + i;
+                String tableName = "t" + i;
+                
+                sb = new StringBuilder(100);
+                
+                // create a table by using the type name as returned by PDataType
+                sb.append("CREATE TABLE " + tableName + " (");
+                sb.append(columnName + " " + sqlTypeName + " NOT NULL PRIMARY KEY, V1 VARCHAR)");
+                conn.createStatement().execute(sb.toString());
+
+                // generate the optimized query plan by going through the pk of the table.
+                PreparedStatement stmt = conn.prepareStatement("SELECT * FROM " + tableName + " WHERE " + columnName  + " = ?");
+                Integer maxLength = pType.isFixedWidth() && pType.getByteSize() == null ? 15 : null;
+                stmt.setObject(1, pType.getSampleValue(maxLength));
+                QueryPlan plan = PhoenixRuntime.getOptimizedQueryPlan(stmt);
+
+                // now go through the utility method, get column name and type name and
+                // try creating another table with the returned info. Use the query plan generated above.
+                // If table can be created with the returned sql type name, then great!
+                // It would mean "Roundtrip" of column data type name works.
+                List<Pair<String, String>> pkCols = new ArrayList<Pair<String, String>>();
+                List<String> dataTypes = new ArrayList<String>();
+                PhoenixRuntime.getPkColsDataTypesForSql(pkCols, dataTypes, plan, conn, true);
+
+                tableName = "newt" + i;
+                columnName = "newCol" + i;
+                String roundTripSqlTypeName = dataTypes.get(0);
+
+                // create a table by using the type name as returned by the utility method
+                sb = new StringBuilder(100);
+                sb.append("CREATE TABLE " + tableName + " (");
+                sb.append(columnName + " " + roundTripSqlTypeName + " NOT NULL PRIMARY KEY)");
+                conn.createStatement().execute(sb.toString());
+            }
+        } catch (Exception e) {
+            fail("Failed sql: " + sb.toString() + ExceptionUtils.getStackTrace(e));
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/phoenix/blob/17eb70d8/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
----------------------------------------------------------------------
diff --git a/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java b/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
index 7c4306f..d0cd0a1 100644
--- a/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
+++ b/phoenix-pig/src/it/java/org/apache/phoenix/pig/PhoenixHBaseLoaderIT.java
@@ -617,7 +617,10 @@ public class PhoenixHBaseLoaderIT {
 
     @AfterClass
     public static void tearDownAfterClass() throws Exception {
-        conn.close();
-        hbaseTestUtil.shutdownMiniCluster();
+        try {
+            conn.close();
+        } finally {
+            hbaseTestUtil.shutdownMiniCluster();
+        }
     }
 }
\ No newline at end of file