org.apache.phoenix.query.BaseTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.phoenix.query.BaseTest.java

Source

/*
 * 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.query;

import static org.apache.phoenix.query.QueryConstants.MILLIS_IN_DAY;
import static org.apache.phoenix.util.PhoenixRuntime.CURRENT_SCN_ATTRIB;
import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL;
import static org.apache.phoenix.util.PhoenixRuntime.JDBC_PROTOCOL_TERMINATOR;
import static org.apache.phoenix.util.PhoenixRuntime.PHOENIX_TEST_DRIVER_URL_PARAM;
import static org.apache.phoenix.util.TestUtil.ATABLE_NAME;
import static org.apache.phoenix.util.TestUtil.A_VALUE;
import static org.apache.phoenix.util.TestUtil.BINARY_NAME;
import static org.apache.phoenix.util.TestUtil.BTABLE_NAME;
import static org.apache.phoenix.util.TestUtil.B_VALUE;
import static org.apache.phoenix.util.TestUtil.CUSTOM_ENTITY_DATA_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.C_VALUE;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID1;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID2;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID3;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID4;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID5;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID6;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID7;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID8;
import static org.apache.phoenix.util.TestUtil.ENTITYHISTID9;
import static org.apache.phoenix.util.TestUtil.ENTITY_HISTORY_SALTED_TABLE_NAME;
import static org.apache.phoenix.util.TestUtil.ENTITY_HISTORY_TABLE_NAME;
import static org.apache.phoenix.util.TestUtil.E_VALUE;
import static org.apache.phoenix.util.TestUtil.FUNKY_NAME;
import static org.apache.phoenix.util.TestUtil.GROUPBYTEST_NAME;
import static org.apache.phoenix.util.TestUtil.HBASE_DYNAMIC_COLUMNS;
import static org.apache.phoenix.util.TestUtil.HBASE_NATIVE;
import static org.apache.phoenix.util.TestUtil.INDEX_DATA_SCHEMA;
import static org.apache.phoenix.util.TestUtil.INDEX_DATA_TABLE;
import static org.apache.phoenix.util.TestUtil.JOIN_COITEM_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_CUSTOMER_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_ITEM_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_ORDER_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.JOIN_SUPPLIER_TABLE_FULL_NAME;
import static org.apache.phoenix.util.TestUtil.KEYONLY_NAME;
import static org.apache.phoenix.util.TestUtil.MDTEST_NAME;
import static org.apache.phoenix.util.TestUtil.MULTI_CF_NAME;
import static org.apache.phoenix.util.TestUtil.MUTABLE_INDEX_DATA_TABLE;
import static org.apache.phoenix.util.TestUtil.PARENTID1;
import static org.apache.phoenix.util.TestUtil.PARENTID2;
import static org.apache.phoenix.util.TestUtil.PARENTID3;
import static org.apache.phoenix.util.TestUtil.PARENTID4;
import static org.apache.phoenix.util.TestUtil.PARENTID5;
import static org.apache.phoenix.util.TestUtil.PARENTID6;
import static org.apache.phoenix.util.TestUtil.PARENTID7;
import static org.apache.phoenix.util.TestUtil.PARENTID8;
import static org.apache.phoenix.util.TestUtil.PARENTID9;
import static org.apache.phoenix.util.TestUtil.PRODUCT_METRICS_NAME;
import static org.apache.phoenix.util.TestUtil.PTSDB2_NAME;
import static org.apache.phoenix.util.TestUtil.PTSDB3_NAME;
import static org.apache.phoenix.util.TestUtil.PTSDB_NAME;
import static org.apache.phoenix.util.TestUtil.ROW1;
import static org.apache.phoenix.util.TestUtil.ROW2;
import static org.apache.phoenix.util.TestUtil.ROW3;
import static org.apache.phoenix.util.TestUtil.ROW4;
import static org.apache.phoenix.util.TestUtil.ROW5;
import static org.apache.phoenix.util.TestUtil.ROW6;
import static org.apache.phoenix.util.TestUtil.ROW7;
import static org.apache.phoenix.util.TestUtil.ROW8;
import static org.apache.phoenix.util.TestUtil.ROW9;
import static org.apache.phoenix.util.TestUtil.STABLE_NAME;
import static org.apache.phoenix.util.TestUtil.TABLE_WITH_ARRAY;
import static org.apache.phoenix.util.TestUtil.TABLE_WITH_SALTING;
import static org.apache.phoenix.util.TestUtil.TEST_PROPERTIES;
import static org.apache.phoenix.util.TestUtil.TRANSACTIONAL_DATA_TABLE;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;

import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.Date;
import java.sql.Driver;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.sql.Types;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Properties;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

import javax.annotation.Nonnull;

import org.apache.commons.lang.RandomStringUtils;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseConfiguration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HColumnDescriptor;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.HTableDescriptor;
import org.apache.hadoop.hbase.IntegrationTestingUtility;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.HBaseAdmin;
import org.apache.hadoop.hbase.io.encoding.DataBlockEncoding;
import org.apache.hadoop.hbase.ipc.PhoenixRpcSchedulerFactory;
import org.apache.hadoop.hbase.ipc.RpcControllerFactory;
import org.apache.hadoop.hbase.ipc.controller.ServerRpcControllerFactory;
import org.apache.hadoop.hbase.regionserver.RSRpcServices;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.phoenix.end2end.BaseClientManagedTimeIT;
import org.apache.phoenix.end2end.BaseHBaseManagedTimeIT;
import org.apache.phoenix.exception.SQLExceptionCode;
import org.apache.phoenix.exception.SQLExceptionInfo;
import org.apache.phoenix.jdbc.PhoenixConnection;
import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData;
import org.apache.phoenix.jdbc.PhoenixDriver;
import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver;
import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver.ConnectionInfo;
import org.apache.phoenix.jdbc.PhoenixTestDriver;
import org.apache.phoenix.schema.NewerTableAlreadyExistsException;
import org.apache.phoenix.schema.PTableType;
import org.apache.phoenix.schema.TableAlreadyExistsException;
import org.apache.phoenix.schema.TableNotFoundException;
import org.apache.phoenix.util.ConfigUtil;
import org.apache.phoenix.util.DateUtil;
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.twill.discovery.DiscoveryService;
import org.apache.twill.discovery.ZKDiscoveryService;
import org.apache.twill.internal.utils.Networks;
import org.apache.twill.zookeeper.RetryStrategies;
import org.apache.twill.zookeeper.ZKClientService;
import org.apache.twill.zookeeper.ZKClientServices;
import org.apache.twill.zookeeper.ZKClients;
import org.junit.ClassRule;
import org.junit.rules.TemporaryFolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.google.inject.util.Providers;

import org.apache.tephra.TransactionManager;
import org.apache.tephra.TxConstants;
import org.apache.tephra.distributed.TransactionService;
import org.apache.tephra.metrics.TxMetricsCollector;
import org.apache.tephra.persist.InMemoryTransactionStateStorage;

/**
 * 
 * Base class that contains all the methods needed by
 * client-time and hbase-time managed tests.
 * 
 * For tests needing connectivity to a cluster, please use
 * {@link BaseHBaseManagedTimeIT} or {@link BaseClientManagedTimeIT}. 
 * 
 * In the rare case when a test can't share the same mini cluster as the 
 * ones used by {@link BaseHBaseManagedTimeIT} or {@link BaseClientManagedTimeIT}
 * one could extend this class and spin up your own mini cluster. Please 
 * make sure to shutdown the mini cluster in a method annotated by @AfterClass.  
 *
 */
public abstract class BaseTest {
    protected static final String TEST_TABLE_SCHEMA = "(" + "   varchar_pk VARCHAR NOT NULL, "
            + "   char_pk CHAR(10) NOT NULL, " + "   int_pk INTEGER NOT NULL, " + "   long_pk BIGINT NOT NULL, "
            + "   decimal_pk DECIMAL(31, 10) NOT NULL, " + "   date_pk DATE NOT NULL, "
            + "   a.varchar_col1 VARCHAR, " + "   a.char_col1 CHAR(10), " + "   a.int_col1 INTEGER, "
            + "   a.long_col1 BIGINT, " + "   a.decimal_col1 DECIMAL(31, 10), " + "   a.date1 DATE, "
            + "   b.varchar_col2 VARCHAR, " + "   b.char_col2 CHAR(10), " + "   b.int_col2 INTEGER, "
            + "   b.long_col2 BIGINT, " + "   b.decimal_col2 DECIMAL(31, 10), " + "   b.date2 DATE "
            + "   CONSTRAINT pk PRIMARY KEY (varchar_pk, char_pk, int_pk, long_pk DESC, decimal_pk, date_pk)) ";
    private static final Map<String, String> tableDDLMap;
    private static final Logger logger = LoggerFactory.getLogger(BaseTest.class);
    protected static final int DEFAULT_TXN_TIMEOUT_SECONDS = 30;
    private static ZKClientService zkClient;
    private static TransactionService txService;
    protected static TransactionManager txManager;
    @ClassRule
    public static TemporaryFolder tmpFolder = new TemporaryFolder();
    private static final int dropTableTimeout = 300; // 5 mins should be long enough.
    private static final ThreadFactory factory = new ThreadFactoryBuilder().setDaemon(true)
            .setNameFormat("DROP-TABLE-BASETEST" + "-thread-%s").build();
    private static final ExecutorService dropHTableService = Executors.newSingleThreadExecutor(factory);

