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>

Reply via email to