Repository: phoenix Updated Branches: refs/heads/4.0 4cced1bf4 -> 57189d4d7
PHOENIX-1125 SQLException when connection string is of form jdbc:phoenix:localhost:1234:userName Project: http://git-wip-us.apache.org/repos/asf/phoenix/repo Commit: http://git-wip-us.apache.org/repos/asf/phoenix/commit/57189d4d Tree: http://git-wip-us.apache.org/repos/asf/phoenix/tree/57189d4d Diff: http://git-wip-us.apache.org/repos/asf/phoenix/diff/57189d4d Branch: refs/heads/4.0 Commit: 57189d4d728f40d5c08781e9ed2d13c95a3649f5 Parents: 4cced1b Author: James Taylor <jtay...@salesforce.com> Authored: Sun Jul 27 16:54:00 2014 -0700 Committer: James Taylor <jtay...@salesforce.com> Committed: Sun Jul 27 17:28:46 2014 -0700 ---------------------------------------------------------------------- .../apache/phoenix/jdbc/PhoenixConnection.java | 22 +- .../phoenix/jdbc/PhoenixDatabaseMetaData.java | 4 +- .../org/apache/phoenix/jdbc/PhoenixDriver.java | 4 +- .../phoenix/jdbc/PhoenixEmbeddedDriver.java | 160 ++++++++------ .../phoenix/query/BaseQueryServicesImpl.java | 4 +- .../phoenix/query/ConnectionQueryServices.java | 2 + .../query/ConnectionQueryServicesImpl.java | 7 + .../query/ConnectionlessQueryServicesImpl.java | 10 +- .../query/DelegateConnectionQueryServices.java | 5 + .../apache/phoenix/query/QueryServicesImpl.java | 6 +- .../phoenix/query/QueryServicesOptions.java | 4 +- .../org/apache/phoenix/util/ReadOnlyProps.java | 21 +- .../phoenix/jdbc/PhoenixEmbeddedDriverTest.java | 37 ++-- .../apache/phoenix/jdbc/PhoenixTestDriver.java | 6 +- .../java/org/apache/phoenix/query/BaseTest.java | 4 +- .../phoenix/query/ConnectionlessTest.java | 220 +++++++++++++++++++ .../phoenix/query/ConnectionlessUpsertTest.java | 183 --------------- .../phoenix/query/QueryServicesTestImpl.java | 10 +- pom.xml | 6 +- 19 files changed, 407 insertions(+), 308 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java index 2368211..609c2ba 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixConnection.java @@ -41,7 +41,12 @@ import java.sql.Savepoint; import java.sql.Statement; import java.sql.Struct; import java.text.Format; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; import java.util.concurrent.Executor; import javax.annotation.Nullable; @@ -131,7 +136,6 @@ public class PhoenixConnection implements Connection, org.apache.phoenix.jdbc.Jd this.isAutoCommit = connection.isAutoCommit; } - @SuppressWarnings("unchecked") public PhoenixConnection(ConnectionQueryServices services, String url, Properties info, PMetaData metaData) throws SQLException { this.url = url; // Copy so client cannot change @@ -148,11 +152,17 @@ public class PhoenixConnection implements Connection, org.apache.phoenix.jdbc.Jd // TODO: we could avoid creating another wrapper if the only property // specified was for the tenant ID Map<String, String> existingProps = services.getProps().asMap(); - Map<String, String> tmpAugmentedProps = Maps.newHashMapWithExpectedSize(existingProps.size() + info.size()); + final Map<String, String> tmpAugmentedProps = Maps.newHashMapWithExpectedSize(existingProps.size() + info.size()); tmpAugmentedProps.putAll(existingProps); - tmpAugmentedProps.putAll((Map)this.info); - final ReadOnlyProps augmentedProps = new ReadOnlyProps(tmpAugmentedProps); - this.services = new DelegateConnectionQueryServices(services) { + boolean needsDelegate = false; + for (Entry<Object, Object> entry : this.info.entrySet()) { + String key = entry.getKey().toString(); + String value = entry.getValue().toString(); + String oldValue = tmpAugmentedProps.put(key, value); + needsDelegate |= !Objects.equal(oldValue, value); + } + this.services = !needsDelegate ? services : new DelegateConnectionQueryServices(services) { + final ReadOnlyProps augmentedProps = new ReadOnlyProps(tmpAugmentedProps); @Override public ReadOnlyProps getProps() { http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java index 75e469c..1fabf97 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDatabaseMetaData.java @@ -59,6 +59,7 @@ import org.apache.phoenix.schema.tuple.Tuple; import org.apache.phoenix.util.ByteUtil; import org.apache.phoenix.util.KeyValueUtil; import org.apache.phoenix.util.SchemaUtil; +import org.apache.phoenix.util.StringUtil; import com.google.common.collect.Lists; @@ -915,7 +916,8 @@ public class PhoenixDatabaseMetaData implements DatabaseMetaData, org.apache.pho @Override public String getUserName() throws SQLException { - return ""; // FIXME: what should we return here? + String userName = connection.getQueryServices().getUserName(); + return userName == null ? StringUtil.EMPTY_STRING : userName; } @Override http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDriver.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDriver.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDriver.java index b305d8f..ac8f330 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDriver.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixDriver.java @@ -94,7 +94,7 @@ public final class PhoenixDriver extends PhoenixEmbeddedDriver { synchronized(this) { result = services; if(result == null) { - services = result = new QueryServicesImpl(); + services = result = new QueryServicesImpl(getDefaultProps()); } } } @@ -117,7 +117,7 @@ public final class PhoenixDriver extends PhoenixEmbeddedDriver { ConnectionQueryServices connectionQueryServices = connectionQueryServicesMap.get(normalizedConnInfo); if (connectionQueryServices == null) { if (normalizedConnInfo.isConnectionless()) { - connectionQueryServices = new ConnectionlessQueryServicesImpl(services); + connectionQueryServices = new ConnectionlessQueryServicesImpl(services, normalizedConnInfo); } else { connectionQueryServices = new ConnectionQueryServicesImpl(services, normalizedConnInfo); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java index 10c24b8..ca27075 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriver.java @@ -35,6 +35,7 @@ import org.apache.phoenix.exception.SQLExceptionInfo; import org.apache.phoenix.query.ConnectionQueryServices; import org.apache.phoenix.query.QueryServices; import org.apache.phoenix.util.PhoenixRuntime; +import org.apache.phoenix.util.PropertiesUtil; import org.apache.phoenix.util.ReadOnlyProps; import org.apache.phoenix.util.SQLCloseable; @@ -64,7 +65,18 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni public final static String MINOR_VERSION_PROP = "DriverMinorVersion"; public final static String DRIVER_NAME_PROP = "DriverName"; + private final ReadOnlyProps defaultProps; + PhoenixEmbeddedDriver() { + Map<String, String> defaultPropsMap = Maps.newHashMapWithExpectedSize(3); + defaultPropsMap.put(MAJOR_VERSION_PROP, Integer.toString(getMajorVersion())); + defaultPropsMap.put(MINOR_VERSION_PROP, Integer.toString(getMinorVersion())); + defaultPropsMap.put(DRIVER_NAME_PROP, getDriverName()); + defaultProps = new ReadOnlyProps(defaultPropsMap); + } + + protected ReadOnlyProps getDefaultProps() { + return defaultProps; } private String getDriverName() { @@ -109,11 +121,10 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni return null; } - ConnectionQueryServices connectionServices = getConnectionQueryServices(url, info); - info.setProperty(MAJOR_VERSION_PROP, Integer.toString(getMajorVersion())); - info.setProperty(MINOR_VERSION_PROP, Integer.toString(getMinorVersion())); - info.setProperty(DRIVER_NAME_PROP, getDriverName()); - PhoenixConnection connection = connectionServices.connect(url, info); + Properties augmentedInfo = PropertiesUtil.deepCopy(info); + augmentedInfo.putAll(defaultProps.asMap()); + ConnectionQueryServices connectionServices = getConnectionQueryServices(url, augmentedInfo); + PhoenixConnection connection = connectionServices.connect(url, augmentedInfo); return connection; } @@ -165,72 +176,79 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni * @since 0.1.1 */ public static class ConnectionInfo { + private static SQLException getMalFormedUrlException(String url) { + return new SQLExceptionInfo.Builder(SQLExceptionCode.MALFORMED_CONNECTION_URL) + .setMessage(url).build().buildException(); + } + + /** + * Detect url with quorum:1,quorum:2 as HBase does not handle different port numbers + * for different quorum hostnames. + * @param portStr + * @return + */ + private static boolean isMultiPortUrl(String portStr) { + int commaIndex = portStr.indexOf(','); + if (commaIndex > 0) { + try { + Integer.parseInt(portStr.substring(0, commaIndex)); + return true; + } catch (NumberFormatException otherE) { + } + } + return false; + } + protected static ConnectionInfo create(String url) throws SQLException { StringTokenizer tokenizer = new StringTokenizer(url == null ? "" : url.substring(PhoenixRuntime.JDBC_PROTOCOL.length()),DELIMITERS, true); - int i = 0; - boolean isMalformedUrl = false; + int nTokens = 0; String[] tokens = new String[5]; String token = null; - while (tokenizer.hasMoreTokens() && !(token=tokenizer.nextToken()).equals(TERMINATOR) && tokenizer.hasMoreTokens() && i < tokens.length) { + while (tokenizer.hasMoreTokens() && !(token=tokenizer.nextToken()).equals(TERMINATOR) && tokenizer.hasMoreTokens() && nTokens < tokens.length) { token = tokenizer.nextToken(); // This would mean we have an empty string for a token which is illegal if (DELIMITERS.contains(token)) { - isMalformedUrl = true; - break; + throw getMalFormedUrlException(url); } - tokens[i++] = token; + tokens[nTokens++] = token; } + if (tokenizer.hasMoreTokens() && !TERMINATOR.equals(token)) { + throw getMalFormedUrlException(url); + } + String quorum = null; Integer port = null; - if (!isMalformedUrl) { - if (tokenizer.hasMoreTokens() && !TERMINATOR.equals(token)) { - isMalformedUrl = true; - } else if (i > 1) { + String rootNode = null; + String principal = null; + String keytabFile = null; + int tokenIndex = 0; + if (nTokens > tokenIndex) { + quorum = tokens[tokenIndex++]; // Found quorum + if (nTokens > tokenIndex) { try { - port = Integer.parseInt(tokens[1]); - isMalformedUrl = port < 0; - if(i == 4){ - if(!tokens[2].endsWith(".keytab")){ - isMalformedUrl = true; - } - tokens[4] = tokens[3]; - tokens[3] = tokens[2]; - tokens[2] = null; + port = Integer.parseInt(tokens[tokenIndex]); + if (port < 0) { + throw getMalFormedUrlException(url); } - } catch (NumberFormatException e) { - // If we have 3 tokens, then the second one must be a port. - // If we only have 2 tokens, the second one might be the root node: - // Assume that is the case if we get a NumberFormatException - if (!tokens[1].startsWith("/")) { - isMalformedUrl = true; + tokenIndex++; // Found port + } catch (NumberFormatException e) { // No port information + if (isMultiPortUrl(tokens[tokenIndex])) { + throw getMalFormedUrlException(url); } - if (i == 2) { - tokens[4] = null; - tokens[3] = null; - tokens[2] = tokens[1]; - tokens[1] = null; - } else if (i == 3) { - tokens[4] = tokens[2]; - tokens[3] = tokens[1]; - tokens[2] = null; - tokens[1] = null; - } else if (i == 4) { - tokens[4] = tokens[3]; - tokens[3] = tokens[2]; - tokens[2] = tokens[1]; - tokens[1] = null; - } else if (i == 5) { - tokens[4] = tokens[3]; - tokens[3] = tokens[2]; - tokens[2] = tokens[1]; + } + if (nTokens > tokenIndex) { + if (tokens[tokenIndex].startsWith("/")) { + rootNode = tokens[tokenIndex++]; // Found rootNode + } + if (nTokens > tokenIndex) { + principal = tokens[tokenIndex++]; // Found principal + if (nTokens > tokenIndex) { + keytabFile = tokens[tokenIndex++]; // Found keytabFile + } } } } } - if (isMalformedUrl) { - throw new SQLExceptionInfo.Builder(SQLExceptionCode.MALFORMED_CONNECTION_URL) - .setMessage(url).build().buildException(); - } - return new ConnectionInfo(tokens[0],port,tokens[2], tokens[3], tokens[4]); + return new ConnectionInfo(quorum,port,rootNode, principal, keytabFile); } public ConnectionInfo normalize(ReadOnlyProps props) throws SQLException { @@ -273,19 +291,17 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni throw new SQLExceptionInfo.Builder(SQLExceptionCode.MALFORMED_CONNECTION_URL) .setMessage("Root node may not be specified when using the connectionless url \"" + this.toString() + "\"").build().buildException(); } + if(principal == null){ + if (!isConnectionless) { + principal = props.get(QueryServices.HBASE_CLIENT_PRINCIPAL); + } + } if(keytab == null){ if (!isConnectionless) { keytab = props.get(QueryServices.HBASE_CLIENT_KEYTAB); } } - if(principal == null){ - if (!isConnectionless) { - principal = props.get(QueryServices.HBASE_CLIENT_PRINCIPAL); - } - } - if (keytab == null || keytab.equals("")) return new ConnectionInfo(zookeeperQuorum, - port, rootNode); - else return new ConnectionInfo(zookeeperQuorum, port, rootNode, keytab, principal); + return new ConnectionInfo(zookeeperQuorum, port, rootNode, principal, keytab); } private final Integer port; @@ -296,7 +312,7 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni private final String keytab; // used for testing - ConnectionInfo(String zookeeperQuorum, Integer port, String rootNode, String keytab, String principal) { + ConnectionInfo(String zookeeperQuorum, Integer port, String rootNode, String principal, String keytab) { this.zookeeperQuorum = zookeeperQuorum; this.port = port; this.rootNode = rootNode; @@ -321,11 +337,9 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni if (getRootNode() != null) { connectionProps.put(QueryServices.ZOOKEEPER_ROOT_NODE_ATTRIB, getRootNode()); } - if (getKeytab() != null) { - connectionProps.put(QueryServices.HBASE_CLIENT_KEYTAB, getKeytab()); - } - if (getPrincipal() != null) { + if (getPrincipal() != null && getKeytab() != null) { connectionProps.put(QueryServices.HBASE_CLIENT_PRINCIPAL, getPrincipal()); + connectionProps.put(QueryServices.HBASE_CLIENT_KEYTAB, getKeytab()); } return connectionProps.isEmpty() ? ReadOnlyProps.EMPTY_PROPS : new ReadOnlyProps( connectionProps.entrySet().iterator()); @@ -362,8 +376,8 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni result = prime * result + ((zookeeperQuorum == null) ? 0 : zookeeperQuorum.hashCode()); result = prime * result + ((port == null) ? 0 : port.hashCode()); result = prime * result + ((rootNode == null) ? 0 : rootNode.hashCode()); + result = prime * result + ((principal == null) ? 0 : principal.hashCode()); result = prime * result + ((keytab == null) ? 0 : keytab.hashCode()); - result = prime * result + ((principal == null) ? 0 : keytab.hashCode()); return result; } @@ -382,12 +396,12 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni if (rootNode == null) { if (other.rootNode != null) return false; } else if (!rootNode.equals(other.rootNode)) return false; - if (keytab == null) { - if (other.keytab != null) return false; - } else if (!keytab.equals(other.keytab)) return false; if (principal == null) { if (other.principal != null) return false; } else if (!principal.equals(other.principal)) return false; + if (keytab == null) { + if (other.keytab != null) return false; + } else if (!keytab.equals(other.keytab)) return false; return true; } @@ -395,8 +409,8 @@ public abstract class PhoenixEmbeddedDriver implements Driver, org.apache.phoeni public String toString() { return zookeeperQuorum + (port == null ? "" : ":" + port) + (rootNode == null ? "" : ":" + rootNode) - + (keytab == null ? "" : ":" + keytab) - + (principal == null ? "" : ":" + principal); + + (principal == null ? "" : ":" + principal) + + (keytab == null ? "" : ":" + keytab); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/BaseQueryServicesImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/BaseQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/BaseQueryServicesImpl.java index 222ea14..f116695 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/BaseQueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/BaseQueryServicesImpl.java @@ -40,7 +40,7 @@ public abstract class BaseQueryServicesImpl implements QueryServices { private final ReadOnlyProps props; private final QueryOptimizer queryOptimizer; - public BaseQueryServicesImpl(QueryServicesOptions options) { + public BaseQueryServicesImpl(ReadOnlyProps defaultProps, QueryServicesOptions options) { this.executor = JobManager.createThreadPoolExec( options.getKeepAliveMs(), options.getThreadPoolSize(), @@ -48,7 +48,7 @@ public abstract class BaseQueryServicesImpl implements QueryServices { this.memoryManager = new GlobalMemoryManager( Runtime.getRuntime().maxMemory() * options.getMaxMemoryPerc() / 100, options.getMaxMemoryWaitMs()); - this.props = options.getProps(); + this.props = options.getProps(defaultProps); this.queryOptimizer = new QueryOptimizer(this); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java index f085464..fd44d6b 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServices.java @@ -103,4 +103,6 @@ public interface ConnectionQueryServices extends QueryServices, MetaDataMutated public enum Feature {REVERSE_SCAN}; public boolean supportsFeature(Feature feature); + + public String getUserName(); } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java index d08108c..cdc7a2a 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionQueryServicesImpl.java @@ -148,6 +148,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement // Copy of config.getProps(), but read-only to prevent synchronization that we // don't need. private final ReadOnlyProps props; + private final String userName; private final ConcurrentHashMap<ImmutableBytesWritable,ConnectionQueryServices> childServices; private final StatsManager statsManager; // Cache the latest meta data here for future connections @@ -192,6 +193,7 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement // set replication required parameter ConfigUtil.setReplicationConfigIfAbsent(this.config); this.props = new ReadOnlyProps(this.config.iterator()); + this.userName = connectionInfo.getPrincipal(); this.latestMetaData = newEmptyMetaData(); // TODO: should we track connection wide memory usage or just org-wide usage? // If connection-wide, create a MemoryManager here, otherwise just use the one from the delegate @@ -1951,4 +1953,9 @@ public class ConnectionQueryServicesImpl extends DelegateQueryServices implement return false; } + @Override + public String getUserName() { + return userName; + } + } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java index 33b846b..22bc271 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/ConnectionlessQueryServicesImpl.java @@ -48,6 +48,7 @@ import org.apache.phoenix.hbase.index.util.GenericKeyValueBuilder; import org.apache.phoenix.hbase.index.util.KeyValueBuilder; import org.apache.phoenix.jdbc.PhoenixConnection; import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver.ConnectionInfo; import org.apache.phoenix.schema.NewerTableAlreadyExistsException; import org.apache.phoenix.schema.PColumn; import org.apache.phoenix.schema.PIndexState; @@ -87,12 +88,14 @@ import com.google.common.collect.Maps; public class ConnectionlessQueryServicesImpl extends DelegateQueryServices implements ConnectionQueryServices { private PMetaData metaData; private final Map<SequenceKey, SequenceInfo> sequenceMap = Maps.newHashMap(); + private final String userName; private KeyValueBuilder kvBuilder; private volatile boolean initialized; private volatile SQLException initializationException; - public ConnectionlessQueryServicesImpl(QueryServices queryServices) { + public ConnectionlessQueryServicesImpl(QueryServices queryServices, ConnectionInfo connInfo) { super(queryServices); + userName = connInfo.getPrincipal(); metaData = newEmptyMetaData(); // Use KeyValueBuilder that builds real KeyValues, as our test utils require this this.kvBuilder = GenericKeyValueBuilder.INSTANCE; @@ -411,4 +414,9 @@ public class ConnectionlessQueryServicesImpl extends DelegateQueryServices imple public boolean supportsFeature(Feature feature) { return false; } + + @Override + public String getUserName() { + return userName; + } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java b/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java index 4fa7993..3c119de 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/DelegateConnectionQueryServices.java @@ -226,4 +226,9 @@ public class DelegateConnectionQueryServices extends DelegateQueryServices imple public boolean supportsFeature(Feature feature) { return getDelegate().supportsFeature(feature); } + + @Override + public String getUserName() { + return getDelegate().getUserName(); + } } \ No newline at end of file http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesImpl.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesImpl.java index beddc46..564da60 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesImpl.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesImpl.java @@ -17,6 +17,8 @@ */ package org.apache.phoenix.query; +import org.apache.phoenix.util.ReadOnlyProps; + @@ -30,7 +32,7 @@ package org.apache.phoenix.query; */ public final class QueryServicesImpl extends BaseQueryServicesImpl { - public QueryServicesImpl() { - super(QueryServicesOptions.withDefaults()); + public QueryServicesImpl(ReadOnlyProps defaultProps) { + super(defaultProps, QueryServicesOptions.withDefaults()); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java index 33ee94c..95269a1 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/query/QueryServicesOptions.java @@ -131,14 +131,14 @@ public class QueryServicesOptions { this.config = config; } - public ReadOnlyProps getProps() { + public ReadOnlyProps getProps(ReadOnlyProps defaultProps) { // Ensure that HBase RPC time out value is at least as large as our thread time out for query. int threadTimeOutMS = config.getInt(THREAD_TIMEOUT_MS_ATTRIB, DEFAULT_THREAD_TIMEOUT_MS); int hbaseRPCTimeOut = config.getInt(HConstants.HBASE_RPC_TIMEOUT_KEY, HConstants.DEFAULT_HBASE_RPC_TIMEOUT); if (threadTimeOutMS > hbaseRPCTimeOut) { config.setInt(HConstants.HBASE_RPC_TIMEOUT_KEY, threadTimeOutMS); } - return new ReadOnlyProps(config.iterator()); + return new ReadOnlyProps(defaultProps, config.iterator()); } public QueryServicesOptions setAll(ReadOnlyProps props) { http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/main/java/org/apache/phoenix/util/ReadOnlyProps.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/main/java/org/apache/phoenix/util/ReadOnlyProps.java b/phoenix-core/src/main/java/org/apache/phoenix/util/ReadOnlyProps.java index 19bc5f3..fe039d3 100644 --- a/phoenix-core/src/main/java/org/apache/phoenix/util/ReadOnlyProps.java +++ b/phoenix-core/src/main/java/org/apache/phoenix/util/ReadOnlyProps.java @@ -18,12 +18,15 @@ package org.apache.phoenix.util; -import java.util.*; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; import java.util.Map.Entry; import java.util.regex.Matcher; import java.util.regex.Pattern; -import com.google.common.collect.*; +import com.google.common.collect.ImmutableMap; /** * @@ -34,11 +37,11 @@ import com.google.common.collect.*; * @since 1.2.2 */ public class ReadOnlyProps implements Iterable<Entry<String, String>> { - public static final ReadOnlyProps EMPTY_PROPS = new ReadOnlyProps(Iterators.<Entry<String, String>>emptyIterator()); + public static final ReadOnlyProps EMPTY_PROPS = new ReadOnlyProps(); private final Map<String, String> props; - public ReadOnlyProps(Iterator<Entry<String, String>> iterator) { - Map<String, String> map = Maps.newHashMap(); + public ReadOnlyProps(ReadOnlyProps defaultProps, Iterator<Entry<String, String>> iterator) { + Map<String, String> map = new HashMap<String,String>(defaultProps.asMap()); while (iterator.hasNext()) { Entry<String,String> entry = iterator.next(); map.put(entry.getKey(), entry.getValue()); @@ -46,6 +49,14 @@ public class ReadOnlyProps implements Iterable<Entry<String, String>> { this.props = ImmutableMap.copyOf(map); } + public ReadOnlyProps(Iterator<Entry<String, String>> iterator) { + this(EMPTY_PROPS, iterator); + } + + private ReadOnlyProps() { + this.props = Collections.emptyMap(); + } + public ReadOnlyProps(Map<String, String> props) { this.props = ImmutableMap.copyOf(props); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java index a9b09e5..79f9ec6 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixEmbeddedDriverTest.java @@ -18,14 +18,17 @@ package org.apache.phoenix.jdbc; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; -import java.sql.*; - -import org.junit.Test; +import java.sql.Driver; +import java.sql.DriverManager; +import java.sql.SQLException; import org.apache.phoenix.exception.SQLExceptionCode; import org.apache.phoenix.jdbc.PhoenixEmbeddedDriver.ConnectionInfo; +import org.junit.Test; public class PhoenixEmbeddedDriverTest { @Test @@ -47,10 +50,12 @@ public class PhoenixEmbeddedDriverTest { "jdbc:phoenix:v1,v2,v3:/hbase;test=true", "jdbc:phoenix:v1,v2,v3:123:/hbase", "jdbc:phoenix:v1,v2,v3:123:/hbase;test=false", - "jdbc:phoenix:v1,v2,v3:123:/hbase:/user.keytab:user/principal;test=false", - "jdbc:phoenix:v1,v2,v3:123:/user.keytab:user/principal;test=false", - "jdbc:phoenix:v1,v2,v3:/user.keytab:user/principal;test=false", - "jdbc:phoenix:v1,v2,v3:/hbase:/user.keytab:user/principal;test=false" + "jdbc:phoenix:v1,v2,v3:123:/hbase:user/principal:/user.keytab;test=false", + "jdbc:phoenix:v1,v2,v3:123:user/principal:/user.keytab;test=false", + "jdbc:phoenix:v1,v2,v3:user/principal:/user.keytab;test=false", + "jdbc:phoenix:v1,v2,v3:/hbase:user/principal:/user.keytab;test=false", + "jdbc:phoenix:v1,v2,v3:LongRunningQueries;test=false", + "jdbc:phoenix:v1,v2,v3:345:LongRunningQueries;test=false", }; ConnectionInfo[] infos = new ConnectionInfo[] { new ConnectionInfo(null,null,null), @@ -69,10 +74,12 @@ public class PhoenixEmbeddedDriverTest { new ConnectionInfo("v1,v2,v3",null,"/hbase"), new ConnectionInfo("v1,v2,v3",123,"/hbase"), new ConnectionInfo("v1,v2,v3",123,"/hbase"), - new ConnectionInfo("v1,v2,v3",123,"/hbase", "/user.keytab","user/principal" ), - new ConnectionInfo("v1,v2,v3",123, null, "/user.keytab","user/principal" ), - new ConnectionInfo("v1,v2,v3", null, null, "/user.keytab","user/principal" ), - new ConnectionInfo("v1,v2,v3",null,"/hbase", "/user.keytab","user/principal" ) + new ConnectionInfo("v1,v2,v3",123,"/hbase","user/principal", "/user.keytab" ), + new ConnectionInfo("v1,v2,v3",123, null,"user/principal", "/user.keytab" ), + new ConnectionInfo("v1,v2,v3", null, null,"user/principal", "/user.keytab" ), + new ConnectionInfo("v1,v2,v3",null,"/hbase","user/principal", "/user.keytab" ), + new ConnectionInfo("v1,v2,v3",null,null,"LongRunningQueries", null ), + new ConnectionInfo("v1,v2,v3",345,null,"LongRunningQueries", null ), }; assertEquals(urls.length,infos.length); for (int i = 0; i < urls.length; i++) { @@ -89,18 +96,12 @@ public class PhoenixEmbeddedDriverTest { String[] urls = new String[] { "jdbc:phoenix::", "jdbc:phoenix:;", - "jdbc:phoenix:localhost:abc:/hbase", - "jdbc:phoenix:localhost:abc:/hbase;foo=bar", - "jdbc:phoenix:localhost:123:/hbase:blah", - "jdbc:phoenix:localhost:123:/hbase:blah;foo=bas", "jdbc:phoenix:v1:1,v2:2,v3:3", "jdbc:phoenix:v1:1,v2:2,v3:3;test=true", "jdbc:phoenix:v1,v2,v3:-1:/hbase;test=true", "jdbc:phoenix:v1,v2,v3:-1", - "jdbc:phoenix:v1,v2,v3:123a:/hbase;test=true", "jdbc:phoenix:v1,v2,v3:123::/hbase", "jdbc:phoenix:v1,v2,v3:123::/hbase;test=false", - "jdbc:phoenix:v1,v2,v3:123:/hbase:user;test=false" }; for (String url : urls) { try { http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixTestDriver.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixTestDriver.java b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixTestDriver.java index 1184fdf..2423344 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixTestDriver.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/jdbc/PhoenixTestDriver.java @@ -56,13 +56,13 @@ public class PhoenixTestDriver extends PhoenixEmbeddedDriver { public PhoenixTestDriver() { this.overrideProps = ReadOnlyProps.EMPTY_PROPS; - queryServices = new QueryServicesTestImpl(); + queryServices = new QueryServicesTestImpl(getDefaultProps()); } // For tests to override the default configuration public PhoenixTestDriver(ReadOnlyProps props) { overrideProps = props; - queryServices = new QueryServicesTestImpl(overrideProps); + queryServices = new QueryServicesTestImpl(getDefaultProps(),overrideProps); } @Override @@ -84,7 +84,7 @@ public class PhoenixTestDriver extends PhoenixEmbeddedDriver { if (connectionQueryServices != null) { return connectionQueryServices; } ConnectionInfo connInfo = ConnectionInfo.create(url); if (connInfo.isConnectionless()) { - connectionQueryServices = new ConnectionlessQueryServicesImpl(queryServices); + connectionQueryServices = new ConnectionlessQueryServicesImpl(queryServices, connInfo); } else { connectionQueryServices = new ConnectionQueryServicesTestImpl(queryServices, connInfo); } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java b/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java index 9a065d8..90f3490 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/query/BaseTest.java @@ -519,8 +519,8 @@ public abstract class BaseTest { private static void setDefaultTestConfig(Configuration conf) { ConfigUtil.setReplicationConfigIfAbsent(conf); - QueryServicesOptions options = QueryServicesTestImpl.getDefaultTestServicesOptions(); - for (Entry<String,String> entry : options.getProps()) { + 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. http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessTest.java b/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessTest.java new file mode 100644 index 0000000..e94da6d --- /dev/null +++ b/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessTest.java @@ -0,0 +1,220 @@ +/* + * 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.junit.Assert.assertArrayEquals; +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.Date; +import java.sql.DriverManager; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; + +import org.apache.hadoop.hbase.KeyValue; +import org.apache.hadoop.hbase.util.Bytes; +import org.apache.hadoop.hbase.util.Pair; +import org.apache.phoenix.exception.SQLExceptionCode; +import org.apache.phoenix.jdbc.PhoenixConnection; +import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; +import org.apache.phoenix.jdbc.PhoenixDriver; +import org.apache.phoenix.schema.PDataType; +import org.apache.phoenix.schema.SaltingUtil; +import org.apache.phoenix.util.ByteUtil; +import org.apache.phoenix.util.PhoenixRuntime; +import org.apache.phoenix.util.StringUtil; +import org.junit.BeforeClass; +import org.junit.Test; + + +public class ConnectionlessTest { + private static final int saltBuckets = 200; + private static final String orgId = "00D300000000XHP"; + private static final String keyPrefix1 = "111"; + private static final String keyPrefix2 = "112"; + private static final String entityHistoryId1 = "123456789012"; + private static final String entityHistoryId2 = "987654321098"; + private static final String name1 = "Eli"; + private static final String name2 = "Simon"; + private static final Date now = new Date(System.currentTimeMillis()); + private static final byte[] unsaltedRowKey1 = ByteUtil.concat( + PDataType.CHAR.toBytes(orgId),PDataType.CHAR.toBytes(keyPrefix1),PDataType.CHAR.toBytes(entityHistoryId1)); + private static final byte[] unsaltedRowKey2 = ByteUtil.concat( + PDataType.CHAR.toBytes(orgId),PDataType.CHAR.toBytes(keyPrefix2),PDataType.CHAR.toBytes(entityHistoryId2)); + private static final byte[] saltedRowKey1 = ByteUtil.concat( + new byte[] {SaltingUtil.getSaltingByte(unsaltedRowKey1, 0, unsaltedRowKey1.length, saltBuckets)}, + unsaltedRowKey1); + private static final byte[] saltedRowKey2 = ByteUtil.concat( + new byte[] {SaltingUtil.getSaltingByte(unsaltedRowKey2, 0, unsaltedRowKey2.length, saltBuckets)}, + unsaltedRowKey2); + + private static String getUrl() { + return PhoenixRuntime.JDBC_PROTOCOL + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + PhoenixRuntime.CONNECTIONLESS; + } + + @BeforeClass + public static void verifyDriverRegistered() throws SQLException { + assertTrue(DriverManager.getDriver(getUrl()) == PhoenixDriver.INSTANCE); + } + + @Test + public void testConnectionlessUpsert() throws Exception { + testConnectionlessUpsert(null); + } + + @Test + public void testSaltedConnectionlessUpsert() throws Exception { + testConnectionlessUpsert(saltBuckets); + } + + private void testConnectionlessUpsert(Integer saltBuckets) throws Exception { + String dmlStmt = "create table core.entity_history(\n" + + " organization_id char(15) not null, \n" + + " key_prefix char(3) not null,\n" + + " entity_history_id char(12) not null,\n" + + " created_by varchar,\n" + + " created_date date\n" + + " CONSTRAINT pk PRIMARY KEY (organization_id, key_prefix, entity_history_id) ) " + + (saltBuckets == null ? "" : (PhoenixDatabaseMetaData.SALT_BUCKETS + "=" + saltBuckets)); + Properties props = new Properties(); + Connection conn = DriverManager.getConnection(getUrl(), props); + PreparedStatement statement = conn.prepareStatement(dmlStmt); + statement.execute(); + + String upsertStmt = "upsert into core.entity_history(organization_id,key_prefix,entity_history_id, created_by, created_date)\n" + + "values(?,?,?,?,?)"; + statement = conn.prepareStatement(upsertStmt); + statement.setString(1, orgId); + statement.setString(2, keyPrefix2); + statement.setString(3, entityHistoryId2); + statement.setString(4, name2); + statement.setDate(5,now); + statement.execute(); + statement.setString(1, orgId); + statement.setString(2, keyPrefix1); + statement.setString(3, entityHistoryId1); + statement.setString(4, name1); + statement.setDate(5,now); + statement.execute(); + + Iterator<Pair<byte[],List<KeyValue>>> dataIterator = PhoenixRuntime.getUncommittedDataIterator(conn); + Iterator<KeyValue> iterator = dataIterator.next().getSecond().iterator(); + + byte[] expectedRowKey1 = saltBuckets == null ? unsaltedRowKey1 : saltedRowKey1; + byte[] expectedRowKey2 = saltBuckets == null ? unsaltedRowKey2 : saltedRowKey2; + if (Bytes.compareTo(expectedRowKey1, expectedRowKey2) < 0) { + assertRow1(iterator, expectedRowKey1); + assertRow2(iterator, expectedRowKey2); + } else { + assertRow2(iterator, expectedRowKey2); + assertRow1(iterator, expectedRowKey1); + } + + assertFalse(iterator.hasNext()); + assertFalse(dataIterator.hasNext()); + conn.rollback(); // to clear the list of mutations for the next + } + + @SuppressWarnings("deprecation") + private static void assertRow1(Iterator<KeyValue> iterator, byte[] expectedRowKey1) { + KeyValue kv; + assertTrue(iterator.hasNext()); + kv = iterator.next(); + assertArrayEquals(expectedRowKey1, kv.getRow()); + assertEquals(name1, PDataType.VARCHAR.toObject(kv.getValue())); + assertTrue(iterator.hasNext()); + kv = iterator.next(); + assertArrayEquals(expectedRowKey1, kv.getRow()); + assertEquals(now, PDataType.DATE.toObject(kv.getValue())); + assertTrue(iterator.hasNext()); + kv = iterator.next(); + assertArrayEquals(expectedRowKey1, kv.getRow()); + assertNull(PDataType.VARCHAR.toObject(kv.getValue())); + } + + @SuppressWarnings("deprecation") + private static void assertRow2(Iterator<KeyValue> iterator, byte[] expectedRowKey2) { + KeyValue kv; + assertTrue(iterator.hasNext()); + kv = iterator.next(); + assertArrayEquals(expectedRowKey2, kv.getRow()); + assertEquals(name2, PDataType.VARCHAR.toObject(kv.getValue())); + assertTrue(iterator.hasNext()); + kv = iterator.next(); + assertArrayEquals(expectedRowKey2, kv.getRow()); + assertEquals(now, PDataType.DATE.toObject(kv.getValue())); + assertTrue(iterator.hasNext()); + kv = iterator.next(); + assertArrayEquals(expectedRowKey2, kv.getRow()); + assertNull(PDataType.VARCHAR.toObject(kv.getValue())); + } + + @Test + public void testNoConnectionInfo() throws Exception { + try { + DriverManager.getConnection(PhoenixRuntime.JDBC_PROTOCOL); + fail(); + } catch (SQLException e) { + assertEquals(SQLExceptionCode.MALFORMED_CONNECTION_URL.getSQLState(),e.getSQLState()); + } + } + + @Test + public void testMultipleConnectionQueryServices() throws Exception { + String url1 = getUrl(); + String url2 = url1 + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + "LongRunningQueries"; + Connection conn1 = DriverManager.getConnection(url1); + try { + assertEquals(StringUtil.EMPTY_STRING, conn1.getMetaData().getUserName()); + Connection conn2 = DriverManager.getConnection(url2); + try { + assertEquals("LongRunningQueries", conn2.getMetaData().getUserName()); + ConnectionQueryServices cqs1 = conn1.unwrap(PhoenixConnection.class).getQueryServices(); + ConnectionQueryServices cqs2 = conn2.unwrap(PhoenixConnection.class).getQueryServices(); + assertTrue(cqs1 != cqs2); + Connection conn3 = DriverManager.getConnection(url1); + try { + ConnectionQueryServices cqs3 = conn3.unwrap(PhoenixConnection.class).getQueryServices(); + assertTrue(cqs1 == cqs3); + Connection conn4 = DriverManager.getConnection(url2); + try { + ConnectionQueryServices cqs4 = conn4.unwrap(PhoenixConnection.class).getQueryServices(); + assertTrue(cqs2 == cqs4); + } finally { + conn4.close(); + } + } finally { + conn3.close(); + } + } finally { + conn2.close(); + } + } finally { + conn1.close(); + } + + } + +} http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessUpsertTest.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessUpsertTest.java b/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessUpsertTest.java deleted file mode 100644 index 89ed891..0000000 --- a/phoenix-core/src/test/java/org/apache/phoenix/query/ConnectionlessUpsertTest.java +++ /dev/null @@ -1,183 +0,0 @@ -/* - * 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.junit.Assert.assertArrayEquals; -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.Date; -import java.sql.DriverManager; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.Iterator; -import java.util.List; -import java.util.Properties; - -import org.apache.hadoop.hbase.KeyValue; -import org.apache.hadoop.hbase.util.Bytes; -import org.apache.hadoop.hbase.util.Pair; -import org.apache.phoenix.exception.SQLExceptionCode; -import org.apache.phoenix.jdbc.PhoenixDatabaseMetaData; -import org.apache.phoenix.jdbc.PhoenixDriver; -import org.apache.phoenix.schema.PDataType; -import org.apache.phoenix.schema.SaltingUtil; -import org.apache.phoenix.util.ByteUtil; -import org.apache.phoenix.util.PhoenixRuntime; -import org.junit.BeforeClass; -import org.junit.Test; - - -public class ConnectionlessUpsertTest { - private static final int saltBuckets = 200; - private static final String orgId = "00D300000000XHP"; - private static final String keyPrefix1 = "111"; - private static final String keyPrefix2 = "112"; - private static final String entityHistoryId1 = "123456789012"; - private static final String entityHistoryId2 = "987654321098"; - private static final String name1 = "Eli"; - private static final String name2 = "Simon"; - private static final Date now = new Date(System.currentTimeMillis()); - private static final byte[] unsaltedRowKey1 = ByteUtil.concat( - PDataType.CHAR.toBytes(orgId),PDataType.CHAR.toBytes(keyPrefix1),PDataType.CHAR.toBytes(entityHistoryId1)); - private static final byte[] unsaltedRowKey2 = ByteUtil.concat( - PDataType.CHAR.toBytes(orgId),PDataType.CHAR.toBytes(keyPrefix2),PDataType.CHAR.toBytes(entityHistoryId2)); - private static final byte[] saltedRowKey1 = ByteUtil.concat( - new byte[] {SaltingUtil.getSaltingByte(unsaltedRowKey1, 0, unsaltedRowKey1.length, saltBuckets)}, - unsaltedRowKey1); - private static final byte[] saltedRowKey2 = ByteUtil.concat( - new byte[] {SaltingUtil.getSaltingByte(unsaltedRowKey2, 0, unsaltedRowKey2.length, saltBuckets)}, - unsaltedRowKey2); - - private static String getUrl() { - return PhoenixRuntime.JDBC_PROTOCOL + PhoenixRuntime.JDBC_PROTOCOL_SEPARATOR + PhoenixRuntime.CONNECTIONLESS; - } - - @BeforeClass - public static void verifyDriverRegistered() throws SQLException { - assertTrue(DriverManager.getDriver(getUrl()) == PhoenixDriver.INSTANCE); - } - - @Test - public void testConnectionlessUpsert() throws Exception { - testConnectionlessUpsert(null); - } - - @Test - public void testSaltedConnectionlessUpsert() throws Exception { - testConnectionlessUpsert(saltBuckets); - } - - public void testConnectionlessUpsert(Integer saltBuckets) throws Exception { - String dmlStmt = "create table core.entity_history(\n" + - " organization_id char(15) not null, \n" + - " key_prefix char(3) not null,\n" + - " entity_history_id char(12) not null,\n" + - " created_by varchar,\n" + - " created_date date\n" + - " CONSTRAINT pk PRIMARY KEY (organization_id, key_prefix, entity_history_id) ) " + - (saltBuckets == null ? "" : (PhoenixDatabaseMetaData.SALT_BUCKETS + "=" + saltBuckets)); - Properties props = new Properties(); - Connection conn = DriverManager.getConnection(getUrl(), props); - PreparedStatement statement = conn.prepareStatement(dmlStmt); - statement.execute(); - - String upsertStmt = "upsert into core.entity_history(organization_id,key_prefix,entity_history_id, created_by, created_date)\n" + - "values(?,?,?,?,?)"; - statement = conn.prepareStatement(upsertStmt); - statement.setString(1, orgId); - statement.setString(2, keyPrefix2); - statement.setString(3, entityHistoryId2); - statement.setString(4, name2); - statement.setDate(5,now); - statement.execute(); - statement.setString(1, orgId); - statement.setString(2, keyPrefix1); - statement.setString(3, entityHistoryId1); - statement.setString(4, name1); - statement.setDate(5,now); - statement.execute(); - - Iterator<Pair<byte[],List<KeyValue>>> dataIterator = PhoenixRuntime.getUncommittedDataIterator(conn); - Iterator<KeyValue> iterator = dataIterator.next().getSecond().iterator(); - - byte[] expectedRowKey1 = saltBuckets == null ? unsaltedRowKey1 : saltedRowKey1; - byte[] expectedRowKey2 = saltBuckets == null ? unsaltedRowKey2 : saltedRowKey2; - if (Bytes.compareTo(expectedRowKey1, expectedRowKey2) < 0) { - assertRow1(iterator, expectedRowKey1); - assertRow2(iterator, expectedRowKey2); - } else { - assertRow2(iterator, expectedRowKey2); - assertRow1(iterator, expectedRowKey1); - } - - assertFalse(iterator.hasNext()); - assertFalse(dataIterator.hasNext()); - conn.rollback(); // to clear the list of mutations for the next - } - - @SuppressWarnings("deprecation") - private static void assertRow1(Iterator<KeyValue> iterator, byte[] expectedRowKey1) { - KeyValue kv; - assertTrue(iterator.hasNext()); - kv = iterator.next(); - assertArrayEquals(expectedRowKey1, kv.getRow()); - assertEquals(name1, PDataType.VARCHAR.toObject(kv.getValue())); - assertTrue(iterator.hasNext()); - kv = iterator.next(); - assertArrayEquals(expectedRowKey1, kv.getRow()); - assertEquals(now, PDataType.DATE.toObject(kv.getValue())); - assertTrue(iterator.hasNext()); - kv = iterator.next(); - assertArrayEquals(expectedRowKey1, kv.getRow()); - assertNull(PDataType.VARCHAR.toObject(kv.getValue())); - } - - @SuppressWarnings("deprecation") - private static void assertRow2(Iterator<KeyValue> iterator, byte[] expectedRowKey2) { - KeyValue kv; - assertTrue(iterator.hasNext()); - kv = iterator.next(); - assertArrayEquals(expectedRowKey2, kv.getRow()); - assertEquals(name2, PDataType.VARCHAR.toObject(kv.getValue())); - assertTrue(iterator.hasNext()); - kv = iterator.next(); - assertArrayEquals(expectedRowKey2, kv.getRow()); - assertEquals(now, PDataType.DATE.toObject(kv.getValue())); - assertTrue(iterator.hasNext()); - kv = iterator.next(); - assertArrayEquals(expectedRowKey2, kv.getRow()); - assertNull(PDataType.VARCHAR.toObject(kv.getValue())); - } - - @Test - public void testNoConnectionInfo() throws Exception { - try { - DriverManager.getConnection(PhoenixRuntime.JDBC_PROTOCOL); - fail(); - } catch (SQLException e) { - assertEquals(SQLExceptionCode.MALFORMED_CONNECTION_URL.getSQLState(),e.getSQLState()); - } - } - - -} http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java ---------------------------------------------------------------------- diff --git a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java index 72e7aef..e125755 100644 --- a/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java +++ b/phoenix-core/src/test/java/org/apache/phoenix/query/QueryServicesTestImpl.java @@ -53,11 +53,11 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl { public static final long DEFAULT_MAX_SERVER_METADATA_CACHE_SIZE = 1024L*1024L*4L; // 4 Mb public static final long DEFAULT_MAX_CLIENT_METADATA_CACHE_SIZE = 1024L*1024L*2L; // 2 Mb - public QueryServicesTestImpl() { - this(ReadOnlyProps.EMPTY_PROPS); + public QueryServicesTestImpl(ReadOnlyProps defaultProps) { + this(defaultProps, ReadOnlyProps.EMPTY_PROPS); } - public static QueryServicesOptions getDefaultTestServicesOptions() { + private static QueryServicesOptions getDefaultServicesOptions() { return withDefaults() .setThreadPoolSize(DEFAULT_THREAD_POOL_SIZE) .setQueueSize(DEFAULT_QUEUE_SIZE) @@ -81,7 +81,7 @@ public final class QueryServicesTestImpl extends BaseQueryServicesImpl { .setMaxServerMetaDataCacheSize(DEFAULT_MAX_SERVER_METADATA_CACHE_SIZE); } - public QueryServicesTestImpl(ReadOnlyProps overrideProps) { - super(getDefaultTestServicesOptions().setAll(overrideProps)); + public QueryServicesTestImpl(ReadOnlyProps defaultProps, ReadOnlyProps overrideProps) { + super(defaultProps, getDefaultServicesOptions().setAll(overrideProps)); } } http://git-wip-us.apache.org/repos/asf/phoenix/blob/57189d4d/pom.xml ---------------------------------------------------------------------- diff --git a/pom.xml b/pom.xml index 1e92940..6802d3a 100644 --- a/pom.xml +++ b/pom.xml @@ -112,10 +112,10 @@ <maven-dependency-plugin.version>2.1</maven-dependency-plugin.version> <maven.assembly.version>2.4</maven.assembly.version> <maven.rat.version>0.8</maven.rat.version> - - <!-- Plugin options --> - <numForkedIT>3</numForkedIT> + + <!-- Plugin options --> <numForkedUT>3</numForkedUT> + <numForkedIT>7</numForkedIT> <!-- Set default encoding so multi-byte tests work correctly on the Mac --> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>