    static {
        ImmutableMap.Builder<String, String> builder = ImmutableMap.builder();
        builder.put(ENTITY_HISTORY_TABLE_NAME,
                "create table " + ENTITY_HISTORY_TABLE_NAME + "   (organization_id char(15) not null,\n"
                        + "    parent_id char(15) not null,\n" + "    created_date date not null,\n"
                        + "    entity_history_id char(15) not null,\n" + "    old_value varchar,\n"
                        + "    new_value varchar,\n" + //create table shouldn't blow up if the last column definition ends with a comma.
                        "    CONSTRAINT pk PRIMARY KEY (organization_id, parent_id, created_date, entity_history_id)\n"
                        + ")");
        builder.put(ENTITY_HISTORY_SALTED_TABLE_NAME, "create table " + ENTITY_HISTORY_SALTED_TABLE_NAME
                + "   (organization_id char(15) not null,\n" + "    parent_id char(15) not null,\n"
                + "    created_date date not null,\n" + "    entity_history_id char(15) not null,\n"
                + "    old_value varchar,\n" + "    new_value varchar\n"
                + "    CONSTRAINT pk PRIMARY KEY (organization_id, parent_id, created_date, entity_history_id))\n"
                + "    SALT_BUCKETS = 4");
        builder.put(ATABLE_NAME,
                "create table " + ATABLE_NAME + "   (organization_id char(15) not null, \n"
                        + "    entity_id char(15) not null,\n" + "    a_string varchar(100),\n"
                        + "    b_string varchar(100),\n" + "    a_integer integer,\n" + "    a_date date,\n"
                        + "    a_time time,\n" + "    a_timestamp timestamp,\n" + "    x_decimal decimal(31,10),\n"
                        + "    x_long bigint,\n" + "    x_integer integer,\n" + "    y_integer integer,\n"
                        + "    a_byte tinyint,\n" + "    a_short smallint,\n" + "    a_float float,\n"
                        + "    a_double double,\n" + "    a_unsigned_float unsigned_float,\n"
                        + "    a_unsigned_double unsigned_double\n"
                        + "    CONSTRAINT pk PRIMARY KEY (organization_id, entity_id)\n" + ") ");
        builder.put(TABLE_WITH_ARRAY,
                "create table " + TABLE_WITH_ARRAY + "   (organization_id char(15) not null, \n"
                        + "    entity_id char(15) not null,\n" + "    a_string_array varchar(100) array[],\n"
                        + "    b_string varchar(100),\n" + "    a_integer integer,\n" + "    a_date date,\n"
                        + "    a_time time,\n" + "    a_timestamp timestamp,\n" + "    x_decimal decimal(31,10),\n"
                        + "    x_long_array bigint array[],\n" + "    x_integer integer,\n"
                        + "    a_byte_array tinyint array[],\n" + "    a_short smallint,\n" + "    a_float float,\n"
                        + "    a_double_array double array[],\n" + "    a_unsigned_float unsigned_float,\n"
                        + "    a_unsigned_double unsigned_double \n"
                        + "    CONSTRAINT pk PRIMARY KEY (organization_id, entity_id)\n" + ")");
        builder.put(BTABLE_NAME,
                "create table " + BTABLE_NAME + "   (a_string varchar not null, \n" + "    a_id char(3) not null,\n"
                        + "    b_string varchar not null, \n" + "    a_integer integer not null, \n"
                        + "    c_string varchar(2) null,\n" + "    b_integer integer,\n"
                        + "    c_integer integer,\n" + "    d_string varchar(3),\n" + "    e_string char(10)\n"
                        + "    CONSTRAINT my_pk PRIMARY KEY (a_string,a_id,b_string,a_integer,c_string))");
        builder.put(TABLE_WITH_SALTING,
                "create table " + TABLE_WITH_SALTING + "   (a_integer integer not null, \n"
                        + "    a_string varchar not null, \n" + "    a_id char(3) not null,\n"
                        + "    b_string varchar, \n" + "    b_integer integer \n"
                        + "    CONSTRAINT pk PRIMARY KEY (a_integer, a_string, a_id))\n" + "    SALT_BUCKETS = 4");
        builder.put(STABLE_NAME, "create table " + STABLE_NAME + "   (id char(1) not null primary key,\n"
                + "    \"value\" integer)");
        builder.put(PTSDB_NAME,
                "create table " + PTSDB_NAME + "   (inst varchar null,\n" + "    host varchar null,\n"
                        + "    date date not null,\n" + "    val decimal(31,10)\n"
                        + "    CONSTRAINT pk PRIMARY KEY (inst, host, date))");
        builder.put(PTSDB2_NAME,
                "create table " + PTSDB2_NAME + "   (inst varchar(10) not null,\n" + "    date date not null,\n"
                        + "    val1 decimal,\n" + "    val2 decimal(31,10),\n" + "    val3 decimal\n"
                        + "    CONSTRAINT pk PRIMARY KEY (inst, date))");
        builder.put(PTSDB3_NAME,
                "create table " + PTSDB3_NAME + "   (host varchar(10) not null,\n" + "    date date not null,\n"
                        + "    val1 decimal,\n" + "    val2 decimal(31,10),\n" + "    val3 decimal\n"
                        + "    CONSTRAINT pk PRIMARY KEY (host DESC, date DESC))");
        builder.put(FUNKY_NAME,
                "create table " + FUNKY_NAME + "   (\"foo!\" varchar not null primary key,\n"
                        + "    \"1\".\"#@$\" varchar, \n" + "    \"1\".\"foo.bar-bas\" varchar, \n"
                        + "    \"1\".\"Value\" integer,\n" + "    \"1\".\"VALUE\" integer,\n"
                        + "    \"1\".\"value\" integer,\n" + "    \"1\".\"_blah^\" varchar)");
        builder.put(KEYONLY_NAME, "create table " + KEYONLY_NAME + "   (i1 integer not null, i2 integer not null\n"
                + "    CONSTRAINT pk PRIMARY KEY (i1,i2))");
        builder.put(MDTEST_NAME,
                "create table " + MDTEST_NAME + "   (id char(1) primary key,\n" + "    a.col1 integer,\n"
                        + "    b.col2 bigint,\n" + "    b.col3 decimal,\n" + "    b.col4 decimal(5),\n"
                        + "    b.col5 decimal(6,3))\n" + "    a." + HConstants.VERSIONS + "=" + 1 + "," + "a."
                        + HColumnDescriptor.DATA_BLOCK_ENCODING + "='" + DataBlockEncoding.NONE + "'");
        builder.put(MULTI_CF_NAME,
                "create table " + MULTI_CF_NAME + "   (id char(15) not null primary key,\n"
                        + "    a.unique_user_count integer,\n" + "    b.unique_org_count integer,\n"
                        + "    c.db_cpu_utilization decimal(31,10),\n" + "    d.transaction_count bigint,\n"
                        + "    e.cpu_utilization decimal(31,10),\n" + "    f.response_time bigint,\n"
                        + "    g.response_time bigint)");
        builder.put(GROUPBYTEST_NAME, "create table " + GROUPBYTEST_NAME + "   (id varchar not null primary key,\n"
                + "    uri varchar, appcpu integer)");
        builder.put(HBASE_NATIVE,
                "create table " + HBASE_NATIVE + "   (uint_key unsigned_int not null,"
                        + "    ulong_key unsigned_long not null," + "    string_key varchar not null,\n"
                        + "    \"1\".uint_col unsigned_int," + "    \"1\".ulong_col unsigned_long"
                        + "    CONSTRAINT pk PRIMARY KEY (uint_key, ulong_key, string_key))\n"
                        + HColumnDescriptor.DATA_BLOCK_ENCODING + "='" + DataBlockEncoding.NONE + "'");
        builder.put(HBASE_DYNAMIC_COLUMNS,
                "create table " + HBASE_DYNAMIC_COLUMNS + "   (entry varchar not null," + "    F varchar,"
                        + "    A.F1v1 varchar," + "    A.F1v2 varchar," + "    B.F2v1 varchar"
                        + "    CONSTRAINT pk PRIMARY KEY (entry))\n");
        builder.put(PRODUCT_METRICS_NAME,
                "create table " + PRODUCT_METRICS_NAME + "   (organization_id char(15) not null,"
                        + "    date date not null," + "    feature char(1) not null,"
                        + "    unique_users integer not null,\n" + "    db_utilization decimal(31,10),\n"
                        + "    transactions bigint,\n" + "    cpu_utilization decimal(31,10),\n"
                        + "    response_time bigint,\n" + "    io_time bigint,\n" + "    region varchar,\n"
                        + "    unset_column decimal(31,10)\n"
                        + "    CONSTRAINT pk PRIMARY KEY (organization_id, DATe, feature, UNIQUE_USERS))");
        builder.put(CUSTOM_ENTITY_DATA_FULL_NAME,
                "create table " + CUSTOM_ENTITY_DATA_FULL_NAME + "   (organization_id char(15) not null, \n"
                        + "    key_prefix char(3) not null,\n" + "    custom_entity_data_id char(12) not null,\n"
                        + "    created_by varchar,\n" + "    created_date date,\n"
                        + "    currency_iso_code char(3),\n" + "    deleted char(1),\n"
                        + "    division decimal(31,10),\n" + "    last_activity date,\n" + "    last_update date,\n"
                        + "    last_update_by varchar,\n" + "    name varchar(240),\n" + "    owner varchar,\n"
                        + "    record_type_id char(15),\n" + "    setup_owner varchar,\n"
                        + "    system_modstamp date,\n" + "    b.val0 varchar,\n" + "    b.val1 varchar,\n"
                        + "    b.val2 varchar,\n" + "    b.val3 varchar,\n" + "    b.val4 varchar,\n"
                        + "    b.val5 varchar,\n" + "    b.val6 varchar,\n" + "    b.val7 varchar,\n"
                        + "    b.val8 varchar,\n" + "    b.val9 varchar\n"
                        + "    CONSTRAINT pk PRIMARY KEY (organization_id, key_prefix, custom_entity_data_id))");
        builder.put("IntKeyTest", "create table IntKeyTest" + "   (i integer not null primary key)");
        builder.put("IntIntKeyTest",
                "create table IntIntKeyTest" + "   (i integer not null primary key, j integer)");
        builder.put("PKIntValueTest", "create table PKIntValueTest" + "   (pk integer not null primary key)");
        builder.put("PKBigIntValueTest", "create table PKBigIntValueTest" + "   (pk bigint not null primary key)");
        builder.put("PKUnsignedIntValueTest",
                "create table PKUnsignedIntValueTest" + "   (pk unsigned_int not null primary key)");
        builder.put("PKUnsignedLongValueTest", "create table PKUnsignedLongValueTest"
                + "   (pk unsigned_long not null\n" + "    CONSTRAINT pk PRIMARY KEY (pk))");
        builder.put("KVIntValueTest",
                "create table KVIntValueTest" + "   (pk integer not null primary key,\n" + "    kv integer)\n");
        builder.put("KVBigIntValueTest",
                "create table KVBigIntValueTest" + "   (pk integer not null primary key,\n" + "    kv bigint)\n");
        builder.put(INDEX_DATA_TABLE, "create table " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR
                + INDEX_DATA_TABLE + TEST_TABLE_SCHEMA + "IMMUTABLE_ROWS=true");
        builder.put(MUTABLE_INDEX_DATA_TABLE, "create table " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR
                + MUTABLE_INDEX_DATA_TABLE + TEST_TABLE_SCHEMA);
        builder.put(TRANSACTIONAL_DATA_TABLE, "create table " + INDEX_DATA_SCHEMA + QueryConstants.NAME_SEPARATOR
                + TRANSACTIONAL_DATA_TABLE + TEST_TABLE_SCHEMA + "TRANSACTIONAL=true");
        builder.put("SumDoubleTest", "create table SumDoubleTest"
                + "   (id varchar not null primary key, d DOUBLE, f FLOAT, ud UNSIGNED_DOUBLE, uf UNSIGNED_FLOAT, i integer, de decimal)");
        builder.put(JOIN_ORDER_TABLE_FULL_NAME,
                "create table " + JOIN_ORDER_TABLE_FULL_NAME + "   (\"order_id\" varchar(15) not null primary key, "
                        + "    \"customer_id\" varchar(10), " + "    \"item_id\" varchar(10), "
                        + "    price integer, " + "    quantity integer, " + "    date timestamp)");
        builder.put(JOIN_CUSTOMER_TABLE_FULL_NAME,
                "create table " + JOIN_CUSTOMER_TABLE_FULL_NAME
                        + "   (\"customer_id\" varchar(10) not null primary key, " + "    name varchar, "
                        + "    phone varchar(12), " + "    address varchar, " + "    loc_id varchar(5), "
                        + "    date date)");
        builder.put(JOIN_ITEM_TABLE_FULL_NAME,
                "create table " + JOIN_ITEM_TABLE_FULL_NAME + "   (\"item_id\" varchar(10) not null primary key, "
                        + "    name varchar, " + "    price integer, " + "    discount1 integer, "
                        + "    discount2 integer, " + "    \"supplier_id\" varchar(10), "
                        + "    description varchar)");
        builder.put(JOIN_SUPPLIER_TABLE_FULL_NAME,
                "create table " + JOIN_SUPPLIER_TABLE_FULL_NAME
                        + "   (\"supplier_id\" varchar(10) not null primary key, " + "    name varchar, "
                        + "    phone varchar(12), " + "    address varchar, " + "    loc_id varchar(5))");
        builder.put(JOIN_COITEM_TABLE_FULL_NAME,
                "create table " + JOIN_COITEM_TABLE_FULL_NAME + "   (item_id varchar(10) NOT NULL, "
                        + "    item_name varchar NOT NULL, " + "    co_item_id varchar(10), "
                        + "    co_item_name varchar " + "   CONSTRAINT pk PRIMARY KEY (item_id, item_name)) "
                        + "   SALT_BUCKETS=4");
        builder.put(BINARY_NAME,
                "create table " + BINARY_NAME + "   (a_binary BINARY(16) not null, \n"
                        + "    b_binary BINARY(16), \n" + "    a_varbinary VARBINARY, \n"
                        + "    b_varbinary VARBINARY, \n" + "    CONSTRAINT pk PRIMARY KEY (a_binary)\n" + ") ");
        tableDDLMap = builder.build();
    }

