This is an automated email from the ASF dual-hosted git repository.

stoty pushed a commit to branch 5.2
in repository https://gitbox.apache.org/repos/asf/phoenix.git


The following commit(s) were added to refs/heads/5.2 by this push:
     new 5314a8a4a4 PHOENIX-7186 Support Square Brackets Notation for IPv6 in 
JDBC URL (#2107)
5314a8a4a4 is described below

commit 5314a8a4a4180b46deec610d72374fc252d243a8
Author: Norbert Meszaros <meszinorbi2...@gmail.com>
AuthorDate: Tue Apr 15 10:17:11 2025 +0200

    PHOENIX-7186 Support Square Brackets Notation for IPv6 in JDBC URL (#2107)
---
 .../org/apache/phoenix/jdbc/ConnectionInfo.java    |  22 ++++-
 .../phoenix/jdbc/PhoenixEmbeddedDriverTest.java    | 100 +++++++++++++++++++++
 2 files changed, 120 insertions(+), 2 deletions(-)

diff --git 
a/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/ConnectionInfo.java 
b/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/ConnectionInfo.java
index faaa9841ec..4c0c4fefb6 100644
--- 
a/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/ConnectionInfo.java
+++ 
b/phoenix-core-client/src/main/java/org/apache/phoenix/jdbc/ConnectionInfo.java
@@ -25,6 +25,8 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.Properties;
 import java.util.StringTokenizer;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 
 import org.apache.hadoop.conf.Configuration;
 import org.apache.hadoop.hbase.security.User;
@@ -116,6 +118,20 @@ public abstract class ConnectionInfo {
         return escaped.replaceAll("\\\\:", "=");
     }
 
+    protected static String escapeIPv6Literals(String unescaped) {
+        String regex = "(\\[.*?\\])";
+        Pattern pattern = Pattern.compile(regex);
+        Matcher matcher = pattern.matcher(unescaped);
+        StringBuffer result = new StringBuffer();
+        while (matcher.find()) {
+            String matchedText = matcher.group(1);
+            String modifiedText = matchedText.replace(":", "~");
+            matcher.appendReplacement(result, modifiedText);
+        }
+        matcher.appendTail(result);
+        return result.toString();
+    }
+
     public static ConnectionInfo createNoLogin(String url, ReadOnlyProps 
props, Properties info)
             throws SQLException {
         return create(url, getCachedConfiguration(), props, info, true);
@@ -140,7 +156,8 @@ public abstract class ConnectionInfo {
             ReadOnlyProps props, Properties info, boolean doNotLogin) throws 
SQLException {
         // registry-independent URL preprocessing
         url = url == null ? "" : url;
-        url = unescape(url);
+        boolean isIPv6 = url.contains("[") && url.contains("]");
+        url = isIPv6 ? unescape(escapeIPv6Literals(url)) : unescape(url);
 
         // Assume missing prefix
         if (url.isEmpty()) {
@@ -509,10 +526,11 @@ public abstract class ConnectionInfo {
             String[] normalizedParts = new String[quorumParts.length];
             for (int i = 0; i < quorumParts.length; i++) {
                 String[] hostAndPort = quorumParts[i].trim().split(":");
+                hostAndPort[0] = hostAndPort[0].replace('~', ':');
                 if (hostAndPort.length == 1) {
                     normalizedParts[i] = hostAndPort[0].trim().toLowerCase() + 
":" + defaultPort;
                 } else if (hostAndPort.length == 2) {
-                    normalizedParts[i] = quorumParts[i].trim().toLowerCase();
+                    normalizedParts[i] = String.join(":", 
hostAndPort).trim().toLowerCase();
                 } else {
                     throw getMalFormedUrlException(url);
                 }
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 cf41c1a45f..27b40754b0 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
@@ -566,6 +566,106 @@ public class PhoenixEmbeddedDriverTest {
         assertFalse(ConnectionInfo.isSameName("user/foo...@apache.net", 
"user/_HOST", "foobar", "APACHE.ORG"));
     }
 
+    @Test
+    public void testMasterIPv6() throws SQLException {
+        assumeTrue(VersionInfo.compareVersion(VersionInfo.getVersion(), 
"2.3.0") >= 0);
+        try {
+            Configuration config =
+                    
HBaseFactoryProvider.getConfigurationFactory().getConfiguration();
+            config.set("hbase.client.registry.impl",
+                    "org.apache.hadoop.hbase.client.MasterRegistry");
+            ConnectionInfo.create("jdbc:phoenix+master", config, null, null);
+            fail("Should have thrown exception");
+        } catch (SQLException e) {
+        }
+
+        Configuration config = 
HBaseFactoryProvider.getConfigurationFactory().getConfiguration();
+        config.set("hbase.client.registry.impl", 
"org.apache.hadoop.hbase.client.MasterRegistry");
+        config.set("hbase.master.port", "17000");
+        MasterConnectionInfo info =
+                (MasterConnectionInfo) ConnectionInfo.create(
+                        "jdbc:phoenix+master:[::1],[\\:\\:2]", config, null, 
null);
+        assertEquals(info.getBoostrapServers(), "[::1]:17000,[::2]:17000");
+
+        config = 
HBaseFactoryProvider.getConfigurationFactory().getConfiguration();
+        config.set("hbase.client.registry.impl", 
"org.apache.hadoop.hbase.client.MasterRegistry");
+        info =
+                (MasterConnectionInfo) ConnectionInfo.create(
+                        "jdbc:phoenix+master:[::1]\\:123,[\\:\\:2]\\:234", 
config, null, null);
+        assertEquals(info.getBoostrapServers(), "[::1]:123,[::2]:234");
+    }
+
+    @Test
+    public void testRPCIPv6() throws SQLException{
+        Configuration config = 
HBaseFactoryProvider.getConfigurationFactory().getConfiguration();
+        config.set("hbase.client.registry.impl",
+                "org.apache.hadoop.hbase.client.RpcConnectionRegistry");
+        RPCConnectionInfo info =
+                (RPCConnectionInfo) ConnectionInfo.create(
+                        "jdbc:phoenix+rpc:[::1]\\:123,[\\:\\:2]\\::234", 
config,
+                        null, null);
+        assertEquals("[::1]:123,[::2]:234", info.getBoostrapServers());
+    }
+
+    @Test
+    public void testZkIPv6() throws Exception {
+        ConnectionInfo connectionInfo = 
ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[::1],127.23.45.678\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        ReadOnlyProps props = connectionInfo.asProps();
+        assertEquals("127.23.45.678:7634,[::1]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[::1]\\:2181,127.23.45.678\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        assertEquals("127.23.45.678:7634,[::1]:2181,host123.48576:723,v3:1",
+
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[fe:80::],127.23.45.678\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        
assertEquals("127.23.45.678:7634,[fe:80::]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[fe:80::]\\:2181,127.23.45.678\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        
assertEquals("127.23.45.678:7634,[fe:80::]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[fe\\:80\\:\\:],127.23.45.678\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        
assertEquals("127.23.45.678:7634,[fe:80::]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[fe\\:80\\:\\:]\\:2181,127.23.45.678\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        
assertEquals("127.23.45.678:7634,[fe:80::]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[fe:80::2]\\:2181,[2001:db8:3c4d:15::1a2f:1a2b]\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        
assertEquals("[2001:db8:3c4d:15::1a2f:1a2b]:7634,[fe:80::2]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+
+        connectionInfo = ConnectionInfo.create("jdbc:phoenix+zk:"
+                + 
"[fe:80::2]\\:2181,[2001\\:db8\\:3c4d\\:15\\:\\:1a2f\\:1a2b]\\:7634,v3\\:1,host123.48576\\:723:/hbase;"
+                + "test=true", null, null);
+        props = connectionInfo.asProps();
+        
assertEquals("[2001:db8:3c4d:15::1a2f:1a2b]:7634,[fe:80::2]:2181,host123.48576:723,v3:1",
+                props.get(HConstants.ZOOKEEPER_QUORUM));
+    }
+
     @Test
     public void testZkQuorumConfigs() throws Exception {
         ConnectionInfo connectionInfo = 
ConnectionInfo.create("jdbc:phoenix+zk:"

Reply via email to