    private static final String ORG_ID = "00D300000000XHP";
    protected static int NUM_SLAVES_BASE = 1;
    private static final String DEFAULT_SERVER_RPC_CONTROLLER_FACTORY = ServerRpcControllerFactory.class.getName();
    private static final String DEFAULT_RPC_SCHEDULER_FACTORY = PhoenixRpcSchedulerFactory.class.getName();

    protected static String getZKClientPort(Configuration conf) {
        return conf.get(QueryServices.ZOOKEEPER_PORT_ATTRIB);
    }

    protected static String url;
    protected static PhoenixTestDriver driver;
    protected static PhoenixDriver realDriver;
    protected static boolean clusterInitialized = false;
    private static HBaseTestingUtility utility;
    protected static final Configuration config = HBaseConfiguration.create();

    protected static String getUrl() {
        if (!clusterInitialized) {
            throw new IllegalStateException("Cluster must be initialized before attempting to get the URL");
        }
        return url;
    }

    private static void teardownTxManager() throws SQLException {
        try {
            if (txService != null)
                txService.stopAndWait();
        } finally {
            try {
                if (zkClient != null)
                    zkClient.stopAndWait();
            } finally {
                txService = null;
                zkClient = null;
            }
        }

    }

    protected static void setupTxManager() throws SQLException, IOException {
        config.setBoolean(TxConstants.Manager.CFG_DO_PERSIST, false);
        config.set(TxConstants.Service.CFG_DATA_TX_CLIENT_RETRY_STRATEGY, "n-times");
        config.setInt(TxConstants.Service.CFG_DATA_TX_CLIENT_ATTEMPTS, 1);
        config.setInt(TxConstants.Service.CFG_DATA_TX_BIND_PORT, Networks.getRandomPort());
        config.set(TxConstants.Manager.CFG_TX_SNAPSHOT_DIR, tmpFolder.newFolder().getAbsolutePath());
        config.setInt(TxConstants.Manager.CFG_TX_TIMEOUT, DEFAULT_TXN_TIMEOUT_SECONDS);

        ConnectionInfo connInfo = ConnectionInfo.create(getUrl());
        zkClient = ZKClientServices
                .delegate(ZKClients.reWatchOnExpire(ZKClients.retryOnFailure(
                        ZKClientService.Builder.of(connInfo.getZookeeperConnectionString())
                                .setSessionTimeout(config.getInt(HConstants.ZK_SESSION_TIMEOUT,
                                        HConstants.DEFAULT_ZK_SESSION_TIMEOUT))
                                .build(),
                        RetryStrategies.exponentialDelay(500, 2000, TimeUnit.MILLISECONDS))));
        zkClient.startAndWait();

        DiscoveryService discovery = new ZKDiscoveryService(zkClient);
        txManager = new TransactionManager(config, new InMemoryTransactionStateStorage(), new TxMetricsCollector());
        txService = new TransactionService(config, zkClient, discovery, Providers.of(txManager));
        txService.startAndWait();
    }

    protected static String checkClusterInitialized(ReadOnlyProps overrideProps) throws Exception {
        if (!clusterInitialized) {
            url = setUpTestCluster(config, overrideProps);
            clusterInitialized = true;
        }
        return url;
    }

    /**
     * Set up the test hbase cluster.
     * @return url to be used by clients to connect to the cluster.
     */
    protected static String setUpTestCluster(@Nonnull Configuration conf, ReadOnlyProps overrideProps) {
        boolean isDistributedCluster = isDistributedClusterModeEnabled(conf);
        if (!isDistributedCluster) {
            return initMiniCluster(conf, overrideProps);
        } else {
            return initClusterDistributedMode(conf, overrideProps);
        }
    }

    protected static void destroyDriver() throws Exception {
        if (driver != null) {
            try {
                assertTrue(destroyDriver(driver));
            } finally {
                driver = null;
            }
        }
        if (realDriver != null) {
            try {
                assertTrue(destroyDriver(realDriver));
            } finally {
                realDriver = null;
            }
        }
        teardownTxManager();
    }

    protected static void dropNonSystemTables() throws Exception {
        try {
            disableAndDropNonSystemTables();
        } finally {
            destroyDriver();
        }
    }

    protected static void tearDownMiniCluster() throws Exception {
        try {
            destroyDriver();
        } finally {
            try {
                if (utility != null) {
                    try {
                        utility.shutdownMiniMapReduceCluster();
                    } finally {
                        utility.shutdownMiniCluster();
                    }
                }
            } finally {
                utility = null;
                clusterInitialized = false;
            }
        }
    }

    protected static void setUpTestDriver(ReadOnlyProps props) throws Exception {
        setUpTestDriver(props, props);
    }

    protected static void setUpTestDriver(ReadOnlyProps serverProps, ReadOnlyProps clientProps) throws Exception {
        String url = checkClusterInitialized(serverProps);
        if (driver == null) {
            driver = initAndRegisterTestDriver(url, clientProps);
            if (clientProps.getBoolean(QueryServices.TRANSACTIONS_ENABLED,
                    QueryServicesOptions.DEFAULT_TRANSACTIONS_ENABLED)) {
                setupTxManager();
            }
        }
    }

    protected static void setUpRealDriver(ReadOnlyProps serverProps, ReadOnlyProps clientProps) throws Exception {
        if (!clusterInitialized) {
            setUpConfigForMiniCluster(config, serverProps);
            utility = new HBaseTestingUtility(config);
            try {
                utility.startMiniCluster(NUM_SLAVES_BASE);
                utility.startMiniMapReduceCluster();
                url = QueryUtil.getConnectionUrl(new Properties(), utility.getConfiguration());
            } catch (Throwable t) {
                throw new RuntimeException(t);
            }
            clusterInitialized = true;
        }
        Class.forName(PhoenixDriver.class.getName());
        realDriver = PhoenixDriver.INSTANCE;
        DriverManager.registerDriver(realDriver);
        if (clientProps.getBoolean(QueryServices.TRANSACTIONS_ENABLED,
                QueryServicesOptions.DEFAULT_TRANSACTIONS_ENABLED)) {
            setupTxManager();
        }
    }

    private static boolean isDistributedClusterModeEnabled(Configuration conf) {
        boolean isDistributedCluster = false;
        //check if the distributed mode was specified as a system property.
        isDistributedCluster = Boolean
                .parseBoolean(System.getProperty(IntegrationTestingUtility.IS_DISTRIBUTED_CLUSTER, "false"));
        if (!isDistributedCluster) {
            //fall back on hbase-default.xml or hbase-site.xml to check for distributed mode              
            isDistributedCluster = conf.getBoolean(IntegrationTestingUtility.IS_DISTRIBUTED_CLUSTER, false);
        }
        return isDistributedCluster;
    }

    /**
     * Initialize the mini cluster using phoenix-test specific configuration.
     * @param overrideProps TODO
     * @return url to be used by clients to connect to the mini cluster.
     */
    private static String initMiniCluster(Configuration conf, ReadOnlyProps overrideProps) {
        setUpConfigForMiniCluster(conf, overrideProps);
        utility = new HBaseTestingUtility(conf);
        try {
            utility.startMiniCluster(NUM_SLAVES_BASE);
            return getLocalClusterUrl(utility);
        } catch (Throwable t) {
            throw new RuntimeException(t);
        }
    }

    protected static String getLocalClusterUrl(HBaseTestingUtility util) throws Exception {
        String url = QueryUtil.getConnectionUrl(new Properties(), util.getConfiguration());
        return url + PHOENIX_TEST_DRIVER_URL_PARAM;
    }

    /**
     * Initialize the cluster in distributed mode
     * @param overrideProps TODO
     * @return url to be used by clients to connect to the mini cluster.
     */
    private static String initClusterDistributedMode(Configuration conf, ReadOnlyProps overrideProps) {
        setTestConfigForDistribuedCluster(conf, overrideProps);
        try {
            IntegrationTestingUtility util = new IntegrationTestingUtility(conf);
            utility = util;
            util.initializeCluster(NUM_SLAVES_BASE);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
        return JDBC_PROTOCOL + JDBC_PROTOCOL_TERMINATOR + PHOENIX_TEST_DRIVER_URL_PARAM;
    }

    private static void setTestConfigForDistribuedCluster(Configuration conf, ReadOnlyProps overrideProps) {
        setDefaultTestConfig(conf, overrideProps);
    }

    private static void setDefaultTestConfig(Configuration conf, ReadOnlyProps overrideProps) {
        ConfigUtil.setReplicationConfigIfAbsent(conf);
        QueryServices services = new PhoenixTestDriver().getQueryServices();
        for (Entry<String, String> entry : services.getProps()) {
            conf.set(entry.getKey(), entry.getValue());
        }
        //no point doing sanity checks when running tests.
        conf.setBoolean("hbase.table.sanity.checks", false);
        // set the server rpc controller and rpc scheduler factory, used to configure the cluster
        conf.set(RpcControllerFactory.CUSTOM_CONTROLLER_CONF_KEY, DEFAULT_SERVER_RPC_CONTROLLER_FACTORY);
        conf.set(RSRpcServices.REGION_SERVER_RPC_SCHEDULER_FACTORY_CLASS, DEFAULT_RPC_SCHEDULER_FACTORY);

        // override any defaults based on overrideProps
        for (Entry<String, String> entry : overrideProps) {
            conf.set(entry.getKey(), entry.getValue());
        }
    }

    public static Configuration setUpConfigForMiniCluster(Configuration conf) {
        return setUpConfigForMiniCluster(conf, ReadOnlyProps.EMPTY_PROPS);
    }

    public static Configuration setUpConfigForMiniCluster(Configuration conf, ReadOnlyProps overrideProps) {
        assertNotNull(conf);
        setDefaultTestConfig(conf, overrideProps);
        /*
         * The default configuration of mini cluster ends up spawning a lot of threads
         * that are not really needed by phoenix for test purposes. Limiting these threads
         * helps us in running several mini clusters at the same time without hitting 
         * the threads limit imposed by the OS. 
         */
        conf.setInt(HConstants.REGION_SERVER_HANDLER_COUNT, 5);
        conf.setInt("hbase.regionserver.metahandler.count", 2);
        conf.setInt(HConstants.MASTER_HANDLER_COUNT, 2);
        conf.setInt("dfs.namenode.handler.count", 2);
        conf.setInt("dfs.namenode.service.handler.count", 2);
        conf.setInt("dfs.datanode.handler.count", 2);
        conf.setInt("ipc.server.read.threadpool.size", 2);
        conf.setInt("ipc.server.handler.threadpool.size", 2);
        conf.setInt("hbase.regionserver.hlog.syncer.count", 2);
        conf.setInt("hbase.hlog.asyncer.number", 2);
        conf.setInt("hbase.assignment.zkevent.workers", 5);
        conf.setInt("hbase.assignment.threads.max", 5);
        conf.setInt("hbase.catalogjanitor.interval", 5000);
        return conf;
    }

    /**
     * Create a {@link PhoenixTestDriver} and register it.
     * @return an initialized and registered {@link PhoenixTestDriver} 
     */
    public static PhoenixTestDriver initAndRegisterTestDriver(String url, ReadOnlyProps props) throws Exception {
        PhoenixTestDriver newDriver = new PhoenixTestDriver(props);
        DriverManager.registerDriver(newDriver);
        Driver oldDriver = DriverManager.getDriver(url);
        if (oldDriver != newDriver) {
            destroyDriver(oldDriver);
        }
        Properties driverProps = PropertiesUtil.deepCopy(TEST_PROPERTIES);
        Connection conn = newDriver.connect(url, driverProps);
        conn.close();
        return newDriver;
    }

    //Close and unregister the driver.
    protected static boolean destroyDriver(Driver driver) {
        if (driver != null) {
            assert (driver instanceof PhoenixEmbeddedDriver);
            PhoenixEmbeddedDriver pdriver = (PhoenixEmbeddedDriver) driver;
            try {
                try {
                    pdriver.close();
                    return true;
                } finally {
                    DriverManager.deregisterDriver(driver);
                }
            } catch (Exception e) {
                logger.warn("Unable to close registered driver: " + driver, e);
            }
        }
        return false;
    }

    protected static String getOrganizationId() {
        return ORG_ID;
    }

    private static long timestamp;

    public static long nextTimestamp() {
        timestamp += 100;
        return timestamp;
    }

    protected static void ensureTableCreated(String url, String tableName) throws SQLException {
        ensureTableCreated(url, tableName, null, null);
    }

    public static void ensureTableCreated(String url, String tableName, byte[][] splits) throws SQLException {
        ensureTableCreated(url, tableName, splits, null);
    }

    protected static void ensureTableCreated(String url, String tableName, Long ts) throws SQLException {
        ensureTableCreated(url, tableName, null, ts);
    }

    protected static void ensureTableCreated(String url, String tableName, byte[][] splits, Long ts)
            throws SQLException {
        String ddl = tableDDLMap.get(tableName);
        createSchema(url, tableName, ts);
        createTestTable(url, ddl, splits, ts);
    }

    protected static String generateRandomString() {
        return RandomStringUtils.randomAlphabetic(20).toUpperCase();
    }

    protected static void createTestTable(String url, String ddl) throws SQLException {
        createTestTable(url, ddl, null, null);
    }

    protected static void createTestTable(String url, String ddl, byte[][] splits, Long ts) throws SQLException {
        createTestTable(url, ddl, splits, ts, true);
    }

    public static void createSchema(String url, String tableName, Long ts) throws SQLException {
        String schema = SchemaUtil.getSchemaNameFromFullName(tableName);
        if (!schema.equals("")) {
            Properties props = new Properties();
            if (ts != null) {
                props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts));
            }
            try (Connection conn = DriverManager.getConnection(url, props);) {
                if (SchemaUtil.isNamespaceMappingEnabled(null,
                        conn.unwrap(PhoenixConnection.class).getQueryServices().getProps())) {
                    conn.createStatement().executeUpdate("CREATE SCHEMA IF NOT EXISTS " + schema);
                }
            }
        }
    }

    protected static void createTestTable(String url, String ddl, byte[][] splits, Long ts,
            boolean swallowTableAlreadyExistsException) throws SQLException {
        assertNotNull(ddl);
        StringBuilder buf = new StringBuilder(ddl);
        if (splits != null) {
            buf.append(" SPLIT ON (");
            for (int i = 0; i < splits.length; i++) {
                buf.append("?,");
            }
            buf.setCharAt(buf.length() - 1, ')');
        }
        ddl = buf.toString();
        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(PhoenixRuntime.CURRENT_SCN_ATTRIB, Long.toString(ts));
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            PreparedStatement stmt = conn.prepareStatement(ddl);
            if (splits != null) {
                for (int i = 0; i < splits.length; i++) {
                    stmt.setBytes(i + 1, splits[i]);
                }
            }
            stmt.execute(ddl);
        } catch (TableAlreadyExistsException e) {
            if (!swallowTableAlreadyExistsException) {
                throw e;
            }
        } finally {
            conn.close();
        }
    }

    protected static byte[][] getDefaultSplits(String tenantId) {
        return new byte[][] { Bytes.toBytes(tenantId + "00A"), Bytes.toBytes(tenantId + "00B"),
                Bytes.toBytes(tenantId + "00C"), };
    }

    private static void deletePriorSchemas(long ts, String url) throws Exception {
        Properties props = new Properties();
        props.put(QueryServices.QUEUE_SIZE_ATTRIB, Integer.toString(1024));
        if (ts != HConstants.LATEST_TIMESTAMP) {
            props.setProperty(CURRENT_SCN_ATTRIB, Long.toString(ts));
        }
        try (Connection conn = DriverManager.getConnection(url, props)) {
            DatabaseMetaData dbmd = conn.getMetaData();
            ResultSet rs = dbmd.getSchemas();
            while (rs.next()) {
                String schemaName = rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM);
                if (schemaName.equals(PhoenixDatabaseMetaData.SYSTEM_SCHEMA_NAME)) {
                    continue;
                }
                schemaName = SchemaUtil.getEscapedArgument(schemaName);

                String ddl = "DROP SCHEMA " + schemaName;
                conn.createStatement().executeUpdate(ddl);
            }
            rs.close();
        }
        // Make sure all schemas have been dropped
        props.remove(CURRENT_SCN_ATTRIB);
        try (Connection seeLatestConn = DriverManager.getConnection(url, props)) {
            DatabaseMetaData dbmd = seeLatestConn.getMetaData();
            ResultSet rs = dbmd.getSchemas();
            boolean hasSchemas = rs.next();
            if (hasSchemas) {
                String schemaName = rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM);
                if (schemaName.equals(PhoenixDatabaseMetaData.SYSTEM_SCHEMA_NAME)) {
                    hasSchemas = rs.next();
                }
            }
            if (hasSchemas) {
                fail("The following schemas are not dropped that should be:" + getSchemaNames(rs));
            }
        }
    }

    protected static void deletePriorMetaData(long ts, String url) throws Exception {
        deletePriorTables(ts, url);
        if (ts != HConstants.LATEST_TIMESTAMP) {
            ts = nextTimestamp() - 1;
        }
        deletePriorSchemas(ts, url);
    }

    private static void deletePriorTables(long ts, String url) throws Exception {
        deletePriorTables(ts, (String) null, url);
    }

    private static void deletePriorTables(long ts, String tenantId, String url) throws Exception {
        Properties props = new Properties();
        props.put(QueryServices.QUEUE_SIZE_ATTRIB, Integer.toString(1024));
        if (ts != HConstants.LATEST_TIMESTAMP) {
            props.setProperty(CURRENT_SCN_ATTRIB, Long.toString(ts));
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            deletePriorTables(ts, conn, url);
            deletePriorSequences(ts, conn);

            // Make sure all tables and views have been dropped
            props.remove(CURRENT_SCN_ATTRIB);
            try (Connection seeLatestConn = DriverManager.getConnection(url, props)) {
                DatabaseMetaData dbmd = seeLatestConn.getMetaData();
                ResultSet rs = dbmd.getTables(null, null, null,
                        new String[] { PTableType.VIEW.toString(), PTableType.TABLE.toString() });
                boolean hasTables = rs.next();
                if (hasTables) {
                    fail("The following tables are not deleted that should be:" + getTableNames(rs));
                }
            }
        } finally {
            conn.close();
        }
    }

    private static void deletePriorTables(long ts, Connection globalConn, String url) throws Exception {
        DatabaseMetaData dbmd = globalConn.getMetaData();
        // Drop VIEWs first, as we don't allow a TABLE with views to be dropped
        // Tables are sorted by TENANT_ID
        List<String[]> tableTypesList = Arrays.asList(new String[] { PTableType.VIEW.toString() },
                new String[] { PTableType.TABLE.toString() });
        for (String[] tableTypes : tableTypesList) {
            ResultSet rs = dbmd.getTables(null, null, null, tableTypes);
            String lastTenantId = null;
            Connection conn = globalConn;
            while (rs.next()) {
                String fullTableName = SchemaUtil.getEscapedTableName(
                        rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM),
                        rs.getString(PhoenixDatabaseMetaData.TABLE_NAME));
                String ddl = "DROP " + rs.getString(PhoenixDatabaseMetaData.TABLE_TYPE) + " " + fullTableName;
                String tenantId = rs.getString(1);
                if (tenantId != null && !tenantId.equals(lastTenantId)) {
                    if (lastTenantId != null) {
                        conn.close();
                    }
                    // Open tenant-specific connection when we find a new one
                    Properties props = PropertiesUtil.deepCopy(globalConn.getClientInfo());
                    props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId);
                    conn = DriverManager.getConnection(url, props);
                    lastTenantId = tenantId;
                }
                try {
                    conn.createStatement().executeUpdate(ddl);
                } catch (NewerTableAlreadyExistsException ex) {
                    logger.info("Newer table " + fullTableName
                            + " or its delete marker exists. Ignore current deletion");
                } catch (TableNotFoundException ex) {
                    logger.info("Table " + fullTableName + " is already deleted.");
                }
            }
            rs.close();
            if (lastTenantId != null) {
                conn.close();
            }
        }
    }

    private static String getTableNames(ResultSet rs) throws SQLException {
        StringBuilder buf = new StringBuilder();
        do {
            buf.append(" ");
            buf.append(SchemaUtil.getTableName(rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM),
                    rs.getString(PhoenixDatabaseMetaData.TABLE_NAME)));
        } while (rs.next());
        return buf.toString();
    }

    private static String getSchemaNames(ResultSet rs) throws SQLException {
        StringBuilder buf = new StringBuilder();
        do {
            buf.append(" ");
            buf.append(rs.getString(PhoenixDatabaseMetaData.TABLE_SCHEM));
        } while (rs.next());
        return buf.toString();
    }

    private static void deletePriorSequences(long ts, Connection globalConn) throws Exception {
        // TODO: drop tenant-specific sequences too
        ResultSet rs = globalConn.createStatement()
                .executeQuery("SELECT " + PhoenixDatabaseMetaData.TENANT_ID + ","
                        + PhoenixDatabaseMetaData.SEQUENCE_SCHEMA + "," + PhoenixDatabaseMetaData.SEQUENCE_NAME
                        + " FROM " + PhoenixDatabaseMetaData.SYSTEM_SEQUENCE);
        String lastTenantId = null;
        Connection conn = globalConn;
        while (rs.next()) {
            String tenantId = rs.getString(1);
            if (tenantId != null && !tenantId.equals(lastTenantId)) {
                if (lastTenantId != null) {
                    conn.close();
                }
                // Open tenant-specific connection when we find a new one
                Properties props = new Properties(globalConn.getClientInfo());
                props.setProperty(PhoenixRuntime.TENANT_ID_ATTRIB, tenantId);
                conn = DriverManager.getConnection(url, props);
                lastTenantId = tenantId;
            }

            logger.info("DROP SEQUENCE STATEMENT: DROP SEQUENCE "
                    + SchemaUtil.getEscapedTableName(rs.getString(2), rs.getString(3)));
            conn.createStatement()
                    .execute("DROP SEQUENCE " + SchemaUtil.getEscapedTableName(rs.getString(2), rs.getString(3)));
        }
        rs.close();
    }

    protected static void initSumDoubleValues(byte[][] splits, String url) throws Exception {
        ensureTableCreated(url, "SumDoubleTest", splits);
        Properties props = new Properties();
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement("upsert into " + "SumDoubleTest(" + "    id, "
                    + "    d, " + "    f, " + "    ud, " + "    uf) " + "VALUES (?, ?, ?, ?, ?)");
            stmt.setString(1, "1");
            stmt.setDouble(2, 0.001);
            stmt.setFloat(3, 0.01f);
            stmt.setDouble(4, 0.001);
            stmt.setFloat(5, 0.01f);
            stmt.execute();

            stmt.setString(1, "2");
            stmt.setDouble(2, 0.002);
            stmt.setFloat(3, 0.02f);
            stmt.setDouble(4, 0.002);
            stmt.setFloat(5, 0.02f);
            stmt.execute();

            stmt.setString(1, "3");
            stmt.setDouble(2, 0.003);
            stmt.setFloat(3, 0.03f);
            stmt.setDouble(4, 0.003);
            stmt.setFloat(5, 0.03f);
            stmt.execute();

            stmt.setString(1, "4");
            stmt.setDouble(2, 0.004);
            stmt.setFloat(3, 0.04f);
            stmt.setDouble(4, 0.004);
            stmt.setFloat(5, 0.04f);
            stmt.execute();

            stmt.setString(1, "5");
            stmt.setDouble(2, 0.005);
            stmt.setFloat(3, 0.05f);
            stmt.setDouble(4, 0.005);
            stmt.setFloat(5, 0.05f);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initATableValues(String tenantId, byte[][] splits, String url) throws Exception {
        initATableValues(tenantId, splits, null, url);
    }

    protected static void initATableValues(String tenantId, byte[][] splits, Date date, String url)
            throws Exception {
        initATableValues(tenantId, splits, date, null, url);
    }

    protected static void initATableValues(String tenantId, byte[][] splits, Date date, Long ts, String url)
            throws Exception {
        if (ts == null) {
            ensureTableCreated(url, ATABLE_NAME, splits);
        } else {
            ensureTableCreated(url, ATABLE_NAME, splits, ts - 5);
        }

        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, Long.toString(ts - 3));
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement("upsert into " + "ATABLE(" + "    ORGANIZATION_ID, "
                    + "    ENTITY_ID, " + "    A_STRING, " + "    B_STRING, " + "    A_INTEGER, " + "    A_DATE, "
                    + "    X_DECIMAL, " + "    X_LONG, " + "    X_INTEGER," + "    Y_INTEGER," + "    A_BYTE,"
                    + "    A_SHORT," + "    A_FLOAT," + "    A_DOUBLE," + "    A_UNSIGNED_FLOAT,"
                    + "    A_UNSIGNED_DOUBLE)" + "VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)");
            stmt.setString(1, tenantId);
            stmt.setString(2, ROW1);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, B_VALUE);
            stmt.setInt(5, 1);
            stmt.setDate(6, date);
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 1);
            stmt.setShort(12, (short) 128);
            stmt.setFloat(13, 0.01f);
            stmt.setDouble(14, 0.0001);
            stmt.setFloat(15, 0.01f);
            stmt.setDouble(16, 0.0001);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW2);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, C_VALUE);
            stmt.setInt(5, 2);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 1));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 2);
            stmt.setShort(12, (short) 129);
            stmt.setFloat(13, 0.02f);
            stmt.setDouble(14, 0.0002);
            stmt.setFloat(15, 0.02f);
            stmt.setDouble(16, 0.0002);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW3);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, E_VALUE);
            stmt.setInt(5, 3);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 2));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 3);
            stmt.setShort(12, (short) 130);
            stmt.setFloat(13, 0.03f);
            stmt.setDouble(14, 0.0003);
            stmt.setFloat(15, 0.03f);
            stmt.setDouble(16, 0.0003);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW4);
            stmt.setString(3, A_VALUE);
            stmt.setString(4, B_VALUE);
            stmt.setInt(5, 4);
            stmt.setDate(6, date == null ? null : date);
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 4);
            stmt.setShort(12, (short) 131);
            stmt.setFloat(13, 0.04f);
            stmt.setDouble(14, 0.0004);
            stmt.setFloat(15, 0.04f);
            stmt.setDouble(16, 0.0004);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW5);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, C_VALUE);
            stmt.setInt(5, 5);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 1));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 5);
            stmt.setShort(12, (short) 132);
            stmt.setFloat(13, 0.05f);
            stmt.setDouble(14, 0.0005);
            stmt.setFloat(15, 0.05f);
            stmt.setDouble(16, 0.0005);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW6);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, E_VALUE);
            stmt.setInt(5, 6);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 2));
            stmt.setBigDecimal(7, null);
            stmt.setNull(8, Types.BIGINT);
            stmt.setNull(9, Types.INTEGER);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 6);
            stmt.setShort(12, (short) 133);
            stmt.setFloat(13, 0.06f);
            stmt.setDouble(14, 0.0006);
            stmt.setFloat(15, 0.06f);
            stmt.setDouble(16, 0.0006);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW7);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, B_VALUE);
            stmt.setInt(5, 7);
            stmt.setDate(6, date == null ? null : date);
            stmt.setBigDecimal(7, BigDecimal.valueOf(0.1));
            stmt.setLong(8, 5L);
            stmt.setInt(9, 5);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 7);
            stmt.setShort(12, (short) 134);
            stmt.setFloat(13, 0.07f);
            stmt.setDouble(14, 0.0007);
            stmt.setFloat(15, 0.07f);
            stmt.setDouble(16, 0.0007);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW8);
            stmt.setString(3, B_VALUE);
            stmt.setString(4, C_VALUE);
            stmt.setInt(5, 8);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 1));
            stmt.setBigDecimal(7, BigDecimal.valueOf(3.9));
            long l = Integer.MIN_VALUE - 1L;
            assert (l < Integer.MIN_VALUE);
            stmt.setLong(8, l);
            stmt.setInt(9, 4);
            stmt.setNull(10, Types.INTEGER);
            stmt.setByte(11, (byte) 8);
            stmt.setShort(12, (short) 135);
            stmt.setFloat(13, 0.08f);
            stmt.setDouble(14, 0.0008);
            stmt.setFloat(15, 0.08f);
            stmt.setDouble(16, 0.0008);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, ROW9);
            stmt.setString(3, C_VALUE);
            stmt.setString(4, E_VALUE);
            stmt.setInt(5, 9);
            stmt.setDate(6, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY * 2));
            stmt.setBigDecimal(7, BigDecimal.valueOf(3.3));
            l = Integer.MAX_VALUE + 1L;
            assert (l > Integer.MAX_VALUE);
            stmt.setLong(8, l);
            stmt.setInt(9, 3);
            stmt.setInt(10, 300);
            stmt.setByte(11, (byte) 9);
            stmt.setShort(12, (short) 0);
            stmt.setFloat(13, 0.09f);
            stmt.setDouble(14, 0.0009);
            stmt.setFloat(15, 0.09f);
            stmt.setDouble(16, 0.0009);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initATableValues(String tenantId, byte[][] splits, Date date, Long ts) throws Exception {
        initATableValues(tenantId, splits, date, ts, getUrl());
    }

    protected static void initEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts)
            throws Exception {
        initEntityHistoryTableValues(tenantId, splits, date, ts, getUrl());
    }

    protected static void initSaltedEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts)
            throws Exception {
        initSaltedEntityHistoryTableValues(tenantId, splits, date, ts, getUrl());
    }

    protected static void initEntityHistoryTableValues(String tenantId, byte[][] splits, String url)
            throws Exception {
        initEntityHistoryTableValues(tenantId, splits, null, null, url);
    }

    protected static void initEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, String url)
            throws Exception {
        initEntityHistoryTableValues(tenantId, splits, date, null, url);
    }

    private static void initEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts,
            String url) throws Exception {
        if (ts == null) {
            ensureTableCreated(url, ENTITY_HISTORY_TABLE_NAME, splits);
        } else {
            ensureTableCreated(url, ENTITY_HISTORY_TABLE_NAME, splits, ts - 2);
        }

        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, ts.toString());
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement("upsert into " + ENTITY_HISTORY_TABLE_NAME + "("
                    + "    ORGANIZATION_ID, " + "    PARENT_ID, " + "    CREATED_DATE, " + "    ENTITY_HISTORY_ID, "
                    + "    OLD_VALUE, " + "    NEW_VALUE) " + "VALUES (?, ?, ?, ?, ?, ?)");
            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID1);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID1);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID2);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID2);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID3);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID3);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID4);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID4);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID5);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID5);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID6);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID6);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID7);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID7);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID8);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID8);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID9);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID9);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initSaltedEntityHistoryTableValues(String tenantId, byte[][] splits, Date date, Long ts,
            String url) throws Exception {
        if (ts == null) {
            ensureTableCreated(url, ENTITY_HISTORY_SALTED_TABLE_NAME, splits);
        } else {
            ensureTableCreated(url, ENTITY_HISTORY_SALTED_TABLE_NAME, splits, ts - 2);
        }

        Properties props = new Properties();
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, ts.toString());
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            // Insert all rows at ts
            PreparedStatement stmt = conn.prepareStatement("upsert into " + ENTITY_HISTORY_SALTED_TABLE_NAME + "("
                    + "    ORGANIZATION_ID, " + "    PARENT_ID, " + "    CREATED_DATE, " + "    ENTITY_HISTORY_ID, "
                    + "    OLD_VALUE, " + "    NEW_VALUE) " + "VALUES (?, ?, ?, ?, ?, ?)");
            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID1);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID1);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID2);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID2);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID3);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID3);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID4);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID4);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID5);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID5);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID6);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID6);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID7);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID7);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID8);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID8);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            stmt.setString(1, tenantId);
            stmt.setString(2, PARENTID9);
            stmt.setDate(3, date);
            stmt.setString(4, ENTITYHISTID9);
            stmt.setString(5, A_VALUE);
            stmt.setString(6, B_VALUE);
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    protected static void initJoinTableValues(String url, byte[][] splits, Long ts) throws Exception {
        if (ts == null) {
            ensureTableCreated(url, JOIN_CUSTOMER_TABLE_FULL_NAME, splits);
            ensureTableCreated(url, JOIN_ITEM_TABLE_FULL_NAME, splits);
            ensureTableCreated(url, JOIN_SUPPLIER_TABLE_FULL_NAME, splits);
            ensureTableCreated(url, JOIN_ORDER_TABLE_FULL_NAME, splits);
        } else {
            ensureTableCreated(url, JOIN_CUSTOMER_TABLE_FULL_NAME, splits, ts - 2);
            ensureTableCreated(url, JOIN_ITEM_TABLE_FULL_NAME, splits, ts - 2);
            ensureTableCreated(url, JOIN_SUPPLIER_TABLE_FULL_NAME, splits, ts - 2);
            ensureTableCreated(url, JOIN_ORDER_TABLE_FULL_NAME, splits, ts - 2);
        }

        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
        if (ts != null) {
            props.setProperty(CURRENT_SCN_ATTRIB, ts.toString());
        }
        Connection conn = DriverManager.getConnection(url, props);
        try {
            conn.createStatement().execute("CREATE SEQUENCE my.seq");
            // Insert into customer table
            PreparedStatement stmt = conn.prepareStatement("upsert into " + JOIN_CUSTOMER_TABLE_FULL_NAME
                    + "   (\"customer_id\", " + "    NAME, " + "    PHONE, " + "    ADDRESS, " + "    LOC_ID, "
                    + "    DATE) " + "values (?, ?, ?, ?, ?, ?)");
            stmt.setString(1, "0000000001");
            stmt.setString(2, "C1");
            stmt.setString(3, "999-999-1111");
            stmt.setString(4, "101 XXX Street");
            stmt.setString(5, "10001");
            stmt.setDate(6, new Date(format.parse("2013-11-01 10:20:36").getTime()));
            stmt.execute();

            stmt.setString(1, "0000000002");
            stmt.setString(2, "C2");
            stmt.setString(3, "999-999-2222");
            stmt.setString(4, "202 XXX Street");
            stmt.setString(5, null);
            stmt.setDate(6, new Date(format.parse("2013-11-25 16:45:07").getTime()));
            stmt.execute();

            stmt.setString(1, "0000000003");
            stmt.setString(2, "C3");
            stmt.setString(3, "999-999-3333");
            stmt.setString(4, "303 XXX Street");
            stmt.setString(5, null);
            stmt.setDate(6, new Date(format.parse("2013-11-25 10:06:29").getTime()));
            stmt.execute();

            stmt.setString(1, "0000000004");
            stmt.setString(2, "C4");
            stmt.setString(3, "999-999-4444");
            stmt.setString(4, "404 XXX Street");
            stmt.setString(5, "10004");
            stmt.setDate(6, new Date(format.parse("2013-11-22 14:22:56").getTime()));
            stmt.execute();

            stmt.setString(1, "0000000005");
            stmt.setString(2, "C5");
            stmt.setString(3, "999-999-5555");
            stmt.setString(4, "505 XXX Street");
            stmt.setString(5, "10005");
            stmt.setDate(6, new Date(format.parse("2013-11-27 09:37:50").getTime()));
            stmt.execute();

            stmt.setString(1, "0000000006");
            stmt.setString(2, "C6");
            stmt.setString(3, "999-999-6666");
            stmt.setString(4, "606 XXX Street");
            stmt.setString(5, "10001");
            stmt.setDate(6, new Date(format.parse("2013-11-01 10:20:36").getTime()));
            stmt.execute();

            // Insert into item table
            stmt = conn.prepareStatement("upsert into " + JOIN_ITEM_TABLE_FULL_NAME + "   (\"item_id\", "
                    + "    NAME, " + "    PRICE, " + "    DISCOUNT1, " + "    DISCOUNT2, " + "    \"supplier_id\", "
                    + "    DESCRIPTION) " + "values (?, ?, ?, ?, ?, ?, ?)");
            stmt.setString(1, "0000000001");
            stmt.setString(2, "T1");
            stmt.setInt(3, 100);
            stmt.setInt(4, 5);
            stmt.setInt(5, 10);
            stmt.setString(6, "0000000001");
            stmt.setString(7, "Item T1");
            stmt.execute();

            stmt.setString(1, "0000000002");
            stmt.setString(2, "T2");
            stmt.setInt(3, 200);
            stmt.setInt(4, 5);
            stmt.setInt(5, 8);
            stmt.setString(6, "0000000001");
            stmt.setString(7, "Item T2");
            stmt.execute();

            stmt.setString(1, "0000000003");
            stmt.setString(2, "T3");
            stmt.setInt(3, 300);
            stmt.setInt(4, 8);
            stmt.setInt(5, 12);
            stmt.setString(6, "0000000002");
            stmt.setString(7, "Item T3");
            stmt.execute();

            stmt.setString(1, "0000000004");
            stmt.setString(2, "T4");
            stmt.setInt(3, 400);
            stmt.setInt(4, 6);
            stmt.setInt(5, 10);
            stmt.setString(6, "0000000002");
            stmt.setString(7, "Item T4");
            stmt.execute();

            stmt.setString(1, "0000000005");
            stmt.setString(2, "T5");
            stmt.setInt(3, 500);
            stmt.setInt(4, 8);
            stmt.setInt(5, 15);
            stmt.setString(6, "0000000005");
            stmt.setString(7, "Item T5");
            stmt.execute();

            stmt.setString(1, "0000000006");
            stmt.setString(2, "T6");
            stmt.setInt(3, 600);
            stmt.setInt(4, 8);
            stmt.setInt(5, 15);
            stmt.setString(6, "0000000006");
            stmt.setString(7, "Item T6");
            stmt.execute();

            stmt.setString(1, "invalid001");
            stmt.setString(2, "INVALID-1");
            stmt.setInt(3, 0);
            stmt.setInt(4, 0);
            stmt.setInt(5, 0);
            stmt.setString(6, "0000000000");
            stmt.setString(7, "Invalid item for join test");
            stmt.execute();

            // Insert into supplier table
            stmt = conn.prepareStatement("upsert into " + JOIN_SUPPLIER_TABLE_FULL_NAME + "   (\"supplier_id\", "
                    + "    NAME, " + "    PHONE, " + "    ADDRESS, " + "    LOC_ID) " + "values (?, ?, ?, ?, ?)");
            stmt.setString(1, "0000000001");
            stmt.setString(2, "S1");
            stmt.setString(3, "888-888-1111");
            stmt.setString(4, "101 YYY Street");
            stmt.setString(5, "10001");
            stmt.execute();

            stmt.setString(1, "0000000002");
            stmt.setString(2, "S2");
            stmt.setString(3, "888-888-2222");
            stmt.setString(4, "202 YYY Street");
            stmt.setString(5, "10002");
            stmt.execute();

            stmt.setString(1, "0000000003");
            stmt.setString(2, "S3");
            stmt.setString(3, "888-888-3333");
            stmt.setString(4, "303 YYY Street");
            stmt.setString(5, null);
            stmt.execute();

            stmt.setString(1, "0000000004");
            stmt.setString(2, "S4");
            stmt.setString(3, "888-888-4444");
            stmt.setString(4, "404 YYY Street");
            stmt.setString(5, null);
            stmt.execute();

            stmt.setString(1, "0000000005");
            stmt.setString(2, "S5");
            stmt.setString(3, "888-888-5555");
            stmt.setString(4, "505 YYY Street");
            stmt.setString(5, "10005");
            stmt.execute();

            stmt.setString(1, "0000000006");
            stmt.setString(2, "S6");
            stmt.setString(3, "888-888-6666");
            stmt.setString(4, "606 YYY Street");
            stmt.setString(5, "10006");
            stmt.execute();

            // Insert into order table
            stmt = conn.prepareStatement("upsert into " + JOIN_ORDER_TABLE_FULL_NAME + "   (\"order_id\", "
                    + "    \"customer_id\", " + "    \"item_id\", " + "    PRICE, " + "    QUANTITY," + "    DATE) "
                    + "values (?, ?, ?, ?, ?, ?)");
            stmt.setString(1, "000000000000001");
            stmt.setString(2, "0000000004");
            stmt.setString(3, "0000000001");
            stmt.setInt(4, 100);
            stmt.setInt(5, 1000);
            stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-22 14:22:56").getTime()));
            stmt.execute();

            stmt.setString(1, "000000000000002");
            stmt.setString(2, "0000000003");
            stmt.setString(3, "0000000006");
            stmt.setInt(4, 552);
            stmt.setInt(5, 2000);
            stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-25 10:06:29").getTime()));
            stmt.execute();

            stmt.setString(1, "000000000000003");
            stmt.setString(2, "0000000002");
            stmt.setString(3, "0000000002");
            stmt.setInt(4, 190);
            stmt.setInt(5, 3000);
            stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-25 16:45:07").getTime()));
            stmt.execute();

            stmt.setString(1, "000000000000004");
            stmt.setString(2, "0000000004");
            stmt.setString(3, "0000000006");
            stmt.setInt(4, 510);
            stmt.setInt(5, 4000);
            stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-26 13:26:04").getTime()));
            stmt.execute();

            stmt.setString(1, "000000000000005");
            stmt.setString(2, "0000000005");
            stmt.setString(3, "0000000003");
            stmt.setInt(4, 264);
            stmt.setInt(5, 5000);
            stmt.setTimestamp(6, new Timestamp(format.parse("2013-11-27 09:37:50").getTime()));
            stmt.execute();

            conn.commit();
        } finally {
            conn.close();
        }
    }

    /**
     * Disable and drop all the tables except SYSTEM.CATALOG and SYSTEM.SEQUENCE
     */
    private static void disableAndDropNonSystemTables() throws Exception {
        if (driver == null)
            return;
        HBaseAdmin admin = driver.getConnectionQueryServices(null, null).getAdmin();
        try {
            HTableDescriptor[] tables = admin.listTables();
            for (HTableDescriptor table : tables) {
                String schemaName = SchemaUtil.getSchemaNameFromFullName(table.getName());
                if (!QueryConstants.SYSTEM_SCHEMA_NAME.equals(schemaName)) {
                    disableAndDropTable(admin, table.getTableName());
                }
            }
        } finally {
            admin.close();
        }
    }

    private static void disableAndDropTable(final HBaseAdmin admin, final TableName tableName) throws Exception {
        Future<Void> future = null;
        boolean success = false;
        try {
            try {
                future = dropHTableService.submit(new Callable<Void>() {
                    @Override
                    public Void call() throws Exception {
                        if (admin.isTableEnabled(tableName)) {
                            admin.disableTable(tableName);
                            admin.deleteTable(tableName);
                        }
                        return null;
                    }
                });
                future.get(dropTableTimeout, TimeUnit.SECONDS);
                success = true;
            } catch (TimeoutException e) {
                throw new SQLExceptionInfo.Builder(SQLExceptionCode.OPERATION_TIMED_OUT)
                        .setMessage("Not able to disable and delete table " + tableName.getNameAsString() + " in "
                                + dropTableTimeout + " seconds.")
                        .build().buildException();
            } catch (Exception e) {
                throw e;
            }
        } finally {
            if (future != null && !success) {
                future.cancel(true);
            }
        }
    }

    public static void assertOneOfValuesEqualsResultSet(ResultSet rs, List<List<Object>>... expectedResultsArray)
            throws SQLException {
        List<List<Object>> results = Lists.newArrayList();
        while (rs.next()) {
            List<Object> result = Lists.newArrayList();
            for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
                result.add(rs.getObject(i + 1));
            }
            results.add(result);
        }
        for (int j = 0; j < expectedResultsArray.length; j++) {
            List<List<Object>> expectedResults = expectedResultsArray[j];
            Set<List<Object>> expectedResultsSet = Sets.newHashSet(expectedResults);
            Iterator<List<Object>> iterator = results.iterator();
            while (iterator.hasNext()) {
                if (expectedResultsSet.contains(iterator.next())) {
                    iterator.remove();
                }
            }
        }
        if (results.isEmpty())
            return;
        fail("Unable to find " + results + " in " + Arrays.asList(expectedResultsArray));
    }

    protected void assertValueEqualsResultSet(ResultSet rs, List<Object> expectedResults) throws SQLException {
        List<List<Object>> nestedExpectedResults = Lists.newArrayListWithExpectedSize(expectedResults.size());
        for (Object expectedResult : expectedResults) {
            nestedExpectedResults.add(Arrays.asList(expectedResult));
        }
        assertValuesEqualsResultSet(rs, nestedExpectedResults);
    }

    /**
     * Asserts that we find the expected values in the result set. We don't know the order, since we don't always
     * have an order by and we're going through indexes, but we assert that each expected result occurs once as
     * expected (in any order).
     */
    public static void assertValuesEqualsResultSet(ResultSet rs, List<List<Object>> expectedResults)
            throws SQLException {
        int expectedCount = expectedResults.size();
        int count = 0;
        List<List<Object>> actualResults = Lists.newArrayList();
        List<Object> errorResult = null;
        while (rs.next() && errorResult == null) {
            List<Object> result = Lists.newArrayList();
            for (int i = 0; i < rs.getMetaData().getColumnCount(); i++) {
                result.add(rs.getObject(i + 1));
            }
            if (!expectedResults.contains(result)) {
                errorResult = result;
            }
            actualResults.add(result);
            count++;
        }
        assertTrue("Could not find " + errorResult + " in expected results: " + expectedResults
                + " with actual results: " + actualResults, errorResult == null);
        assertEquals(expectedCount, count);
    }

    public static HBaseTestingUtility getUtility() {
        return utility;
    }

    public static void upsertRows(Connection conn, String fullTableName, int numRows) throws SQLException {
        for (int i = 1; i <= numRows; ++i) {
            upsertRow(conn, fullTableName, i, false);
        }
    }

    public static void upsertRow(Connection conn, String fullTableName, int index, boolean firstRowInBatch)
            throws SQLException {
        String upsert = "UPSERT INTO " + fullTableName
                + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
        PreparedStatement stmt = conn.prepareStatement(upsert);
        stmt.setString(1, firstRowInBatch ? "firstRowInBatch_" : "" + "varchar" + index);
        stmt.setString(2, "char" + index);
        stmt.setInt(3, index);
        stmt.setLong(4, index);
        stmt.setBigDecimal(5, new BigDecimal(index));
        Date date = DateUtil.parseDate("2015-01-01 00:00:00");
        stmt.setDate(6, date);
        stmt.setString(7, "varchar_a");
        stmt.setString(8, "chara");
        stmt.setInt(9, index + 1);
        stmt.setLong(10, index + 1);
        stmt.setBigDecimal(11, new BigDecimal(index + 1));
        stmt.setDate(12, date);
        stmt.setString(13, "varchar_b");
        stmt.setString(14, "charb");
        stmt.setInt(15, index + 2);
        stmt.setLong(16, index + 2);
        stmt.setBigDecimal(17, new BigDecimal(index + 2));
        stmt.setDate(18, date);
        stmt.executeUpdate();
    }

    // Populate the test table with data.
    public static void populateTestTable(String fullTableName) throws SQLException {
        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
        try (Connection conn = DriverManager.getConnection(getUrl(), props)) {
            upsertRows(conn, fullTableName, 3);
            conn.commit();
        }
    }

    protected static void createMultiCFTestTable(String tableName, String options) throws SQLException {
        String ddl = "create table if not exists " + tableName + "(" + "   varchar_pk VARCHAR NOT NULL, "
                + "   char_pk CHAR(5) NOT NULL, " + "   int_pk INTEGER NOT NULL, " + "   long_pk BIGINT NOT NULL, "
                + "   decimal_pk DECIMAL(31, 10) NOT NULL, " + "   a.varchar_col1 VARCHAR, "
                + "   a.char_col1 CHAR(5), " + "   a.int_col1 INTEGER, " + "   a.long_col1 BIGINT, "
                + "   a.decimal_col1 DECIMAL(31, 10), " + "   b.varchar_col2 VARCHAR, " + "   b.char_col2 CHAR(5), "
                + "   b.int_col2 INTEGER, " + "   b.long_col2 BIGINT, " + "   b.decimal_col2 DECIMAL, "
                + "   b.date_col DATE "
                + "   CONSTRAINT pk PRIMARY KEY (varchar_pk, char_pk, int_pk, long_pk DESC, decimal_pk)) "
                + (options != null ? options : "");
        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
        Connection conn = DriverManager.getConnection(getUrl(), props);
        conn.createStatement().execute(ddl);
        conn.close();
    }

    // Populate the test table with data.
    protected static void populateMultiCFTestTable(String tableName) throws SQLException {
        populateMultiCFTestTable(tableName, null);
    }

    // Populate the test table with data.
    protected static void populateMultiCFTestTable(String tableName, Date date) throws SQLException {
        Properties props = PropertiesUtil.deepCopy(TEST_PROPERTIES);
        Connection conn = DriverManager.getConnection(getUrl(), props);
        try {
            String upsert = "UPSERT INTO " + tableName + " VALUES(?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
            PreparedStatement stmt = conn.prepareStatement(upsert);
            stmt.setString(1, "varchar1");
            stmt.setString(2, "char1");
            stmt.setInt(3, 1);
            stmt.setLong(4, 1L);
            stmt.setBigDecimal(5, new BigDecimal("1.1"));
            stmt.setString(6, "varchar_a");
            stmt.setString(7, "chara");
            stmt.setInt(8, 2);
            stmt.setLong(9, 2L);
            stmt.setBigDecimal(10, new BigDecimal("2.1"));
            stmt.setString(11, "varchar_b");
            stmt.setString(12, "charb");
            stmt.setInt(13, 3);
            stmt.setLong(14, 3L);
            stmt.setBigDecimal(15, new BigDecimal("3.1"));
            stmt.setDate(16, date == null ? null : new Date(date.getTime() + MILLIS_IN_DAY));
            stmt.executeUpdate();

            stmt.setString(1, "varchar2");
            stmt.setString(2, "char2");
            stmt.setInt(3, 2);
            stmt.setLong(4, 2L);
            stmt.setBigDecimal(5, new BigDecimal("2.2"));
            stmt.setString(6, "varchar_a");
            stmt.setString(7, "chara");
            stmt.setInt(8, 3);
            stmt.setLong(9, 3L);
            stmt.setBigDecimal(10, new BigDecimal("3.2"));
            stmt.setString(11, "varchar_b");
            stmt.setString(12, "charb");
            stmt.setInt(13, 4);
            stmt.setLong(14, 4L);
            stmt.setBigDecimal(15, new BigDecimal("4.2"));
            stmt.setDate(16, date);
            stmt.executeUpdate();

            stmt.setString(1, "varchar3");
            stmt.setString(2, "char3");
            stmt.setInt(3, 3);
            stmt.setLong(4, 3L);
            stmt.setBigDecimal(5, new BigDecimal("3.3"));
            stmt.setString(6, "varchar_a");
            stmt.setString(7, "chara");
            stmt.setInt(8, 4);
            stmt.setLong(9, 4L);
            stmt.setBigDecimal(10, new BigDecimal("4.3"));
            stmt.setString(11, "varchar_b");
            stmt.setString(12, "charb");
            stmt.setInt(13, 5);
            stmt.setLong(14, 5L);
            stmt.setBigDecimal(15, new BigDecimal("5.3"));
            stmt.setDate(16, date == null ? null : new Date(date.getTime() + 2 * MILLIS_IN_DAY));
            stmt.executeUpdate();

            conn.commit();
        } finally {
            conn.close();
        }
    }
}